PdbLib/UpLoader/HTTP/HttpClient.cpp
2025-06-05 10:51:52 +08:00

402 lines
10 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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