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;
|
||
}
|
||
|