HttpChannelFactory.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Channels / HttpChannelFactory.cs / 4 / HttpChannelFactory.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------
namespace System.ServiceModel.Channels
{ 
    using System.Collections;
    using System.ServiceModel; 
    using System.ServiceModel.Description; 
    using System.ServiceModel.Dispatcher;
    using System.Collections.Generic; 
    using System.Collections.ObjectModel;
    using System.Diagnostics;
    using System.Globalization;
    using System.IO; 
    using System.Net;
    using System.Net.Cache; 
    using System.Net.Security; 
    using System.Runtime.Serialization;
    using System.IdentityModel.Claims; 
    using System.IdentityModel.Policy;
    using System.IdentityModel.Selectors;
    using System.IdentityModel.Tokens;
    using System.Security; 
    using System.Security.Cryptography;
    using System.Security.Principal; 
    using System.ServiceModel.Diagnostics; 
    using System.ServiceModel.Security;
    using System.ServiceModel.Security.Tokens; 
    using System.Text;
    using System.Threading;
    using System.Web;
    using System.Web.Hosting; 
    using System.Runtime.CompilerServices;
 
    class HttpChannelFactory 
        : TransportChannelFactory, IHttpTransportFactorySettings
    { 
        bool allowCookies;
        AuthenticationSchemes authenticationScheme;
        CookieContainer cookieContainer;
        MruCache credentialCacheUriPrefixCache; 

        ///  
        ///   Critical - This cache stores strings that contain domain/user name/password. 
        ///                    must not be settable from PT code
        ///  
        [SecurityCritical]
        MruCache credentialHashCache;

        ///  
        ///   Critical - This hash algorithm takes strings that contain domain/user name/password.
        ///                    must not be settable from PT code 
        ///  
        [SecurityCritical]
        HashAlgorithm hashAlgorithm; 
        static bool httpWebRequestWebPermissionDenied = false;
        bool keepAliveEnabled;
        int maxBufferSize;
        IWebProxy proxy; 
        WebProxyFactory proxyFactory;
        static RequestCachePolicy requestCachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache); 
        SecurityCredentialsManager channelCredentials; 
        SecurityTokenManager securityTokenManager;
        TransferMode transferMode; 
        ISecurityCapabilities securityCapabilities;

        internal HttpChannelFactory(HttpTransportBindingElement bindingElement, BindingContext context)
            : base(bindingElement, context, HttpTransportDefaults.GetDefaultMessageEncoderFactory()) 
        {
            // validate setting interactions 
            if (bindingElement.TransferMode == TransferMode.Buffered) 
            {
                if (bindingElement.MaxReceivedMessageSize > int.MaxValue) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new ArgumentOutOfRangeException("bindingElement.MaxReceivedMessageSize",
                        SR.GetString(SR.MaxReceivedMessageSizeMustBeInIntegerRange))); 
                }
 
                if (bindingElement.MaxBufferSize != bindingElement.MaxReceivedMessageSize) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("bindingElement", 
                        SR.GetString(SR.MaxBufferSizeMustMatchMaxReceivedMessageSize));
                }
            }
            else 
            {
                if (bindingElement.MaxBufferSize > bindingElement.MaxReceivedMessageSize) 
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("bindingElement",
                        SR.GetString(SR.MaxBufferSizeMustNotExceedMaxReceivedMessageSize)); 
                }
            }

            if (TransferModeHelper.IsRequestStreamed(bindingElement.TransferMode) && 
                bindingElement.AuthenticationScheme != AuthenticationSchemes.Anonymous)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("bindingElement", SR.GetString( 
                    SR.HttpAuthDoesNotSupportRequestStreaming));
            } 

            this.allowCookies = bindingElement.AllowCookies;
            this.authenticationScheme = bindingElement.AuthenticationScheme;
            this.keepAliveEnabled = bindingElement.KeepAliveEnabled; 
            this.maxBufferSize = bindingElement.MaxBufferSize;
            this.transferMode = bindingElement.TransferMode; 
 
            if (bindingElement.Proxy != null)
            { 
                this.proxy = bindingElement.Proxy;
            }
            else if (bindingElement.ProxyAddress != null)
            { 
                if (bindingElement.UseDefaultWebProxy)
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.UseDefaultWebProxyCantBeUsedWithExplicitProxyAddress))); 
                }
 
                if (bindingElement.ProxyAuthenticationScheme == AuthenticationSchemes.Anonymous)
                {
                    this.proxy = new WebProxy(bindingElement.ProxyAddress, bindingElement.BypassProxyOnLocal);
                } 
                else
                { 
                    this.proxy = null; 
                    this.proxyFactory =
                        new WebProxyFactory(bindingElement.ProxyAddress, bindingElement.BypassProxyOnLocal, 
                        bindingElement.ProxyAuthenticationScheme);
                }
            }
            else if (!bindingElement.UseDefaultWebProxy) 
            {
                this.proxy = new WebProxy(); 
            } 

            channelCredentials = context.BindingParameters.Find(); 
            this.securityCapabilities = bindingElement.GetProperty(context);
        }

        public bool AllowCookies 
        {
            get 
            { 
                return this.allowCookies;
            } 
        }

        public AuthenticationSchemes AuthenticationScheme
        { 
            get
            { 
                return this.authenticationScheme; 
            }
        } 

        public bool KeepAliveEnabled
        {
            get 
            {
                return this.keepAliveEnabled; 
            } 
        }
 
        public SecurityTokenManager SecurityTokenManager
        {
            get
            { 
                return this.securityTokenManager;
            } 
        } 

        // must be called under lock (this.credentialHashCache) 
        HashAlgorithm HashAlgorithm
        {
            [SecurityCritical]
            get 
            {
                if (this.hashAlgorithm == null) 
                { 
                    this.hashAlgorithm = CryptoHelper.CreateHashAlgorithm(SecurityAlgorithms.Sha1Digest);
                } 
                else
                {
                    this.hashAlgorithm.Initialize();
                } 

                return this.hashAlgorithm; 
            } 
        }
 
        public int MaxBufferSize
        {
            get
            { 
                return maxBufferSize;
            } 
        } 

        public IWebProxy Proxy 
        {
            get
            {
                return this.proxy; 
            }
        } 
 
        public TransferMode TransferMode
        { 
            get
            {
                return transferMode;
            } 
        }
 
        int IHttpTransportFactorySettings.MaxBufferSize 
        {
            get { return MaxBufferSize; } 
        }

        TransferMode IHttpTransportFactorySettings.TransferMode
        { 
            get { return TransferMode; }
        } 
 
        public override string Scheme
        { 
            get
            {
                return Uri.UriSchemeHttp;
            } 
        }
 
        public override T GetProperty() 
        {
            if (typeof(T) == typeof(ISecurityCapabilities)) 
            {
                return (T)(object)this.securityCapabilities;
            }
 
            return base.GetProperty();
        } 
 
        internal virtual SecurityMessageProperty CreateReplySecurityProperty(HttpWebRequest request,
            HttpWebResponse response) 
        {
            // Don't pull in System.Authorization if we don't need to!
            if (!response.IsMutuallyAuthenticated)
                return null; 

            return CreateMutuallyAuthenticatedReplySecurityProperty(response); 
        } 

        internal Exception CreateToMustEqualViaException(Uri to, Uri via) 
        {
            return new ArgumentException(SR.GetString(SR.HttpToMustEqualVia, to, via));
        }
 
        [MethodImpl(MethodImplOptions.NoInlining)]
        SecurityMessageProperty CreateMutuallyAuthenticatedReplySecurityProperty(HttpWebResponse response) 
        { 
            string spn = AuthenticationManager.CustomTargetNameDictionary[response.ResponseUri.AbsoluteUri];
            if (spn == null) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.HttpSpnNotFound,
                    response.ResponseUri)));
            } 
            ReadOnlyCollection spnPolicies = SecurityUtils.CreatePrincipalNameAuthorizationPolicies(spn);
            SecurityMessageProperty remoteSecurity = new SecurityMessageProperty(); 
            remoteSecurity.TransportToken = new SecurityTokenSpecification(null, spnPolicies); 
            remoteSecurity.ServiceSecurityContext = new ServiceSecurityContext(spnPolicies);
            return remoteSecurity; 
        }

        internal override int GetMaxBufferSize()
        { 
            return MaxBufferSize;
        } 
 
        SecurityTokenProviderContainer CreateAndOpenTokenProvider(TimeSpan timeout, AuthenticationSchemes authenticationScheme,
            EndpointAddress target, Uri via, ChannelParameterCollection channelParameters) 
        {
            SecurityTokenProvider tokenProvider = null;
            switch (authenticationScheme)
            { 
                case AuthenticationSchemes.Anonymous:
                    break; 
                case AuthenticationSchemes.Basic: 
                    tokenProvider = TransportSecurityHelpers.GetUserNameTokenProvider(this.SecurityTokenManager, target, via, this.Scheme, authenticationScheme, channelParameters);
                    break; 
                case AuthenticationSchemes.Negotiate:
                case AuthenticationSchemes.Ntlm:
                    tokenProvider = TransportSecurityHelpers.GetSspiTokenProvider(this.SecurityTokenManager, target, via, this.Scheme, authenticationScheme, channelParameters);
                    break; 
                case AuthenticationSchemes.Digest:
                    tokenProvider = TransportSecurityHelpers.GetDigestTokenProvider(this.SecurityTokenManager, target, via, this.Scheme, authenticationScheme, channelParameters); 
                    break; 
                default:
                    // The setter for this property should prevent this. 
                    DiagnosticUtility.DebugAssert("CreateAndOpenTokenProvider: Invalid authentication scheme");
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
            }
            SecurityTokenProviderContainer result; 
            if (tokenProvider != null)
            { 
                result = new SecurityTokenProviderContainer(tokenProvider); 
                result.Open(timeout);
            } 
            else
            {
                result = null;
            } 
            return result;
        } 
 
        protected virtual void ValidateCreateChannelParameters(EndpointAddress remoteAddress, Uri via)
        { 
            base.ValidateScheme(via);

            if (this.MessageVersion.Addressing == AddressingVersion.None && remoteAddress.Uri != via)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateToMustEqualViaException(remoteAddress.Uri, via));
            } 
        } 

        protected override IRequestChannel OnCreateChannel(EndpointAddress remoteAddress, Uri via) 
        {
            ValidateCreateChannelParameters(remoteAddress, via);

            return new HttpRequestChannel(this, remoteAddress, via, ManualAddressing); 
        }
 
        [MethodImpl(MethodImplOptions.NoInlining)] 
        void InitializeSecurityTokenManager()
        { 
            if (this.channelCredentials == null)
            {
                this.channelCredentials = ClientCredentials.CreateDefaultCredentials();
            } 
            this.securityTokenManager = this.channelCredentials.CreateSecurityTokenManager();
        } 
 
        protected virtual bool IsSecurityTokenManagerRequired()
        { 
            if (this.AuthenticationScheme != AuthenticationSchemes.Anonymous)
            {
                return true;
            } 
            if (this.proxyFactory != null && this.proxyFactory.AuthenticationScheme != AuthenticationSchemes.Anonymous)
            { 
                return true; 
            }
            else 
            {
                return false;
            }
        } 

        protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state) 
        { 
            this.OnOpen(timeout);
            return new CompletedAsyncResult(callback, state); 
        }

        protected override void OnEndOpen(IAsyncResult result)
        { 
            CompletedAsyncResult.End(result);
        } 
 
        protected override void OnOpen(TimeSpan timeout)
        { 
            if (IsSecurityTokenManagerRequired())
            {
                this.InitializeSecurityTokenManager();
            } 

            if (this.AllowCookies) 
            { 
                this.cookieContainer = new CookieContainer();
            } 

            // we need to make sure System.Net will buffer faults (sent as 500 requests) up to our allowed size
            // Their value is in Kbytes and ours is in bytes. We round up so that the KB value is large enough to
            // encompass our MaxReceivedMessageSize. See MB#20860 and related for details 

            if (!httpWebRequestWebPermissionDenied && HttpWebRequest.DefaultMaximumErrorResponseLength != -1) 
            { 
                int MaxReceivedMessageSizeKbytes;
                if (MaxBufferSize >= (int.MaxValue - 1024)) // make sure NCL doesn't overflow 
                {
                    MaxReceivedMessageSizeKbytes = -1;
                }
                else 
                {
                    MaxReceivedMessageSizeKbytes = (int)(MaxBufferSize / 1024); 
                    if (MaxReceivedMessageSizeKbytes * 1024 < MaxBufferSize) 
                        MaxReceivedMessageSizeKbytes++;
                } 

                if (MaxReceivedMessageSizeKbytes == -1
                    || MaxReceivedMessageSizeKbytes > HttpWebRequest.DefaultMaximumErrorResponseLength)
                { 
                    try
                    { 
                        HttpWebRequest.DefaultMaximumErrorResponseLength = MaxReceivedMessageSizeKbytes; 
                    }
                    catch (SecurityException exception) 
                    {
                        // CSDMain\33725 - setting DefaultMaximumErrorResponseLength should not fail HttpChannelFactory.OnOpen
                        // if the user does not have the permission to do so.
                        httpWebRequestWebPermissionDenied = true; 

                        if (DiagnosticUtility.ShouldTraceWarning) 
                        { 
                            DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Warning);
                        } 
                    }
                }
            }
        } 

        static internal void TraceResponseReceived(HttpWebResponse response, Message message, object receiver) 
        { 
            if (DiagnosticUtility.ShouldTraceVerbose)
            { 
                if (response != null && response.ResponseUri != null)
                {
                    TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.HttpResponseReceived, new StringTraceRecord("ResponseUri", response.ResponseUri.ToString()), receiver, null, message);
                } 
                else
                { 
                    TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.HttpResponseReceived, receiver, message); 
                }
            } 
        }

        /// 
        ///  Critical - Uses unsafe critical method AppendWindowsAuthenticationInfo to access the credential domain/user name/password 
        /// 
        [SecurityCritical] 
        [MethodImpl(MethodImplOptions.NoInlining)] 
        string AppendWindowsAuthenticationInfo(string inputString, NetworkCredential credential,
            AuthenticationLevel authenticationLevel, TokenImpersonationLevel impersonationLevel) 
        {
            return SecurityUtils.AppendWindowsAuthenticationInfo(inputString, credential, authenticationLevel, impersonationLevel);
        }
 
        protected virtual string OnGetConnectionGroupPrefix(HttpWebRequest httpWebRequest, SecurityTokenContainer clientCertificateToken)
        { 
            return string.Empty; 
        }
 
        /// 
        ///  Critical - Uses unsafe critical method AppendWindowsAuthenticationInfo to access the credential domain/user name/password
        ///  Safe - Uses the domain/user name/password to store and compute a hash. The store is SecurityCritical. The hash leaks but
        ///         the hash cannot be reversed to the domain/user name/password. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        string GetConnectionGroupName(HttpWebRequest httpWebRequest, NetworkCredential credential, AuthenticationLevel authenticationLevel, 
            TokenImpersonationLevel impersonationLevel, SecurityTokenContainer clientCertificateToken)
        { 
            if (this.credentialHashCache == null)
            {
                lock (ThisLock)
                { 
                    if (this.credentialHashCache == null)
                    { 
                        this.credentialHashCache = new MruCache(5); 
                    }
                } 
            }

            // The following line is a work-around for VSWhidbey 558605.  In particular, we need to isolate our
            // connection groups based on whether we are streaming the request. 
            string inputString = TransferModeHelper.IsRequestStreamed(this.TransferMode) ? "streamed" : string.Empty;
 
            if (AuthenticationSchemesHelper.IsWindowsAuth(this.AuthenticationScheme)) 
            {
                // for NTLM & Negotiate, System.Net doesn't pool connections by default. This is because 
                // IIS doesn't re-authenticate NTLM connections (made for a perf reason), and HttpWebRequest
                // shared connections among multiple callers.
                // This causes Indigo a performance problem in turn. We mitigate this by (1) enabling
                // connection sharing for NTLM connections on our pool, and (2) scoping the pool we use 
                // to be based on the NetworkCredential that is being used to authenticate the connection.
                // Therefore we're only sharing connections among the same Credential. 
 
                httpWebRequest.UnsafeAuthenticatedConnectionSharing = true;
 
                inputString = AppendWindowsAuthenticationInfo(inputString, credential, authenticationLevel, impersonationLevel);
            }

            string prefix = this.OnGetConnectionGroupPrefix(httpWebRequest, clientCertificateToken); 
            inputString = string.Concat(prefix, inputString);
 
            string credentialHash = null; 

            // we have to lock around each call to TryGetValue since the MruCache modifies the 
            // contents of it's mruList in a single-threaded manner underneath TryGetValue

            if (!string.IsNullOrEmpty(inputString))
            { 
                lock (this.credentialHashCache)
                { 
                    if (!this.credentialHashCache.TryGetValue(inputString, out credentialHash)) 
                    {
                        byte[] inputBytes = new UTF8Encoding().GetBytes(inputString); 
                        byte[] digestBytes = this.HashAlgorithm.ComputeHash(inputBytes);
                        credentialHash = Convert.ToBase64String(digestBytes);
                        this.credentialHashCache.Add(inputString, credentialHash);
                    } 
                }
            } 
 
            return credentialHash;
        } 

        Uri GetCredentialCacheUriPrefix(Uri via)
        {
            Uri result; 

            if (this.credentialCacheUriPrefixCache == null) 
            { 
                lock (ThisLock)
                { 
                    if (this.credentialCacheUriPrefixCache == null)
                    {
                        this.credentialCacheUriPrefixCache = new MruCache(10);
                    } 
                }
            } 
 
            lock (this.credentialCacheUriPrefixCache)
            { 
                if (!this.credentialCacheUriPrefixCache.TryGetValue(via, out result))
                {
                    result = new UriBuilder(via.Scheme, via.Host, via.Port).Uri;
                    this.credentialCacheUriPrefixCache.Add(via, result); 
                }
            } 
 
            return result;
        } 

        // core code for creating an HttpWebRequest
        HttpWebRequest GetWebRequest(EndpointAddress to, Uri via, NetworkCredential credential,
            TokenImpersonationLevel impersonationLevel, AuthenticationLevel authenticationLevel, 
            SecurityTokenProviderContainer proxyTokenProvider, SecurityTokenContainer clientCertificateToken, TimeSpan timeout)
        { 
            HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(via); 
            httpWebRequest.Method = "POST";
 
            if (TransferModeHelper.IsRequestStreamed(TransferMode))
            {
                httpWebRequest.SendChunked = true;
                httpWebRequest.AllowWriteStreamBuffering = false; 
            }
            else 
            { 
                httpWebRequest.AllowWriteStreamBuffering = true;
            } 

            httpWebRequest.CachePolicy = requestCachePolicy;
            httpWebRequest.KeepAlive = this.keepAliveEnabled;
 
            if (credential != null)
            { 
                CredentialCache credentials = new CredentialCache(); 
                credentials.Add(this.GetCredentialCacheUriPrefix(via),
                    AuthenticationSchemesHelper.ToString(this.authenticationScheme), credential); 
                httpWebRequest.Credentials = credentials;
            }
            httpWebRequest.AuthenticationLevel = authenticationLevel;
            httpWebRequest.ImpersonationLevel = impersonationLevel; 

            string connectionGroupName = GetConnectionGroupName(httpWebRequest, credential, authenticationLevel, impersonationLevel, clientCertificateToken); 
            if (!string.IsNullOrEmpty(connectionGroupName)) 
            {
                httpWebRequest.ConnectionGroupName = connectionGroupName; 
            }

            if (AuthenticationScheme == AuthenticationSchemes.Basic)
            { 
                httpWebRequest.PreAuthenticate = true;
            } 
 
            if (this.proxy != null)
            { 
                httpWebRequest.Proxy = this.proxy;
            }
            else if (this.proxyFactory != null)
            { 
                httpWebRequest.Proxy = this.proxyFactory.CreateWebProxy(httpWebRequest, proxyTokenProvider, timeout);
            } 
 
            if (this.AllowCookies)
            { 
                httpWebRequest.CookieContainer = this.cookieContainer;
            }

            // we do this at the end so that we access the correct ServicePoint 
            httpWebRequest.ServicePoint.UseNagleAlgorithm = false;
 
            return httpWebRequest; 
        }
 
        void ApplyManualAddressing(ref EndpointAddress to, ref Uri via, Message message)
        {
            if (ManualAddressing)
            { 
                Uri toHeader = message.Headers.To;
                if (toHeader == null) 
                { 
                    throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ManualAddressingRequiresAddressedMessages)), message);
                } 

                to = new EndpointAddress(toHeader);

                if (this.MessageVersion.Addressing == AddressingVersion.None) 
                {
                    via = toHeader; 
                } 
            }
 
            // now apply query string property
            object property;
            if (message.Properties.TryGetValue(HttpRequestMessageProperty.Name, out property))
            { 
                HttpRequestMessageProperty requestProperty = (HttpRequestMessageProperty)property;
                if (!string.IsNullOrEmpty(requestProperty.QueryString)) 
                { 
                    UriBuilder uriBuilder = new UriBuilder(via);
 
                    if (requestProperty.QueryString.StartsWith("?", StringComparison.Ordinal))
                    {
                        uriBuilder.Query = requestProperty.QueryString.Substring(1);
                    } 
                    else
                    { 
                        uriBuilder.Query = requestProperty.QueryString; 
                    }
 
                    via = uriBuilder.Uri;
                }
            }
        } 

        [MethodImpl(MethodImplOptions.NoInlining)] 
        void CreateAndOpenTokenProvidersCore(EndpointAddress to, Uri via, ChannelParameterCollection channelParameters, TimeSpan timeout, out SecurityTokenProviderContainer tokenProvider, out SecurityTokenProviderContainer proxyTokenProvider) 
        {
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); 
            tokenProvider = CreateAndOpenTokenProvider(timeoutHelper.RemainingTime(), this.AuthenticationScheme, to, via, channelParameters);
            if (this.proxyFactory != null)
            {
                proxyTokenProvider = CreateAndOpenTokenProvider(timeoutHelper.RemainingTime(), this.proxyFactory.AuthenticationScheme, to, via, channelParameters); 
            }
            else 
            { 
                proxyTokenProvider = null;
            } 
        }

        void CreateAndOpenTokenProviders(EndpointAddress to, Uri via, ChannelParameterCollection channelParameters, TimeSpan timeout, out SecurityTokenProviderContainer tokenProvider, out SecurityTokenProviderContainer proxyTokenProvider)
        { 
            if (!IsSecurityTokenManagerRequired())
            { 
                tokenProvider = null; 
                proxyTokenProvider = null;
            } 
            else
            {
                CreateAndOpenTokenProvidersCore(to, via, channelParameters, timeout, out tokenProvider, out proxyTokenProvider);
            } 
        }
 
        HttpWebRequest GetWebRequest(EndpointAddress to, Uri via, SecurityTokenProviderContainer tokenProvider, 
            SecurityTokenProviderContainer proxyTokenProvider, SecurityTokenContainer clientCertificateToken, TimeSpan timeout)
        { 
            TokenImpersonationLevel impersonationLevel;
            AuthenticationLevel authenticationLevel;
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
            NetworkCredential credential = HttpChannelUtilities.GetCredential(this.authenticationScheme, 
              tokenProvider, timeoutHelper.RemainingTime(), out impersonationLevel, out authenticationLevel);
 
            return GetWebRequest(to, via, credential, impersonationLevel, authenticationLevel, proxyTokenProvider, clientCertificateToken, timeoutHelper.RemainingTime()); 
        }
 
        bool MapIdentity(EndpointAddress target)
        {
            return AuthenticationSchemesHelper.IsWindowsAuth(this.AuthenticationScheme);
        } 

        protected class HttpRequestChannel : RequestChannel 
        { 
            bool cleanupIdentity;
            HttpChannelFactory factory; 
            SecurityTokenProviderContainer tokenProvider;
            SecurityTokenProviderContainer proxyTokenProvider;
            ServiceModelActivity activity = null;
            ChannelParameterCollection channelParameters; 

            public HttpRequestChannel(HttpChannelFactory factory, EndpointAddress to, Uri via, bool manualAddressing) 
                : base(factory, to, via, manualAddressing) 
            {
                this.factory = factory; 
            }

            internal ServiceModelActivity Activity
            { 
                get { return this.activity; }
            } 
 
            public HttpChannelFactory Factory
            { 
                get { return this.factory; }
            }

            protected ChannelParameterCollection ChannelParameters 
            {
                get 
                { 
                    return this.channelParameters;
                } 
            }

            public override T GetProperty()
            { 
                if (typeof(T) == typeof(ChannelParameterCollection))
                { 
                    if (this.State == CommunicationState.Created) 
                    {
                        lock (ThisLock) 
                        {
                            if (this.channelParameters == null)
                            {
                                this.channelParameters = new ChannelParameterCollection(); 
                            }
                        } 
                    } 
                    return (T) (object) this.channelParameters;
                } 
                else
                {
                    return base.GetProperty();
                } 
            }
 
            void PrepareOpen() 
            {
                if (Factory.MapIdentity(RemoteAddress)) 
                {
                    lock (ThisLock)
                    {
                        cleanupIdentity = HttpTransportSecurityHelpers.AddIdentityMapping(Via, RemoteAddress); 
                    }
                } 
            } 

            void CreateAndOpenTokenProviders(TimeSpan timeout) 
            {
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                if (!ManualAddressing)
                { 
                    Factory.CreateAndOpenTokenProviders(this.RemoteAddress, this.Via, this.channelParameters, timeoutHelper.RemainingTime(), out this.tokenProvider, out this.proxyTokenProvider);
                } 
            } 

            void CloseTokenProviders(TimeSpan timeout) 
            {
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                if (this.tokenProvider != null)
                { 
                    tokenProvider.Close(timeoutHelper.RemainingTime());
                } 
                if (this.proxyTokenProvider != null) 
                {
                    proxyTokenProvider.Close(timeoutHelper.RemainingTime()); 
                }
            }

            void AbortTokenProviders() 
            {
                if (this.tokenProvider != null) 
                { 
                    tokenProvider.Abort();
                } 
                if (this.proxyTokenProvider != null)
                {
                    proxyTokenProvider.Abort();
                } 
            }
 
            protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state) 
            {
                PrepareOpen(); 
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                CreateAndOpenTokenProviders(timeoutHelper.RemainingTime());
                return new CompletedAsyncResult(callback, state);
            } 

            protected override void OnOpen(TimeSpan timeout) 
            { 
                PrepareOpen();
                CreateAndOpenTokenProviders(timeout); 
            }

            protected override void OnEndOpen(IAsyncResult result)
            { 
                CompletedAsyncResult.End(result);
            } 
 
            void PrepareClose(bool aborting)
            { 
                if (cleanupIdentity)
                {
                    lock (ThisLock)
                    { 
                        if (cleanupIdentity)
                        { 
                            cleanupIdentity = false; 
                            HttpTransportSecurityHelpers.RemoveIdentityMapping(Via, RemoteAddress, !aborting);
                        } 
                    }
                }
            }
 
            protected override void OnAbort()
            { 
                PrepareClose(true); 
                AbortTokenProviders();
                base.OnAbort(); 
            }

            protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
            { 
                IAsyncResult retval = null;
                using (ServiceModelActivity.BoundOperation(this.activity)) 
                { 
                    PrepareClose(false);
                    TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); 
                    CloseTokenProviders(timeoutHelper.RemainingTime());
                    retval =  base.BeginWaitForPendingRequests(timeoutHelper.RemainingTime(), callback, state);
                }
                ServiceModelActivity.Stop(this.activity); 
                return retval;
            } 
 
            protected override void OnEndClose(IAsyncResult result)
            { 
                using (ServiceModelActivity.BoundOperation(this.activity))
                {
                    base.EndWaitForPendingRequests(result);
                } 
                ServiceModelActivity.Stop(this.activity);
            } 
 
            protected override void OnClose(TimeSpan timeout)
            { 
                using (ServiceModelActivity.BoundOperation(this.activity))
                {
                    PrepareClose(false);
                    TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); 
                    CloseTokenProviders(timeoutHelper.RemainingTime());
                    base.WaitForPendingRequests(timeoutHelper.RemainingTime()); 
                } 
                ServiceModelActivity.Stop(this.activity);
            } 

            protected override IAsyncRequest CreateAsyncRequest(Message message, AsyncCallback callback, object state)
            {
                if (DiagnosticUtility.ShouldUseActivity && this.activity == null) 
                {
                    this.activity = ServiceModelActivity.CreateActivity(); 
                    DiagnosticUtility.DiagnosticTrace.TraceTransfer(this.activity.Id); 
                    ServiceModelActivity.Start(this.activity, SR.GetString(SR.ActivityReceiveBytes, this.RemoteAddress.Uri.ToString()), ActivityType.ReceiveBytes);
                } 

                return new HttpChannelAsyncRequest(this, callback, state);
            }
 
            protected override IRequest CreateRequest(Message message)
            { 
                return new HttpChannelRequest(this, Factory); 
            }
 
            public virtual HttpWebRequest GetWebRequest(EndpointAddress to, Uri via, ref TimeoutHelper timeoutHelper)
            {
                return GetWebRequest(to, via, null, ref timeoutHelper);
            } 

            protected HttpWebRequest GetWebRequest(EndpointAddress to, Uri via, SecurityTokenContainer clientCertificateToken, ref TimeoutHelper timeoutHelper) 
            { 
                SecurityTokenProviderContainer webRequestTokenProvider;
                SecurityTokenProviderContainer webRequestProxyTokenProvider; 
                if (this.ManualAddressing)
                {
                    this.Factory.CreateAndOpenTokenProviders(to, via, this.channelParameters, timeoutHelper.RemainingTime(),
                        out webRequestTokenProvider, out webRequestProxyTokenProvider); 
                }
                else 
                { 
                    webRequestTokenProvider = this.tokenProvider;
                    webRequestProxyTokenProvider = this.proxyTokenProvider; 
                }
                try
                {
                    return this.Factory.GetWebRequest(to, via, webRequestTokenProvider, webRequestProxyTokenProvider, clientCertificateToken, timeoutHelper.RemainingTime()); 
                }
                finally 
                { 
                    if (this.ManualAddressing)
                    { 
                        if (webRequestTokenProvider != null)
                        {
                            webRequestTokenProvider.Abort();
                        } 
                        if (webRequestProxyTokenProvider != null)
                        { 
                            webRequestProxyTokenProvider.Abort(); 
                        }
                    } 
                }
            }

            protected IAsyncResult BeginGetWebRequest( 
                EndpointAddress to, Uri via, SecurityTokenContainer clientCertificateToken, ref TimeoutHelper timeoutHelper, AsyncCallback callback, object state)
            { 
                return new GetWebRequestAsyncResult(this, to, via, clientCertificateToken, ref timeoutHelper, callback, state); 
            }
 
            public virtual IAsyncResult BeginGetWebRequest(
                EndpointAddress to, Uri via, ref TimeoutHelper timeoutHelper, AsyncCallback callback, object state)
            {
                return BeginGetWebRequest(to, via, null, ref timeoutHelper, callback, state); 
            }
 
            public virtual HttpWebRequest EndGetWebRequest(IAsyncResult result) 
            {
                return GetWebRequestAsyncResult.End(result); 
            }

            public virtual bool WillGetWebRequestCompleteSynchronously()
            { 
                return ((this.tokenProvider == null) && !Factory.ManualAddressing);
            } 
 
            internal virtual void OnWebRequestCompleted(HttpWebRequest request)
            { 
                // empty
            }

            class HttpChannelRequest : IRequest 
            {
                HttpRequestChannel channel; 
                HttpChannelFactory factory; 
                EndpointAddress to;
                Uri via; 
                HttpWebRequest webRequest;
                HttpAbortReason abortReason;

                public HttpChannelRequest(HttpRequestChannel channel, HttpChannelFactory factory) 
                {
                    this.channel = channel; 
                    this.to = channel.RemoteAddress; 
                    this.via = channel.Via;
                    this.factory = factory; 
                }

                public void SendRequest(Message message, TimeSpan timeout)
                { 
                    TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                    factory.ApplyManualAddressing(ref this.to, ref this.via, message); 
                    this.webRequest = channel.GetWebRequest(this.to, this.via, ref timeoutHelper); 
                    if (channel.State != CommunicationState.Opened)
                    { 
                        // if we were aborted while getting our request, we need to abort the web request and bail
                        Cleanup();
                        channel.ThrowIfDisposedOrNotOpen();
                    } 
                    HttpChannelUtilities.SetRequestTimeout(this.webRequest, timeoutHelper.RemainingTimeExpireZero());
                    HttpOutput httpOutput = HttpOutput.CreateHttpOutput(this.webRequest, this.factory, message); 
 
                    bool success = false;
                    try 
                    {
                        httpOutput.Send(timeoutHelper.RemainingTime());
                        httpOutput.Close();
                        success = true; 
                    }
                    finally 
                    { 
                        if (!success)
                        { 
                            httpOutput.Abort(HttpAbortReason.Aborted);
                        }
                    }
                } 

                void Cleanup() 
                { 
                    if (this.webRequest != null)
                    { 
                        HttpChannelUtilities.AbortRequest(this.webRequest);
                        this.channel.OnWebRequestCompleted(this.webRequest);
                    }
                } 

                public void Abort(RequestChannel channel) 
                { 
                    Cleanup();
                    abortReason = HttpAbortReason.Aborted; 
                }

                public void Fault(RequestChannel channel)
                { 
                    Cleanup();
                } 
 
                public Message WaitForReply(TimeSpan timeout)
                { 
                    HttpWebResponse response = null;
                    WebException responseException = null;
                    try
                    { 
                        try
                        { 
                            response = (HttpWebResponse)webRequest.GetResponse(); 
                        }
                        catch (NullReferenceException nullReferenceException) 
                        {
                            // workaround for Whidbey bug #558605 - only happens in streamed case.
                            if (TransferModeHelper.IsRequestStreamed(this.factory.transferMode))
                            { 
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                                    HttpChannelUtilities.CreateNullReferenceResponseException(nullReferenceException)); 
                            } 
                            throw;
                        } 
                        if (DiagnosticUtility.ShouldTraceVerbose)
                        {
                            HttpChannelFactory.TraceResponseReceived(response, null, this);
                        } 
                    }
                    catch (WebException webException) 
                    { 
                        responseException = webException;
                        response = HttpChannelUtilities.ProcessGetResponseWebException(webException, this.webRequest, 
                            abortReason);
                    }

                    HttpInput httpInput = HttpChannelUtilities.ValidateRequestReplyResponse(this.webRequest, response, 
                        this.factory, responseException);
 
                    Message replyMessage = null; 
                    if (httpInput != null)
                    { 
                        Exception exception = null;
                        replyMessage = httpInput.ParseIncomingMessage(out exception);
                        DiagnosticUtility.DebugAssert(exception == null, "ParseIncomingMessage should not set an exception after parsing a response message.");
 
                        if (replyMessage != null)
                        { 
                            HttpChannelUtilities.AddReplySecurityProperty(this.factory, this.webRequest, response, 
                                replyMessage);
                        } 
                    }

                    this.channel.OnWebRequestCompleted(this.webRequest);
                    return replyMessage; 
                }
            } 
 
            class HttpChannelAsyncRequest : TraceAsyncResult, IAsyncRequest
            { 
                HttpChannelFactory factory;
                HttpRequestChannel channel;
                HttpOutput httpOutput;
                HttpInput httpInput; 
                Message message;
                Message replyMessage; 
                HttpWebResponse response; 
                static AsyncCallback onProcessIncomingMessage = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnParseIncomingMessage));
                static AsyncCallback onGetResponse = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnGetResponse)); 
                static AsyncCallback onGetWebRequestCompleted;
                static AsyncCallback onSend = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnSend));
                static WaitCallback onSendTimeout;
                HttpWebRequest request; 
                object sendLock = new object();
                IOThreadTimer sendTimer; 
                TimeoutHelper timeoutHelper; 
                EndpointAddress to;
                Uri via; 
                HttpAbortReason abortReason;

                public HttpChannelAsyncRequest(HttpRequestChannel channel,  AsyncCallback callback, object state)
                    : base(callback, state) 
                {
                    this.channel = channel; 
                    this.to = channel.RemoteAddress; 
                    this.via = channel.Via;
                    this.factory = channel.Factory; 
                }

                public static void End(IAsyncResult result)
                { 
                    AsyncResult.End(result);
                } 
 
                IOThreadTimer SendTimer
                { 
                    get
                    {
                        if (this.sendTimer == null)
                        { 
                            if (onSendTimeout == null)
                            { 
                                onSendTimeout = new WaitCallback(OnSendTimeout); 
                            }
 
                            this.sendTimer = new IOThreadTimer(onSendTimeout, this, false);
                        }

                        return this.sendTimer; 
                    }
                } 
 
                public void BeginSendRequest(Message message, TimeSpan timeout)
                { 
                    this.message = message;
                    this.timeoutHelper = new TimeoutHelper(timeout);

                    factory.ApplyManualAddressing(ref this.to, ref this.via, message); 
                    if (this.channel.WillGetWebRequestCompleteSynchronously())
                    { 
                        SetWebRequest(channel.GetWebRequest(this.to, this.via, ref this.timeoutHelper)); 
                        if (this.SendWebRequest())
                        { 
                            base.Complete(true);
                        }
                    }
                    else 
                    {
                        if (onGetWebRequestCompleted == null) 
                        { 
                            onGetWebRequestCompleted = DiagnosticUtility.ThunkAsyncCallback(
                                new AsyncCallback(OnGetWebRequestCompletedCallback)); 
                        }

                        IAsyncResult result = channel.BeginGetWebRequest(
                            to, via, ref this.timeoutHelper, onGetWebRequestCompleted, this); 

                        if (result.CompletedSynchronously) 
                        { 
                            if (OnGetWebRequestCompleted(result))
                            { 
                                base.Complete(true);
                            }
                        }
                    } 
                }
 
                static void OnGetWebRequestCompletedCallback(IAsyncResult result) 
                {
                    if (result.CompletedSynchronously) 
                    {
                        return;
                    }
 
                    HttpChannelAsyncRequest thisPtr = (HttpChannelAsyncRequest)result.AsyncState;
                    Exception completionException = null; 
                    bool completeSelf; 
                    try
                    { 
                        completeSelf = thisPtr.OnGetWebRequestCompleted(result);
                    }
#pragma warning suppress 56500 // [....], transferring exception to another thread
                    catch (Exception e) 
                    {
                        if (DiagnosticUtility.IsFatal(e)) 
                        { 
                            throw;
                        } 
                        completeSelf = true;
                        completionException = e;
                    }
                    if (completeSelf) 
                    {
                        thisPtr.Complete(false, completionException); 
                    } 
                }
 
                void AbortSend()
                {
                    CancelSendTimer();
                    if (this.request != null) 
                    {
                        this.channel.OnWebRequestCompleted(this.request); 
                        this.abortReason = HttpAbortReason.TimedOut; 
                        httpOutput.Abort(this.abortReason);
                    } 
                }

                void CancelSendTimer()
                { 
                    lock (sendLock)
                    { 
                        if (this.sendTimer != null) 
                        {
                            this.sendTimer.Cancel(); 
                            this.sendTimer = null;
                        }
                    }
                } 

                bool OnGetWebRequestCompleted(IAsyncResult result) 
                { 
                    SetWebRequest(this.channel.EndGetWebRequest(result));
                    return SendWebRequest(); 
                }

                bool SendWebRequest()
                { 
                    this.httpOutput = HttpOutput.CreateHttpOutput(this.request, this.factory, this.message);
 
                    bool throwing = true; 
                    try
                    { 
                        bool result = false;
                        SetSendTimeout(timeoutHelper.RemainingTime());
                        IAsyncResult asyncResult = httpOutput.BeginSend(timeoutHelper.RemainingTime(), onSend, this);
                        if (asyncResult.CompletedSynchronously) 
                        {
                            result = CompleteSend(asyncResult); 
                        } 

                        throwing = false; 
                        return result;
                    }
                    finally
                    { 
                        if (throwing)
                        { 
                            this.httpOutput.Abort(HttpAbortReason.Aborted); 
                        }
                    } 
                }

                bool CompleteSend(IAsyncResult result)
                { 
                    bool success = false;
                    try 
                    { 
                        httpOutput.EndSend(result);
                        httpOutput.Close(); 
                        success = true;
                    }
                    finally
                    { 
                        if (!success)
                        { 
                            httpOutput.Abort(HttpAbortReason.Aborted); 
                        }
                    } 

                    try
                    {
                        IAsyncResult getResponseResult; 
                        try
                        { 
                            getResponseResult = request.BeginGetResponse(onGetResponse, this); 
                        }
                        catch (NullReferenceException nullReferenceException) 
                        {
                            // workaround for Whidbey bug #558605 - only happens in streamed case.
                            if (TransferModeHelper.IsRequestStreamed(this.factory.transferMode))
                            { 
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                                    HttpChannelUtilities.CreateNullReferenceResponseException(nullReferenceException)); 
                            } 
                            throw;
                        } 


                        if (getResponseResult.CompletedSynchronously)
                        { 
                            return CompleteGetResponse(getResponseResult);
                        } 
 
                        return false;
                    } 
                    catch (IOException ioException)
                    {
                        throw TraceUtility.ThrowHelperError(new CommunicationException(ioException.Message,
                            ioException), this.message); 
                    }
                    catch (WebException webException) 
                    { 
                        throw TraceUtility.ThrowHelperError(new CommunicationException(webException.Message,
                            webException), this.message); 
                    }
                    catch (ObjectDisposedException objectDisposedException)
                    {
                        if (abortReason == HttpAbortReason.Aborted) 
                        {
                            throw TraceUtility.ThrowHelperError(new CommunicationObjectAbortedException(SR.GetString(SR.HttpRequestAborted, to.Uri), 
                                objectDisposedException), this.message); 
                        }
 
                        throw TraceUtility.ThrowHelperError(new TimeoutException(SR.GetString(SR.HttpRequestTimedOut,
                            to.Uri, this.timeoutHelper.OriginalTimeout), objectDisposedException), this.message);
                    }
                } 

                bool CompleteGetResponse(IAsyncResult result) 
                { 
                    using (ServiceModelActivity.BoundOperation(this.channel.Activity))
                    { 
                        HttpWebResponse response = null;
                        WebException responseException = null;
                        try
                        { 
                            try
                            { 
                                CancelSendTimer(); 
                                response = (HttpWebResponse)request.EndGetResponse(result);
                            } 
                            catch (NullReferenceException nullReferenceException)
                            {
                                // workaround for Whidbey bug #558605 - only happens in streamed case.
                                if (TransferModeHelper.IsRequestStreamed(this.factory.transferMode)) 
                                {
                                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                                        HttpChannelUtilities.CreateNullReferenceResponseException(nullReferenceException)); 
                                }
                                throw; 
                            }

                            if (DiagnosticUtility.ShouldTraceVerbose)
                            { 
                                HttpChannelFactory.TraceResponseReceived(response, message, this);
                            } 
                        } 
                        catch (WebException webException)
                        { 
                            responseException = webException;
                            response = HttpChannelUtilities.ProcessGetResponseWebException(webException, request,
                                abortReason);
                        } 

                        return ProcessResponse(response, responseException); 
                    } 
                }
 
                void Cleanup()
                {
                    if (this.request != null)
                    { 
                        HttpChannelUtilities.AbortRequest(this.request);
                        this.channel.OnWebRequestCompleted(this.request); 
                    } 
                }
 
                void SetSendTimeout(TimeSpan timeout)
                {
                    // We also set the timeout on the HttpWebRequest so that we can subsequently use it in the
                    // exception message in the event of a timeout. 
                    HttpChannelUtilities.SetRequestTimeout(this.request, timeout);
 
                    if (timeout == TimeSpan.MaxValue) 
                    {
                        CancelSendTimer(); 
                    }
                    else
                    {
                        SendTimer.Set(timeout); 
                    }
                } 
 
                public void Abort(RequestChannel channel)
                { 
                    Cleanup();
                    abortReason = HttpAbortReason.Aborted;
                }
 
                public void Fault(RequestChannel channel)
                { 
                    Cleanup(); 
                }
 
                void SetWebRequest(HttpWebRequest webRequest)
                {
                    this.request = webRequest;
 
                    if (channel.State != CommunicationState.Opened)
                    { 
                        // if we were aborted while getting our request, we need to abort the web request and bail 
                        Cleanup();
                        channel.ThrowIfDisposedOrNotOpen(); 
                    }
                }

                public Message End() 
                {
                    HttpChannelAsyncRequest.End(this); 
                    return replyMessage; 
                }
 
                bool ProcessResponse(HttpWebResponse response, WebException responseException)
                {
                    this.httpInput = HttpChannelUtilities.ValidateRequestReplyResponse(this.request, response,
                        this.factory, responseException); 

                    if (httpInput != null) 
                    { 
                        this.response = response;
                        IAsyncResult result = 
                            httpInput.BeginParseIncomingMessage(onProcessIncomingMessage, this);
                        if (!result.CompletedSynchronously)
                        {
                            return false; 
                        }
 
                        CompleteParseIncomingMessage(result); 
                    }
                    else 
                    {
                        this.replyMessage = null;
                    }
 
                    this.channel.OnWebRequestCompleted(this.request);
                    return true; 
                } 

                void CompleteParseIncomingMessage(IAsyncResult result) 
                {
                    Exception exception = null;
                    this.replyMessage = this.httpInput.EndParseIncomingMessage(result, out exception);
                    DiagnosticUtility.DebugAssert(exception == null, "ParseIncomingMessage should not set an exception after parsing a response message."); 

                    if (this.replyMessage != null) 
                    { 
                        HttpChannelUtilities.AddReplySecurityProperty(this.factory, this.request, this.response,
                            this.replyMessage); 
                    }
                }

                static void OnParseIncomingMessage(IAsyncResult result) 
                {
                    if (result.CompletedSynchronously) 
                        return; 

                    HttpChannelAsyncRequest thisPtr = (HttpChannelAsyncRequest)result.AsyncState; 

                    Exception completionException = null;
                    try
                    { 
                        thisPtr.CompleteParseIncomingMessage(result);
                    } 
#pragma warning suppress 56500 // [....], transferring exception to another thread 
                    catch (Exception e)
                    { 
                        if (DiagnosticUtility.IsFatal(e))
                        {
                            throw;
                        } 
                        completionException = e;
                    } 
                    thisPtr.Complete(false, completionException); 
                }
 
                static void OnSend(IAsyncResult result)
                {
                    if (result.CompletedSynchronously)
                    { 
                        return;
                    } 
 
                    HttpChannelAsyncRequest thisPtr = (HttpChannelAsyncRequest)result.AsyncState;
 
                    Exception completionException = null;
                    bool completeSelf;
                    try
                    { 
                        completeSelf = thisPtr.CompleteSend(result);
                    } 
#pragma warning suppress 56500 // [....], transferring exception to another thread 
                    catch (Exception e)
                    { 
                        if (DiagnosticUtility.IsFatal(e))
                        {
                            throw;
                        } 

                        completeSelf = true; 
                        completionException = e; 
                    }
                    if (completeSelf) 
                    {
                        thisPtr.Complete(false, completionException);
                    }
                } 

                static void OnSendTimeout(object state) 
                { 
                    HttpChannelAsyncRequest thisPtr = (HttpChannelAsyncRequest)state;
                    thisPtr.AbortSend(); 
                }

                static void OnGetResponse(IAsyncResult result)
                { 
                    if (result.CompletedSynchronously)
                        return; 
 
                    HttpChannelAsyncRequest thisPtr = (HttpChannelAsyncRequest)result.AsyncState;
 
                    Exception completionException = null;
                    bool completeSelf;
                    try
                    { 
                        completeSelf = thisPtr.CompleteGetResponse(result);
                    } 
                    catch (WebException webException) 
                    {
                        completeSelf = true; 
                        completionException = new CommunicationException(webException.Message, webException);
                    }
#pragma warning suppress 56500 // [....], transferring exception to another thread
                    catch (Exception e) 
                    {
                        if (DiagnosticUtility.IsFatal(e)) 
                        { 
                            throw;
                        } 
                        completeSelf = true;
                        completionException = e;
                    }
                    if (completeSelf) 
                    {
                        thisPtr.Complete(false, completionException); 
                    } 
                }
            } 

            class GetWebRequestAsyncResult : AsyncResult
            {
                SecurityTokenContainer clientCertificateToken; 
                HttpChannelFactory factory;
                SecurityTokenProviderContainer proxyTokenProvider; 
                HttpWebRequest request; 
                EndpointAddress to;
                TimeoutHelper timeoutHelper; 
                SecurityTokenProviderContainer tokenProvider;
                Uri via;

                static AsyncCallback onGetSspiCredential; 
                static AsyncCallback onGetUserNameCredential;
 
                public GetWebRequestAsyncResult(HttpRequestChannel channel, 
                    EndpointAddress to, Uri via, SecurityTokenContainer clientCertificateToken, ref TimeoutHelper timeoutHelper,
                    AsyncCallback callback, object state) 
                    : base(callback, state)
                {
                    this.to = to;
                    this.via = via; 
                    this.clientCertificateToken = clientCertificateToken;
                    this.timeoutHelper = timeoutHelper; 
                    this.factory = channel.Factory; 
                    this.tokenProvider = channel.tokenProvider;
                    this.proxyTokenProvider = channel.proxyTokenProvider; 
                    if (factory.ManualAddressing)
                    {
                        this.factory.CreateAndOpenTokenProviders(to, via,  channel.channelParameters, timeoutHelper.RemainingTime(),
                            out this.tokenProvider, out this.proxyTokenProvider); 
                    }
 
                    bool completeSelf = false; 
                    IAsyncResult result = null;
                    if (factory.AuthenticationScheme == AuthenticationSchemes.Anonymous) 
                    {
                        SetupWebRequest(AuthenticationLevel.None, TokenImpersonationLevel.None, null);
                        completeSelf = true;
                    } 
                    else if (factory.AuthenticationScheme == AuthenticationSchemes.Basic)
                    { 
                        if (onGetUserNameCredential == null) 
                        {
                            onGetUserNameCredential = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnGetUserNameCredential)); 
                        }

                        result = TransportSecurityHelpers.BeginGetUserNameCredential(
                            tokenProvider, timeoutHelper.RemainingTime(), onGetUserNameCredential, this); 

                        if (result.CompletedSynchronously) 
                        { 
                            CompleteGetUserNameCredential(result);
                            completeSelf = true; 
                        }
                    }
                    else
                    { 
                        if (onGetSspiCredential == null)
                        { 
                            onGetSspiCredential = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnGetSspiCredential)); 
                        }
 
                        result = TransportSecurityHelpers.BeginGetSspiCredential(
                            tokenProvider, timeoutHelper.RemainingTime(), onGetSspiCredential, this);

                        if (result.CompletedSynchronously) 
                        {
                            CompleteGetSspiCredential(result); 
                            completeSelf = true; 
                        }
                    } 

                    if (completeSelf)
                    {
                        CloseTokenProvidersIfRequired(); 
                        base.Complete(true);
                    } 
                } 

                public static HttpWebRequest End(IAsyncResult result) 
                {
                    GetWebRequestAsyncResult thisPtr = AsyncResult.End(result);
                    return thisPtr.request;
                } 

                void CompleteGetUserNameCredential(IAsyncResult result) 
                { 
                    NetworkCredential credential =
                        TransportSecurityHelpers.EndGetUserNameCredential(result); 
                    SetupWebRequest(AuthenticationLevel.None, TokenImpersonationLevel.None, credential);
                }

                void CompleteGetSspiCredential(IAsyncResult result) 
                {
                    AuthenticationLevel authenticationLevel; 
                    TokenImpersonationLevel impersonationLevel; 
                    NetworkCredential credential =
                        TransportSecurityHelpers.EndGetSspiCredential(result, out impersonationLevel, out authenticationLevel); 

                    if (factory.AuthenticationScheme == AuthenticationSchemes.Digest)
                    {
                        HttpChannelUtilities.ValidateDigestCredential(ref credential, impersonationLevel); 
                    }
                    else if (factory.AuthenticationScheme == AuthenticationSchemes.Ntlm) 
                    { 
                        if (authenticationLevel == AuthenticationLevel.MutualAuthRequired)
                        { 
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                                SR.GetString(SR.CredentialDisallowsNtlm)));
                        }
                    } 

                    SetupWebRequest(authenticationLevel, impersonationLevel, credential); 
                } 

                void SetupWebRequest(AuthenticationLevel authenticationLevel, TokenImpersonationLevel impersonationLevel, NetworkCredential credential) 
                {
                    this.request = factory.GetWebRequest(to, via, credential, impersonationLevel,
                        authenticationLevel, this.proxyTokenProvider, this.clientCertificateToken, timeoutHelper.RemainingTime());
                } 

                void CloseTokenProvidersIfRequired() 
                { 
                    if (this.factory.ManualAddressing)
                    { 
                        if (this.tokenProvider != null)
                        {
                            tokenProvider.Abort();
                        } 
                        if (this.proxyTokenProvider != null)
                        { 
                            proxyTokenProvider.Abort(); 
                        }
                    } 
                }

                static void OnGetSspiCredential(IAsyncResult result)
                { 
                    if (result.CompletedSynchronously)
                    { 
                        return; 
                    }
 
                    GetWebRequestAsyncResult thisPtr = (GetWebRequestAsyncResult)result.AsyncState;

                    Exception completionException = null;
                    try 
                    {
                        thisPtr.CompleteGetSspiCredential(result); 
                        thisPtr.CloseTokenProvidersIfRequired(); 
                    }
#pragma warning suppress 56500 // [....], transferring exception to another thread 
                    catch (Exception e)
                    {
                        if (DiagnosticUtility.IsFatal(e))
                        { 
                            throw;
                        } 
 
                        completionException = e;
                    } 
                    thisPtr.Complete(false, completionException);
                }

                static void OnGetUserNameCredential(IAsyncResult result) 
                {
                    if (result.CompletedSynchronously) 
                    { 
                        return;
                    } 

                    GetWebRequestAsyncResult thisPtr = (GetWebRequestAsyncResult)result.AsyncState;

                    Exception completionException = null; 
                    try
                    { 
                        thisPtr.CompleteGetUserNameCredential(result); 
                        thisPtr.CloseTokenProvidersIfRequired();
                    } 
#pragma warning suppress 56500 // [....], transferring exception to another thread
                    catch (Exception e)
                    {
                        if (DiagnosticUtility.IsFatal(e)) 
                        {
                            throw; 
                        } 

                        completionException = e; 
                    }
                    thisPtr.Complete(false, completionException);
                }
            } 
        }
 
        class WebProxyFactory 
        {
            Uri address; 
            bool bypassOnLocal;
            AuthenticationSchemes authenticationScheme;

            public WebProxyFactory(Uri address, bool bypassOnLocal, AuthenticationSchemes authenticationScheme) 
            {
                this.address = address; 
                this.bypassOnLocal = bypassOnLocal; 
                this.authenticationScheme = authenticationScheme;
            } 

            internal AuthenticationSchemes AuthenticationScheme
            {
                get 
                {
                    return authenticationScheme; 
                } 
            }
 
            public IWebProxy CreateWebProxy(HttpWebRequest request, SecurityTokenProviderContainer tokenProvider, TimeSpan timeout)
            {
                WebProxy result = new WebProxy(this.address, this.bypassOnLocal);
 
                if (this.authenticationScheme != AuthenticationSchemes.Anonymous)
                { 
                    TokenImpersonationLevel impersonationLevel; 
                    AuthenticationLevel authenticationLevel;
                    NetworkCredential credential = HttpChannelUtilities.GetCredential(this.authenticationScheme, 
                     tokenProvider, timeout, out impersonationLevel, out authenticationLevel);

                    // The impersonation level for target auth is also used for proxy auth (by System.Net).  Therefore,
                    // fail if the level stipulated for proxy auth is more restrictive than that for target auth. 
                    if (!TokenImpersonationLevelHelper.IsGreaterOrEqual(impersonationLevel, request.ImpersonationLevel))
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString( 
                            SR.ProxyImpersonationLevelMismatch, impersonationLevel, request.ImpersonationLevel)));
                    } 

                    // The authentication level for target auth is also used for proxy auth (by System.Net).
                    // Therefore, fail if proxy auth requires mutual authentication but target auth does not.
                    if ((authenticationLevel == AuthenticationLevel.MutualAuthRequired) && 
                        (request.AuthenticationLevel != AuthenticationLevel.MutualAuthRequired))
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString( 
                            SR.ProxyAuthenticationLevelMismatch, authenticationLevel, request.AuthenticationLevel)));
                    } 

                    CredentialCache credentials = new CredentialCache();
                    credentials.Add(this.address, AuthenticationSchemesHelper.ToString(this.authenticationScheme),
                        credential); 
                    result.Credentials = credentials;
                } 
 
                return result;
            } 
        }
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK