Using PAC files proxy






4.88/5 (10 votes)
Nov 4, 2005

148280

4010
This article explains how to set a proxy using PAC files.
Introduction
This article explains how to set a proxy using PAC files. PAC files are Proxy Automatic Configuration files, which define a proxy for a specific URL. The solution presented in the article uses the WinHttp.dll for obtaining a proxy URL.
Background
- PAC files information: Proxy Auto-Config File Format.
- WinHttp library information: Microsoft Library.
Using the code
I’ve created a simple testing application that sends a web request to www.google.com using a proxy obtained from a PAC file.
In order to run the application you need to put the proxy.pac file into your home directory for the default web site. Usually this directory is c:\inetpub\wwwroot.
The main function that returns the proxy for a specific URL is GetProxyForUrlUsingPac
that is defined in the Proxy
class:
public static string GetProxyForUrlUsingPac ( string DestinationUrl, string PacUri ){
IntPtr WinHttpSession = Win32Api.WinHttpOpen("User",
Win32Api.WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
IntPtr.Zero,
IntPtr.Zero,
0);
Win32Api.WINHTTP_AUTOPROXY_OPTIONS ProxyOptions =
new Win32Api.WINHTTP_AUTOPROXY_OPTIONS();
Win32Api.WINHTTP_PROXY_INFO ProxyInfo =
new Win32Api.WINHTTP_PROXY_INFO();
ProxyOptions.dwFlags = Win32Api.WINHTTP_AUTOPROXY_CONFIG_URL;
ProxyOptions.dwAutoDetectFlags = (Win32Api.WINHTTP_AUTO_DETECT_TYPE_DHCP |
Win32Api.WINHTTP_AUTO_DETECT_TYPE_DNS_A);
ProxyOptions.lpszAutoConfigUrl = PacUri;
// Get Proxy
bool IsSuccess = Win32Api.WinHttpGetProxyForUrl( WinHttpSession,
DestinationUrl,
ref ProxyOptions,
ref ProxyInfo );
Win32Api.WinHttpCloseHandle(WinHttpSession);
if ( IsSuccess ){
return ProxyInfo.lpszProxy;
}else {
Console.WriteLine("Error: {0}", Win32Api.GetLastError() );
return null;
}
}
The Win32Api
class contains a definition of the Win32 functions:
/// <summary>
/// This function implements the Web Proxy Auto-Discovery (WPAD) protocol
/// for automatically configuring the proxy settings for an HTTP request.
/// The WPAD protocol downloads a Proxy Auto-Configuration (PAC) file,
/// which is a script that identifies the proxy server to use for a given
/// target URL. PAC files are typically deployed by the IT department within
/// a corporate network environment. The URL of the PAC file can either be
/// specified explicitly or WinHttpGetProxyForUrl can be instructed to
/// automatically discover the location of the PAC file on the local network.
/// </summary>
/// <param name="hSession">The WinHTTP session handle
/// returned by the WinHttpOpen function</param>
/// <param name="lpcwszUrl">A pointer
/// to a null-terminated Unicode string that contains the
/// URL of the HTTP request that the application is preparing to send.</param>
/// <param name="pAutoProxyOptions">A pointer
/// to a WINHTTP_AUTOPROXY_OPTIONS structure that
/// specifies the auto-proxy options to use.</param>
/// <param name="pProxyInfo">A pointer
/// to a WINHTTP_PROXY_INFO structure that receives the
/// proxy setting. This structure is then applied to the request handle using the
/// WINHTTP_OPTION_PROXY option.</param>
/// <returns></returns>
[DllImport("winhttp.dll", SetLastError=true, CharSet=CharSet.Unicode)]
public static extern bool WinHttpGetProxyForUrl(
IntPtr hSession,
string lpcwszUrl,
ref WINHTTP_AUTOPROXY_OPTIONS pAutoProxyOptions,
ref WINHTTP_PROXY_INFO pProxyInfo);
/// <summary>
/// The function initializes, for an application, the use of WinHTTP
/// functions and returns a WinHTTP-session handle
/// </summary>
/// <param name="pwszUserAgent">A pointer
/// to a string variable that contains the name of the
/// application or entity calling the WinHTTP functions.</param>
/// <param name="dwAccessType">Type of access required.
/// This can be one of the following values</param>
/// <param name="pwszProxyName"> A pointer
/// to a string variable that contains the name of the
/// proxy server to use when proxy access
/// is specified by setting dwAccessType to
/// WINHTTP_ACCESS_TYPE_NAMED_PROXY. The WinHTTP functions
/// recognize only CERN type proxies for HTTP.
/// If dwAccessType is not set to WINHTTP_ACCESS_TYPE_NAMED_PROXY,
/// this parameter must be set
/// to WINHTTP_NO_PROXY_NAME</param>
/// <param name="pwszProxyBypass">A pointer
/// to a string variable that contains an optional list
/// of host names or IP addresses, or both,
/// that should not be routed through the proxy when
/// dwAccessType is set to WINHTTP_ACCESS_TYPE_NAMED_PROXY.
/// The list can contain wildcard characters.
/// Do not use an empty string, because
/// the WinHttpOpen function uses it as the proxy bypass list.
/// If this parameter specifies the "<local>" macro
/// as the only entry, this function bypasses
/// any host name that does not contain a period.
/// If dwAccessType is not set to WINHTTP_ACCESS_TYPE_NAMED_PROXY,
/// this parameter must be set to WINHTTP_NO_PROXY_BYPASS.</param>
/// <param name="dwFlags">Unsigned long integer value
/// that contains the flags that indicate various options
/// affecting the behavior of this function</param>
/// <returns>Returns a valid session handle
/// if successful, or NULL otherwise</returns>
[DllImport("winhttp.dll", SetLastError=true, CharSet=CharSet.Unicode)]
public static extern IntPtr WinHttpOpen(
string pwszUserAgent,
int dwAccessType,
IntPtr pwszProxyName,
IntPtr pwszProxyBypass,
int dwFlags
);
/// <summary>
/// The function closes a single HINTERNET handle
/// </summary>
/// <param name="hInternet">Valid HINTERNET handle to be closed.</param>
/// <returns>Returns TRUE if the handle
/// is successfully closed, or FALSE otherwise</returns>
[DllImport("winhttp.dll", SetLastError=true, CharSet=CharSet.Unicode)]
public static extern bool WinHttpCloseHandle(IntPtr hInternet);
The main function that uses the GetProxyForUrlUsingPac
is:
// Create test request
WebRequest TestRequest = WebRequest.Create ( DestinationUrl );
// Optain Proxy address for the URL
string ProxyAddresForUrl = Proxy.GetProxyForUrlUsingPac (DestinationUrl, PacUri);
if ( ProxyAddresForUrl != null ){
Console.WriteLine ("Found Proxy: {0}", ProxyAddresForUrl );
TestRequest.Proxy = new WebProxy ( ProxyAddresForUrl ) ;
}else{
Console.WriteLine ( "Proxy Not Found. Send request directly." );
}
That's it.