Porting WinINet Applications to WinHTTP
Microsoft Windows HTTP Services (WinHTTP) is targeted at middle-tier and back-end server applications that require access to an HTTP client stack. Microsoft Windows Internet (WinINet) provides an HTTP client stack for client applications, as well as access to the File Transfer Protocol (FTP), SOCKSv4, and Gopher protocols. This overview can help determine whether porting your WinINet applications to WinHTTP would be beneficial. It also describes specific conversion requirements.
- Things to Consider Before Porting Your WinINet Application
- WinHTTP Equivalents to WinINet Functions
- Different Handling of Asynchronous Requests
- Differences in WinHTTP Callback Notifications
- Authentication Differences
- Differences in Secure HTTP Transactions
Things to Consider Before Porting Your WinINet Application
Consider porting your WinINet application to WinHTTP if your application would benefit from:
- A server-safe HTTP client stack.
- Minimized stack usage.
- The scalability of a server application.
- Fewer dependencies on platform-related APIs.
- Support for thread impersonation.
- A service-friendly HTTP stack.
- Access to the scriptable WinHttpRequest object.
Do not consider porting your WinINet application to WinHTTP if it must support one or more of the following:
- The FTP or Gopher protocol from the HTTP stack.
- Support for SOCKSv4 protocol for communicating with SOCKS proxies.
- Automatic dial-up services.
If you decide to port your application to WinHTTP, the following sections guide you through the conversion process.
For a sample application for both WinINet and WinHTTP, compare the AsyncDemo sample for WinINet with the AsyncDemo sample for WinHTTP.
WinHTTP Equivalents to WinINet Functions
The following table lists WinINet functions related to the HTTP client stack together with the WinHTTP equivalents.
If your application requires WinINet functions that are not listed, do not port your application to WinHTTP.
WinINet function | WinHTTP equivalent | Notable changes |
---|---|---|
HttpAddRequestHeaders | WinHttpAddRequestHeaders | None. |
HttpEndRequest | WinHttpReceiveResponse | The context value is set with WinHttpSendRequest or WinHttpSetOption. Request options are set with WinHttpOpenRequest. WinHttpReceiveResponse must be called after sending a request. |
HttpOpenRequest | WinHttpOpenRequest | The context value is set with WinHttpSendRequest or WinHttpSetOption. |
HttpQueryInfo | WinHttpQueryHeaders | None. |
HttpSendRequest | WinHttpSendRequest | The context value can be set with WinHttpSendRequest. |
HttpSendRequestEx | WinHttpSendRequest | Buffers cannot be provided. |
InternetCanonicalizeUrl | No equivalent | URLs are now put in canonical form in WinHttpOpenRequest. |
InternetCheckConnection | No equivalent | Not implemented in WinHTTP. |
InternetCloseHandle | WinHttpCloseHandle | Closing a parent handle in WinHTTP does not recursively close child handles. |
InternetCombineUrl | No equivalent | URLs can be assembled with the WinHttpCreateUrl function. |
InternetConfirmZoneCrossing | No equivalent | Not implemented in WinHTTP. |
InternetConnect | WinHttpConnect | The context value is set with WinHttpSendRequest or WinHttpSetOption. Request options are set with WinHttpOpenRequest. User credentials are set with WinHttpSetCredentials. |
InternetCrackUrl | WinHttpCrackUrl | Opposite behavior of the ICU_ESCAPE flag: with InternetCrackUrl, this flag causes escape sequences (%xx) to be converted to characters, but with WinHttpCrackUrl, it causes characters that must be escaped from in an HTTP request to be converted to escape sequences. |
InternetCreateUrl | WinHttpCreateUrl | None. |
InternetErrorDlg | No equivalent | Because WinHTTP is targeted at server-side applications, it does not implement any user interface. |
InternetGetCookie | No equivalent | WinHTTP does not persist data between sessions and cannot access WinINet cookies. |
InternetOpen | WinHttpOpen | None. |
InternetOpenUrl | WinHttpConnect, WinHttpOpenRequest, WinHttpSendRequest, WinHttpReceiveResponse | This functionality is available in the WinHTTP functions listed. |
InternetQueryDataAvailable | WinHttpQueryDataAvailable | No reserved parameters. |
InternetQueryOption | WinHttpQueryOption | WinHTTP offers a different set of options from WinINet. For more information and options offered by WinHTTP, see Option flags. |
InternetReadFile | WinHttpReadData | None. |
InternetReadFileEx | WinHttpReadData | Rather than a structure, the buffer is a region of memory addressed with a pointer. |
InternetSetOption | WinHttpSetOption | None. |
InternetSetStatusCallback | WinHttpSetStatusCallback | For more information, see "Different Handling of Asynchronous Requests" in this topic. |
InternetTimeFromSystemTime | WinHttpTimeFromSystemTime | None. |
InternetTimeToSystemTime | WinHttpTimeToSystemTime | None. |
InternetWriteFile | WinHttpWriteData | None. |
Different Handling of Asynchronous Requests
Be aware that in WinINet and WinHTTP, some functions can complete asynchronous requests either synchronously or asynchronously. Your application must handle either situation. There are significant differences in how WinINet and WinHTTP handle these potentially asynchronous functions.
WinINet
Synchronous completion: If a potentially asynchronous WinINet function call completes synchronously, the OUT parameters of the function return the results of the operation. When an error occurs, retrieve the error code by calling GetLastError after the WinINet function call.
Asynchronous completion: If a potentially asynchronous function call completes asynchronously, the results of the operation, and any errors, are accessible in the callback function. The callback function is executed on a worker thread, not on the thread that made the initial function call.
In other words, your application must duplicate logic to handle the results of such operations in two places: both immediately after the function call and in the callback function.
WinHTTP simplifies this model by enabling you to implement the operational logic only in the callback function, which receives a completion notification regardless of whether the operation completed synchronously or asynchronously. When asynchronous operation is enabled, the OUT parameters of WinHTTP functions do not return meaningful data and must be set to NULL.
The only significant difference between asynchronous and synchronous completion in WinHTTP, from the application perspective, is in where the callback function is executed.
WinHTTP
Synchronous completion: When an operation completes synchronously, the results are returned in a callback function that executes in the same thread as the original function call.
Asynchronous completion: When an operation completes asynchronously, the results are returned in a callback function that executes in a worker thread.
Although most errors can also be handled entirely within the callback function, WinHTTP applications must still be prepared for a function to return FALSE because of an ERROR_INVALID_PARAMETER or other similar error retrieved by calling GetLastError.
Unlike WinINet, which can execute multiple asynchronous operations simultaneously, WinHTTP enforces a policy of one pending asynchronous operation per request handle. If one operation is pending and another WinHTTP function is called, the second function fails and GetLastError returns ERROR_INVALID_OPERATION.
WinHTTP simplifies this model by enabling you to implement the operational logic only in the callback function, which receives a completion notification regardless of whether the operation completed synchronously or asynchronously. When asynchronous operation is enabled, the OUT parameters of WinHTTP functions do not return meaningful data and must be set to NULL.
Differences in WinHTTP Callback Notifications
The status callback function receives updates on the status of operations through notification flags. In WinHTTP, notifications are selected using the dwNotificationFlags parameter of the WinHttpSetStatusCallback function. Use the WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS flag to be notified of all status updates.
Notifications that indicate a particular operation is complete are called completion notifications, or just completions. In WinINet, each time the callback function receives a completion, the lpvStatusInformation parameter contains an INTERNET_ASYNC_RESULT structure. In WinHTTP, this structure is not available for all completions. It is important to review the reference page for WINHTTP_STATUS_CALLBACK, which contains information about notifications and what type of data can be expected for each.
In WinHTTP, a single completion, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, indicates that an operation failed. All other completions indicate a successful operation.
Both WinINet and WinHTTP use a user-defined context value to pass information from the main thread to the status callback function, which can be executed on a worker thread. In WinINet, the context value used by the status callback function is set by calling one of several functions. In WinHTTP, the context value is set only with WinHttpSendRequest or WinHttpSetOption. Because of this, it is possible in WinHTTP for a notification to occur before a context value is set. If the callback function receives a notification before the context value is set, the application must be prepared to receive NULL in the dwContext parameter of the callback function.
Authentication Differences
In WinINet, user credentials are set by calling the InternetSetOption function, using code similar to that provided in the following code example.
// Use the WinINet InternetSetOption function to set the
// user credentials to the user name contained in strUsername
// and the password to the contents of strPassword.
InternetSetOption( hRequest, INTERNET_OPTION_PROXY_USERNAME,
strUsername, strlen(strUsername) + 1 );
InternetSetOption( hRequest, INTERNET_OPTION_PROXY_PASSWORD,
strPassword, strlen(strPassword) + 1 );
For compatibility, user credentials can similarly be set in WinHTTP using the WinHttpSetOption function, but this is not recommended because it can pose a security vulnerability.
Instead, when an application receives a 401 status code in WinHTTP, the recommended method of setting credentials is first to identify an authentication scheme using WinHttpQueryAuthSchemes and, second, set the credentials using WinHttpSetCredentials. The following code example shows how to do this.
DWORD dwSupportedSchemes;
DWORD dwPrefered;
DWORD dwTarget;
// Obtain the supported and first schemes.
WinHttpQueryAuthSchemes( hRequest, &dwSupportedSchemes, &dwPrefered, &dwTarget );
// Set the credentials before resending the request.
WinHttpSetCredentials( hRequest, dwTarget, dwPrefered, strUsername, strPassword, NULL );
Because there is no equivalent to InternetErrorDlg in WinHTTP, applications that obtain credentials through a user interface must provide their own interface.
Unlike WinINet, WinHTTP does not cache passwords. Valid user credentials must be supplied for each request.
WinHTTP does not support the Distributed Password Authentication (DPA) scheme supported by WinINet. WinHTTP does, however, support Microsoft Passport 1.4. For more information about using Passport authentication in WinHTTP, see Passport Authentication in WinHTTP.
WinHTTP does not rely on Internet Explorer settings to determine the automatic logon policy. Instead, the auto-logon policy is set with WinHttpSetOption. For more information about authentication in WinHTTP, including the auto-logon policy, see Authentication in WinHTTP.
Differences in Secure HTTP Transactions
In WinINet, initiate a secure session using either HttpOpenRequest or InternetConnect, but in WinHTTP, you must call WinHttpOpenRequest using the WINHTTP_FLAG_SECURE flag.
In a secure HTTP transaction, server certificates can be used to authenticate a server to the client. In WinINet, if a server certificate contains errors, HttpSendRequest fails and provides details about the certificate errors.
In WinHttp, server certificate errors are handled according to the version as follows:
- Starting with WinHttp 5.1, if a server certificate fails or contains errors, the call to WinHttpSendRequest reports a WINHTTP_CALLBACK_STATUS_SECURE_FAILURE in the callback function. If the error generated by WinHttpSendRequest is ignored, subsequent calls to WinHttpReceiveResponse fail with an ERROR_WINHTTP_OPERATION_CANCELLED error.
- In WinHTTP 5.0, errors in server certificates do not, by default, cause a request to fail. Instead, the errors are reported in the callback function with the WINHTTP_CALLBACK_STATUS_SECURE_FAILURE notification.
On some earlier platforms, WinINet supported the Private Communication Technology (PCT) and/or Fortezza protocols, although not on Windows XP.
WinHTTP does not support the PCT and Fortezza protocols on any platform, and instead relies on Secure Sockets Layer (SSL) 2.0, SSL 3.0, or Transport Layer Security (TLS) 1.0.