SharedHttpTransportManager.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 / SharedHttpTransportManager.cs / 1 / SharedHttpTransportManager.cs

                            //---------------------------------------------------------------------------- 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//---------------------------------------------------------------------------
namespace System.ServiceModel.Channels
{ 
    using System.Diagnostics;
    using System.ServiceModel; 
    using System.Net; 
    using System.ServiceModel.Diagnostics;
    using System.ServiceModel.Dispatcher; 
    using System.Threading;
    using System.Security.Principal;

    class SharedHttpTransportManager : HttpTransportManager 
    {
        const int maxPendingGetContexts = 10; 
#if DEBUG // add performance counter instead in v.Next - see MessageBus bug #54117 
        int currentPendingGetContexts;
#endif 
        HttpListener listener;
        ManualResetEvent listenStartedEvent;
        Exception listenStartedException;
        AsyncCallback onGetContext; 
        ItemDequeuedCallback onMessageDequeued;
        WaitCallback onCompleteGetContextLater; 
        bool unsafeConnectionNtlmAuthentication; 

        internal SharedHttpTransportManager(Uri listenUri, HttpChannelListener channelListener) 
            : base(listenUri, channelListener.HostNameComparisonMode, channelListener.Realm)
        {
            this.onGetContext = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnGetContext));
            this.onMessageDequeued = new ItemDequeuedCallback(OnMessageDequeued); 
            this.unsafeConnectionNtlmAuthentication = channelListener.UnsafeConnectionNtlmAuthentication;
        } 
 
        internal override bool IsCompatible(HttpChannelListener channelListener)
        { 
            if (channelListener.InheritBaseAddressSettings)
                return true;

            if (!channelListener.IsScopeIdCompatible(HostNameComparisonMode, this.ListenUri)) 
            {
                return false; 
            } 

            return channelListener.UnsafeConnectionNtlmAuthentication == this.unsafeConnectionNtlmAuthentication 
                && base.IsCompatible(channelListener);
        }

        internal override void OnClose() 
        {
            try 
            { 
                listener.Stop();
            } 
            finally
            {
                try
                { 
                    listener.Close();
                } 
                finally 
                {
                    base.OnClose(); 
                }
            }
            listener = null;
        } 

        IAsyncResult BeginGetContext(AsyncCallback callback, object state, bool startListening) 
        { 
            while (true)
            { 
                Exception unexpectedException = null;
                try
                {
                    try 
                    {
                        if (ExecutionContext.IsFlowSuppressed()) 
                        { 
                            return listener.BeginGetContext(callback, state);
                        } 
                        else
                        {
                            using (ExecutionContext.SuppressFlow())
                            { 
                                return listener.BeginGetContext(callback, state);
                            } 
                        } 
                    }
                    catch (HttpListenerException e) 
                    {
                        switch (e.ErrorCode)
                        {
                            case UnsafeNativeMethods.ERROR_NOT_ENOUGH_MEMORY: 
                            case UnsafeNativeMethods.ERROR_OUTOFMEMORY:
                            case UnsafeNativeMethods.ERROR_NO_SYSTEM_RESOURCES: 
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InsufficientMemoryException(SR.GetString(SR.InsufficentMemory), e)); 
                            default:
                                if (!ExceptionHandler.HandleTransportExceptionHelper(e)) 
                                    throw;
                                break;
                        }
 
                    }
                } 
                catch (Exception e) 
                {
                    if (DiagnosticUtility.IsFatal(e)) 
                    {
                        throw;
                    }
                    if (startListening) 
                    {
                        // Since we're under a call to StartListening(), just throw the exception up the stack. 
                        throw; 
                    }
                    unexpectedException = e; 
                }

                if (unexpectedException != null)
                { 
                    this.Fault(unexpectedException);
                    return null; 
                } 
            }
        } 

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

            OnGetContextCore(result); 
        }

        void OnGetContextCore(IAsyncResult result)
        { 
            bool enqueued = false;
 
            while (!enqueued) 
            {
                Exception unexpectedException = null; 
                try
                {
                    try
                    { 
                        HttpListenerContext listenerContext = null;
 
                        lock (base.ThisLock) 
                        {
                            if (listener == null) // we've been closed 
                                return;

                            listenerContext = listener.EndGetContext(result);
                            DiagnosticUtility.DebugAssert(listenerContext != null && listenerContext.Request != null, ""); 
                        }
 
                        HttpChannelListener channelListener = null; 

                        // Grab the activity from the context and set that as the surrounding activity. 
                        // If a message appears, we will transfer to the message's activity next
                        using (DiagnosticUtility.ShouldUseActivity ? ServiceModelActivity.BoundOperation(this.Activity) : null)
                        {
                            using (ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity ? ServiceModelActivity.CreateBoundedActivityWithTransferInOnly(listenerContext.Request.RequestTraceIdentifier) : null) 
                            {
                                if (activity != null && DiagnosticUtility.ShouldUseActivity) 
                                { 
                                    ServiceModelActivity.Start(activity, SR.GetString(SR.ActivityReceiveBytes, listenerContext.Request.Url.ToString()), ActivityType.ReceiveBytes);
                                } 
                                if (DiagnosticUtility.ShouldTraceInformation)
                                {
                                    TraceUtility.TraceHttpConnectionInformation(listenerContext.Request.LocalEndPoint.ToString(),
                                        listenerContext.Request.RemoteEndPoint.ToString(), this); 
                                }
                                if (base.TryLookupUri(listenerContext.Request.Url, listenerContext.Request.HttpMethod, 
                                    this.HostNameComparisonMode, out channelListener)) 
                                {
                                    enqueued = channelListener.HttpContextReceived( 
                                        HttpRequestContext.CreateContext(channelListener, listenerContext), onMessageDequeued);
#if DEBUG // add performance counter instead in v.Next - see MessageBus bug #54117
                                    if (enqueued)
                                    { 
                                        bool traceLimit = false;
                                        lock (ThisLock) 
                                        { 
                                            currentPendingGetContexts++;
                                            if (currentPendingGetContexts >= maxPendingGetContexts) 
                                            {
                                                traceLimit = true;
                                            }
                                        } 

                                        if (traceLimit) 
                                        { 
                                            if (DiagnosticUtility.ShouldTraceWarning)
                                            { 
                                                DiagnosticUtility.DiagnosticTrace.TraceEvent(TraceEventType.Warning,
                                                                                            TraceCode.HttpChannelConcurrentReceiveQuotaReached,
                                                                                            SR.GetString(SR.HttpConcurrentReceiveQuotaReached, maxPendingGetContexts));
                                            } 
                                        }
                                    } 
#endif 
                                }
                                else 
                                {
                                    if (DiagnosticUtility.ShouldTraceWarning)
                                    {
                                        TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.HttpChannelMessageReceiveFailed, null); 
                                    }
 
                                    // no match -- 405 or 404 
                                    if (string.Compare(listenerContext.Request.HttpMethod, "POST", StringComparison.OrdinalIgnoreCase) != 0)
                                    { 
                                        listenerContext.Response.StatusCode = (int)HttpStatusCode.MethodNotAllowed;
                                        listenerContext.Response.Headers.Add(HttpResponseHeader.Allow, "POST");
                                    }
                                    else 
                                    {
                                        listenerContext.Response.StatusCode = (int)HttpStatusCode.NotFound; 
                                    } 

                                    listenerContext.Response.ContentLength64 = 0; 
                                    listenerContext.Response.Close();
                                }
                            }
                        } 
                    }
                    catch (HttpListenerException e) 
                    { 
                        switch (e.ErrorCode)
                        { 
                            case UnsafeNativeMethods.ERROR_NOT_ENOUGH_MEMORY:
                            case UnsafeNativeMethods.ERROR_OUTOFMEMORY:
                            case UnsafeNativeMethods.ERROR_NO_SYSTEM_RESOURCES:
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InsufficientMemoryException(SR.GetString(SR.InsufficentMemory), e)); 
                            default:
                                if (!ExceptionHandler.HandleTransportExceptionHelper(e)) 
                                    throw; 
                                break;
                        } 
                    }
                }
                catch (Exception exception)
                { 
                    if (DiagnosticUtility.IsFatal(exception))
                    { 
                        throw; 
                    }
                    unexpectedException = exception; 
                }

                if (unexpectedException != null)
                { 
                    this.Fault(unexpectedException);
                } 
 
                if (!enqueued) // onMessageDequeued will handle this in the enqueued case
                { 
                    lock (base.ThisLock)
                    {
                        if (listener != null)
                        { 
                            result = BeginGetContext(onGetContext, null, false);
                            if ((result == null) || !result.CompletedSynchronously) 
                            { 
                                return;
                            } 
                        }
                    }
                }
            } 
        }
 
        void OnCompleteGetContextLater(object state) 
        {
            OnGetContextCore((IAsyncResult)state); 
        }

        void StartListening()
        { 
            for (int i = 0; i < maxPendingGetContexts; i++)
            { 
                IAsyncResult result = BeginGetContext(onGetContext, null, true); 
                if (result.CompletedSynchronously)
                { 
                    if (onCompleteGetContextLater == null)
                    {
                        onCompleteGetContextLater = new WaitCallback(OnCompleteGetContextLater);
                    } 
                    IOThreadScheduler.ScheduleCallback(onCompleteGetContextLater, result);
                } 
            } 
        }
 
        void OnListening(object state)
        {
            try
            { 
                StartListening();
            } 
            catch (Exception e) 
            {
                if (DiagnosticUtility.IsFatal(e)) 
                {
                    throw;
                }
                listenStartedException = e; 
            }
            finally 
            { 
                listenStartedEvent.Set();
            } 
        }

        void OnMessageDequeued()
        { 
            ThreadTrace.Trace("message dequeued");
            IAsyncResult result = null; 
            lock (base.ThisLock) 
            {
                if (listener != null) 
                {
#if DEBUG // add performance counter instead in v.Next - see MessageBus bug #54117
                    currentPendingGetContexts--;
#endif 
                    result = BeginGetContext(onGetContext, null, false);
                } 
            } 

            if (result != null && result.CompletedSynchronously) 
            {
                if (onCompleteGetContextLater == null)
                {
                    onCompleteGetContextLater = new WaitCallback(OnCompleteGetContextLater); 
                }
                IOThreadScheduler.ScheduleCallback(onCompleteGetContextLater, result); 
            } 
        }
 
        internal override void OnOpen()
        {
            listener = new HttpListener();
 
            string host;
 
            switch (HostNameComparisonMode) 
            {
                case HostNameComparisonMode.Exact: 
                    // Uri.DnsSafeHost strips the [], but preserves the scopeid for IPV6 addresses.
                    if (ListenUri.HostNameType == UriHostNameType.IPv6)
                    {
                        host = string.Concat("[", ListenUri.DnsSafeHost, "]"); 
                    }
                    else 
                    { 
                        host = ListenUri.DnsSafeHost;
                    } 
                    break;

                case HostNameComparisonMode.StrongWildcard:
                    host = "+"; 
                    break;
 
                case HostNameComparisonMode.WeakWildcard: 
                    host = "*";
                    break; 

                default:
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.UnrecognizedHostNameComparisonMode, HostNameComparisonMode.ToString())));
            } 

            string path = ListenUri.GetComponents(UriComponents.Path, UriFormat.Unescaped); 
            if (!path.StartsWith("/", StringComparison.Ordinal)) 
                path = "/" + path;
 
            if (!path.EndsWith("/", StringComparison.Ordinal))
                path = path + "/";

            string httpListenUrl = string.Concat(Scheme, "://", host, ":", ListenUri.Port, path); 

            listener.UnsafeConnectionNtlmAuthentication = this.unsafeConnectionNtlmAuthentication; 
            listener.AuthenticationSchemeSelectorDelegate = 
                new AuthenticationSchemeSelector(SelectAuthenticationScheme);
            if (this.Realm != null) 
            {
                listener.Realm = this.Realm;
            }
 
            bool success = false;
            try 
            { 
                listener.Prefixes.Add(httpListenUrl);
                listener.Start(); 

                bool startedListening = false;
                try
                { 
                    if (Thread.CurrentThread.IsThreadPoolThread)
                    { 
                        StartListening(); 
                    }
                    else 
                    {
                        // If we're not on a threadpool thread, then we need to post a callback to start our accepting loop
                        // Otherwise if the calling thread aborts then the async I/O will get inadvertantly cancelled
                        listenStartedEvent = new ManualResetEvent(false); 
                        IOThreadScheduler.ScheduleCallback(OnListening, null);
                        listenStartedEvent.WaitOne(); 
                        listenStartedEvent.Close(); 
                        listenStartedEvent = null;
                        if (listenStartedException != null) 
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(listenStartedException);
                        }
                    } 
                    startedListening = true;
                } 
                finally 
                {
                    if (!startedListening) 
                    {
                        listener.Stop();
                    }
                } 

                success = true; 
            } 
            catch (HttpListenerException listenerException)
            { 
                switch (listenerException.NativeErrorCode)
                {
                    case UnsafeNativeMethods.ERROR_ALREADY_EXISTS:
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new AddressAlreadyInUseException(SR.GetString(SR.HttpRegistrationAlreadyExists, httpListenUrl), listenerException)); 

                    case UnsafeNativeMethods.ERROR_SHARING_VIOLATION: 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new AddressAlreadyInUseException(SR.GetString(SR.HttpRegistrationPortInUse, httpListenUrl, ListenUri.Port), listenerException)); 

                    case UnsafeNativeMethods.ERROR_ACCESS_DENIED: 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new AddressAccessDeniedException(SR.GetString(SR.HttpRegistrationAccessDenied, httpListenUrl), listenerException));

                    case UnsafeNativeMethods.ERROR_ALLOTTED_SPACE_EXCEEDED:
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.HttpRegistrationLimitExceeded, httpListenUrl), listenerException)); 

                    case UnsafeNativeMethods.ERROR_INVALID_PARAMETER: 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.HttpInvalidListenURI, ListenUri.OriginalString), listenerException)); 

                    default: 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                            HttpChannelUtilities.CreateCommunicationException(listenerException));
                }
            } 
            finally
            { 
                if (!success) 
                {
                    listener.Abort(); 
                }
            }
        }
 
        AuthenticationSchemes SelectAuthenticationScheme(HttpListenerRequest request)
        { 
            try 
            {
                AuthenticationSchemes result; 
                HttpChannelListener channelListener;
                if (base.TryLookupUri(request.Url, request.HttpMethod,
                    this.HostNameComparisonMode, out channelListener))
                { 
                    result = channelListener.AuthenticationScheme;
                } 
                else 
                {
                    // if we don't match a listener factory, we want to "fall through" the 
                    // auth delegate code and run through our normal OnGetContext codepath.
                    // System.Net treats "None" as Access Denied, which is not our intent here.
                    // In most cases this will just fall through to the code that returns a "404 Not Found"
                    result = AuthenticationSchemes.Anonymous; 
                }
 
                return result; 
            }
            catch (Exception e) 
            {
                DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Error);
                throw;
            } 
        }
    } 
} 

// 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