#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) {//下载失败,删除文件 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;//文件大小超过预设最大值,不建议下载到内存 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*/) { //添加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; }