WinHTTP AutoProxy 函数

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

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 配置为跳过自动检测阶段。

例如,如果 PAC 文件在 URL 的本地网络上可用,则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 的方案,请参阅 “没有自动配置文件的发现”。