Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Net / System / Net / WinHttpWebProxyFinder.cs / 1305376 / WinHttpWebProxyFinder.cs
using System.Text; using System.Collections.Generic; using System.Runtime.InteropServices; using Microsoft.Win32; using System.Runtime.CompilerServices; using System.Net.Configuration; namespace System.Net { // This class uses WinHttp APIs only to find, download and execute the PAC file. internal sealed class WinHttpWebProxyFinder : BaseWebProxyFinder { private SafeInternetHandle session; public WinHttpWebProxyFinder(AutoWebProxyScriptEngine engine) : base(engine) { // Don't specify a user agent and dont' specify proxy settings. This is the same behavior WinHttp // uses when downloading the PAC file. session = UnsafeNclNativeMethods.WinHttp.WinHttpOpen(null, UnsafeNclNativeMethods.WinHttp.AccessType.NoProxy, null, null, 0); // Don't throw on error, just log the error information. This is consistent with how auto-proxy // works: we never throw on error (discovery, download, execution errors). if (session == null || session.IsInvalid) { int errorCode = GetLastWin32Error(); if (Logging.On) Logging.PrintError(Logging.Web, SR.GetString(SR.net_log_proxy_winhttp_cant_open_session, errorCode)); } else { // The default download-timeout is 1 min. // WinHTTP will use the sum of all four timeouts provided in WinHttpSetTimeouts as the // actual timeout. Setting a value to 0 means "infinite". // Since we don't provide the ability to specify finegrained timeouts like WinHttp does, // we simply apply the configured timeout to all four WinHttp timeouts. int timeout = SettingsSectionInternal.Section.DownloadTimeout; if (!UnsafeNclNativeMethods.WinHttp.WinHttpSetTimeouts(session, timeout, timeout, timeout, timeout)) { // We weren't able to set the timeouts. Just log and continue. int errorCode = GetLastWin32Error(); if (Logging.On) Logging.PrintError(Logging.Web, SR.GetString(SR.net_log_proxy_winhttp_timeout_error, errorCode)); } } } public override bool GetProxies(Uri destination, out IListproxyList) { proxyList = null; if (session == null || session.IsInvalid) { return false; } if (State == AutoWebProxyState.UnrecognizedScheme) { // If a previous call already determined that we don't support the scheme of the script // location, then just return false. return false; } string proxyListString = null; // Set to auto-detect failed. In case auto-detect is turned off and a script-location is available // we'll try downloading the script from that location. int errorCode = (int)UnsafeNclNativeMethods.WinHttp.ErrorCodes.AudodetectionFailed; // If auto-detect is turned on, try to execute DHCP/DNS query to get PAC file, then run the script if (Engine.AutomaticallyDetectSettings) { errorCode = GetProxies(destination, null, out proxyListString); if (errorCode == (int)UnsafeNclNativeMethods.WinHttp.ErrorCodes.UnrecognizedScheme) { // DHCP returned FILE or FTP scheme for the PAC file location: We should stop here // since this is not an error, but a feature WinHttp doesn't currently support. The // caller may be able to handle this case by using another WebProxyFinder. State = AutoWebProxyState.UnrecognizedScheme; return false; } } // If auto-detect failed or was turned off, and a config-script location is available, download // the script from that location and execute it. if ((Engine.AutomaticConfigurationScript != null) && (IsRecoverableAutoProxyError(errorCode))) { errorCode = GetProxies(destination, Engine.AutomaticConfigurationScript, out proxyListString); } State = GetStateFromErrorCode(errorCode); if (State == AutoWebProxyState.Completed) { if (string.IsNullOrEmpty(proxyListString)) { // In this case the PAC file execution returned "DIRECT", i.e. WinHttp returned // 'true' with a 'null' proxy string. This state is represented as a list // containing one element with value 'null'. proxyList = new string[1] { null }; } else { // WinHttp doesn't really clear all whitespaces. It does a pretty good job with // spaces, but e.g. tabs aren't removed. Therefore make sure all whitespaces get // removed. // Note: Even though the PAC script could use space characters as separators, // WinHttp will always use ';' as separator character. E.g. for the PAC result // "PROXY 192.168.0.1 PROXY 192.168.0.2" WinHttp will return "192.168.0.1;192.168.0.2". // WinHttp will also remove trailing ';'. proxyListString = RemoveWhitespaces(proxyListString); proxyList = proxyListString.Split(';'); } return true; } // We get here if something went wrong, or if neither auto-detect nor script-location // were turned on. return false; } public override void Abort() { // WinHttp doesn't support aborts. Therefore we can't do anything here. } protected override void Dispose(bool disposing) { if (disposing) { if (session != null && !session.IsInvalid) { session.Close(); } } } private int GetProxies(Uri destination, Uri scriptLocation, out string proxyListString) { int errorCode = 0; proxyListString = null; UnsafeNclNativeMethods.WinHttp.WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions = new UnsafeNclNativeMethods.WinHttp.WINHTTP_AUTOPROXY_OPTIONS(); // Always try to download the PAC file without authentication. If we turn auth. on, the WinHttp // service will create a new session for every request (performance/memory implications). // Therefore we only turn auto-logon on if it is really needed. autoProxyOptions.AutoLogonIfChallenged = false; if (scriptLocation == null) { // Use auto-discovery to find the script location. autoProxyOptions.Flags = UnsafeNclNativeMethods.WinHttp.AutoProxyFlags.AutoDetect; autoProxyOptions.AutoConfigUrl = null; autoProxyOptions.AutoDetectFlags = UnsafeNclNativeMethods.WinHttp.AutoDetectType.Dhcp | UnsafeNclNativeMethods.WinHttp.AutoDetectType.DnsA; } else { // Use the provided script location for the PAC file. autoProxyOptions.Flags = UnsafeNclNativeMethods.WinHttp.AutoProxyFlags.AutoProxyConfigUrl; autoProxyOptions.AutoConfigUrl = scriptLocation.ToString(); autoProxyOptions.AutoDetectFlags = UnsafeNclNativeMethods.WinHttp.AutoDetectType.None; } if (!WinHttpGetProxyForUrl(destination.ToString(), ref autoProxyOptions, out proxyListString)) { errorCode = GetLastWin32Error(); // If the PAC file can't be downloaded because auth. was required, we check if the // credentials are set; if so, then we try again using auto-logon. // Note that by default webProxy.Credentials will be null. The user needs to set // in the config file, in order for // webProxy.Credentials to be set to DefaultNetworkCredentials. if ((errorCode == (int)UnsafeNclNativeMethods.WinHttp.ErrorCodes.LoginFailure) && (Engine.Credentials != null)) { // Now we need to try again, this time by enabling auto-logon. autoProxyOptions.AutoLogonIfChallenged = true; if (!WinHttpGetProxyForUrl(destination.ToString(), ref autoProxyOptions, out proxyListString)) { errorCode = GetLastWin32Error(); } } if (Logging.On) Logging.PrintError(Logging.Web, SR.GetString(SR.net_log_proxy_winhttp_getproxy_failed, destination, errorCode)); } return errorCode; } private bool WinHttpGetProxyForUrl(string destination, ref UnsafeNclNativeMethods.WinHttp.WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions, out string proxyListString) { proxyListString = null; bool success = false; UnsafeNclNativeMethods.WinHttp.WINHTTP_PROXY_INFO proxyInfo = new UnsafeNclNativeMethods.WinHttp.WINHTTP_PROXY_INFO(); // Make sure the strings get cleaned up in a CER (thus unexpected exceptions, like // ThreadAbortException will not interrupt the execution of the finally block, and we'll not // leak resources). RuntimeHelpers.PrepareConstrainedRegions(); try { success = UnsafeNclNativeMethods.WinHttp.WinHttpGetProxyForUrl(session, destination, ref autoProxyOptions, out proxyInfo); if (success) { proxyListString = Marshal.PtrToStringUni(proxyInfo.Proxy); } } finally { Marshal.FreeHGlobal(proxyInfo.Proxy); Marshal.FreeHGlobal(proxyInfo.ProxyBypass); } return success; } private static int GetLastWin32Error() { int errorCode = Marshal.GetLastWin32Error(); if (errorCode == NativeMethods.ERROR_NOT_ENOUGH_MEMORY) { throw new OutOfMemoryException(); } return errorCode; } private static bool IsRecoverableAutoProxyError(int errorCode) { GlobalLog.Assert(errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_INVALID_PARAMETER, "WinHttpGetProxyForUrl() call: Error code 'Invalid parameter' should not be returned."); // According to WinHttp the following states can be considered "recoverable", i.e. // we should continue trying WinHttpGetProxyForUrl() with the provided script-location // (if available). switch ((UnsafeNclNativeMethods.WinHttp.ErrorCodes)errorCode) { case UnsafeNclNativeMethods.WinHttp.ErrorCodes.AutoProxyServiceError: case UnsafeNclNativeMethods.WinHttp.ErrorCodes.AudodetectionFailed: case UnsafeNclNativeMethods.WinHttp.ErrorCodes.BadAutoProxyScript: case UnsafeNclNativeMethods.WinHttp.ErrorCodes.LoginFailure: case UnsafeNclNativeMethods.WinHttp.ErrorCodes.OperationCancelled: case UnsafeNclNativeMethods.WinHttp.ErrorCodes.Timeout: case UnsafeNclNativeMethods.WinHttp.ErrorCodes.UnableToDownloadScript: case UnsafeNclNativeMethods.WinHttp.ErrorCodes.UnrecognizedScheme: return true; } return false; } private static AutoWebProxyState GetStateFromErrorCode(int errorCode) { if (errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { return AutoWebProxyState.Completed; } switch ((UnsafeNclNativeMethods.WinHttp.ErrorCodes)errorCode) { case UnsafeNclNativeMethods.WinHttp.ErrorCodes.AudodetectionFailed: return AutoWebProxyState.DiscoveryFailure; case UnsafeNclNativeMethods.WinHttp.ErrorCodes.UnableToDownloadScript: return AutoWebProxyState.DownloadFailure; case UnsafeNclNativeMethods.WinHttp.ErrorCodes.BadAutoProxyScript: return AutoWebProxyState.CompilationFailure; case UnsafeNclNativeMethods.WinHttp.ErrorCodes.UnrecognizedScheme: return AutoWebProxyState.UnrecognizedScheme; default: // We don't know the exact cause of the failure. Set the state to compilation failure to // indicate that something went wrong. return AutoWebProxyState.CompilationFailure; } } private static string RemoveWhitespaces(string value) { StringBuilder result = new StringBuilder(); foreach (char c in value) { if (!char.IsWhiteSpace(c)) { result.Append(c); } } return result.ToString(); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- XmlMapping.cs
- NavigatorOutput.cs
- AuthenticationException.cs
- COM2ICategorizePropertiesHandler.cs
- BitmapImage.cs
- AsnEncodedData.cs
- QuadraticEase.cs
- MD5HashHelper.cs
- BatchServiceHost.cs
- ResourceLoader.cs
- DateTimeOffsetConverter.cs
- ReverseInheritProperty.cs
- WizardForm.cs
- embossbitmapeffect.cs
- ConfigurationSectionGroupCollection.cs
- XmlSerializationReader.cs
- ConnectionOrientedTransportManager.cs
- OracleNumber.cs
- ConfigXmlCDataSection.cs
- MailMessage.cs
- ContactManager.cs
- ValidatedControlConverter.cs
- TogglePattern.cs
- DataBinder.cs
- MetadataCacheItem.cs
- storagemappingitemcollection.viewdictionary.cs
- OletxTransactionHeader.cs
- TableLayoutPanelCellPosition.cs
- CodeNamespaceCollection.cs
- ConnectionPoint.cs
- XamlPointCollectionSerializer.cs
- LexicalChunk.cs
- RenderData.cs
- QilPatternFactory.cs
- RayHitTestParameters.cs
- ApplicationBuildProvider.cs
- JsonWriter.cs
- StringUtil.cs
- SqlWorkflowInstanceStore.cs
- DriveNotFoundException.cs
- SelectingProviderEventArgs.cs
- VirtualDirectoryMappingCollection.cs
- ConsumerConnectionPointCollection.cs
- SettingsPropertyCollection.cs
- BaseTemplateBuildProvider.cs
- AnimationTimeline.cs
- DragDropManager.cs
- AsymmetricAlgorithm.cs
- RuntimeArgumentHandle.cs
- listitem.cs
- ReadOnlyCollectionBase.cs
- XmlSchemaAttribute.cs
- ReliabilityContractAttribute.cs
- RotateTransform3D.cs
- MultiView.cs
- Win32.cs
- TextTrailingCharacterEllipsis.cs
- EntityDataSourceState.cs
- PersonalizationProvider.cs
- CngKey.cs
- XMLUtil.cs
- Native.cs
- HttpProcessUtility.cs
- JavaScriptSerializer.cs
- GetLastErrorDetailsRequest.cs
- TemporaryBitmapFile.cs
- XmlSignatureProperties.cs
- MainMenu.cs
- CharAnimationBase.cs
- AuthenticationServiceManager.cs
- CachedCompositeFamily.cs
- ForEachAction.cs
- RightsManagementManager.cs
- ServiceModelConfigurationElementCollection.cs
- HtmlInputButton.cs
- CodeDomSerializationProvider.cs
- WindowsBrush.cs
- _ReceiveMessageOverlappedAsyncResult.cs
- DataGridViewCellStateChangedEventArgs.cs
- SweepDirectionValidation.cs
- XmlDictionaryString.cs
- CodeGen.cs
- XmlUtilWriter.cs
- WindowsNonControl.cs
- UIPermission.cs
- DuplicateWaitObjectException.cs
- OdbcFactory.cs
- PolygonHotSpot.cs
- DataPager.cs
- _SslState.cs
- BoolExpression.cs
- ParseHttpDate.cs
- AttributeTable.cs
- ToolBar.cs
- ImageBrush.cs
- PrincipalPermission.cs
- ConfigXmlAttribute.cs
- DbBuffer.cs
- BypassElementCollection.cs
- AttachedPropertyInfo.cs