Click here to Skip to main content
12,350,605 members (25,993 online)
Click here to Skip to main content
Add your own
alternative version

Stats

301.9K views
20.6K downloads
155 bookmarked
Posted

CHttpClient - A Helper Class Using WinInet

, 10 Aug 2007
Rate this:
Please Sign up or sign in to vote.
A C++ class which helps you to interact with a HTTP web server.
Screenshot - lyoulhttpclient.jpg

Introduction

CHttpClient is a helper class using WinInet API. The purpose of this class is to help you interact with a HTTP web server. The class design goal is as follows:

  • Easy to use.
  • As many flexibilities as possible.
  • Strict error handling.

I will briefly show you how to use this class. All detailed description has been documented in the attached help file.

How to use CHttpClient

In your project, include the following files:

  • RyeolException.h
  • RyeolException.cpp
  • RyeolHttpClient.h
  • RyeolHttpClient.cpp
  • SafeInt.hpp

In your stdafx.h file, add the following line:

#include "RyeolHttpClient.h"

Note: The namespace and file names have been changed. If you use the previous version of the CHttpClient, you need to update as follows:

  • LyoulException.h --> RyeolException.h
  • LyoulException.cpp --> RyeolException.cpp
  • LyoulHttpClient.h --> RyeolHttpClient.h
  • LyoulHttpClient.cpp --> RyeolHttpClient.cpp
  • #include "LyoulHttpClient.h" --> #include "RyeolHttpClient.h"
  • using namespace Lyoul --> using namespace Ryeol

How to Send a Request Using HTTP GET

CHttpClient supports RequestGet method which sends a request using HTTP GET:

// Retrieves the resource specified by the szUrl using HTTP GET request.
// szUrl            [in] A HTTP URL.
// bUseCache        [in] Specifies whether to use cache.
CHttpResponse * CHttpClient::RequestGet (PCSZ szUrl, 
   BOOL bUseCache = FALSE) throw (Exception &) ;

The following code demonstrates the basic usage of the RequestGet method:

using namespace Ryeol ;

CHttpClient         objHttpReq ;
CHttpResponse *     pobjHttpRes = NULL ;

try {
    // Initialize the User Agent
    objHttpReq.SetInternet (_T ("My User Agent v1.0")) ;

    // Specifies whether to use UTF-8 encoding. 
    // (This uses ANSI encoding)
    // Default is FALSE
    objHttpReq.SetUseUtf8 (FALSE) ;

    // Specifies a code page for ANSI strings. 
    // (This uses Korean)
    // Default is CP_ACP
    objHttpReq.SetAnsiCodePage (949) ;

    // Add user's custom HTTP headers
    objHttpReq.AddHeader (_T ("Ryeol-Magic"), _T ("My Magic Header")) ;
    objHttpReq.AddHeader (_T ("User-Magic"), _T ("User's Magic Header")) ;

    // Add user's parameters
    objHttpReq.AddParam (_T ("where"), _T ("nexearch")) ;
    objHttpReq.AddParam (_T ("frm"), _T ("t1")) ;
    objHttpReq.AddParam (_T ("query"), 
       _T ("%C3%D6%C1%F6%BF%EC"), CHttpClient::ParamEncodedValue) ;

    // Send a request
    pobjHttpRes = 
      objHttpReq.RequestGet (_T ("http://search.naver.com/search.naver")) ;

    ...     // Place codes to handle the returned CHttpResponse object.

} catch (httpclientexception & e) {
    ...     // Place exception handling codes here.
}

How to Send a Request Using HTTP POST

The HTTP POST method is used in two ways. One is to post simple text, the other is to upload files. To post simple text, CHttpClient provides BeginPost method.

// Starts a new HTTP POST request
// szUrl            [in] A HTTP URL.
// bUseCache        [in] Specifies whether to use cache.
void CHttpClient::BeginPost (PCSZ szUrl, 
   BOOL bUseCache = FALSE) throw (Exception &) ;

The following code demonstrates the basic usage of the BeginPost method:

using namespace Ryeol ;

CHttpClient         objHttpReq ;
CHttpResponse *     pobjHttpRes = NULL ;

try {
    // Initialize the User Agent
    objHttpReq.SetInternet (_T ("My User Agent v1.0")) ;

    // Add user's custom HTTP headers
    objHttpReq.AddHeader (_T ("Ryeol-Magic"), _T ("My Magic Header")) ;
    objHttpReq.AddHeader (_T ("User-Magic"), _T ("User's Magic Header")) ;

    // Add user's parameters
    objHttpReq.AddParam (_T ("st"), _T ("kw")) ;
    objHttpReq.AddParam (_T ("target"), _T ("WinInet")) ;

    // Start a new request
    objHttpReq.BeginPost (_T ("http://www.codeproject.com/info/search.asp")) ;

    // Specifies the number of bytes to send when the Proceed method is called.
    const DWORD     cbProceed = 1024 ;  // 1K

    do {

        ...     // Place codes to report progress information to user.
    } while ( !(pobjHttpRes = objHttpReq.Proceed (cbProceed)) ) ;
    ...     // Place codes to handle the returned CHttpResponse object.
} catch (httpclientexception & e) {
    ...     // Place exception handling codes here.
}

To upload file, CHttpClient provides BeginUpload method.

// Starts a new UPLOAD request
// szUrl            [in] A HTTP URL.
// bUseCache        [in] Specifies whether to use cache.
void CHttpClient::BeginUpload (PCSZ szUrl, 
   BOOL bUseCache = FALSE) throw (Exception &) ;

The following code demonstrates the basic usage of the BeginUpload method:

using namespace Ryeol ;

CHttpClient         objHttpReq ;
CHttpResponse *     pobjHttpRes = NULL ;

try {
    // Initialize the User Agent
    objHttpReq.SetInternet (_T ("My User Agent v1.0")) ;

    // Add user's custom HTTP headers
    objHttpReq.AddHeader (_T ("Ryeol-Magic"), _T ("My Magic Header")) ;
    objHttpReq.AddHeader (_T ("User-Magic"), _T ("User's Magic Header")) ;

    // Add user's parameters
    objHttpReq.AddParam (_T ("nohtml"), _T ("1")) ;
    objHttpReq.AddParam (_T ("title"), _T ("The K-NET photo")) ;
    objHttpReq.AddParam (_T ("content"), _T ("A photo of the K-NET")) ;

    // Specifies a file to upload
    objHttpReq.AddParam (_T ("ufile01"), 
       _T ("D:\\My Photo\\K-NET\\photo1.jpg"), 
       CHttpClient::ParamFile) ;

    // Start a new request
    objHttpReq.BeginUpload (_T ("http://club.hooriza.com")
       _T ("/cmd/box.html?clubid=1&boxid=53&action=store&link=")) ;

    // Specifies the number of bytes to send when the Proceed method is called.
    const DWORD     cbProceed = 1024 ;  // 1K

    do {

        ...     // Place codes to report progress information to user.
    } while ( !(pobjHttpRes = objHttpReq.Proceed (cbProceed)) ) ;
    ...     // Place codes to handle the returned CHttpResponse object.
} catch (httpclientexception && e) {
    ...     // Place exception handling codes here.
}

How to Handle the Returned CHttpResponse Object

When you send a request using CHttpClient, all the methods will return CHttpResponse object. CHttpResponse represents the response returned by a HTTP web server. CHttpResponse provides the following methods:

// Returns the number of headers of which name is the szName
DWORD CHttpResponse::GetHeaderCount (PCSZ szName) throw (Exception &) ;

// Returns the header of which name is the szName
PCSZ CHttpResponse::GetHeader (PCSZ szName, 
          DWORD nIdx = 0) throw (Exception &) ;

// Returns the HTTP status code returned by a HTTP server
DWORD CHttpResponse::GetStatus (void) throw (Exception &) ;

// Returns the HTTP status text returned by a HTTP server
PCSZ CHttpResponse::GetStatusText (void) throw (Exception &) ;

// Retrieves the length of the content returned by a HTTP server
BOOL CHttpResponse::GetContentLength (DWORD & cbContLen) throw (Exception &) ;

// Reads the content returned by a HTTP server
DWORD CHttpResponse::ReadContent (BYTE * pbyBuff, 
          DWORD cbBuff) throw (Exception &) ;

The following code demonstrates the basic usage of the CHttpResponse object:

using namespace Ryeol ;

CHttpResponse *     pobjHttpRes = NULL ;

try {
    // Get the CHttpResponse object
    pobjHttpRes = ... ;

    // Reads the HTTP status code
    _tprintf (_T ("%u"), pobjHttpRes->GetStatus ()) ;
    // Reads the HTTP status text
    _tprintf (_T (" %s\n"), pobjHttpRes->GetStatusText ()) ;

    // Reads HTTP headers using an array of header names
    static LPCTSTR      szHeaders[] = 
    { _T ("Server"), _T ("Date"), _T ("X-Powered-By"), 
                _T ("Content-Length"), _T ("Set-Cookie")
    , _T ("Expires"), _T ("Cache-control"), 
                _T ("Connection"), _T ("Transfer-Encoding")
    , _T ("Content-Type") } ;

    LPCTSTR     szHeader ;
    for (size_t i = 0; i < sizeof (szHeaders) / sizeof (LPCTSTR); i++) {
        if ( szHeader = pobjHttpRes->GetHeader (szHeaders[i]) )
            _tprintf (_T ("%s: %s\n"), szHeaders[i], szHeader) ;
        else
            // If the header is not found..
            _tprintf (_T ("'%s' header does not exist..\n"), 
                                                    szHeaders[i]) ;
    }
    _tprintf (_T ("\n")) ;

    // Checks whether the returned stream is a text
    BOOL        bIsText = FALSE ;
    if ( szHeader = pobjHttpRes->GetHeader (_T ("Content-Type")) )
        bIsText = (0 == ::_tcsncicmp (szHeader, _T ("text/"), 5)) ;

    // Reads the length of the stream
    DWORD       dwContSize ;
    // If the length is not specified
    if ( !pobjHttpRes->GetContentLength (dwContSize) )
        dwContSize = 0 ;

    const DWORD     cbBuff = 1024 * 10 ;
    BYTE            byBuff[cbBuff] ;
    DWORD           dwRead ;
    size_t          cbTotal = 0 ;

    // Reads the data stream returned by the HTTP server.
    while ( dwRead = pobjHttpRes->ReadContent (byBuff, cbBuff - 1) ) {
        cbTotal += dwRead ;

        if ( bIsText ) {
            byBuff[dwRead] = '\0' ;
            printf ("%s", reinterpret_cast<LPCSTR> (byBuff)) ;
        }
    }
    if ( !bIsText )
        _tprintf (_T ("%u bytes skipped..\n"), cbTotal) ;
} catch (httpclientexception & e) {
    ...     // Place exception handling codes here.
}
delete pobjHttpRes ;
pobjHttpRes = NULL ;

How to Handle Exception

When an error occurs, httpclientexception object is thrown:

class httpclientexception {
public:
    // Returns the last error code.
    // The error codes is defined in RyeolHttpClient.h
    DWORD LastError (void) const throw () ;

    // Returns the last error message.
    LPCTSTR errmsg (void) const throw () ;

    // Returns the last win32 error code retrieved by
    // using ::GetLastError when an error occurred.
    DWORD Win32LastError (void) const throw () ;
} ;

Before throwing an exception, most methods restore their internal states (all or nothing like transaction). But if you call BeginPost or BeginUpload method, the POST context is automatically canceled. You should write the following try-catch block to handle the exception:

using namespace Ryeol ;

try {
    ...     // Place codes which throw a httpclientexception exception
} catch (httpclientexception & e) {
    _tprintf (_T ("An error has been occured\n")) ;
    _tprintf (_T ("ErrCode: 0x%x\n"), e.LastError ()) ;
    _tprintf (_T ("ErrMsg: %s\n"), e.errmsg ()) ;
    if ( e.Win32LastError () != NO_ERROR ) {
        TCHAR       szErrMsg[512] ;
        GetWinInetErrMsg (szErrMsg, 512, e.Win32LastError ()) ;

        _tprintf (_T ("Win32ErrCode: 0x%x\n"), e.Win32LastError ()) ;
        _tprintf (_T ("Win32ErrMsg: %s\n"), szErrMsg) ;
    }
}

How to Show the Progress Information to the User

If you call BeginPost or BeginUpload method, you can retrieve the progress information using the Query method:

// Queries progress information of the current POST context
// objPostStat      [out] A CHttpPostStat object.
void CHttpClient::Query (CHttpPostStat & objPostStat) throw () ;

CHttpPostStat represents the progress information of the current POST context. The following code demonstrates the basic usage of the CHttpPostStat object:

using namespace Ryeol ;

CHttpClient         objHttpReq ;
CHttpResponse *     pobjHttpRes = NULL ;
size_t              cbProceed = 1024 ;  // 1k

try {
    ... ;   // Intialize the CHttpClient object

    // Starts a new POST request
    objHttpReq.BeginPost (...) or objHttpReq.BeginUpload (...) ;

    // Displays progress information
    CHttpPostStat       objPostStat ;
    do {
        // Retrieves progress information
        objHttpReq.Query (objPostStat) ;

        _tprintf (_T ("\nPost in progress... %2u/%2u\n")
            , objPostStat.PostedCount ()   // The number of posted parameters
            , objPostStat.TotalCount ()) ; // The total number of parameters

        _tprintf (_T ("%s: %10u/%10u %10u/%10u %10u/%10u\n")
            // The name of the current parameter
            , objPostStat.CurrParam ()
            // The number of posted bytes of the current parameter
            , objPostStat.CurrParamPostedByte ()
            // The total number of bytes of the current parameter
            , objPostStat.CurrParamTotalByte ()
            // The number of posted bytes of the request
            , objPostStat.PostedByte ()
            // The total number of bytes of the request
            , objPostStat.TotalByte ()
            // The actual number of posted bytes of the request
            , objPostStat.ActualPostedByte ()
            // The actual total number of bytes of the request
            , objPostStat.ActualTotalByte ()) ;

        // If the current parameter is a file parameter,
        // displays the file path
        if ( objPostStat.CurrParamIsFile () )
            _tprintf (_T ("-->%s\n")
                , objPostStat.CurrFile ()) ;
        // Sends the number of bytes specified by cbProceed to the server
    } while ( !(pobjHttpRes = objHttpReq.Proceed (cbProceed)) ) ;
    ... ;   // Handles the returned CHttpResponse object
} catch (httpclientexception & e) {
    ...     // Place exception handling codes here.
}

About CHttpClient COM Edition

CHttpClient COM Edition is the component version of CHttpClient. I won't explain here how to use it because it is similar to CHttpClient. You can refer to the attached examples and the help file of CHttpClient COM edition. If you want to use CHttpClient COM edition, you need to install RyeolHttpClient2.dll. Because it is a COM DLL, you have to register it by using the regsvr32.exe program. You can install it anywhere you want provided you don't distribute it. But if you want to distribute it, I recommend that you install it in the %WINDOWS%System32 folder and do not remove it even if your program is uninstalled.

History

  • 3rd February, 2006
    • The assertion behavior has been changed to throw an exception if the assertion expression is failed.
    • The pragma warning (push) and (pop) directives are used to restore the previous warning state.
    • The SaveContent method has been added.
    • The namespace and file names have been changed.
    • CHttpClient COM Edition has been added.
  • 9th August, 2004
    • Some methods have been added to support proxy authorization.
  • 29th July, 2004
    • Initial release.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

JO Hyeong-Ryeol
Software Developer
Korea (Republic of) Korea (Republic of)
No Biography provided

You may also be interested in...

Comments and Discussions

 
GeneralMy vote of 2 Pin
MaitreyaBuddha16-May-15 1:15
memberMaitreyaBuddha16-May-15 1:15 
General[My vote of 2] Too complex - not user friendly Pin
MaitreyaBuddha16-May-15 1:13
memberMaitreyaBuddha16-May-15 1:13 
GeneralMy vote of 5 Pin
Member 111107042-May-15 5:26
memberMember 111107042-May-15 5:26 
QuestionWinInet and WinHttp Pin
Thejaswi Krishna4-Sep-13 23:47
memberThejaswi Krishna4-Sep-13 23:47 
GeneralRe: WinInet and WinHttp Pin
JO Hyeong-Ryeol5-Sep-13 11:32
memberJO Hyeong-Ryeol5-Sep-13 11:32 
QuestionSome Win7 Pcs BeginUpload is giving 12002( ERROR_INTERNET_TIMEOUT) error Pin
KUMARRaju21-May-13 8:02
memberKUMARRaju21-May-13 8:02 
AnswerRe: Some Win7 Pcs BeginUpload is giving 12002( ERROR_INTERNET_TIMEOUT) error Pin
JO Hyeong-Ryeol22-May-13 3:12
memberJO Hyeong-Ryeol22-May-13 3:12 
Questionsupoort for over 2.2G file upload Pin
merlin321-Jun-12 16:17
membermerlin321-Jun-12 16:17 
AnswerRe: supoort for over 2.2G file upload Pin
JO Hyeong-Ryeol25-Jun-12 3:06
memberJO Hyeong-Ryeol25-Jun-12 3:06 
GeneralRe: supoort for over 2.2G file upload Pin
merlin326-Jun-12 15:09
membermerlin326-Jun-12 15:09 
AnswerRe: supoort for over 2.2G file upload Pin
JO Hyeong-Ryeol27-Jun-12 3:16
memberJO Hyeong-Ryeol27-Jun-12 3:16 
GeneralRe: supoort for over 2.2G file upload Pin
merlin34-Jul-12 20:29
membermerlin34-Jul-12 20:29 
AnswerRe: supoort for over 2.2G file upload Pin
JO Hyeong-Ryeol5-Jul-12 11:06
memberJO Hyeong-Ryeol5-Jul-12 11:06 
GeneralRe: supoort for over 2.2G file upload Pin
merlin35-Jul-12 16:11
membermerlin35-Jul-12 16:11 
GeneralRe: supoort for over 2.2G file upload Pin
JO Hyeong-Ryeol7-Jul-12 3:25
memberJO Hyeong-Ryeol7-Jul-12 3:25 
Questionhow to set the postdata in COM version? Pin
apprentice31429-Mar-12 15:37
memberapprentice31429-Mar-12 15:37 
GeneralOne little fix for avoiding [error C2665: 'operator new'] problem in VS2008 Pin
BruceWang_korea16-Oct-09 1:45
memberBruceWang_korea16-Oct-09 1:45 
AnswerRe: One little fix for avoiding [error C2665: 'operator new'] problem in VS2008 Pin
JO Hyeong-ryeol2-Nov-09 4:35
memberJO Hyeong-ryeol2-Nov-09 4:35 
QuestionCrash in Windows mobile Pin
general_horse24-Sep-09 16:15
membergeneral_horse24-Sep-09 16:15 
AnswerRe: Crash in Windows mobile Pin
jassonwang10-Jan-10 20:01
memberjassonwang10-Jan-10 20:01 
QuestionHow to upload files? Pin
RichyMong10-Jun-09 21:05
memberRichyMong10-Jun-09 21:05 
AnswerRe: How to upload files? Pin
JO Hyeong-ryeol12-Jun-09 5:56
memberJO Hyeong-ryeol12-Jun-09 5:56 
GeneralRe: How to upload files? Pin
RichyMong14-Jun-09 15:49
memberRichyMong14-Jun-09 15:49 
GeneralIt seems to "some Resource leaks" [modified] Pin
Tsukisiro Namo20-May-09 20:28
memberTsukisiro Namo20-May-09 20:28 
QuestionRe: It seems to "some Resource leaks" Pin
JO Hyeong-ryeol21-May-09 5:48
memberJO Hyeong-ryeol21-May-09 5:48 
AnswerRe: It seems to "some Resource leaks" [modified] Pin
Tsukisiro Namo21-May-09 15:03
memberTsukisiro Namo21-May-09 15:03 
Generalvc6 Compiling... error Pin
Qiank4-Mar-09 20:10
memberQiank4-Mar-09 20:10 
GeneralSetting http Header Pin
sodevrom20-Oct-08 13:39
membersodevrom20-Oct-08 13:39 
QuestionHow to post a xml/text file using ChttpClient Pin
manishrsa13-Oct-08 19:19
membermanishrsa13-Oct-08 19:19 
AnswerRe: How to post a xml/text file using ChttpClient Pin
raytse4-Jan-11 18:09
memberraytse4-Jan-11 18:09 
GeneralResponse Header information!! Pin
Member #177768623-Jun-08 0:33
memberMember #177768623-Jun-08 0:33 
QuestionMemory leak? [modified] Pin
ahamade13-Apr-08 20:52
memberahamade13-Apr-08 20:52 
QuestionProxy account & password can't be NULL!! Pin
Member #177768617-Mar-08 19:58
memberMember #177768617-Mar-08 19:58 
AnswerRe: Proxy account & password can't be NULL!! Pin
JO Hyeong-ryeol20-Mar-08 3:50
memberJO Hyeong-ryeol20-Mar-08 3:50 
GeneralRe: Proxy account & password can't be NULL!! Pin
Member #177768625-Mar-08 17:01
memberMember #177768625-Mar-08 17:01 
Questionhttps request by PostData via proxy server!! [modified] Pin
Member #177768610-Mar-08 23:49
memberMember #177768610-Mar-08 23:49 
AnswerRe: https request by PostData via proxy server!! Pin
JO Hyeong-ryeol15-Mar-08 8:43
memberJO Hyeong-ryeol15-Mar-08 8:43 
GeneralRe: https request by PostData via proxy server!! Pin
Member #177768617-Mar-08 16:47
memberMember #177768617-Mar-08 16:47 
GeneralCookie handling Pin
qd5kcf54m16-Feb-08 9:10
memberqd5kcf54m16-Feb-08 9:10 
AnswerRe: Cookie handling Pin
JO Hyeong-ryeol15-Mar-08 8:48
memberJO Hyeong-ryeol15-Mar-08 8:48 
Questionhow to set flag - SECURITY_FLAG_IGNORE_UNKNOWN_CA Pin
tw_vincent7-Nov-07 15:46
membertw_vincent7-Nov-07 15:46 
AnswerRe: how to set flag - SECURITY_FLAG_IGNORE_UNKNOWN_CA Pin
JO Hyeong-ryeol15-Mar-08 9:54
memberJO Hyeong-ryeol15-Mar-08 9:54 
GeneralSometime Crash in vs2005 Pin
wangniu13-Oct-07 7:41
memberwangniu13-Oct-07 7:41 
AnswerRe: Sometime Crash in vs2005 Pin
JO Hyeong-ryeol17-Oct-07 2:36
memberJO Hyeong-ryeol17-Oct-07 2:36 
GeneralMemory Leak!! Pin
Sangminnnnnnnnnnnnnnnnnn10-Jul-07 23:30
memberSangminnnnnnnnnnnnnnnnnn10-Jul-07 23:30 
AnswerRe: Memory Leak!! Pin
JO Hyeong-ryeol24-Jul-07 6:05
memberJO Hyeong-ryeol24-Jul-07 6:05 
GeneralWindows CE port and compilation fixes [modified] Pin
Vincent_RICHOMME1-Jul-07 3:48
memberVincent_RICHOMME1-Jul-07 3:48 
GeneralRe: Windows CE port and compilation fixes [modified] Pin
Vincent_RICHOMME2-Jul-07 0:19
memberVincent_RICHOMME2-Jul-07 0:19 
GeneralRe: Windows CE port and compilation fixes Pin
Vincent_RICHOMME4-Jul-07 13:35
memberVincent_RICHOMME4-Jul-07 13:35 
GeneralUse this program to deal with YouTube Pin
Evan Lin26-Jun-07 20:26
memberEvan Lin26-Jun-07 20:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.160621.1 | Last Updated 10 Aug 2007
Article Copyright 2004 by JO Hyeong-Ryeol
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid