2009-03-27

How to make an HTTP connection in C++ on Windows (Mobile) using WinINet

Making a programmatical HTTP request from an application is a very common use case. However, I found that there are some obstacles, especially if it is not just a standard GET request.

for example, let's say there is an application that needs to upload a binary file to a web server with SSL. Obviously, this makes it slightly more complicated, since the file needs to be read, custom headers added, HTTPS used instead of HTTP, etc.

The below example, for starters, shows how utilize the WinINet library to send a GET request using either HTTP or HTTPS, depending on whether the flag m_bUseSSL is set. The difference between those two is the port setting in InternetConnect() and also the additional flag INTERNET_FLAG_SECURE in HttpOpenRequest.

One thing that kept me in the dark for a while is the accept type parameter in HttpOpenRequest. On Windows Mobile 5.0, if this parameter is NULL, the function will fail with error code 87 ("invalid parameter"), contrary to what the documentation says. Hence, you need to pass the array as documented and also shown below. this is especially a pain because in the emulator for Win Mobile 6.0, which I used for testing, it tolerates a NULL accept type parameter. I hope this saves you some time.



// Accept any text content
const TCHAR * c_szAcceptTypes[] = { TEXT("text/*"), NULL };

HINTERNET hIntrn = InternetOpen(TEXT("HTTP_Connnect_Example"),
INTERNET_OPEN_TYPE_DIRECT,
NULL, // no proxy
NULL,
0); // make it synchronous


if (!hIntrn)
{ // error handling
}

INTERNET_PORT wPort = (m_bUseSSL ? INTERNET_DEFAULT_HTTPS_PORT
: INTERNET_DEFAULT_HTTP_PORT);
HINTERNET hConn = InternetConnect( hIntrn,
m_szServerName,
wPort,
NULL,
NULL,
INTERNET_SERVICE_HTTP,
0,
NULL);
if (!hConn)
{ // error handling
}
else
{

DWORD dwOpenRequestFlags = INTERNET_FLAG_NO_UI |
INTERNET_FLAG_NO_CACHE_WRITE;
// add more flags here as needed
if (m_bUseSSL)
{
dwOpenRequestFlags = dwOpenRequestFlags |
INTERNET_FLAG_SECURE;
}

HINTERNET hReq = HttpOpenRequest(hConn,
TEXT("GET"),
TEXT("index.html"),
TEXT("HTTP/1.1"),
NULL, // no referer
c_szAcceptTypes,
dwOpenRequestFlags,
NULL); // no asynchronous context

if (!hReq)
{ // error handling
}
else
{
if (!HttpSendRequest(hReq, NULL, 0, NULL, 0))
{ // error handling
}
else
{
// read server response
char* pcBuffer = new char[READBUFFSIZE];
DWORD dwBytesRead;

do
{
dwBytesRead=0;
if(InternetReadFile(hReq, pcBuffer,
READBUFFSIZE-1, &dwBytesRead))
{
pcBuffer[dwBytesRead]=0x00; // Null-terminate buffer
sprintf("%S", pcBuffer);
}
else
{ // error handling
}
}
while(dwBytesRead>0);

delete[] pcBuffer;
pcBuffer = NULL;
}
if (!InternetCloseHandle(hReq))
{ // error handling
}
}
if (!InternetCloseHandle(hConn))
{ // error handling
}
}
if (!InternetCloseHandle(hIntrn))
{ // error handling
}

No comments:

Post a Comment