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
- XmlToDatasetMap.cs
- ConfigXmlSignificantWhitespace.cs
- SimpleBitVector32.cs
- ComboBoxItem.cs
- TextContainerChangeEventArgs.cs
- DataList.cs
- HttpGetProtocolReflector.cs
- CustomValidator.cs
- AffineTransform3D.cs
- EpmSyndicationContentSerializer.cs
- TreeWalker.cs
- SchemaImporterExtension.cs
- CodeEventReferenceExpression.cs
- parserscommon.cs
- RemoteDebugger.cs
- DateTimeParse.cs
- _HTTPDateParse.cs
- BatchParser.cs
- ControlPersister.cs
- MultipartContentParser.cs
- ExecutionContext.cs
- XmlChildNodes.cs
- PropertyInformation.cs
- ToolStripItemRenderEventArgs.cs
- LogSwitch.cs
- ToolStripOverflow.cs
- RubberbandSelector.cs
- SafeFindHandle.cs
- EventNotify.cs
- PageEventArgs.cs
- DeviceContexts.cs
- RegistryDataKey.cs
- Rotation3DKeyFrameCollection.cs
- SqlOuterApplyReducer.cs
- ScriptReference.cs
- DataGridViewSelectedCellCollection.cs
- EntityModelBuildProvider.cs
- TreeViewItem.cs
- MatrixIndependentAnimationStorage.cs
- counter.cs
- WebBodyFormatMessageProperty.cs
- XamlUtilities.cs
- CorruptStoreException.cs
- DescendantOverDescendantQuery.cs
- FindCriteria.cs
- SiteMapNodeItemEventArgs.cs
- File.cs
- ImageDrawing.cs
- MobileTextWriter.cs
- QilDataSource.cs
- RTLAwareMessageBox.cs
- StrokeCollectionDefaultValueFactory.cs
- CodeAttributeArgumentCollection.cs
- EmptyImpersonationContext.cs
- MulticastNotSupportedException.cs
- DesignerResources.cs
- StrokeFIndices.cs
- ElementHost.cs
- SafeSystemMetrics.cs
- CountdownEvent.cs
- __ComObject.cs
- ReadOnlyPropertyMetadata.cs
- SelectorItemAutomationPeer.cs
- safex509handles.cs
- SetterBase.cs
- DelegateSerializationHolder.cs
- ControlType.cs
- OpCodes.cs
- DiscoveryMessageSequenceGenerator.cs
- DoWorkEventArgs.cs
- FrameworkContentElement.cs
- UnsafeNativeMethods.cs
- OracleFactory.cs
- GACIdentityPermission.cs
- HttpInputStream.cs
- Size3DValueSerializer.cs
- KeyEvent.cs
- WorkflowServiceNamespace.cs
- KeyedCollection.cs
- ContentPosition.cs
- JsonReader.cs
- OutputScope.cs
- ComponentDispatcher.cs
- PropertyKey.cs
- ResetableIterator.cs
- SchemaConstraints.cs
- SecurityHelper.cs
- InputQueue.cs
- HandledEventArgs.cs
- SourceInterpreter.cs
- TextTreeRootTextBlock.cs
- DynamicObject.cs
- TypeToken.cs
- TreeNode.cs
- CompositeFontParser.cs
- Util.cs
- FileSecurity.cs
- UseAttributeSetsAction.cs
- TrackingLocation.cs
- FastPropertyAccessor.cs