// ==========================================================================
// Author: Yee Hsu
// Date: 9/5/2008
// File: HTTP.cpp
//
// Desc: HTTP wrapper that does simple HTTP API calls. Now we have an HTTP
// object we can call and use to make HTTP connections, make HTTP
// requests via the HTTP protocol
// ==========================================================================
// GenericHTTPClient.cpp: implementation of the GenericHTTPClient class.
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "CHTTP.h"
#include <winreg.h>
// ==========================================================================
// Identifier: GenericHTTPClient()
//
// Description: GenericHTTPClient Constructor
// ==========================================================================
GenericHTTPClient::GenericHTTPClient(){
_hHTTPOpen=_hHTTPConnection=_hHTTPRequest=NULL;
}
// ==========================================================================
// Identifier: GenericHTTPClient()
//
// Description: GenericHTTPClient Destructor
// ==========================================================================
GenericHTTPClient::~GenericHTTPClient(){
_hHTTPOpen=_hHTTPConnection=_hHTTPRequest=NULL;
}
// ==========================================================================
// Identifier: GetMethod()
//
// Description: Gets the HTTP request method
// ==========================================================================
GenericHTTPClient::RequestMethod GenericHTTPClient::GetMethod(int nMethod){
return nMethod<=0 ? GenericHTTPClient::RequestGetMethod : static_cast<GenericHTTPClient::RequestMethod>(nMethod);
}
// ==========================================================================
// Identifier: GetPostArgumentType()
//
// Description: Gets POST argument type
// ==========================================================================
GenericHTTPClient::TypePostArgument GenericHTTPClient::GetPostArgumentType(int nType){
return nType<=0 ? GenericHTTPClient::TypeNormal : static_cast<GenericHTTPClient::TypePostArgument>(nType);
}
// ==========================================================================
// Identifier: Connect()
//
// Description: Makes and HTTP connection
// ==========================================================================
BOOL GenericHTTPClient::Connect(LPCTSTR szAddress, LPCTSTR szAgent, unsigned short nPort, LPCTSTR szUserAccount, LPCTSTR szPassword){
_hHTTPOpen=::InternetOpen(szAgent, // agent name
INTERNET_OPEN_TYPE_PRECONFIG, // proxy option
"", // proxy
"", // proxy bypass
0); // flags
if(!_hHTTPOpen){
_dwError=::GetLastError();
#ifdef _DEBUG
LPVOID lpMsgBuffer;
DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuffer),
0,
NULL);
OutputDebugString(reinterpret_cast<LPTSTR>(lpMsgBuffer));
LocalFree(lpMsgBuffer);
#endif
return FALSE;
}
_hHTTPConnection=::InternetConnect( _hHTTPOpen, // internet opened handle
szAddress, // server name
nPort, // ports
szUserAccount, // user name
szPassword, // password
INTERNET_SERVICE_HTTP, // service type
INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_CACHE_WRITE, // service option
0); // context call-back option
if(!_hHTTPConnection){
_dwError=::GetLastError();
::CloseHandle(_hHTTPOpen);
#ifdef _DEBUG
LPVOID lpMsgBuffer;
DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuffer),
0,
NULL);
OutputDebugString(reinterpret_cast<LPTSTR>(lpMsgBuffer));
LocalFree(lpMsgBuffer);
#endif
return FALSE;
}
if(::InternetAttemptConnect(NULL)!=ERROR_SUCCESS){
_dwError=::GetLastError();
::CloseHandle(_hHTTPConnection);
::CloseHandle(_hHTTPOpen);
#ifdef _DEBUG
LPVOID lpMsgBuffer;
DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuffer),
0,
NULL);
OutputDebugString(reinterpret_cast<LPTSTR>(lpMsgBuffer));
LocalFree(lpMsgBuffer);
#endif
return FALSE;
}
return TRUE;
}
// ==========================================================================
// Identifier: Close()
//
// Description: Closes and HTTP connection
// ==========================================================================
BOOL GenericHTTPClient::Close(){
if(_hHTTPRequest)
::InternetCloseHandle(_hHTTPRequest);
if(_hHTTPConnection)
::InternetCloseHandle(_hHTTPConnection);
if(_hHTTPOpen)
::InternetCloseHandle(_hHTTPOpen);
return TRUE;
}
// ==========================================================================
// Identifier: Request()
//
// Description: Makes an HTTP request
// ==========================================================================
BOOL GenericHTTPClient::Request(LPCTSTR szURL, int nMethod, LPCTSTR szAgent){
BOOL bReturn=TRUE;
DWORD dwPort=0;
TCHAR szProtocol[__SIZE_BUFFER]="";
TCHAR szAddress[__SIZE_BUFFER]="";
TCHAR szURI[__SIZE_BUFFER]="";
DWORD dwSize=0;
ParseURL(szURL, szProtocol, szAddress, dwPort, szURI);
if(Connect(szAddress, szAgent, dwPort)){
if(!RequestOfURI(szURI, nMethod)){
bReturn=FALSE;
}else{
if(!Response((PBYTE)_szHTTPResponseHeader, __SIZE_HTTP_BUFFER, (PBYTE)_szHTTPResponseHTML, __SIZE_HTTP_BUFFER, dwSize)){
bReturn=FALSE;
}
}
Close();
}else{
bReturn=FALSE;
}
return bReturn;
}
// ==========================================================================
// Identifier: RequestOfURI()
//
// Description: Makes an HTTP request of URI
// ==========================================================================
BOOL GenericHTTPClient::RequestOfURI(LPCTSTR szURI, int nMethod){
BOOL bReturn=TRUE;
// try{
switch(nMethod){
case GenericHTTPClient::RequestGetMethod:
default:
bReturn=RequestGet(szURI);
break;
case GenericHTTPClient::RequestPostMethod:
bReturn=RequestPost(szURI);
break;
case GenericHTTPClient::RequestPostMethodMultiPartsFormData:
bReturn=RequestPostMultiPartsFormData(szURI);
break;
}/*
}catch(CException *e){
#ifdef _DEBUG
TRACE("\nEXCEPTION\n");
TCHAR szERROR[1024];
e->GetErrorMessage(szERROR, 1024);
TRACE(szERROR);
#endif
}
*/
return bReturn;
}
// ==========================================================================
// Identifier: RequestGet()
//
// Description: Makes an HTTP request get
// ==========================================================================
BOOL GenericHTTPClient::RequestGet(LPCTSTR szURI){
CONST TCHAR *szAcceptType=__HTTP_ACCEPT_TYPE;
_hHTTPRequest=::HttpOpenRequest( _hHTTPConnection,
__HTTP_VERB_GET, // HTTP Verb
szURI, // Object Name
HTTP_VERSION, // Version
"", // Reference
&szAcceptType, // Accept Type
INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_CACHE_WRITE,
0); // context call-back point
if(!_hHTTPRequest){
_dwError=::GetLastError();
#ifdef _DEBUG
LPVOID lpMsgBuffer;
DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuffer),
0,
NULL);
OutputDebugString(reinterpret_cast<LPTSTR>(lpMsgBuffer));
LocalFree(lpMsgBuffer);
#endif
return FALSE;
}
// REPLACE HEADER
if(!::HttpAddRequestHeaders( _hHTTPRequest, __HTTP_ACCEPT, _tcslen(__HTTP_ACCEPT), HTTP_ADDREQ_FLAG_REPLACE)){
_dwError=::GetLastError();
#ifdef _DEBUG
LPVOID lpMsgBuffer;
DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuffer),
0,
NULL);
// TRACE(reinterpret_cast<LPTSTR>(lpMsgBuffer));
LocalFree(lpMsgBuffer);
#endif
return FALSE;
}
// SEND REQUEST
if(!::HttpSendRequest( _hHTTPRequest, // handle by returned HttpOpenRequest
NULL, // additional HTTP header
0, // additional HTTP header length
NULL, // additional data in HTTP Post or HTTP Put
0) // additional data length
){
_dwError=::GetLastError();
#ifdef _DEBUG
LPVOID lpMsgBuffer;
DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuffer),
0,
NULL);
OutputDebugString(reinterpret_cast<LPTSTR>(lpMsgBuffer));
LocalFree(lpMsgBuffer);
#endif
return FALSE;
}
return TRUE;
}
// ==========================================================================
// Identifier: RequestPost()
//
// Description: Makes an HTTP request post
// ==========================================================================
BOOL GenericHTTPClient::RequestPost(LPCTSTR szURI){
CONST TCHAR *szAcceptType=__HTTP_ACCEPT_TYPE;
TCHAR szPostArguments[__SIZE_BUFFER]="";
LPCTSTR szContentType=TEXT("Content-Type: application/x-www-form-urlencoded\r\n");
DWORD dwPostArgumentsLegnth=GetPostArguments(szPostArguments, __SIZE_BUFFER);
_hHTTPRequest=::HttpOpenRequest( _hHTTPConnection,
__HTTP_VERB_POST, // HTTP Verb
szURI, // Object Name
HTTP_VERSION, // Version
"", // Reference
&szAcceptType, // Accept Type
INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_FORMS_SUBMIT,
0); // context call-back point
if(!_hHTTPRequest){
_dwError=::GetLastError();
#ifdef _DEBUG
LPVOID lpMsgBuffer;
DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuffer),
0,
NULL);
// TRACE("\n%d : %s\n", _dwError, reinterpret_cast<LPTSTR>(lpMsgBuffer));
LocalFree(lpMsgBuffer);
#endif
return FALSE;
}
// REPLACE HEADER
if(!::HttpAddRequestHeaders( _hHTTPRequest, __HTTP_ACCEPT, _tcslen(__HTTP_ACCEPT), HTTP_ADDREQ_FLAG_REPLACE)){
_dwError=::GetLastError();
#ifdef _DEBUG
LPVOID lpMsgBuffer;
DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuffer),
0,
NULL);
// TRACE("\n%d : %s\n", _dwError, reinterpret_cast<LPTSTR>(lpMsgBuffer));
LocalFree(lpMsgBuffer);
#endif
return FALSE;
}
// SEND REQUEST
if(!::HttpSendRequest( _hHTTPRequest, // handle by returned HttpOpenRequest
szContentType, // additional HTTP header
_tcslen(szContentType), // additional HTTP header length
(LPVOID)szPostArguments, // additional data in HTTP Post or HTTP Put
_tcslen(szPostArguments)) // additional data length
){
_dwError=::GetLastError();
#ifdef _DEBUG
LPVOID lpMsgBuffer;
DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuffer),
0,
NULL);
// TRACE("\n%d : %s\n", _dwError, reinterpret_cast<LPTSTR>(lpMsgBuffer));
LocalFree(lpMsgBuffer);
#endif
return FALSE;
}
return TRUE;
}
// ==========================================================================
// Identifier: RequestPostMultiPartsFormData()
//
// Description: Makes an HTTP request post multi part data
// ==========================================================================
BOOL GenericHTTPClient::RequestPostMultiPartsFormData(LPCTSTR szURI){
CONST TCHAR *szAcceptType=__HTTP_ACCEPT_TYPE;
LPCTSTR szContentType=TEXT("Content-Type: multipart/form-data; boundary=--MULTI-PARTS-FORM-DATA-BOUNDARY\r\n");
// ALLOCATE POST MULTI-PARTS FORM DATA ARGUMENTS
PBYTE pPostBuffer=NULL;
DWORD dwPostBufferLength=AllocMultiPartsFormData(pPostBuffer, "--MULTI-PARTS-FORM-DATA-BOUNDARY");
_hHTTPRequest=::HttpOpenRequest( _hHTTPConnection,
__HTTP_VERB_POST, // HTTP Verb
szURI, // Object Name
HTTP_VERSION, // Version
"", // Reference
&szAcceptType, // Accept Type
INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_FORMS_SUBMIT, // flags
0); // context call-back point
if(!_hHTTPRequest){
_dwError=::GetLastError();
#ifdef _DEBUG
LPVOID lpMsgBuffer;
DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuffer),
0,
NULL);
OutputDebugString(reinterpret_cast<LPTSTR>(lpMsgBuffer));
LocalFree(lpMsgBuffer);
#endif
return FALSE;
}
// REPLACE HEADER
if(!::HttpAddRequestHeaders( _hHTTPRequest, __HTTP_ACCEPT, _tcslen(__HTTP_ACCEPT), HTTP_ADDREQ_FLAG_REPLACE)){
_dwError=::GetLastError();
#ifdef _DEBUG
LPVOID lpMsgBuffer;
DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuffer),
0,
NULL);
// TRACE(reinterpret_cast<LPTSTR>(lpMsgBuffer));
LocalFree(lpMsgBuffer);
#endif
return FALSE;
}
if(!::HttpAddRequestHeaders( _hHTTPRequest, szContentType, _tcslen(szContentType), HTTP_ADDREQ_FLAG_ADD_IF_NEW)){
_dwError=::GetLastError();
#ifdef _DEBUG
LPVOID lpMsgBuffer;
DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuffer),
0,
NULL);
// TRACE(reinterpret_cast<LPTSTR>(lpMsgBuffer));
LocalFree(lpMsgBuffer);
#endif
return FALSE;
}
TCHAR szContentLength[__SIZE_BUFFER]="";
::ZeroMemory(szContentLength, __SIZE_BUFFER);
_stprintf( szContentLength, "Content-Length: %d\r\n", dwPostBufferLength);
if(!::HttpAddRequestHeaders( _hHTTPRequest, szContentLength, _tcslen(szContentLength), HTTP_ADDREQ_FLAG_ADD_IF_NEW)){
_dwError=::GetLastError();
#ifdef _DEBUG
LPVOID lpMsgBuffer;
DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuffer),
0,
NULL);
// TRACE(reinterpret_cast<LPTSTR>(lpMsgBuffer));
LocalFree(lpMsgBuffer);
#endif
return FALSE;
}
#ifdef _DEBUG
TCHAR szHTTPRequest[__SIZE_HTTP_BUFFER]="";
DWORD dwHTTPRequestLength=__SIZE_HTTP_BUFFER;
::ZeroMemory(szHTTPRequest, __SIZE_HTTP_BUFFER);
if(!::HttpQueryInfo(_hHTTPRequest, HTTP_QUERY_RAW_HEADERS_CRLF, szHTTPRequest, &dwHTTPRequestLength, NULL)){
_dwError=::GetLastError();
LPVOID lpMsgBuffer;
DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuffer),
0,
NULL);
// TRACE("\n%d : %s\n", ::GetLastError(), reinterpret_cast<LPTSTR>(lpMsgBuffer));
LocalFree(lpMsgBuffer);
//return FALSE;
}
// TRACE(szHTTPRequest);
#endif
// SEND REQUEST WITH HttpSendRequestEx and InternetWriteFile
INTERNET_BUFFERS InternetBufferIn={0};
InternetBufferIn.dwStructSize=sizeof(INTERNET_BUFFERS);
InternetBufferIn.Next=NULL;
if(!::HttpSendRequestEx(_hHTTPRequest, &InternetBufferIn, NULL, HSR_INITIATE, 0)){
_dwError=::GetLastError();
#ifdef _DEBUG
LPVOID lpMsgBuffer;
DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuffer),
0,
NULL);
// TRACE(reinterpret_cast<LPTSTR>(lpMsgBuffer));
LocalFree(lpMsgBuffer);
#endif
return FALSE;
}
DWORD dwOutPostBufferLength=0;
if(!::InternetWriteFile(_hHTTPRequest, pPostBuffer, dwPostBufferLength, &dwOutPostBufferLength)){
_dwError=::GetLastError();
#ifdef _DEBUG
LPVOID lpMsgBuffer;
DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuffer),
0,
NULL);
OutputDebugString(reinterpret_cast<LPTSTR>(lpMsgBuffer));
LocalFree(lpMsgBuffer);
#endif
return FALSE;
}
if(!::HttpEndRequest(_hHTTPRequest, NULL, HSR_INITIATE, 0)){
_dwError=::GetLastError();
#ifdef _DEBUG
LPVOID lpMsgBuffer;
DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuffer),
0,
NULL);
OutputDebugString(reinterpret_cast<LPTSTR>(lpMsgBuffer));
LocalFree(lpMsgBuffer);
#endif
return FALSE;
}
// FREE POST MULTI-PARTS FORM DATA ARGUMENTS
FreeMultiPartsFormData(pPostBuffer);
return TRUE;
}
// ==========================================================================
// Identifier: ResponseOfBytes()
//
// Description: HTTP response in bytes
// ==========================================================================
DWORD GenericHTTPClient::ResponseOfBytes(PBYTE pBuffer, DWORD dwSize){
static DWORD dwBytes=0;
if(!_hHTTPRequest){
_dwError=::GetLastError();
#ifdef _DEBUG
LPVOID lpMsgBuffer;
DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuffer),
0,
NULL);
OutputDebugString(reinterpret_cast<LPTSTR>(lpMsgBuffer));
LocalFree(lpMsgBuffer);
#endif
return 0;
}
::ZeroMemory(pBuffer, dwSize);
if(!::InternetReadFile( _hHTTPRequest,
pBuffer,
dwSize,
&dwBytes)){
_dwError=::GetLastError();
#ifdef _DEBUG
LPVOID lpMsgBuffer;
DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuffer),
0,
NULL);
OutputDebugString(reinterpret_cast<LPTSTR>(lpMsgBuffer));
LocalFree(lpMsgBuffer);
#endif
return 0;
}
return dwBytes;
}
// ==========================================================================
// Identifier: Response()
//
// Description: HTTP response
// ==========================================================================
BOOL GenericHTTPClient::Response(PBYTE pHeaderBuffer, DWORD dwHeaderBufferLength, PBYTE pBuffer, DWORD dwBufferLength, DWORD &dwResultSize){
BYTE pResponseBuffer[__SIZE_BUFFER]="";
DWORD dwNumOfBytesToRead=0;
if(!_hHTTPRequest){
_dwError=::GetLastError();
#ifdef _DEBUG
LPVOID lpMsgBuffer;
DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuffer),
0,
NULL);
OutputDebugString(reinterpret_cast<LPTSTR>(lpMsgBuffer));
LocalFree(lpMsgBuffer);
#endif
return FALSE;
}
::ZeroMemory(pBuffer, dwBufferLength);
dwResultSize=0;
while((dwNumOfBytesToRead=ResponseOfBytes(pResponseBuffer, __SIZE_BUFFER))!=NULL && dwResultSize<dwBufferLength){
::CopyMemory( (pBuffer+dwResultSize), pResponseBuffer, dwNumOfBytesToRead);
dwResultSize+=dwNumOfBytesToRead;
}
::ZeroMemory(pHeaderBuffer, dwHeaderBufferLength);
if(!::HttpQueryInfo(_hHTTPRequest, HTTP_QUERY_RAW_HEADERS_CRLF, pHeaderBuffer, &dwHeaderBufferLength, NULL)){
_dwError=::GetLastError();
#ifdef _DEBUG
LPVOID lpMsgBuffer;
DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
::GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPTSTR>(&lpMsgBuffer),
0,
NULL);
OutputDebugString(reinterpret_cast<LPTSTR>(lpMsgBuffer));
LocalFree(lpMsgBuffer);
#endif
return FALSE;
}
return (dwResultSize? TRUE: FALSE);
}
// ==========================================================================
// Identifier: AddPostArguments()
//
// Description: Add post arguments to HTTP request
// ==========================================================================
VOID GenericHTTPClient::AddPostArguments(LPCTSTR szName, LPCTSTR szValue, BOOL bBinary){
GenericHTTPArgument arg;
::ZeroMemory(&arg, sizeof(arg));
_tcscpy(arg.szName, szName);
_tcscpy(arg.szValue, szValue);
if(!bBinary)
arg.dwType = GenericHTTPClient::TypeNormal;
else
arg.dwType = GenericHTTPClient::TypeBinary;
_vArguments.push_back(arg);
return;
}
// ==========================================================================
// Identifier: AddPostArguments()
//
// Description: Add post arguments to HTTP request
// ==========================================================================
VOID GenericHTTPClient::AddPostArguments(LPCTSTR szName, DWORD nValue){
GenericHTTPArgument arg;
::FillMemory(&arg, sizeof(arg), 0x00);
_tcscpy(arg.szName, szName);
_stprintf(arg.szValue, "%d", nValue);
arg.dwType = GenericHTTPClient::TypeNormal;
_vArguments.push_back(arg);
return;
}
// ==========================================================================
// Identifier: GetPostArguments()
//
// Description: Get post arguments to HTTP request
// ==========================================================================
DWORD GenericHTTPClient::GetPostArguments(LPTSTR szArguments, DWORD dwLength){
std::vector<GenericHTTPArgument>::iterator itArg;
::ZeroMemory(szArguments, dwLength);
for(itArg=_vArguments.begin(); itArg<_vArguments.end(); ){
_tcscat(szArguments, itArg->szName);
_tcscat(szArguments, "=");
_tcscat(szArguments, itArg->szValue);
if((++itArg)<_vArguments.end()){
_tcscat(szArguments, "&");
}
}
*(szArguments+dwLength)='\0';
return _tcslen(szArguments);
}
// ==========================================================================
// Identifier: InitilizePostArguments()
//
// Description: Initialize post arguments
// ==========================================================================
VOID GenericHTTPClient::InitilizePostArguments(){
_vArguments.clear();
return;
}
// ==========================================================================
// Identifier: FreeMultiPartsFormData()
//
// Description: Frees the multi parts data
// ==========================================================================
VOID GenericHTTPClient::FreeMultiPartsFormData(PBYTE &pBuffer){
if(pBuffer){
::LocalFree(pBuffer);
pBuffer=NULL;
}
return;
}
// ==========================================================================
// Identifier: AllocMultiPartsFormData()
//
// Description: Allocates the multi parts data
// ==========================================================================
DWORD GenericHTTPClient::AllocMultiPartsFormData(PBYTE &pInBuffer, LPCTSTR szBoundary){
if(pInBuffer){
::LocalFree(pInBuffer);
pInBuffer=NULL;
}
pInBuffer=(PBYTE)::LocalAlloc(LPTR, GetMultiPartsFormDataLength());
std::vector<GenericHTTPArgument>::iterator itArgv;
DWORD dwPosition=0;
DWORD dwBufferSize=0;
for(itArgv=_vArguments.begin(); itArgv<_vArguments.end(); ++itArgv){
PBYTE pBuffer=NULL;
// SET MULTI_PRATS FORM DATA BUFFER
switch(itArgv->dwType){
case GenericHTTPClient::TypeNormal:
pBuffer=(PBYTE)::LocalAlloc(LPTR, __SIZE_HTTP_HEAD_LINE*4);
_stprintf( (TCHAR*)pBuffer,
"--%s\r\n"
"Content-Disposition: form-data; name=\"%s\"\r\n"
"\r\n"
"%s\r\n",
szBoundary,
itArgv->szName,
itArgv->szValue);
dwBufferSize=_tcslen((TCHAR*)pBuffer);
break;
case GenericHTTPClient::TypeBinary:
DWORD dwNumOfBytesToRead=0;
DWORD dwTotalBytes=0;
HANDLE hFile=::CreateFile(itArgv->szValue,
GENERIC_READ, // desired access
FILE_SHARE_READ, // share mode
NULL, // security attribute
OPEN_EXISTING, // create disposition
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, // flag and attributes
NULL); // template file handle
DWORD dwSize=::GetFileSize(hFile, NULL);
pBuffer=(PBYTE)::LocalAlloc(LPTR, __SIZE_HTTP_HEAD_LINE*3+dwSize+1);
BYTE pBytes[__SIZE_BUFFER+1]="";
_stprintf( (TCHAR*)pBuffer,
"--%s\r\n"
"Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\n"
"Content-Type: %s\r\n"
"\r\n",
szBoundary,
itArgv->szName, itArgv->szValue,
GetContentType(itArgv->szValue)
);
DWORD dwBufPosition=_tcslen((TCHAR*)pBuffer);
while(::ReadFile(hFile, pBytes, __SIZE_BUFFER, &dwNumOfBytesToRead, NULL) && dwNumOfBytesToRead>0 && dwTotalBytes<=dwSize){
::CopyMemory((pBuffer+dwBufPosition+dwTotalBytes), pBytes, dwNumOfBytesToRead);
::ZeroMemory(pBytes, __SIZE_BUFFER+1);
dwTotalBytes+=dwNumOfBytesToRead;
}
::CopyMemory((pBuffer+dwBufPosition+dwTotalBytes), "\r\n", _tcslen("\r\n"));
::CloseHandle(hFile);
dwBufferSize=dwBufPosition+dwTotalBytes+_tcslen("\r\n");
break;
}
::CopyMemory((pInBuffer+dwPosition), pBuffer, dwBufferSize);
dwPosition+=dwBufferSize;
if(pBuffer){
::LocalFree(pBuffer);
pBuffer=NULL;
}
}
::CopyMemory((pInBuffer+dwPosition), "--", 2);
::CopyMemory((pInBuffer+dwPosition+2), szBoundary, _tcslen(szBoundary));
::CopyMemory((pInBuffer+dwPosition+2+_tcslen(szBoundary)), "--\r\n", 3);
return dwPosition+5+_tcslen(szBoundary);
}
// ==========================================================================
// Identifier: GetMultiPartsFormDataLength()
//
// Description: Gets the multi parts data
// ==========================================================================
DWORD GenericHTTPClient::GetMultiPartsFormDataLength(){
std::vector<GenericHTTPArgument>::iterator itArgv;
DWORD dwLength=0;
for(itArgv=_vArguments.begin(); itArgv<_vArguments.end(); ++itArgv){
switch(itArgv->dwType){
case GenericHTTPClient::TypeNormal:
dwLength+=__SIZE_HTTP_HEAD_LINE*4;
break;
case GenericHTTPClient::TypeBinary:
HANDLE hFile=::CreateFile(itArgv->szValue,
GENERIC_READ, // desired access
FILE_SHARE_READ, // share mode
NULL, // security attribute
OPEN_EXISTING, // create disposition
FILE_ATTRIBUTE_NORMAL, // flag and attributes
NULL); // template file handle
dwLength+=__SIZE_HTTP_HEAD_LINE*3+::GetFileSize(hFile, NULL);
::CloseHandle(hFile);
break;
}
}
return dwLength;
}
// ==========================================================================
// Identifier: GetContentType()
//
// Description: Gets the content type
// ==========================================================================
LPCTSTR GenericHTTPClient::GetContentType(LPCTSTR szName){
static TCHAR szReturn[1024]="";
LONG dwLen=1024;
DWORD dwDot=0;
for(dwDot=_tcslen(szName);dwDot>0;dwDot--){
if(!_tcsncmp((szName+dwDot),".", 1))
break;
}
HKEY hKEY;
LPTSTR szWord=(char*)(szName+dwDot);
if(RegOpenKeyEx(HKEY_CLASSES_ROOT, szWord, 0, KEY_QUERY_VALUE, &hKEY)==ERROR_SUCCESS){
if(RegQueryValueEx(hKEY, TEXT("Content Type"), NULL, NULL, (LPBYTE)szReturn, (unsigned long*)&dwLen)!=ERROR_SUCCESS)
_tcsncpy(szReturn, "application/octet-stream", _tcslen("application/octet-stream"));
RegCloseKey(hKEY);
}else{
_tcsncpy(szReturn, "application/octet-stream", _tcslen("application/octet-stream"));
}
return szReturn;
}
// ==========================================================================
// Identifier: GetLastError()
//
// Description: Gets the last error
// ==========================================================================
DWORD GenericHTTPClient::GetLastError(){
return _dwError;
}
// ==========================================================================
// Identifier: ParseURL()
//
// Description: Parse the URL
// ==========================================================================
VOID GenericHTTPClient::ParseURL(LPCTSTR szURL, LPTSTR szProtocol, LPTSTR szAddress, DWORD &dwPort, LPTSTR szURI){
TCHAR szPort[__SIZE_BUFFER]="";
DWORD dwPosition=0;
BOOL bFlag=FALSE;
while(_tcslen(szURL)>0 && dwPosition<_tcslen(szURL) && _tcsncmp((szURL+dwPosition), ":", 1))
++dwPosition;
if(!_tcsncmp((szURL+dwPosition+1), "/", 1)){ // is PROTOCOL
if(szProtocol){
_tcsncpy(szProtocol, szURL, dwPosition);
szProtocol[dwPosition]=0;
}
bFlag=TRUE;
}else{ // is HOST
if(szProtocol){
_tcsncpy(szProtocol, "http", 4);
szProtocol[5]=0;
}
}
DWORD dwStartPosition=0;
if(bFlag){
dwStartPosition=dwPosition+=3;
}else{
dwStartPosition=dwPosition=0;
}
bFlag=FALSE;
while(_tcslen(szURL)>0 && dwPosition<_tcslen(szURL) && _tcsncmp((szURL+dwPosition), "/", 1))
++dwPosition;
DWORD dwFind=dwStartPosition;
for(;dwFind<=dwPosition;dwFind++){
if(!_tcsncmp((szURL+dwFind), ":", 1)){ // find PORT
bFlag=TRUE;
break;
}
}
if(bFlag){
TCHAR sztmp[__SIZE_BUFFER]="";
_tcsncpy(sztmp, (szURL+dwFind+1), dwPosition-dwFind);
dwPort=_ttol(sztmp);
_tcsncpy(szAddress, (szURL+dwStartPosition), dwFind-dwStartPosition);
}else if(!_tcscmp(szProtocol,"https")){
dwPort=INTERNET_DEFAULT_HTTPS_PORT;
_tcsncpy(szAddress, (szURL+dwStartPosition), dwPosition-dwStartPosition);
}else {
dwPort=INTERNET_DEFAULT_HTTP_PORT;
_tcsncpy(szAddress, (szURL+dwStartPosition), dwPosition-dwStartPosition);
}
if(dwPosition<_tcslen(szURL)){ // find URI
_tcsncpy(szURI, (szURL+dwPosition), _tcslen(szURL)-dwPosition);
}else{
szURI[0]=0;
}
return;
}
// ==========================================================================
// Identifier: QueryHTTPResponseHeader()
//
// Description: Gets HTTP response header
// ==========================================================================
LPCTSTR GenericHTTPClient::QueryHTTPResponseHeader(){
return _szHTTPResponseHeader;
}
// ==========================================================================
// Identifier: QueryHTTPResponse()
//
// Description: Gets HTTP response
// ==========================================================================
LPCTSTR GenericHTTPClient::QueryHTTPResponse(){
return _szHTTPResponseHTML;
}
/* *************************** MODIFIED CODE BEFLOW *************************** */
// HTTP Request uses threading to simulate timeout.
// Timeout is used to prevent an HTTP request to hang while the server never responses.
// Without timeout, this is potentially dangerous as the program execution may halt for a very long
// time. We reimplement Request() with threads for timeouts.
// ==========================================================================
// Identifier: HTTP()
//
// Description: HTTP Constructor
// ==========================================================================
HTTP::HTTP()
{
this->lpThreadId = 0L;
this->lpThreadExitCode = 0L;
this->lpThreadIdleMSec = 2000L; // Default Timeout: 1 minute
this->bHTTPSuccess = FALSE;
this->nMethod = HTTP::RequestGetMethod;
this->szAgent = __DEFAULT_AGENT_NAME;
this->szURL = "";
this->szHTTPUser = NULL;
this->szHTTPPass = NULL;
}
// ==========================================================================
// Identifier: Request()
//
// Description: HTTP request method
// ==========================================================================
BOOL HTTP::Request(const LPCTSTR szURL, LPCTSTR szHTTPUSER, LPCTSTR szHTTPPass)
{
this->szURL = szURL;
this->bHTTPSuccess = FALSE;
this->szHTTPUser = szHTTPUSER;
this->szHTTPPass = szHTTPPass;
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) ThreadStart, this, 0, &lpThreadId);
if ( WaitForSingleObject(hThread, lpThreadIdleMSec) == WAIT_TIMEOUT)
{
HTTP::Close();
WaitForSingleObject(hThread, lpThreadIdleMSec);
this->bHTTPSuccess = FALSE;
}
CloseHandle(hThread);
return this->bHTTPSuccess; // returns TRUE (in mult-threaded code) when HTTP request success
}
// ==========================================================================
// Identifier: LoadPage()
//
// Description: loads a page in a browser
// ==========================================================================
BOOL HTTP::LoadPage(const LPCSTR szURL)
{
ShellExecute( NULL, "open", szURL, NULL, "C:\\", SW_SHOW );
return TRUE;
}
// ==========================================================================
// Identifier: GetResponseStatusCode()
//
// Description: Gets status code from response
// ==========================================================================
LONG HTTP::GetResponseStatusCode()
{
LONG lgStatusCode = 0;
sscanf(_szHTTPResponseHeader, "%*s %ld %*s", &lgStatusCode);
return lgStatusCode;
}
// ==========================================================================
// Identifier: GetResponseHeaderInfo()
//
// Description: Gets response header information
// ==========================================================================
std::string HTTP::GetResponseHeaderInfo(const std::string sHeaderInfo)
{
string::size_type pos;
string sResponseInfo = "";
string sResponseHeader = _szHTTPResponseHeader;
string sHeadInfo = sHeaderInfo;
sHeadInfo.insert(sHeadInfo.length(), ": ");
if ((pos = sResponseHeader.find( sHeadInfo ) ) != sResponseHeader.npos )
{
sResponseInfo = sResponseHeader.erase( 0, pos + sHeadInfo.length() -1 );
sResponseInfo = sResponseInfo.substr( 0, sResponseInfo.find("\n") );
}
return sResponseInfo;
}
// ==========================================================================
// Identifier: GetLastModifiedTime()
//
// Description: Gets response header modified time
// ==========================================================================
std::string HTTP::GetLastModifiedTime()
{
string sLastModifiedTime = GetResponseHeaderInfo("Last-Modified");
if (sLastModifiedTime.empty())
{
sLastModifiedTime = GetResponseHeaderInfo("Date");
}
return sLastModifiedTime;
}
// ==========================================================================
// Identifier: ThreadHTTPRequestTimeOut()
//
// Description: HTTP request made in a threaded execution
// ==========================================================================
BOOL WINAPI HTTP::ThreadHTTPRequestTimeOut()
{
DWORD dwPort = 0;
DWORD dwSize = 0;
bHTTPSuccess = FALSE;
TCHAR szProtocol[__SIZE_BUFFER] = "";
TCHAR szAddress[__SIZE_BUFFER] = "";
TCHAR szURI[__SIZE_BUFFER] = "";
ParseURL(szURL, szProtocol, szAddress, dwPort, szURI);
if (Connect(szAddress, szAgent, dwPort, szHTTPUser, szHTTPPass))
{
if (RequestOfURI(szURI, nMethod))
{
if (Response((PBYTE)_szHTTPResponseHeader, __SIZE_HTTP_BUFFER, (PBYTE)_szHTTPResponseHTML, __SIZE_HTTP_BUFFER, dwSize))
bHTTPSuccess = TRUE;
}
Close();
}
ExitThread(lpThreadExitCode);
return bHTTPSuccess;
}
// ==========================================================================
// Identifier: ThreadStart()
//
// Description: Start the HTTP request in a thread
// ==========================================================================
DWORD HTTP::ThreadStart(HTTP* pHTTP)
{
pHTTP->ThreadHTTPRequestTimeOut();
return 0;
}