Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / WinMobile

An Asynchronous HTTP Request WinINet Wrapper in C++

4.90/5 (45 votes)
25 Aug 2011CPOL2 min read 138.1K   8.8K  
An asynchronous HTTP download class for C++
Image 1

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

  1. Include http_request_manager.h file in your project. normally include it at the end of the stdafx.h.
  2. Create HTTP request manager class derived from class FCHttpRequestManager.
    C++
    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 and OnAfterRequestFinish, overwrite event you find interesting. Most of the time, we should overwrite OnAfterRequestFinish to process received data.

  3. Now, you can send HTTP request by calling AddRequest.

Examples

... Download File

Send HTTP request:

C++
// 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:

C++
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

C++
// 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

C++
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

C++
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:

C++
#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:

C++
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.

C++
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

C++
// this example loads image to memory, then posts to server using multipart/form-data
std::vector<byte />   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

C++
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 to FCHttpDownload
    • 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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)