WinHTTP AutoProxy 函数

WinHTTP 使用 WinHttpGetProxyForUrl 函数以及两个支持实用工具函数实现 WPAD 协议,WinHttpDetectAutoProxyConfigUrlWinHttpGetIEProxyConfigForCurrentUser

AutoProxy 支持未完全集成到 WinHTTP 中的 HTTP 堆栈中。 在发送请求之前,应用程序必须调用 WinHttpGetProxyForUrl 以获取代理服务器的名称,然后使用 WINHTTP_OPTION_PROXY 调用 WinHttpSetOption,以在 WinHttpOpenRequest创建的 WinHTTP 请求句柄上设置代理配置。

WinHttpGetProxyForUrl 函数可以执行上述概述中所述的 WPAD 协议的所有三个步骤:(1)发现 PAC URL,(2)下载 PAC 脚本文件(3)执行脚本代码,并在 WINHTTP_PROXY_INFO 结构中返回代理配置。 (可选)如果应用程序事先知道 PAC URL,则可以将其指定为 WinHttpGetProxyForUrl

以下示例代码使用 autoproxy。 它首先创建 WinHTTP 会话连接和请求句柄来设置 HTTP GET 请求。 winHttpOpen调用指定初始代理配置的 WINHTTP_ACCESS_TYPE_NO_PROXY,以指示请求默认直接发送到目标服务器。 然后,使用 autoproxy 直接在请求句柄上设置代理配置。

  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 );

在提供的示例代码中,调用 WinHttpGetProxyForUrl 指示函数通过在 WINHTTP_AUTOPROXY_OPTIONS 结构中指定 WINHTTP_AUTOPROXY_AUTO_DETECT 标志来自动发现代理自动配置文件。 使用 WINHTTP_AUTOPROXY_AUTO_DETECT 标志需要代码指定一个或两个自动检测标志(WINHTTP_AUTO_DETECT_TYPE_DHCPWINHTTP_AUTO_DETECT_TYPE_DNS_A)。 该示例代码使用 WinHttpGetProxyForUrl 的自动检测功能,因为提前不知道 PAC URL。 如果在此方案中找不到 PAC URL,WinHttpGetProxyForUrl 失败(GetLastError 返回 ERROR_WINHTTP_AUTODETECTION_FAILED)。

如果提前知道 PAC URL

如果应用程序知道 PAC URL,则可以在WINHTTP_AUTOPROXY_OPTIONS结构中指定它,并配置 WinHttpGetProxyForUrl 以跳过自动检测阶段。

例如,如果在 URL 的本地网络上提供 PAC 文件“https://InternalSite/proxy-config.pac",则调用 WinHttpGetProxyForUrl 将如下所示。

//
// 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 ) )
{
  //...

如果 WINHTTP_AUTOPROXY_OPTIONS 结构同时指定 WINHTTP_AUTOPROXY_AUTO_DETECTWINHTTP_AUTOPROXY_CONFIG_URL 标志(并指定自动取消功能标志和自动配置 URL),WinHttpGetProxyForUrl 首次尝试自动检测,然后,如果自动检测找不到 PAC URL,则“回退”到应用程序提供的自动配置 URL。

WinHttpDetectAutoProxyConfigUrl 函数

WinHttpDetectAutoProxyConfigUrl 函数实现 WPAD 协议的子集:它尝试自动检测代理自动配置文件的 URL,而无需下载或执行 PAC 文件。 在 Web 客户端应用程序必须处理 PAC 文件本身的下载和执行的特殊情况下,此函数非常有用。

WinHttpGetIEProxyConfigForCurrentUser 函数

WinHttpGetIEProxyConfigForCurrentUser 函数返回当前活动网络连接的当前用户 Internet Explorer 代理设置,而无需调用“WinInet.dll”。 仅当在交互式用户帐户标识下运行的进程内调用此函数时,此函数才有用,因为其他情况下可能没有 Internet Explorer 代理配置可用。 例如,从 IIS 服务进程中运行的 ISAPI DLL 调用此函数将不起作用。 有关详细信息和基于 WinHTTP 的应用程序将使用 WinHttpGetIEProxyConfigForCurrentUser的方案,请参阅 发现(没有自动配置文件)。