So far, all the HTTP calls covered in this chapter have been used to obtain data from an Internet server. Obviously, if you intend to use HTTP to access, for example, enterprise databases, you will need to send data back to the server. This can be done by doing the following:
The first technique is the easier to use, but the second is more flexible. Sending Data with the URLData is appended onto a URL following a "?" character. The data must follow the standard rules regarding legal characters. For example, spaces must be sent as "%20". This requires the data to be encoded by the client application and decoded by the server. You can only append limited amounts of data to a URL since the overall length of the URL is limited, and the limit varies from Internet server to Internet server. The function InternetCanonicalizeUrl can be used to encode data. This function, through the Flags parameter, allows control over how the encoding takes place. The function will fail if the buffer is not large enough to contain the encoded characters. Because of the nature of the encoding, the returned string can be significantly longer than the string passed for encoding.
Listing 8.5 shows a code fragment that prompts the user for a URL and data to append onto the URL. The HTTP connection is opened using InternetOpen. Next, InternetCanonicalizeUrl is called to encode the data, and this data is appended onto the URL. Finally, InternetOpenUrl is called to request the data back from the server. The data can be read using the code shown in Listing 8.1 using InternetReadFile. Listing 8.5 Sending data with the URLif(!GetTextResponse(_T("Enter URL to Display: "), szURL, MAX_PATH)) return; if(!GetTextResponse(_T("Data To Send: "), szData, MAX_PATH)) return; hHttpOpen = InternetOpen(_T("Example Agent"), INTERNET_OPEN_TYPE_DIRECT, NULL, // no proxy NULL, // no bypass addresses 0); // no flags dwBuffLen = MAX_PATH; if(!InternetCanonicalizeUrl(szData, szDataCan, &dwBuffLen, 0)) { cout _T("Could not encode request %d") GetLastError(); return; } wcscpy(szURLRequest, szURL); wcscat(szURLRequest, szDataCan); cout _T("URL Request: ") szURLRequest endl; hHttpRequest = InternetOpenUrl(hHttpOpen, szURLRequest, NULL, 0, 0, 0); The nature of the URL depends on how the server application is written. The following example shows a URL with data being sent to a Microsoft Visual Basic WebClass application that is called through an Active Server Page (ASP): http://MyServer/WinCETest/WinCETest.ASP?WCI=Bounce&WCE=Test %20Data In this case, the server is called "MyServer," the path is "WinCETest,", and the resource to be opened is WinCETest.ASP. The data follows the "?". In the case of Visual Basic web classes, the data following WCE= is an entry point into the Visual Basic DLL, and the data following WCE= is passed to the Visual Basic code. Notice how the data "Test Data" has been encoded into "Test%20Data." If you do not have a suitable site to test against, you can enter the following for the URL: http://www.softwarepaths.com/WinCEProgramming/WinCETest.ASP?WCI=Bounce&WCE= You can enter anything you like for the data, and the ASP page will send back the data to you as the resource. Posting Data to the ServerSo far, all the HTTP requests sent from the Windows CE device have used the HTTP "GET" verb. This verb simply requests that the given resource is returned to the client. The "POST" verb can be used to send information to the server, and this data can be read by a server application. You can send any type of data (both text and binary), and there is no effective limit to the amount of data that can be sent. Using "POST" is much the same as using "GET", except that you should do the following:
Listing 8.6 shows code used to send a "POST" HTTP request in the HttpOpenRequest and the sending of data using HttpSendRequest. Listing 8.6 Using the "POST" verbLPCTSTR lpHeader = _T("Content-Type: application/x-www-form-urlencoded\r\n"); LPCTSTR lpData = _T("The data to be sent to the Internet Server"); hHttpRequest = HttpOpenRequest(hHttpSession, _T("POST"), // verb 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(!HttpAddRequestHeaders(hHttpRequest, lpHeader, wcslen(lpHeader), HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD)) { cout _T("Could not add HTTP header ") GetLastError(); goto cleanUp; } // convert the data to ANSI char szAnsi[1024]; wcstombs(szAnsi, lpData, wcslen(lpData)); szAnsi[wcslen(lpData)] = '\0'; if(!HttpSendRequest(hHttpRequest, NULL, 0, // no extra headers (LPVOID)szAnsi, // data to be sent strlen(szAnsi))) // length of data { cout _T("Could not send request ") GetLastError(); goto cleanUp; } The "Content-Type" header pointed to by lpHeader must be added to the request using HttpAddRequestHeaders before HttpSendRequest is called. Note that this header string should be Unicode. Once this is done, HttpSendRequest is called. The last two parameters of the call specify the pointer to the data (szAnsi) and its length to be sent to the server. Note that this data should be sent as ANSI unless the server application is specifically written to accept Unicode. The usual code can be used to read a response from the server following the call to HttpSendRequest.
You can use the following URL if you do not have an Internet site to test against. This Microsoft Visual Basic WebClass application will send back the posted data converted to upper case. http://www.softwarepaths.com/WinCEProgramming/WinCETest.ASP? WCI=PostData&WCE=
|