The simple HTTP request described in previous sections allows resources to be downloaded. However, you will need more control when sending data to the server or making more complex requests. For example, you may want to specify usernames and passwords. This section describes how to open a request, to send headers, and to send data to the server.
The following calls are required in order to make HTTP requests:
InternetOpen to initialize the Windows CE Internet functions and return a handle to access other Internet functions
InternetConnect to make a connection to the Internet server and return a connection, or session, handle
HttpOpenRequest to specify the URL (Universal Resource Locator) of the resource to be acquired (for example, the HTML page) and return a request handle
HttpSendRequest to send the request specified in HttpOpenRequest to the server
InternetReadFile repeatedly until all the data has been read from the server
InternetCloseHandle on each handle returned from steps 1-3
Certain steps in the above list can be repeated. For example, if you want to request multiple HTML files from the same server, you can repeat steps 3 and 4 as required. You need only call step 1 once when the application starts, and step 6 for the handle returned from InternetOpen when the application terminates (Figure 8.2).
Each resource on the Internet or on an intranet has a unique name called a Universal Resource Locator, or URL. The URL contains information such as the following:
The protocol used to access the URL (such as HTTP).
The server the resource is located on, either as a named server (for example, www.microsoft.com) or an IP address (192.168.0.2).
The resource name's location on the server. This is typically a folder or directory specification including the name of the file.
The port number used on the server for the protocol being specified. Most protocols usually have a default port number (HTTP is 80), but this may be different on some servers.
A fully qualified URL, including a port number and fully qualified resource name, looks like "http://www.microsoft.com:80/windowsce/default.asp," which can be shortened using defaults to http://www.microsoft.com/windowsce/, since 80 is the default port number and default.asp is the default resource name for this site.
When you receive a URL from the user, you need to be able to parse out the server name and resource name, and this can become quite complex. Fortunately, Windows CE provides the InternetCrackUrl function for doing this (Table 8.5).
InternetCrackURL | |
---|---|
LPCTSTR lpszUrl | Pointer to the URL to be parsed |
DWORD dwUrlLength | Length of the URL, or zero if NULL-terminated |
DWORD dwFlags | Set to 0 to parse URL without encoding or decoding characters |
LPURL_COMPONENTS lpUrlComponents | URL_COMPONENTS structure into which the parsed URL elements are returned |
BOOL Return Value | TRUE for success, FALSE for failure |
The trick to using this function successfully is the initialization of the URL_COMPONENTS structure. This structure contains pointers to the various possible elements of the URL. These pointers must either be initialized to NULL if the element is not to be returned, or point at a string buffer if it is to be returned. In the following code fragment a URL_COMPONENT structure is initialized to return the server name and the path to the resource. Further, the dwStructSize member must be initialized to the size of the structure.
URL_COMPONENTS crackedURL; TCHAR szServer[1024]; TCHAR szPath[1024]; memset(&crackedURL, 0, sizeof(crackedURL)); crackedURL.dwStructSize = sizeof(crackedURL); crackedURL.lpszHostName = szServer; crackedURL.dwHostNameLength = 1024; crackedURL.lpszUrlPath = szPath; crackedURL.dwUrlPathLength = 1024; InternetCrackUrl(szURL, 0, 0, &crackedURL);
In this code fragment, the string szURL contains the full URL (for example, http://www.microsoft.com/windowsce/default.asp. On return lpszHostName would contain www.microsoft.com and lpszURLPath would contain "/windowsce/default.asp".
The function InternetConnect (Table 8.6) is used to make a connection to a specified server, and is passed access information (for example, the user-name and password to connect with) and the port number and protocol to use. Once a connection has been made, multiple requests can be made to retrieve resources.
InternetConnect | |
---|---|
HINTERNET hInternet | Handle returned from InternetOpen |
LPCTSTR lpszServerName | Server name, e.g. "www.microsoft.com" |
INTERNET_PORT nServerPort | Port number, e.g. INTERNET_DEFAULT_HTTP_PORT for HTTP |
LPCTSTR lpszUserName | Pointer to the user name used to validate access to the server, or NULL for anonymous login |
LPCTSTR lpszPassword | Pointer to the password, or NULL for anonymous login |
DWORD dwService | Service or protocol to use, e.g. INTERNET_SERVICE_HTTP |
DWORD dwFlags | Flags specifying options, or 0 for no options |
DWORD dwContext | Context value used in callback functions |
HANDLE Return Value | Session handle, or NULL if function call fails |
Most servers on the Internet do not require valid usernames and passwords—they use anonymous login. In this situation, the call to InternetConnect is straightforward. In the following code fragment, a connection is made to the server name returned from cracking a fully qualified URL using the HTTP protocol.
HINTERNET hHttpSession = NULL; hHttpSession = InternetConnect(hHttpOpen, crackedURL.lpszHostName, // server name INTERNET_DEFAULT_HTTP_PORT, NULL // username NULL, // password INTERNET_SERVICE_HTTP, 0, // no flags 0); // no context
There are a number of issues to consider when connecting to a secure Internet site, and these are covered later in the chapter.
All the functions used so far are generic Internet functions—they are used for HTTP, FTP, and any other supported protocols. The function HttpOpenRequest (Table 8.7) is, as its name implies, specific to the HTTP protocol and is used to open a handle through which a request to download a resource (such as a file or image) is made.
Simple requests generally use the GET verb. Small amounts of information can be sent to the server in the URL. The POST verb is used for sending larger amounts of data (such as files) to the server. These topics are covered later in this chapter.
The next code fragment shows how to make a simple request to an HTTP server using the resource path obtained through calling InternetCrackUrl.
hHttpRequest = HttpOpenRequest(hHttpSession, NULL, // verb is 'GET' crackedURL.lpszUrlPath, NULL, // default version NULL, // no referrer NULL, // only accept text/* files 0, // no flags 0); // no context for call backs
After opening a request using HttpOpenRequest, the function HttpSendRequest (Table 8.8) is called to send the request off to the server:
HttpSendRequest(hHttpRequest, NULL, 0, // no headers 0, 0)); // no optional data
Additional HTTP headers can be specified when the request is sent by calling HttpSendRequest. Alternatively, additional headers can be added using the function HttpAddRequestHeaders before the request is sent. This is illustrated later in the chapter.
HttpSendRequest | |
---|---|
HINTERNET hRequest | Request handle obtained from HttpOpenRequest |
LPCTSTR lpszHeaders | Additional headers, or NULL for none |
DWORD dwHeadersLength | Length of additional headers, or 0 for none |
LPVOID lpOptional | Optional data, or NULL for none |
DWORD dwOptionalLength | Length of optional data, or 0 for none |
BOOL Return Value | TRUE on success, otherwise FALSE |
Listing 8.2 shows the entire code used to prompt the user for a URL and display the HTML code returned from the server.
#define CHUNKSIZE 500 void Listing8_2() { TCHAR szURL[MAX_PATH + 1]; HINTERNET hHttpOpen = NULL; HINTERNET hHttpSession = NULL; HINTERNET hHttpRequest = NULL; char charBuffer[CHUNKSIZE + 1]; TCHAR szBuffer[CHUNKSIZE + 1]; DWORD dwRead; URL_COMPONENTS crackedURL; TCHAR szServer[1024]; TCHAR szPath[1024]; if(!GetTextResponse(_T("Enter URL to Display: "), szURL, MAX_PATH)) return; hHttpOpen = InternetOpen( _T("Example Agent"), INTERNET_OPEN_TYPE_DIRECT, NULL, // no proxy NULL, // no bypass addresses 0); // no flags if(hHttpOpen == NULL) { cout ≪ _T("Could not open internet session ") ≪ GetLastError(); goto cleanUp; } // Crack the URL to get the server name memset(&crackedURL, 0, sizeof(crackedURL)); crackedURL.dwStructSize = sizeof(crackedURL); crackedURL.lpszHostName = szServer; crackedURL.dwHostNameLength = 1024; crackedURL.lpszUrlPath = szPath; crackedURL.dwUrlPathLength = 1024; if(!InternetCrackUrl(szURL, 0, 0, &crackedURL)) { cout ≪ _T("Cannot crack URL") ≪ GetLastError(); goto cleanUp; } hHttpSession = InternetConnect(hHttpOpen, crackedURL.lpszHostName, // server name INTERNET_DEFAULT_HTTP_PORT, NULL, // username NULL, // password INTERNET_SERVICE_HTTP, 0, // no flags 0); // no context if(hHttpSession == NULL) { cout ≪ _T("Could not open Internet connection") ≪ GetLastError(); goto cleanUp; } hHttpRequest = HttpOpenRequest(hHttpSession, NULL, // verb is 'GET' crackedURL.lpszUrlPath, NULL, // default version NULL, // no referrer NULL, // only accept text/* files 0, // no flags 0); // no context for call backs if(hHttpRequest == NULL) { cout ≪ _T("Could not get HTTP request ") ≪ GetLastError(); goto cleanUp; } if(!HttpSendRequest(hHttpRequest, NULL, 0, // no headers 0, 0)) // no optional data { cout ≪ _T("Could not read data ") ≪ GetLastError(); goto cleanUp; } do { // read from Internet HTTP server if(!InternetReadFile(hHttpRequest, charBuffer, CHUNKSIZE, &dwRead)) { cout ≪ _T("Could not send request") ≪ GetLastError(); goto cleanUp; } // convert to Unicode and display charBuffer[dwRead] = ' '; mbstowcs(szBuffer, charBuffer, dwRead); szBuffer[dwRead] = ' '; cout ≪ szBuffer; } while(dwRead > 0); cleanUp: if(hHttpRequest != NULL) InternetCloseHandle(hHttpRequest); if(hHttpSession != NULL) InternetCloseHandle(hHttpSession); if(hHttpOpen != NULL) InternetCloseHandle(hHttpOpen); } |
18.216.190.167