402 lines
10 KiB
C++
402 lines
10 KiB
C++
|
#include "HttpClient.h"
|
|||
|
#include "http_common.h"
|
|||
|
inline void CloseInternetHandle(HINTERNET* hInternet)
|
|||
|
{
|
|||
|
if (*hInternet)
|
|||
|
{
|
|||
|
WinHttpCloseHandle(*hInternet);
|
|||
|
*hInternet = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
HttpClient::HttpClient(void)
|
|||
|
: m_hInternet(NULL)
|
|||
|
, m_hConnect(NULL)
|
|||
|
, m_hRequest(NULL)
|
|||
|
, m_nConnTimeout(500000)
|
|||
|
, m_nSendTimeout(500000)
|
|||
|
, m_nRecvTimeout(500000)
|
|||
|
, m_bHttps(false)
|
|||
|
, m_nResponseCode(0)
|
|||
|
{
|
|||
|
memset(&m_paramsData, 0, sizeof(HttpParamsData));
|
|||
|
Init();
|
|||
|
}
|
|||
|
|
|||
|
HttpClient::~HttpClient(void)
|
|||
|
{
|
|||
|
Release();
|
|||
|
}
|
|||
|
|
|||
|
bool HttpClient::Init()
|
|||
|
{
|
|||
|
m_hInternet = ::WinHttpOpen(
|
|||
|
L"Microsoft Internet Explorer",
|
|||
|
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
|
|||
|
WINHTTP_NO_PROXY_NAME,
|
|||
|
WINHTTP_NO_PROXY_BYPASS,
|
|||
|
0);
|
|||
|
if (NULL == m_hInternet)
|
|||
|
{
|
|||
|
m_paramsData.errcode = HttpErrorInit;
|
|||
|
return false;
|
|||
|
}
|
|||
|
::WinHttpSetTimeouts(m_hInternet, 0, m_nConnTimeout, m_nSendTimeout, m_nRecvTimeout);
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
void HttpClient::Release()
|
|||
|
{
|
|||
|
CloseInternetHandle(&m_hRequest);
|
|||
|
CloseInternetHandle(&m_hConnect);
|
|||
|
CloseInternetHandle(&m_hInternet);
|
|||
|
}
|
|||
|
|
|||
|
bool HttpClient::ConnectHttpServer(LPCWSTR lpIP, WORD wPort)
|
|||
|
{
|
|||
|
m_hConnect = ::WinHttpConnect(m_hInternet, lpIP, wPort, 0);
|
|||
|
return m_hConnect != NULL;
|
|||
|
}
|
|||
|
|
|||
|
bool HttpClient::CreateHttpRequest(LPCWSTR lpPage, HttpRequestType type, DWORD dwFlag/*=0*/)
|
|||
|
{
|
|||
|
const wchar_t* pVerb = (type == HttpGet) ? L"GET" : L"POST";
|
|||
|
m_hRequest = ::WinHttpOpenRequest(
|
|||
|
m_hConnect,
|
|||
|
pVerb,
|
|||
|
lpPage,
|
|||
|
NULL,
|
|||
|
WINHTTP_NO_REFERER,
|
|||
|
WINHTTP_DEFAULT_ACCEPT_TYPES,
|
|||
|
dwFlag);
|
|||
|
return m_hRequest != NULL;
|
|||
|
}
|
|||
|
|
|||
|
void HttpClient::SetTimeOut(int dwConnectTime, int dwSendTime, int dwRecvTime)
|
|||
|
{
|
|||
|
m_nConnTimeout = dwConnectTime;
|
|||
|
m_nSendTimeout = dwSendTime;
|
|||
|
m_nRecvTimeout = dwRecvTime;
|
|||
|
}
|
|||
|
|
|||
|
bool HttpClient::DownloadFile(LPCWSTR lpUrl, LPCWSTR lpFilePath)
|
|||
|
{
|
|||
|
Release();
|
|||
|
if (!Init())
|
|||
|
return false;
|
|||
|
bool bRet = false;
|
|||
|
DWORD dwBytesToRead = 0, dwFileSize = 0, dwReadSize = 0, dwRecvSize = 0;
|
|||
|
if (!InitConnect(lpUrl, HttpGet))
|
|||
|
return false;
|
|||
|
if (!QueryContentLength(dwFileSize))
|
|||
|
{
|
|||
|
m_paramsData.errcode = HttpErrorQuery;
|
|||
|
return false;
|
|||
|
}
|
|||
|
m_nResponseCode = QueryStatusCode();
|
|||
|
if (m_nResponseCode == HTTP_STATUS_NOT_FOUND) {
|
|||
|
m_paramsData.errcode = HttpError404;
|
|||
|
return false;
|
|||
|
}
|
|||
|
HANDLE hFile = CreateFile(lpFilePath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|||
|
if (INVALID_HANDLE_VALUE == hFile)
|
|||
|
{
|
|||
|
m_paramsData.errcode = HttpErrorCreateFile;
|
|||
|
return false;
|
|||
|
}
|
|||
|
SetFilePointer(hFile, dwFileSize, 0, FILE_BEGIN);
|
|||
|
SetEndOfFile(hFile);
|
|||
|
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
|
|||
|
if (!::WinHttpQueryDataAvailable(m_hRequest, &dwBytesToRead))
|
|||
|
{
|
|||
|
CloseHandle(hFile);
|
|||
|
DeleteFile(lpFilePath);
|
|||
|
return false;
|
|||
|
}
|
|||
|
void* lpBuff = malloc(READ_BUFFER_SIZE);
|
|||
|
while (true)
|
|||
|
{
|
|||
|
if (dwBytesToRead > READ_BUFFER_SIZE)
|
|||
|
{
|
|||
|
free(lpBuff);
|
|||
|
lpBuff = malloc(dwBytesToRead);
|
|||
|
}
|
|||
|
if (!::WinHttpReadData(m_hRequest, lpBuff, dwBytesToRead, &dwReadSize))
|
|||
|
break;
|
|||
|
DWORD dwWriteByte;
|
|||
|
if (!WriteFile(hFile, lpBuff, dwReadSize, &dwWriteByte, NULL) || (dwReadSize != dwWriteByte))
|
|||
|
break;
|
|||
|
dwRecvSize += dwReadSize;
|
|||
|
if (m_paramsData.callback)
|
|||
|
m_paramsData.callback->OnDownloadCallback(m_paramsData.lpparam, HttpLoading, dwFileSize, dwRecvSize);
|
|||
|
if (!::WinHttpQueryDataAvailable(m_hRequest, &dwBytesToRead))
|
|||
|
break;
|
|||
|
if (dwBytesToRead <= 0)
|
|||
|
{
|
|||
|
bRet = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
free(lpBuff);
|
|||
|
CloseHandle(hFile);
|
|||
|
if (!bRet)
|
|||
|
{//<2F><><EFBFBD><EFBFBD>ʧ<EFBFBD>ܣ<EFBFBD>ɾ<EFBFBD><C9BE><EFBFBD>ļ<EFBFBD>
|
|||
|
DeleteFile(lpFilePath);
|
|||
|
}
|
|||
|
return bRet;
|
|||
|
}
|
|||
|
|
|||
|
bool HttpClient::DownloadToMem(LPCWSTR lpUrl, OUT void** ppBuffer, OUT int* nSize)
|
|||
|
{
|
|||
|
bool bResult = false;
|
|||
|
BYTE* lpFileMem = NULL;
|
|||
|
void* lpBuff = NULL;
|
|||
|
DWORD dwLength = 0, dwBytesToRead = 0, dwReadSize = 0, dwRecvSize = 0;
|
|||
|
try
|
|||
|
{
|
|||
|
if (!InitConnect(lpUrl, HttpGet))
|
|||
|
throw HttpErrorInit;
|
|||
|
if (!QueryContentLength(dwLength))
|
|||
|
throw HttpErrorQuery;
|
|||
|
m_nResponseCode = QueryStatusCode();
|
|||
|
if (m_nResponseCode == HTTP_STATUS_NOT_FOUND) {
|
|||
|
throw HttpError404;
|
|||
|
}
|
|||
|
if (!::WinHttpQueryDataAvailable(m_hRequest, &dwBytesToRead))
|
|||
|
throw HttpErrorQuery;
|
|||
|
if (dwLength > DOWNLOAD_BUFFER_SIZE)
|
|||
|
throw HttpErrorBuffer;//<2F>ļ<EFBFBD><C4BC><EFBFBD>С<EFBFBD><D0A1><EFBFBD><EFBFBD>Ԥ<EFBFBD><D4A4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD><D8B5>ڴ<EFBFBD>
|
|||
|
lpFileMem = (BYTE*)malloc(dwLength);
|
|||
|
lpBuff = malloc(READ_BUFFER_SIZE);
|
|||
|
while (true)
|
|||
|
{
|
|||
|
if (dwBytesToRead > READ_BUFFER_SIZE)
|
|||
|
{
|
|||
|
free(lpBuff);
|
|||
|
lpBuff = malloc(dwBytesToRead);
|
|||
|
}
|
|||
|
if (!::WinHttpReadData(m_hRequest, lpBuff, dwBytesToRead, &dwReadSize))
|
|||
|
throw HttpErrorDownload;
|
|||
|
memcpy(lpFileMem + dwRecvSize, lpBuff, dwReadSize);
|
|||
|
dwRecvSize += dwReadSize;
|
|||
|
if (!::WinHttpQueryDataAvailable(m_hRequest, &dwBytesToRead))
|
|||
|
throw HttpErrorDownload;
|
|||
|
if (dwBytesToRead <= 0)
|
|||
|
{
|
|||
|
bResult = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
catch (HttpInterfaceError error)
|
|||
|
{
|
|||
|
m_paramsData.errcode = error;
|
|||
|
}
|
|||
|
if (lpBuff)
|
|||
|
free(lpBuff);
|
|||
|
if (bResult)
|
|||
|
{
|
|||
|
*ppBuffer = lpFileMem;
|
|||
|
*nSize = dwRecvSize;
|
|||
|
}
|
|||
|
else
|
|||
|
free(lpFileMem);
|
|||
|
return bResult;
|
|||
|
}
|
|||
|
|
|||
|
void HttpClient::SetDownloadCallback(IHttpCallback* pCallback, void* pParam)
|
|||
|
{
|
|||
|
m_paramsData.callback = pCallback;
|
|||
|
m_paramsData.lpparam = pParam;
|
|||
|
}
|
|||
|
|
|||
|
void HttpClient::AddHeader(LPCSTR key, LPCSTR value)
|
|||
|
{
|
|||
|
if (isEmptyString(key) || isEmptyString(value)) {
|
|||
|
return;
|
|||
|
}
|
|||
|
m_header.addHeader(string(key), string(value));
|
|||
|
}
|
|||
|
|
|||
|
string HttpClient::Request(LPCSTR lpUrl, HttpRequestType type, void* lpPostData /*= NULL*/, LPCSTR lpHeader/*=NULL*/)
|
|||
|
{
|
|||
|
string strRet;
|
|||
|
wstring strUrl = A2U(string(lpUrl));
|
|||
|
if (!InitConnect(strUrl.c_str(), type, lpPostData, 0, (lpHeader == NULL) ? NULL : A2U(string(lpHeader)).c_str()))
|
|||
|
return strRet;
|
|||
|
m_nResponseCode = QueryStatusCode();
|
|||
|
if (m_nResponseCode == HTTP_STATUS_NOT_FOUND) {
|
|||
|
throw HttpError404;
|
|||
|
}
|
|||
|
DWORD dwBytesToRead, dwReadSize;
|
|||
|
void* lpBuff = malloc(READ_BUFFER_SIZE);
|
|||
|
bool bFinish = false;
|
|||
|
while (true)
|
|||
|
{
|
|||
|
if (!::WinHttpQueryDataAvailable(m_hRequest, &dwBytesToRead))
|
|||
|
break;
|
|||
|
if (dwBytesToRead <= 0)
|
|||
|
{
|
|||
|
bFinish = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
if (dwBytesToRead > READ_BUFFER_SIZE)
|
|||
|
{
|
|||
|
free(lpBuff);
|
|||
|
lpBuff = malloc(dwBytesToRead);
|
|||
|
}
|
|||
|
if (!::WinHttpReadData(m_hRequest, lpBuff, dwBytesToRead, &dwReadSize))
|
|||
|
break;
|
|||
|
strRet.append((const char*)lpBuff, dwReadSize);
|
|||
|
}
|
|||
|
free(lpBuff);
|
|||
|
if (!bFinish)
|
|||
|
strRet.clear();
|
|||
|
return strRet;
|
|||
|
}
|
|||
|
|
|||
|
string HttpClient::Request(LPCWSTR lpUrl, HttpRequestType type, void* lpPostData /*= NULL*/, int datelen, LPCWSTR lpHeader/*=NULL*/)
|
|||
|
{
|
|||
|
string strRet;
|
|||
|
if (!InitConnect(lpUrl, type, lpPostData, datelen, lpHeader))
|
|||
|
return strRet;
|
|||
|
m_nResponseCode = QueryStatusCode();
|
|||
|
if (m_nResponseCode == HTTP_STATUS_NOT_FOUND) {
|
|||
|
throw HttpError404;
|
|||
|
}
|
|||
|
DWORD dwBytesToRead, dwReadSize;
|
|||
|
void* lpBuff = malloc(READ_BUFFER_SIZE);
|
|||
|
bool bFinish = false;
|
|||
|
while (true)
|
|||
|
{
|
|||
|
if (!::WinHttpQueryDataAvailable(m_hRequest, &dwBytesToRead))
|
|||
|
break;
|
|||
|
if (dwBytesToRead <= 0)
|
|||
|
{
|
|||
|
bFinish = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
if (dwBytesToRead > READ_BUFFER_SIZE)
|
|||
|
{
|
|||
|
free(lpBuff);
|
|||
|
lpBuff = malloc(dwBytesToRead);
|
|||
|
}
|
|||
|
if (!::WinHttpReadData(m_hRequest, lpBuff, dwBytesToRead, &dwReadSize))
|
|||
|
break;
|
|||
|
strRet.append((const char*)lpBuff, dwReadSize);
|
|||
|
}
|
|||
|
free(lpBuff);
|
|||
|
if (!bFinish)
|
|||
|
strRet.clear();
|
|||
|
return strRet;
|
|||
|
}
|
|||
|
|
|||
|
string HttpClient::Get(LPCWSTR lpUrl)
|
|||
|
{
|
|||
|
return this->Request(lpUrl, HttpGet);
|
|||
|
}
|
|||
|
string HttpClient::Post(LPCWSTR lpUrl,const void* lpPostData, int datelen, LPCWSTR lpHeader)
|
|||
|
{
|
|||
|
return this->Request(lpUrl, HttpPost,(void*) lpPostData, datelen, lpHeader);
|
|||
|
}
|
|||
|
bool HttpClient::QueryRawHeaders(OUT wstring& strHeaders)
|
|||
|
{
|
|||
|
bool bRet = false;
|
|||
|
DWORD dwSize;
|
|||
|
BOOL bResult = ::WinHttpQueryHeaders(m_hRequest, WINHTTP_QUERY_RAW_HEADERS, WINHTTP_HEADER_NAME_BY_INDEX, NULL, &dwSize, WINHTTP_NO_HEADER_INDEX);
|
|||
|
if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
|
|||
|
{
|
|||
|
wchar_t* lpData = (wchar_t*)malloc(dwSize);
|
|||
|
bResult = ::WinHttpQueryHeaders(m_hRequest, WINHTTP_QUERY_RAW_HEADERS, WINHTTP_HEADER_NAME_BY_INDEX, lpData, &dwSize, WINHTTP_NO_HEADER_INDEX);
|
|||
|
if (bResult)
|
|||
|
{
|
|||
|
strHeaders = lpData;
|
|||
|
bRet = true;
|
|||
|
}
|
|||
|
free(lpData);
|
|||
|
}
|
|||
|
return bRet;
|
|||
|
}
|
|||
|
|
|||
|
bool HttpClient::QueryContentLength(OUT DWORD& dwLength)
|
|||
|
{
|
|||
|
bool bRet = false;
|
|||
|
wchar_t szBuffer[24] = { 0 };
|
|||
|
DWORD dwSize = 24 * sizeof(wchar_t);
|
|||
|
if (::WinHttpQueryHeaders(m_hRequest, WINHTTP_QUERY_CONTENT_LENGTH, WINHTTP_HEADER_NAME_BY_INDEX, szBuffer, &dwSize, WINHTTP_NO_HEADER_INDEX))
|
|||
|
{
|
|||
|
TCHAR* p = NULL;
|
|||
|
dwLength = wcstoul(szBuffer, &p, 10);
|
|||
|
bRet = true;
|
|||
|
}
|
|||
|
return bRet;
|
|||
|
}
|
|||
|
|
|||
|
int HttpClient::QueryStatusCode()
|
|||
|
{
|
|||
|
int http_code = 0;
|
|||
|
wchar_t szBuffer[24] = { 0 };
|
|||
|
DWORD dwSize = 24 * sizeof(wchar_t);
|
|||
|
if (::WinHttpQueryHeaders(m_hRequest, WINHTTP_QUERY_STATUS_CODE, WINHTTP_HEADER_NAME_BY_INDEX, szBuffer, &dwSize, WINHTTP_NO_HEADER_INDEX)) {
|
|||
|
wchar_t* p = NULL;
|
|||
|
http_code = wcstoul(szBuffer, &p, 10);
|
|||
|
}
|
|||
|
return http_code;
|
|||
|
}
|
|||
|
|
|||
|
bool HttpClient::InitConnect(LPCWSTR lpUrl, HttpRequestType type, void* lpPostData/*=NULL*/, int datelen, LPCWSTR lpHeader/*=NULL*/)
|
|||
|
{
|
|||
|
Release();
|
|||
|
if (!Init())
|
|||
|
return false;
|
|||
|
wstring strHostName, strPage;
|
|||
|
WORD wPort;
|
|||
|
MyParseUrlW(lpUrl, strHostName, strPage, wPort);
|
|||
|
if (wPort == INTERNET_DEFAULT_HTTPS_PORT)
|
|||
|
m_bHttps = true;
|
|||
|
if (!ConnectHttpServer(strHostName.c_str(), wPort))
|
|||
|
{
|
|||
|
m_paramsData.errcode = HttpErrorConnect;
|
|||
|
return false;
|
|||
|
}
|
|||
|
DWORD dwFlag = m_bHttps ? WINHTTP_FLAG_SECURE : 0;
|
|||
|
if (!CreateHttpRequest(strPage.c_str(), type, dwFlag))
|
|||
|
{
|
|||
|
m_paramsData.errcode = HttpErrorInit;
|
|||
|
return false;
|
|||
|
}
|
|||
|
if (m_bHttps)
|
|||
|
{
|
|||
|
DWORD dwFlags = SECURITY_FLAG_SECURE |
|
|||
|
SECURITY_FLAG_IGNORE_UNKNOWN_CA |
|
|||
|
SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE |
|
|||
|
SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
|
|||
|
SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
|
|||
|
WinHttpSetOption(m_hRequest, WINHTTP_OPTION_SECURITY_FLAGS, &dwFlags, sizeof(dwFlags));
|
|||
|
}
|
|||
|
if (!SendHttpRequest(lpPostData, datelen, lpHeader))
|
|||
|
{
|
|||
|
m_paramsData.errcode = HttpErrorSend;
|
|||
|
return false;
|
|||
|
}
|
|||
|
if (!WinHttpReceiveResponse(m_hRequest, NULL))
|
|||
|
{
|
|||
|
m_paramsData.errcode = HttpErrorInit;
|
|||
|
return false;
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
bool HttpClient::SendHttpRequest(void* lpPostData/*=NULL*/,int datelen, LPCWSTR lpHeader/*=NULL*/)
|
|||
|
{
|
|||
|
//<2F><><EFBFBD><EFBFBD>HTTPͷ
|
|||
|
std::wstring header = A2U(m_header.toHttpHeaders());
|
|||
|
::WinHttpAddRequestHeaders(m_hRequest, header.c_str(), header.size(), WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE);
|
|||
|
if (lpHeader == NULL)
|
|||
|
return ::WinHttpSendRequest(m_hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, lpPostData, datelen, datelen, NULL) == TRUE;
|
|||
|
else
|
|||
|
return ::WinHttpSendRequest(m_hRequest, lpHeader, -1L, lpPostData, datelen, datelen, NULL) == TRUE;
|
|||
|
}
|
|||
|
|