/// <summary> /// Gets the proxy URI. (IWebProxy interface) /// </summary> public Uri GetProxy(Uri uri) { if (_proxyHelper.ManualSettingsOnly) { return(_proxyUri); } var proxyInfo = new Interop.WinHttp.WINHTTP_PROXY_INFO(); try { if (_proxyHelper.GetProxyForUrl(_sessionHandle, uri, out proxyInfo)) { return(GetUriFromString(Marshal.PtrToStringUni(proxyInfo.Proxy))); } } finally { Marshal.FreeHGlobal(proxyInfo.Proxy); Marshal.FreeHGlobal(proxyInfo.ProxyBypass); } return(null); }
/// <summary> /// Gets the proxy URI. (IWebProxy interface) /// </summary> public Uri GetProxy(Uri uri) { if (_proxyHelper.ManualSettingsOnly) { if (_bypassLocal) { IPAddress address = null; if (uri.IsLoopback) { // This is optimization for loopback addresses. // Unfortunately this does not work for all local addresses. return(null); } // Pre-Check if host may be IP address to avoid parsing. if (uri.HostNameType == UriHostNameType.IPv6 || uri.HostNameType == UriHostNameType.IPv4) { // RFC1123 allows labels to start with number. // Leading number may or may not be IP address. // IPv6 [::1] notation. '[' is not valid character in names. if (IPAddress.TryParse(uri.IdnHost, out address)) { // Host is valid IP address. // Check if it belongs to local system. foreach (IPAddress a in _localIp) { if (a.Equals(address)) { return(null); } } } } if (uri.HostNameType != UriHostNameType.IPv6 && uri.IdnHost.IndexOf('.') == -1) { // Not address and does not have a dot. // Hosts without FQDN are considered local. return(null); } } // Check if we have other rules for bypass. if (_bypass != null) { foreach (Regex entry in _bypass) { // IdnHost does not have []. if (entry.IsMatch(uri.IdnHost)) { return(null); } } } // We did not find match on bypass list. return((uri.Scheme == UriScheme.Https || uri.Scheme == UriScheme.Wss) ? _secureProxyUri : _insecureProxyUri); } // For anything else ask WinHTTP. var proxyInfo = new Interop.WinHttp.WINHTTP_PROXY_INFO(); try { if (_proxyHelper.GetProxyForUrl(_sessionHandle, uri, out proxyInfo)) { return(GetUriFromString(Marshal.PtrToStringUni(proxyInfo.Proxy))); } } finally { Marshal.FreeHGlobal(proxyInfo.Proxy); Marshal.FreeHGlobal(proxyInfo.ProxyBypass); } return(null); }
private void SetRequestHandleProxyOptions(WinHttpRequestState state) { // We've already set the proxy on the session handle if we're using no proxy or default proxy settings. // We only need to change it on the request handle if we have a specific IWebProxy or need to manually // implement Wininet-style auto proxy detection. if (state.WindowsProxyUsePolicy == WindowsProxyUsePolicy.UseCustomProxy || state.WindowsProxyUsePolicy == WindowsProxyUsePolicy.UseWinInetProxy) { var proxyInfo = new Interop.WinHttp.WINHTTP_PROXY_INFO(); bool updateProxySettings = false; Uri uri = state.RequestMessage.RequestUri; try { if (state.Proxy != null) { Debug.Assert(state.WindowsProxyUsePolicy == WindowsProxyUsePolicy.UseCustomProxy); updateProxySettings = true; if (state.Proxy.IsBypassed(uri)) { proxyInfo.AccessType = Interop.WinHttp.WINHTTP_ACCESS_TYPE_NO_PROXY; } else { proxyInfo.AccessType = Interop.WinHttp.WINHTTP_ACCESS_TYPE_NAMED_PROXY; Uri proxyUri = state.Proxy.GetProxy(uri); string proxyString = string.Format( CultureInfo.InvariantCulture, "{0}://{1}", proxyUri.Scheme, proxyUri.Authority); proxyInfo.Proxy = Marshal.StringToHGlobalUni(proxyString); } } else if (_proxyHelper != null && _proxyHelper.AutoSettingsUsed) { updateProxySettings = true; _proxyHelper.GetProxyForUrl(_sessionHandle, uri, out proxyInfo); } if (updateProxySettings) { GCHandle pinnedHandle = GCHandle.Alloc(proxyInfo, GCHandleType.Pinned); try { SetWinHttpOption( state.RequestHandle, Interop.WinHttp.WINHTTP_OPTION_PROXY, pinnedHandle.AddrOfPinnedObject(), (uint)Marshal.SizeOf(proxyInfo)); } finally { pinnedHandle.Free(); } } } finally { Marshal.FreeHGlobal(proxyInfo.Proxy); Marshal.FreeHGlobal(proxyInfo.ProxyBypass); } } }
/// <summary> /// Gets the proxy URIs. /// </summary> public MultiProxy GetMultiProxy(Uri uri) { // We need WinHTTP to detect and/or process a PAC (JavaScript) file. This maps to // "Automatically detect settings" and/or "Use automatic configuration script" from IE // settings. But, calling into WinHTTP can be slow especially when it has to call into // the out-of-process service to discover, load, and run the PAC file. So, we skip // calling into WinHTTP if there was a recent failure to detect a PAC file on the network. // This is a common error. The default IE settings on a Windows machine consist of the // single checkbox for "Automatically detect settings" turned on and most networks // won't actually discover a PAC file on the network since WPAD protocol isn't configured. if (_proxyHelper.AutoSettingsUsed && !_proxyHelper.RecentAutoDetectionFailure) { Interop.WinHttp.WINHTTP_PROXY_INFO proxyInfo = default; try { if (_proxyHelper.GetProxyForUrl(_sessionHandle, uri, out proxyInfo)) { // If WinHTTP just specified a Proxy with no ProxyBypass list, then // we can return the Proxy uri directly. if (proxyInfo.ProxyBypass == IntPtr.Zero) { if (proxyInfo.Proxy != IntPtr.Zero) { string proxyStr = Marshal.PtrToStringUni(proxyInfo.Proxy) !; return(MultiProxy.CreateLazy(_failedProxies, proxyStr, IsSecureUri(uri))); } else { return(MultiProxy.Empty); } } // A bypass list was also specified. This means that WinHTTP has fallen back to // using the manual IE settings specified and there is a ProxyBypass list also. // Since we're not really using the full WinHTTP stack, we need to use HttpSystemProxy // to do the computation of the final proxy uri merging the information from the Proxy // and ProxyBypass strings. } else { return(MultiProxy.Empty); } } finally { Marshal.FreeHGlobal(proxyInfo.Proxy); Marshal.FreeHGlobal(proxyInfo.ProxyBypass); } } // Fallback to manual settings if present. if (_proxyHelper.ManualSettingsUsed) { if (_bypassLocal) { IPAddress?address; if (uri.IsLoopback) { // This is optimization for loopback addresses. // Unfortunately this does not work for all local addresses. return(MultiProxy.Empty); } // Pre-Check if host may be IP address to avoid parsing. if (uri.HostNameType == UriHostNameType.IPv6 || uri.HostNameType == UriHostNameType.IPv4) { // RFC1123 allows labels to start with number. // Leading number may or may not be IP address. // IPv6 [::1] notation. '[' is not valid character in names. if (IPAddress.TryParse(uri.IdnHost, out address)) { // Host is valid IP address. // Check if it belongs to local system. foreach (IPAddress a in _localIp !) { if (a.Equals(address)) { return(MultiProxy.Empty); } } } } if (uri.HostNameType != UriHostNameType.IPv6 && !uri.IdnHost.Contains('.')) { // Not address and does not have a dot. // Hosts without FQDN are considered local. return(MultiProxy.Empty); } } // Check if we have other rules for bypass. if (_bypass != null) { foreach (string entry in _bypass) { // IdnHost does not have []. if (SimpleRegex.IsMatchWithStarWildcard(uri.IdnHost, entry)) { return(MultiProxy.Empty); } } } // We did not find match on bypass list. return(IsSecureUri(uri) ? _secureProxy : _insecureProxy); } return(MultiProxy.Empty); }