WinHTTP AutoProxy Functions
WinHTTP implements the WPAD protocol using the WinHttpGetProxyForUrl function along with two supporting utility functions, WinHttpDetectAutoProxyConfigUrl and WinHttpGetIEProxyConfigForCurrentUser.
AutoProxy support is not fully integrated into the HTTP stack in WinHTTP. Before sending a request, the application must call WinHttpGetProxyForUrl to obtain the name of a proxy server and then call WinHttpSetOption using WINHTTP_OPTION_PROXY to set the proxy configuration on the WinHTTP request handle created by WinHttpOpenRequest.
The WinHttpGetProxyForUrl function can execute all three steps of the WPAD protocol described in the previous overview: (1) discover the PAC URL, (2) download the PAC script file, (3) execute the script code and return the proxy configuration in a WINHTTP_PROXY_INFO structure. Optionally, if the application knows in advance the PAC URL it can specify this to WinHttpGetProxyForUrl.
The following example code uses autoproxy. It sets up an HTTP GET request by first creating the WinHTTP session connect and request handles. The WinHttpOpen call specifies WINHTTP_ACCESS_TYPE_NO_PROXY for the initial proxy configuration, to indicate that requests are sent directly to the target server by default. Using autoproxy, it then sets the proxy configuration directly on the request handle.
HINTERNET hHttpSession = NULL;
HINTERNET hConnect = NULL;
HINTERNET hRequest = NULL;
WINHTTP_AUTOPROXY_OPTIONS AutoProxyOptions;
WINHTTP_PROXY_INFO ProxyInfo;
DWORD cbProxyInfoSize = sizeof(ProxyInfo);
ZeroMemory( &AutoProxyOptions, sizeof(AutoProxyOptions) );
ZeroMemory( &ProxyInfo, sizeof(ProxyInfo) );
//
// Create the WinHTTP session.
//
hHttpSession = WinHttpOpen( L"WinHTTP AutoProxy Sample/1.0",
WINHTTP_ACCESS_TYPE_NO_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS,
0 );
// Exit if WinHttpOpen failed.
if( !hHttpSession )
goto Exit;
//
// Create the WinHTTP connect handle.
//
hConnect = WinHttpConnect( hHttpSession,
L"www.microsoft.com",
INTERNET_DEFAULT_HTTP_PORT,
0 );
// Exit if WinHttpConnect failed.
if( !hConnect )
goto Exit;
//
// Create the HTTP request handle.
//
hRequest = WinHttpOpenRequest( hConnect,
L"GET",
L"ms.htm",
L"HTTP/1.1",
WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
0 );
// Exit if WinHttpOpenRequest failed.
if( !hRequest )
goto Exit;
//
// Set up the autoproxy call.
//
// Use auto-detection because the Proxy
// Auto-Config URL is not known.
AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
// Use DHCP and DNS-based auto-detection.
AutoProxyOptions.dwAutoDetectFlags =
WINHTTP_AUTO_DETECT_TYPE_DHCP |
WINHTTP_AUTO_DETECT_TYPE_DNS_A;
// If obtaining the PAC script requires NTLM/Negotiate
// authentication, then automatically supply the client
// domain credentials.
AutoProxyOptions.fAutoLogonIfChallenged = TRUE;
//
// Call WinHttpGetProxyForUrl with our target URL. If
// auto-proxy succeeds, then set the proxy info on the
// request handle. If auto-proxy fails, ignore the error
// and attempt to send the HTTP request directly to the
// target server (using the default WINHTTP_ACCESS_TYPE_NO_PROXY
// configuration, which the requesthandle will inherit
// from the session).
//
if( WinHttpGetProxyForUrl( hHttpSession,
L"https://www.microsoft.com/ms.htm",
&AutoProxyOptions,
&ProxyInfo))
{
// A proxy configuration was found, set it on the
// request handle.
if( !WinHttpSetOption( hRequest,
WINHTTP_OPTION_PROXY,
&ProxyInfo,
cbProxyInfoSize ) )
{
// Exit if setting the proxy info failed.
goto Exit;
}
}
//
// Send the request.
//
if( !WinHttpSendRequest( hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS,
0,
WINHTTP_NO_REQUEST_DATA,
0,
0,
NULL ) )
{
// Exit if WinHttpSendRequest failed.
goto Exit;
}
//
// Wait for the response.
//
if( !WinHttpReceiveResponse( hRequest, NULL ) )
goto Exit;
//
// A response has been received, then process it.
// (omitted)
//
Exit:
//
// Clean up the WINHTTP_PROXY_INFO structure.
//
if( ProxyInfo.lpszProxy != NULL )
GlobalFree(ProxyInfo.lpszProxy);
if( ProxyInfo.lpszProxyBypass != NULL )
GlobalFree( ProxyInfo.lpszProxyBypass );
//
// Close the WinHTTP handles.
//
if( hRequest != NULL )
WinHttpCloseHandle( hRequest );
if( hConnect != NULL )
WinHttpCloseHandle( hConnect );
if( hHttpSession != NULL )
WinHttpCloseHandle( hHttpSession );
In the provided example code, the call to WinHttpGetProxyForUrl instructs the function to discover the proxy auto-config file automatically by specifying the WINHTTP_AUTOPROXY_AUTO_DETECT flag in the WINHTTP_AUTOPROXY_OPTIONS structure. Use of the WINHTTP_AUTOPROXY_AUTO_DETECT flag requires the code to specify one or both of the auto-detection flags (WINHTTP_AUTO_DETECT_TYPE_DHCP, WINHTTP_AUTO_DETECT_TYPE_DNS_A). The example code uses the auto-detection feature of WinHttpGetProxyForUrl because the PAC URL is not known in advance. If a PAC URL cannot be located on the network in this scenario, WinHttpGetProxyForUrl fails (GetLastError returns ERROR_WINHTTP_AUTODETECTION_FAILED).
If the PAC URL is Known in Advance
If the application does know the PAC URL, it can specify it in the WINHTTP_AUTOPROXY_OPTIONS structure and configure WinHttpGetProxyForUrl to skip the auto-detection phase.
For example, if a PAC file is available on the local network at the URL, "https://InternalSite/proxy-config.pac", the call to WinHttpGetProxyForUrl would look the following.
//
// Set up the autoproxy call.
//
// The proxy auto-config URL is known. Auto-detection
// is not required.
AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
// Set the proxy auto-config URL.
AutoProxyOptions. lpszAutoConfigUrl = L"https://InternalSite/proxy-config.pac";
// If obtaining the PAC script requires NTLM/Negotiate
// authentication, then automatically supply the client
// domain credentials.
AutoProxyOptions.fAutoLogonIfChallenged = TRUE;
//
// Call WinHttpGetProxyForUrl with our target URL. If auto-proxy
// succeeds, then set the proxy info on the request handle.
// If auto-proxy fails, ignore the error and attempt to send the
// HTTP request directly to the target server (using the default
// WINHTTP_ACCESS_TYPE_NO_PROXY configuration, which the request
// handle will inherit from the session).
//
if( WinHttpGetProxyForUrl( hHttpSession,
L"https://www.microsoft.com/ms.htm",
&AutoProxyOptions,
&ProxyInfo ) )
{
//...
If the WINHTTP_AUTOPROXY_OPTIONS structure specifies both WINHTTP_AUTOPROXY_AUTO_DETECT and WINHTTP_AUTOPROXY_CONFIG_URL flags (and specifies auto-detction flags and an auto-config URL), WinHttpGetProxyForUrl first attempts auto-detection, and then, if auto-detection fails to locate a PAC URL, "falls back" to the auto-config URL supplied by the application.
The WinHttpDetectAutoProxyConfigUrl Function
The WinHttpDetectAutoProxyConfigUrl function implements a subset of the WPAD protocol: it attempts to auto-detect the URL for the proxy auto-config file, without downloading or executing the PAC file. This function is useful in special situations where a Web client application must handle the download and execution of the PAC file itself.
The WinHttpGetIEProxyConfigForCurrentUser Function
The WinHttpGetIEProxyConfigForCurrentUser function returns the current user Internet Explorer proxy settings for the current active network connection, without calling into "WinInet.dll". This function is only useful when called within a process that is running under an interactive user account identity, because no Internet Explorer proxy configuration is likely to be available otherwise. For example, it would not be useful to call this function from an ISAPI DLL running in the IIS service process. For more information and a scenario in which a WinHTTP-based application would use WinHttpGetIEProxyConfigForCurrentUser, see Discovery Without an Auto-Config File.