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:
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). Figure 8.2. Function-calling sequence for Internet and HTTP functionsCracking the URL InternetCrackUrlEach 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:
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).
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". Connecting to a Server InternetConnectThe 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.
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. Obtaining a Request Handle HttpOpenRequestAll 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 Making the Request HttpSendRequestAfter 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.
Listing 8.2 shows the entire code used to prompt the user for a URL and display the HTML code returned from the server. Listing 8.2 Making an HTTP request using a session#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] = '\0'; mbstowcs(szBuffer, charBuffer, dwRead); szBuffer[dwRead] = '\0'; cout szBuffer; } while(dwRead > 0); cleanUp: if(hHttpRequest != NULL) InternetCloseHandle(hHttpRequest); if(hHttpSession != NULL) InternetCloseHandle(hHttpSession); if(hHttpOpen != NULL) InternetCloseHandle(hHttpOpen); }
|