An Asynchronous HTTP Request WinINet Wrapper in C++
An asynchronous HTTP download class for C++

Introduction
WinINet makes network programming easier, but it's difficult to use for C++ because of its C-style interface, so I write this code to wrap it. Using it, you can easily create an asynchronous HTTP request and receive event callback. It can be applied to MFC and ATL projects.
This code mainly consists of two classes: class FCHttpRequest
and class FCHttpRequestManager
.
Class FCHttpRequest
is responsible for implementing send HTTP request and receive response, it's a wrapper class for WinINet.
Class FCHttpRequestManager
is a management of FCHttpRequest
, responsible for add, delete FCHttpRequest
object and receive event from FCHttpRequest
.
Similar to the STL and Boost, all source code consists of .h and .inl file, you can easily integrate it into your program.
How to Use
- Include http_request_manager.h file in your project. normally include it at the end of the stdafx.h.
- Create HTTP request manager class derived from class
FCHttpRequestManager
.class CMyManager : public FCHttpRequestManager { //... }; // multiple inheritance attach an exist class class CMyManager : public CDialog, public FCHttpRequestManager { virtual void OnAfterRequestSend (FCHttpRequest& rTask) { // ... } virtual void OnAfterRequestFinish (FCHttpRequest& rTask) { // ... } };
The manager will receive two events:
OnAfterRequestSend
andOnAfterRequestFinish
, overwrite event you find interesting. Most of the time, we should overwriteOnAfterRequestFinish
to process received data. - Now, you can send HTTP request by calling
AddRequest
.
Examples
... Download File
Send HTTP request:
// download whole file
AddDownload (_T("http://phoxo.com/t.zip")) ;
// download file and specifies the starting position
HTTP_REQUEST_HEADER h ;
h.m_url = _T("http://phoxo.com/t.zip") ;
h.m_start = 30 ; // in byte
AddRequest (h) ;
Response finish event, process downloaded data:
void OnAfterRequestFinish (FCHttpRequest& rTask)
{
const HTTP_RESPONSE_INFO & r = rTask.GetResponseInfo() ;
bool bOK = false ;
if (r.m_status_code == HTTP_STATUS_OK)
{
if (r.m_content_length)
{
// avoid network broken during downloading
if (r.m_content_length == rTask.GetTotalReceiveByte())
bOK = true ;
}
else
{
// no Content-Type field, maybe is a dynamic page, such as PHP, ASP...
if (r.m_final_read_result)
bOK = true ;
}
}
if (bOK)
{
std::string receive_data ;
rTask.PopReceived (receive_data) ;
// ... process received data
}
}
... Specifying the User-Agent
// default User-Agent is same to User-Agent of IE
HTTP_REQUEST_HEADER h ;
h.m_url = _T("http://phoxo.com/") ;
h.m_user_agent = _T("My User-Agent") ;
AddRequest (h) ;
... Custom HTTP Header
HTTP_REQUEST_HEADER h ;
h.m_url = _T("http://phoxo.com/") ;
// \r\n at end of each line
h.m_header += _T("Referer: http://google.com\r\n") ;
h.m_header += _T("Accept: */*\r\n") ;
h.m_header += _T("x-flash-version: 10,0,0,1\r\n") ;
AddRequest (h) ;
... Specifying the Proxy
HTTP_REQUEST_HEADER h ;
h.m_url = _T("http://phoxo.com/") ;
h.m_proxy_ip = _T("8.8.8.8") ;
h.m_proxy_port = 8080 ;
AddRequest (h) ;
... Decompress GZip HTTP Data
This feature requires the ZLib library, you can get it from http://www.zlib.org.
Include headers in the following order:
#include "zlib.h"
#include "http_request_manager.h"
#include "utility/gzip_decompress.h"
Add Accept-Encoding
field in request header, notify the server that you can accept gzip compressed data:
HTTP_REQUEST_HEADER h ;
h.m_url = _T("http://phoxo.com/") ;
h.m_header += L"Accept-Encoding: gzip, deflate\r\n" ;
AddRequest (h) ;
In finish callback, you can use gzip_decompress
to decompress received data.
void OnAfterRequestFinish (FCHttpRequest& rTask)
{
std::string receive_data ;
rTask.PopReceived (receive_data) ;
if (IsReceiveGZipStream(rTask) && receive_data.size())
{
std::string raw_data ;
if (gzip_decompress (receive_data.c_str(), receive_data.size(), raw_data))
{
receive_data = raw_data ;
}
}
}
... Post multipart/form-data
// this example loads image to memory, then posts to server using multipart/form-data
std::vector buf ;
FCFileEx::Read (_T("c:\\1.jpg"), buf) ;
HTTP_REQUEST_HEADER h (HTTP_REQUEST_HEADER::VERB_TYPE_POST_MULTIPART) ;
h.m_url = _T("http://phoxo.com/") ;
h.AddMultipartFormData ("param1", "value1") ;
h.AddMultipartFormData ("param2", "value2") ;
h.AddMultipartFormData ("pic", &buf[0], buf.size(), "1.jpg") ;
h.EndMultipartFormData() ;
m_task_id = AddRequest (h) ;
... HTTPS
HTTP_REQUEST_HEADER h ;
h.m_url = _T("https://phoxo.com/") ;
// ignores errors that can be caused by the certificate
// host name of the server not matching the host name in the request
h.m_open_flag |= INTERNET_FLAG_IGNORE_CERT_CN_INVALID ;
// ignores errors that can be caused by an expired server certificate
h.m_open_flag |= INTERNET_FLAG_IGNORE_CERT_DATE_INVALID ;
AddRequest (h) ;
History
- 25th August, 2011: V2.0
- Refactoring code, more features, more efficient
- Added multipart/form-data POST support
- Added HTTPS support
- Added GZip decompress support
- 30th January, 2010: V1.1
- Renamed from
FCHttpDownloadExec
toFCHttpDownload
- Fixed a bug when popping a modal dialog in callback
- Modified interface of
FCHttpRequestManager
- Got default User-Agent from Internet Explorer
- 17th November, 2009: Initial post