// HttpHelper.cpp
//
#include "stdafx.h"
#include "HttpHelper.h"
using namespace LGHttp;
HINTERNET m_hConnect = NULL; // global param for member function and thread function
const DWORD TIMEOUT = 5000; // timeout value
BOOL CHttpHelper::HttpGet(std::string strUrl, std::string& strRequest)
{
return HttpRequest(strUrl, L"GET", "", strRequest);
}
BOOL CHttpHelper::HttpPost(std::string strUrl, std::string strPostData, std::string& strRequest)
{
return HttpRequest(strUrl, L"POST", strPostData, strRequest);
}
BOOL CHttpHelper::HttpRequest(std::string strUrl, LPCTSTR lpszMethod, std::string strPostData, std::string& strRequest)
{
BOOL bRet = TRUE;
// 1. parse url
std::string strServer, strObject;
INTERNET_PORT nPort = 0;
if (!ParseUrl(strUrl, strServer, strObject, nPort))
return FALSE;
// 2. transform string to wstring
std::wstring wstrServer = LGTools::S2WS(strServer);
std::wstring wstrObject = LGTools::S2WS(strObject);
// 3.
HINTERNET hInternet = NULL, hRequest = NULL;
hInternet = InternetOpen(L"User-Agent", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (!hInternet)
{
DWORD dwError = GetLastError();
std::string strLog = std::string("InternetOpen failed on ErrorCode:") + std::to_string((long)dwError);
if (hInternet)
InternetCloseHandle(hInternet);
return FALSE;
}
// 4. transfer thread param
CONNECT_PARAM connectParam;
connectParam.hInternet = hInternet;
connectParam.wstrServer = wstrServer;
connectParam.nPort = nPort;
// 5. begin thread
HANDLE hThread;
unsigned threadId;
hThread = (HANDLE)_beginthreadex(NULL, 0, ConnectInternet, &connectParam, 0, &threadId);
// 6. wait for the call to InternetConnect in worker function to complete
if (WaitForSingleObject(hThread, TIMEOUT) == WAIT_TIMEOUT)
{
// write to log
std::string strLog = std::string("Can't connect to server in") + std::to_string((long)TIMEOUT) + "milliseconds";
if (hInternet)
InternetCloseHandle(hInternet);
// Wait until the thread exits
WaitForSingleObject(hThread, INFINITE);
return FALSE;
}
// 7. the state of the specifieed object(thread) is signaled
DWORD dwExitCode = 0;
if (!GetExitCodeThread(hThread, &dwExitCode))
{
DWORD dwError = GetLastError();
std::string strLog = std::string("Error on GetExitCodeThread:") + std::to_string((long)dwError);
bRet = FALSE;
goto Ret0;
}
// 8. Close Thread Handle
CloseHandle(hThread);
if (dwExitCode)
{
bRet = FALSE;
goto Ret0;
}
// 9.
hRequest = HttpOpenRequest(m_hConnect, lpszMethod, wstrObject.c_str(), L"HTTP/1.1", NULL, NULL, INTERNET_FLAG_RELOAD, 0);
if (!hRequest)
{
bRet = FALSE;
goto Ret0;
}
// 10. send request
bRet = HttpAddRequestHeaders(hRequest, L"Content-Type: application/x-www-form-urlencoded",
_tcslen(L"Content-Type: application/x-www-form-urlencoded"), HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD);
if (strPostData.empty())
{
bRet = HttpSendRequest(hRequest, NULL, 0, (LPVOID)"", 0);
}
else
{
ConvertUnicodeToUtf8(strPostData);
bRet = HttpSendRequest(hRequest, NULL, 0, (LPVOID)strPostData.c_str(), strPostData.length());
}
if (!bRet)
{
bRet = FALSE;
goto Ret0;
}
// 11. read file
while (true)
{
char szReadBuffer[4096] = { 0 };
unsigned long ulNumberOfBytesRead;
bRet = InternetReadFile(hRequest, szReadBuffer, sizeof(szReadBuffer) - 1, &ulNumberOfBytesRead);
if (!bRet || !ulNumberOfBytesRead)
break;
szReadBuffer[ulNumberOfBytesRead] = 0;
strRequest += szReadBuffer;
}
// 12. convert code
ConvertUtf8ToUnicode(strRequest);
Ret0:
if (hRequest)
InternetCloseHandle(hRequest);
if (m_hConnect)
InternetCloseHandle(m_hConnect);
if (hInternet)
InternetCloseHandle(hInternet);
return bRet;
}
BOOL CHttpHelper::ParseUrl(const std::string& strUrl, std::string& strHost, std::string& strObject, WORD& nPort)
{
size_t nLen = strUrl.length();
if (nLen > 2000) return FALSE;
// 1. remove "http://"
std::string strUrlTemp = strUrl;
if (strUrlTemp.substr(0, 7) != "http://")
return FALSE;
else
strUrlTemp = strUrlTemp.substr(7, nLen - 7);
// 2. get ip:port
size_t pos1 = strUrlTemp.find('/');
if (std::string::npos == pos1)
{
return FALSE;
}
else
{
std::string strServerTemp = strUrlTemp.substr(0, pos1);
size_t pos2 = strServerTemp.find(':');
if (pos2 == std::string::npos) // default port
{
strHost = strServerTemp;
nPort = 80;
}
else // custom port
{
strHost = strServerTemp.substr(0, pos2);
nPort = (WORD)stoi(strServerTemp.substr(pos2 + 1, strServerTemp.length() - pos2 - 1));
}
strObject = strUrlTemp.substr(pos1, strUrlTemp.length() - pos1);
}
return TRUE;
}
unsigned __stdcall CHttpHelper::ConnectInternet(LPVOID param)
{
PCONNECT_PARAM pThreadParam;
pThreadParam = (PCONNECT_PARAM)param;
m_hConnect = InternetConnect(pThreadParam->hInternet, pThreadParam->wstrServer.c_str(),
pThreadParam->nPort, NULL, L"HTTP/1.1", INTERNET_SERVICE_HTTP, 0, 0);
if (!m_hConnect)
{
DWORD dw = GetLastError();
return 1;
}
return 0;
}
void CHttpHelper::ConvertUtf8ToUnicode(std::string& strText)
{
int unicodeLen = MultiByteToWideChar(CP_UTF8, 0, strText.c_str(), -1, NULL, 0);
WCHAR *pUnicode = new WCHAR[unicodeLen + 1];
if (NULL != pUnicode)
{
MultiByteToWideChar(CP_UTF8, 0, strText.c_str(), -1, pUnicode, unicodeLen);
pUnicode[unicodeLen] = '\0';
USES_CONVERSION;
strText = T2A(pUnicode);
delete[] pUnicode;
pUnicode = NULL;
}
}
void CHttpHelper::ConvertUnicodeToUtf8(std::string& strText)
{
std::wstring ss = LGTools::S2WS(strText);
int nLen = WideCharToMultiByte(CP_UTF8, 0, ss.c_str(), -1, NULL, 0, NULL, NULL);
char *pBuf = new char[nLen + 1];
if (NULL != pBuf)
{
WideCharToMultiByte(CP_UTF8, 0, ss.c_str(), -1, pBuf, nLen, NULL, NULL);
pBuf[nLen] = '\0';
strText = pBuf;
delete[] pBuf;
pBuf = NULL;
}
}
BOOL LGHttp::http_get(std::string strUrl, std::string& strRequest)
{
CHttpHelper hh;
return hh.HttpGet(strUrl, strRequest);
}
BOOL LGHttp::http_post(std::string strUrl, std::string strPostData, std::string& strRequest)
{
CHttpHelper hh;
return hh.HttpPost(strUrl, strPostData, strRequest);
}