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

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.