Click here to Skip to main content
15,913,305 members
Articles / Desktop Programming / MFC
Article

Simple HTTP Client using WININET

Rate me:
Please Sign up or sign in to vote.
3.76/5 (46 votes)
2 Sep 20031 min read 593.6K   13.2K   145   167
Simple HTTP Client, HTTP GET, HTTP POST, HTTP POST-MultiPartFormData

Introduction

This class is used for HTTP REQUEST. It supports HTTP GET, HTTP POST and HTTP POST-MultiPartFormData.

Class Overview

C++
class GenericHTTPClient {
public:                    
    ...
    // CONSTRUCTOR & DESTRUCTOR
    GenericHTTPClient();
    virtual ~GenericHTTPClient();

    ...
    // Connection handler    
    BOOL Connect(    LPCTSTR szAddress,
            LPCTSTR szAgent = __DEFAULT_AGENT_NAME,
            unsigned short nPort = INTERNET_DEFAULT_HTTP_PORT,
            LPCTSTR szUserAccount = NULL,
            LPCTSTR szPassword = NULL);

    BOOL Close();
    VOID InitilizePostArguments();

    // HTTP Arguments handler    
    VOID AddPostArguments(LPCTSTR szName, DWORD nValue);
    VOID AddPostArguments(LPCTSTR szName, LPCTSTR szValue, 
      BOOL bBinary = FALSE);

    // HTTP Method handler 
    BOOL Request(    LPCTSTR szURL,
            int nMethod = GenericHTTPClient::RequestGetMethod,
            LPCTSTR szAgent = __DEFAULT_AGENT_NAME);

    BOOL RequestOfURI(LPCTSTR szURI, int nMethod = 
           GenericHTTPClient::RequestGetMethod);
    BOOL Response(PBYTE pHeaderBuffer, DWORD dwHeaderBufferLength, 
           PBYTE pBuffer, DWORD dwBufferLength, DWORD &dwResultSize);    
    LPCTSTR QueryHTTPResponse();
    LPCTSTR QueryHTTPResponseHeader();    

    // General Handler
    DWORD GetLastError();
    LPCTSTR GetContentType(LPCTSTR szName);
    VOID ParseURL(LPCTSTR szURL, LPTSTR szProtocol, LPTSTR szAddress, 
          DWORD &dwPort, LPTSTR szURI);
    
protected:                
    ...
};
  • Connect(...) method connects to HTTP Server.
  • Close() method closes connection. These are used with RequestOfURI(...).
  • InitilizePostArguments() method initializes post arguments.
  • AddPostArguments(...) method is supported so that you can add new post arguments of the following 3 types ( TCHAR, DWORD, FILE).
  • Request(...) method is for you to attempt request for HTTP REQUEST( GET, POST, POST-MULTIPARTFORMDATA) with URL. HTTP METHOD indirector have 3 types.
    • GenericHTTPClient::GetMethod is HTTP GET REQUEST
    • GenericHTTPClient::PostMethod is HTTP POST REQUEST
    • GenericHTTPClient::PostMultiPartsFormData is HTTP POST REQUEST with BINARY FORM DATA
  • RequestOfURI(...) method is that you could have attempt request for HTTP REQUEST with URI. This method is used with Connect(...) and Close().
  • Response(...) method is that you have HTTP Response by BYTES.
  • QueryHTTPResponse() method is you have receive HTML of your HTTP REQUEST.
  • QueryHTTPResponseHeader() method is you have receive HTTP HEADER about QueryHTTPResponse().
  • GetLastError() method is you get windows error code.
  • GetContentType(...) method is you have get MIME-TYPE.
  • ParseURL(...) method parse URL to protocol(HTTP, HTTPS) and address(or hostname) and port, URI.

Usage

Now, you have to simply do  HTTP GET REQUEST iteration.

C++
....

GenericHTTPClient    httpClient;

if(httpRequest.Request("http://www.codeproject.com")){
    LPCTSTR szHTML=httpRequest.QueryResponse();
}else{
    LPVOID     lpMsgBuffer;
    DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | 
             FORMAT_MESSAGE_FROM_SYSTEM,
             NULL,
             httpRequest.GetLastError(),
             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
             reinterpret_cast<LPTSTR>(&lpMsgBuffer),
             0,
             NULL);                         

    MessageBox( reinterpret_cast<LPTSTR>(lpMsgBuffer), "ERROR", MB_OK);
    LocalFree(lpMsgBuffer);
}

This is HTTP POST REQUEST with file posting ( HTTP POST Multipart/form-data)

C++
GenericHTTPClient *pClient=new GenericHTTPClient();

    pClient->InitilizePostArguments();
    pClient->AddPostArguments(__TAG_USRID, szUserID);
    pClient->AddPostArguments(__TAG_JUMIN, szSocialIndex);
    pClient->AddPostArguments(__TAG_SRC, szSource);
    pClient->AddPostArguments(__TAG_DST, szDestination);            
    pClient->AddPostArguments(__TAG_FORMAT, szFormat);
    pClient->AddPostArguments(__TAG_SUBJECT, szMessage);

    if(bCharge){
        pClient->AddPostArguments(__TAG_CHARGE, "Y");
    }else{
        pClient->AddPostArguments(__TAG_CHARGE, "N");
    }
    pClient->AddPostArguments(__TAG_CPCODE, szCPCode);
    pClient->AddPostArguments(__TAG_FILE, szFile, TRUE);

    if(pClient->Request(szURL, 
        GenericHTTPClient::RequestPostMethodMultiPartsFormData)){        
        LPCTSTR szResult=pClient->QueryHTTPResponse();
    }else{
#ifdef    _DEBUG
        LPVOID     lpMsgBuffer;
        DWORD dwRet=FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
                      FORMAT_MESSAGE_FROM_SYSTEM,
                      NULL,
                      pClient->GetLastError(),
                      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                      reinterpret_cast<LPTSTR>(&lpMsgBuffer),
                      0,
                      NULL);
        OutputDebugString(reinterpret_cast<LPTSTR>(lpMsgBuffer));
        LocalFree(lpMsgBuffer);
#endif
    }

}

Thanks

Thanks that you have been reading my article and my bad English. ;p

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


Written By
Software Developer
Korea (Republic of) Korea (Republic of)
Poke tongue | ;-P

Comments and Discussions

 
GeneralRe: BUG: HTML encode Pin
Heo Yongseon18-Feb-04 13:14
Heo Yongseon18-Feb-04 13:14 
GeneralHTTPS Pin
Julien Davard3-Feb-04 6:43
Julien Davard3-Feb-04 6:43 
GeneralRe: HTTPS Pin
Heo Yongseon3-Feb-04 13:38
Heo Yongseon3-Feb-04 13:38 
GeneralRe: HTTPS Pin
julienD6-Feb-04 0:19
julienD6-Feb-04 0:19 
GeneralRe: HTTPS Pin
mingluen30-Nov-04 20:02
mingluen30-Nov-04 20:02 
GeneralUse in ATL Pin
Monty210-Jan-04 0:59
Monty210-Jan-04 0:59 
GeneralRe: Use in ATL Pin
Heo Yongseon11-Jan-04 12:59
Heo Yongseon11-Jan-04 12:59 
GeneralCloseHandle fix Pin
Anonymous5-Jan-04 12:59
Anonymous5-Jan-04 12:59 
I found a few instances of CloseHandle in your code. It should have used InternetCloseHandle().

In the GenericHTTPClient::Connect function and GenericHTTPClient::Close. You should also NULL out the handles on closing the handles.

Finally, if you really want this code to be tight, I would recommend changing the functions to explicitly load wininet.dll, vs dynamic loading. Dynamic linking of dlls in a uncontrolled target environment is not a good idea for production grade code. Applications linking in this class will not always function appropriately if the wininet.dll is not installed, or older versions are installed, etc, etc.

Try something like this:

static HINTERNET (WINAPI *f_InternetOpen)(
IN LPCTSTR lpszAgent,
IN DWORD dwAccessType,
IN LPCTSTR lpszProxy OPTIONAL,
IN LPCTSTR lpszProxyBypass OPTIONAL,
IN DWORD dwFlags) = NULL;
static HINTERNET (WINAPI *f_InternetConnect)(
IN HINTERNET hInternet,
IN LPCTSTR lpszServerName,
IN INTERNET_PORT nServerPort,
IN LPCTSTR lpszUsername,
IN LPCTSTR lpszPassword,
IN DWORD dwService,
IN DWORD dwFlags,
IN DWORD_PTR dwContext) = NULL;
static DWORD (WINAPI *f_InternetAttemptConnect)(
IN DWORD dwReserved ) = NULL;
static BOOL (WINAPI *f_InternetCloseHandle)(
IN HINTERNET hInternet) = NULL;
static HINTERNET (WINAPI *f_HttpOpenRequest)(
IN HINTERNET hConnect,
IN LPCTSTR lpszVerb,
IN LPCTSTR lpszObjectName,
IN LPCTSTR lpszVersion,
IN LPCTSTR lpszReferer,
IN LPCTSTR* lpszAcceptTypes,
IN DWORD dwFlags,
IN DWORD_PTR dwContext ) = NULL;
static BOOL (WINAPI *f_HttpAddRequestHeaders)(
IN HINTERNET hConnect,
IN LPCTSTR lpszHeaders,
IN DWORD dwHeadersLength,
IN DWORD dwModifiers ) = NULL;
static BOOL (WINAPI *f_HttpSendRequest)(
IN HINTERNET hRequest,
IN LPCTSTR lpszHeaders,
IN DWORD dwHeadersLength,
IN LPVOID lpOptional,
IN DWORD dwOptionalLength ) = NULL;
static BOOL (WINAPI *f_InternetQueryOption)(
IN HINTERNET hInternet,
IN DWORD dwOption,
OUT LPVOID lpBuffer,
IN LPDWORD lpdwBufferLength ) = NULL;
static BOOL (WINAPI *f_InternetSetOption)(
HINTERNET hInternet,
DWORD dwOption,
LPVOID lpBuffer,
DWORD dwBufferLength ) = NULL;
static BOOL (WINAPI *f_HttpSendRequestEx)(
HINTERNET hRequest,
LPINTERNET_BUFFERS lpBuffersIn,
LPINTERNET_BUFFERS lpBuffersOut,
DWORD dwFlags,
DWORD dwContext ) = NULL;
static BOOL (WINAPI *f_InternetWriteFile)(
HINTERNET hFile,
LPCVOID lpBuffer,
DWORD dwNumberOfBytesToWrite,
LPDWORD lpdwNumberOfBytesWritten ) = NULL;
static BOOL (WINAPI *f_HttpEndRequest)(
HINTERNET hRequest,
LPINTERNET_BUFFERS lpBuffersOut,
DWORD dwFlags,
DWORD dwContext ) = NULL;
static BOOL (WINAPI *f_InternetReadFile)(
IN HINTERNET hFile,
IN LPVOID lpBuffer,
IN DWORD dwNumberOfBytesToRead,
OUT LPDWORD lpdwNumberOfBytesRead) = NULL;
static BOOL (WINAPI *f_HttpQueryInfo)(
IN HINTERNET hRequest,
IN DWORD dwInfoLevel,
IN OUT LPVOID lpBuffer OPTIONAL,
IN OUT LPDWORD lpdwBufferLength,
IN OUT LPDWORD lpdwIndex OPTIONAL) = NULL;

static HMODULE wininet = NULL;



static int InitWinInet(void)
{
wininet = LoadLibrary("wininet.dll");

if (!wininet)
{
return -1;
}

CPPASS f_InternetOpen = GetProcAddress(wininet, "InternetOpenA");
CPPASS f_InternetConnect = GetProcAddress(wininet, "InternetConnectA");
CPPASS f_InternetAttemptConnect = GetProcAddress(wininet, "InternetAttemptConnect");
CPPASS f_InternetCloseHandle = GetProcAddress(wininet, "InternetCloseHandle");
CPPASS f_HttpOpenRequest = GetProcAddress(wininet, "HttpOpenRequestA");
CPPASS f_HttpAddRequestHeaders = GetProcAddress(wininet, "HttpAddRequestHeadersA");
CPPASS f_HttpSendRequest = GetProcAddress(wininet, "HttpSendRequestA");
CPPASS f_InternetQueryOption = GetProcAddress(wininet, "InternetQueryOptionA");
CPPASS f_InternetSetOption = GetProcAddress(wininet, "InternetSetOptionA");
CPPASS f_HttpSendRequestEx = GetProcAddress(wininet, "HttpSendRequestExA");
CPPASS f_InternetWriteFile = GetProcAddress(wininet, "InternetWriteFile");
CPPASS f_HttpEndRequest = GetProcAddress(wininet, "HttpEndRequestA");
CPPASS f_InternetReadFile = GetProcAddress(wininet, "InternetReadFile");
CPPASS f_HttpQueryInfo = GetProcAddress(wininet, "HttpQueryInfoA");


if ( !f_InternetOpen ||
!f_InternetConnect ||
!f_InternetAttemptConnect ||
!f_InternetCloseHandle ||
!f_HttpOpenRequest ||
!f_HttpAddRequestHeaders ||
!f_HttpSendRequest ||
!f_InternetQueryOption ||
!f_InternetSetOption ||
!f_HttpSendRequestEx ||
!f_InternetWriteFile ||
!f_HttpEndRequest ||
!f_InternetReadFile ||
!f_HttpQueryInfo )
{
return -2;
}

return 0;

}


void UnloadWinInet()
{
if (wininet)
FreeLibrary(wininet);
wininet = NULL;
}

Finally, I thing your sample is excellent. I would make two other ammendments, per some of the suggestions:

1. Add HTTPS support
2. Add custom content types

(remove underscores to retrieve my email address).

k_e_i_t_h@p_i_r_k_l_s.com

GeneralHas anyone tried this with Unicode Pin
Telekinetic18-Dec-03 9:30
Telekinetic18-Dec-03 9:30 
GeneralRe: Has anyone tried this with Unicode Pin
erincode17-Mar-04 16:27
erincode17-Mar-04 16:27 
Questioninone bug? Pin
blastball1-Dec-03 22:37
blastball1-Dec-03 22:37 
AnswerRe: inone bug? Pin
Heo Yongseon2-Dec-03 18:02
Heo Yongseon2-Dec-03 18:02 
GeneralRe: one bug? Pin
blastball2-Dec-03 18:56
blastball2-Dec-03 18:56 
GeneralVery Easy Interface for File send... Pin
Sumit Kapoor24-Nov-03 22:46
Sumit Kapoor24-Nov-03 22:46 
GeneralRe: Very Easy Interface for File send... Pin
Heo Yongseon24-Nov-03 23:06
Heo Yongseon24-Nov-03 23:06 
GeneralRe: Very Easy Interface for File send... Pin
Heo Yongseon25-Nov-03 4:00
Heo Yongseon25-Nov-03 4:00 
GeneralRe: Very Easy Interface for File send... Pin
Sumit Kapoor25-Nov-03 4:14
Sumit Kapoor25-Nov-03 4:14 
GeneralOne problem.... Pin
Sumit Kapoor26-Nov-03 18:15
Sumit Kapoor26-Nov-03 18:15 
GeneralRe: One problem.... Pin
Heo Yongseon26-Nov-03 18:45
Heo Yongseon26-Nov-03 18:45 
GeneralPlease help..me Pin
Sumit Kapoor26-Nov-03 18:50
Sumit Kapoor26-Nov-03 18:50 
GeneralRe: Please help..me Pin
Heo Yongseon26-Nov-03 19:05
Heo Yongseon26-Nov-03 19:05 
GeneralRe: Please help..me Pin
Sumit Kapoor26-Nov-03 20:09
Sumit Kapoor26-Nov-03 20:09 
GeneralRe: Please help..me Pin
Heo Yongseon26-Nov-03 20:24
Heo Yongseon26-Nov-03 20:24 
GeneralThanks its working...but one other... Pin
Sumit Kapoor27-Nov-03 18:07
Sumit Kapoor27-Nov-03 18:07 
GeneralRe: Thanks its working...but one other... Pin
Heo Yongseon30-Nov-03 2:44
Heo Yongseon30-Nov-03 2:44 

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.