HttpListener.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / Net / System / Net / HttpListener.cs / 1 / HttpListener.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

//disabled until BindHandle has an overload that accepts Criticalhandles 
#pragma warning disable 618 

namespace System.Net { 
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.Specialized; 
    using System.IO;
    using System.Net; 
    using System.Net.Sockets; 
    using System.Runtime.InteropServices;
    using System.Security.Permissions; 
    using System.Text;
    using System.Threading;
    using System.ComponentModel;
    using System.Diagnostics; 
    using System.Globalization;
    using System.Security; 
    using System.Security.Principal; 
    using System.Security.Cryptography.X509Certificates;
    using Microsoft.Win32; 

    public class HttpListenerBasicIdentity : GenericIdentity
    {
        private string m_Password; 

        public HttpListenerBasicIdentity(string username, string password) : 
            base(username, BasicClient.AuthType) 
        {
            m_Password = password; 
        }

        public virtual string Password
        { 
            get
            { 
                return m_Password; 
            }
        } 
    }

    internal abstract unsafe class RequestContextBase : IDisposable
    { 
        private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* m_MemoryBlob;
        private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* m_OriginalBlobAddress; 
        private byte[] m_BackingBuffer; 

        // Must call this from derived class' constructors. 
        protected void BaseConstruction(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* requestBlob)
        {
            if (requestBlob == null)
            { 
                GC.SuppressFinalize(this);
            } 
            else 
            {
                m_MemoryBlob = requestBlob; 
            }
        }

        // ReleasePins() should be called exactly once.  It must be called before Dispose() is called, which means it must be called 
        // before an object (HttpListenerReqeust) which closes the RequestContext on demand is returned to the application.
        internal void ReleasePins() 
        { 
            GlobalLog.Assert(m_MemoryBlob != null || m_BackingBuffer == null, "RequestContextBase::ReleasePins()|ReleasePins() called twice.");
            m_OriginalBlobAddress = m_MemoryBlob; 
            UnsetBlob();
            OnReleasePins();
        }
 
        protected abstract void OnReleasePins();
 
        public void Close() 
        {
            Dispose(); 
        }

        public void Dispose()
        { 
            GlobalLog.Assert(m_MemoryBlob == null, "RequestContextBase::Dispose()|Dispose() called before ReleasePins().");
            Dispose(true); 
        } 

        protected virtual void Dispose(bool disposing) { } 

        ~RequestContextBase()
        {
            Dispose(false); 
        }
 
        internal UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* RequestBlob 
        {
            get 
            {
                GlobalLog.Assert(m_MemoryBlob != null || m_BackingBuffer == null, "RequestContextBase::Dispose()|RequestBlob requested after ReleasePins().");
                return m_MemoryBlob;
            } 
        }
 
        internal byte[] RequestBuffer 
        {
            get 
            {
                return m_BackingBuffer;
            }
        } 

        internal uint Size 
        { 
            get
            { 
                return (uint) m_BackingBuffer.Length;
            }
        }
 
        internal IntPtr OriginalBlobAddress
        { 
            get 
            {
                UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* blob = m_MemoryBlob; 
                return (IntPtr) (blob == null ? m_OriginalBlobAddress : blob);
            }
        }
 
        protected void SetBlob(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* requestBlob)
        { 
            GlobalLog.Assert(m_MemoryBlob != null || m_BackingBuffer == null, "RequestContextBase::Dispose()|SetBlob() called after ReleasePins()."); 
            if (requestBlob == null)
            { 
                UnsetBlob();
                return;
            }
 
            if (m_MemoryBlob == null)
            { 
                GC.ReRegisterForFinalize(this); 
            }
            m_MemoryBlob = requestBlob; 
        }

        protected void UnsetBlob()
        { 
            if (m_MemoryBlob != null)
            { 
                GC.SuppressFinalize(this); 
            }
            m_MemoryBlob = null; 
        }

        protected void SetBuffer(int size)
        { 
            m_BackingBuffer = size == 0 ? null : new byte[size];
        } 
    } 

    internal unsafe class AsyncRequestContext : RequestContextBase 
    {
        private NativeOverlapped* m_NativeOverlapped;
        private ListenerAsyncResult m_Result;
 
        internal AsyncRequestContext(ListenerAsyncResult result)
        { 
            m_Result = result; 
            BaseConstruction(Allocate(0));
        } 

        private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* Allocate(uint size)
        {
            uint newSize = size != 0 ? size : RequestBuffer == null ? 4096 : Size; 
            if (m_NativeOverlapped != null && newSize != RequestBuffer.Length)
            { 
                NativeOverlapped* nativeOverlapped = m_NativeOverlapped; 
                m_NativeOverlapped = null;
                Overlapped.Free(nativeOverlapped); 
            }
            if (m_NativeOverlapped == null)
            {
                SetBuffer(checked((int) newSize)); 
                Overlapped overlapped = new Overlapped();
                overlapped.AsyncResult = m_Result; 
                m_NativeOverlapped = overlapped.Pack(ListenerAsyncResult.IOCallback, RequestBuffer); 
                return (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST*) Marshal.UnsafeAddrOfPinnedArrayElement(RequestBuffer, 0);
            } 
            return RequestBlob;
        }

        internal void Reset(ulong requestId, uint size) 
        {
            SetBlob(Allocate(size)); 
            RequestBlob->RequestId = requestId; 
        }
 
        protected override void OnReleasePins()
        {
            if (m_NativeOverlapped != null)
            { 
                NativeOverlapped* nativeOverlapped = m_NativeOverlapped;
                m_NativeOverlapped = null; 
                Overlapped.Free(nativeOverlapped); 
            }
        } 

        protected override void Dispose(bool disposing)
        {
            if (m_NativeOverlapped != null) 
            {
                GlobalLog.Assert(!disposing, "AsyncRequestContext::Dispose()|Must call ReleasePins() before calling Dispose()."); 
                if (!NclUtilities.HasShutdownStarted || disposing) 
                {
                    Overlapped.Free(m_NativeOverlapped); 
                }
            }
            base.Dispose(disposing);
        } 

        internal NativeOverlapped* NativeOverlapped 
        { 
            get
            { 
                return m_NativeOverlapped;
            }
        }
    } 

    internal unsafe class SyncRequestContext : RequestContextBase 
    { 
        private GCHandle m_PinnedHandle;
 
        internal SyncRequestContext(int size)
        {
            BaseConstruction(Allocate(size));
        } 

        private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* Allocate(int size) 
        { 
            if (m_PinnedHandle.IsAllocated)
            { 
                if (RequestBuffer.Length == size)
                {
                    return RequestBlob;
                } 
                m_PinnedHandle.Free();
            } 
            SetBuffer(size); 
            if (RequestBuffer == null)
            { 
                return null;
            }
            m_PinnedHandle = GCHandle.Alloc(RequestBuffer, GCHandleType.Pinned);
            return (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST*) Marshal.UnsafeAddrOfPinnedArrayElement(RequestBuffer, 0); 
        }
 
        internal void Reset(int size) 
        {
            SetBlob(Allocate(size)); 
        }

        protected override void OnReleasePins()
        { 
            if (m_PinnedHandle.IsAllocated)
            { 
                m_PinnedHandle.Free(); 
            }
        } 

        protected override void Dispose(bool disposing)
        {
            if (m_PinnedHandle.IsAllocated) 
            {
                GlobalLog.Assert(!disposing, "AsyncRequestContext::Dispose()|Must call ReleasePins() before calling Dispose()."); 
                if (!NclUtilities.HasShutdownStarted || disposing) 
                {
                    m_PinnedHandle.Free(); 
                }
            }
            base.Dispose(disposing);
        } 
    }
 
    public sealed unsafe class HttpListener : IDisposable 
    {
        private static byte[] s_WwwAuthenticateBytes = new byte[] 
        {
            (byte) 'W', (byte) 'W', (byte) 'W', (byte) '-', (byte) 'A', (byte) 'u', (byte) 't', (byte) 'h',
            (byte) 'e', (byte) 'n', (byte) 't', (byte) 'i', (byte) 'c', (byte) 'a', (byte) 't', (byte) 'e'
        }; 

        private class AuthenticationSelectorInfo 
        { 
            private AuthenticationSchemeSelector m_SelectorDelegate;
            private bool m_CanUseAdvancedAuth; 

            internal AuthenticationSelectorInfo(AuthenticationSchemeSelector selectorDelegate, bool canUseAdvancedAuth)
            {
                m_SelectorDelegate = selectorDelegate; 
                m_CanUseAdvancedAuth = canUseAdvancedAuth;
            } 
 
            internal AuthenticationSchemeSelector Delegate
            { 
                get
                {
                    return m_SelectorDelegate;
                } 
            }
 
            internal bool AdvancedAuth 
            {
                get 
                {
                    return m_CanUseAdvancedAuth;
                }
            } 
        }
 
        private AuthenticationSelectorInfo m_AuthenticationDelegate; 
        private AuthenticationSchemes m_AuthenticationScheme = AuthenticationSchemes.Anonymous;
        private SecurityException m_SecurityException; 
        private string m_Realm;
        private SafeCloseHandle m_RequestQueueHandle;
        private bool m_RequestHandleBound;
        private State m_State; 
        private HttpListenerPrefixCollection m_Prefixes;
        private bool m_IgnoreWriteExceptions; 
        private bool m_UnsafeConnectionNtlmAuthentication; 

        private Hashtable m_DisconnectResults;         // ulong -> DisconnectAsyncResult 
        private object m_InternalLock;

        internal Hashtable m_UriPrefixes = new Hashtable();
 
        public HttpListener() {
            if(Logging.On)Logging.Enter(Logging.HttpListener, this, "HttpListener", ""); 
            if (!UnsafeNclNativeMethods.HttpApi.Supported) { 
                throw new PlatformNotSupportedException();
            } 
            m_State = State.Stopped;
            m_InternalLock = new object();
            if(Logging.On)Logging.Exit(Logging.HttpListener, this, "HttpListener", "");
        } 

        internal SafeCloseHandle RequestQueueHandle { 
            get { 
                return m_RequestQueueHandle;
            } 
        }

        public AuthenticationSchemeSelector AuthenticationSchemeSelectorDelegate {
            get { 
                AuthenticationSelectorInfo selector = m_AuthenticationDelegate;
                return selector == null ? null : selector.Delegate; 
            } 
            set {
                CheckDisposed(); 

                try
                {
                    new SecurityPermission(SecurityPermissionFlag.ControlPrincipal).Demand(); 
                    m_AuthenticationDelegate = new AuthenticationSelectorInfo(value, true);
                } 
                catch (SecurityException exception) 
                {
                    m_SecurityException = exception; 
                    m_AuthenticationDelegate = new AuthenticationSelectorInfo(value, false);
                }
            }
        } 

        public AuthenticationSchemes AuthenticationSchemes { 
            get { 
                return m_AuthenticationScheme;
            } 
            set {
                CheckDisposed();

                // Enabling certain schemes requires special permissions. 
                if ((value & (AuthenticationSchemes.Digest | AuthenticationSchemes.Negotiate | AuthenticationSchemes.Ntlm)) != 0)
                { 
                    new SecurityPermission(SecurityPermissionFlag.ControlPrincipal).Demand(); 
                }
 
                m_AuthenticationScheme = value;
            }
        }
 
        public string Realm {
            get { 
                return m_Realm; 
            }
            set { 
                CheckDisposed();
                m_Realm = value;
            }
        } 

        public static bool IsSupported { 
            get { 
                return UnsafeNclNativeMethods.HttpApi.Supported;
            } 
        }

        public bool IsListening {
            get { 
                return m_State==State.Started;
            } 
        } 

        public bool IgnoreWriteExceptions { 
            get {
                return m_IgnoreWriteExceptions;
            }
            set { 
                CheckDisposed();
                m_IgnoreWriteExceptions = value; 
            } 
        }
 
        public bool UnsafeConnectionNtlmAuthentication {
            get {
                return m_UnsafeConnectionNtlmAuthentication;
            } 

            set { 
                CheckDisposed(); 
                if (m_UnsafeConnectionNtlmAuthentication==value) {
                    return; 
                }
                lock (DisconnectResults.SyncRoot)
                {
                    if (m_UnsafeConnectionNtlmAuthentication == value) 
                    {
                        return; 
                    } 
                    m_UnsafeConnectionNtlmAuthentication = value;
                    if (!value) 
                    {
                        foreach (DisconnectAsyncResult result in DisconnectResults.Values)
                        {
                            result.AuthenticatedConnection = null; 
                        }
                    } 
                } 
            }
        } 

        private Hashtable DisconnectResults
        {
            get 
            {
                if (m_DisconnectResults == null) 
                { 
                    lock (m_InternalLock)
                    { 
                        if (m_DisconnectResults == null)
                        {
                            m_DisconnectResults = Hashtable.Synchronized(new Hashtable());
                        } 
                    }
                } 
                return m_DisconnectResults; 
            }
        } 

        internal void AddPrefix(string uriPrefix)
        {
            if(Logging.On)Logging.Enter(Logging.HttpListener, this, "AddPrefix", "uriPrefix:" + uriPrefix); 
            string registeredPrefix = null;
            try { 
                if (uriPrefix==null) { 
                    throw new ArgumentNullException("uriPrefix");
                } 
                (new WebPermission(NetworkAccess.Accept, uriPrefix)).Demand();
                CheckDisposed();
                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::AddPrefix() uriPrefix:" + uriPrefix);
                int i; 
                if (string.Compare(uriPrefix, 0, "http://", 0, 7, StringComparison.OrdinalIgnoreCase)==0) {
                    i = 7; 
                } 
                else if (string.Compare(uriPrefix, 0, "https://", 0, 8, StringComparison.OrdinalIgnoreCase)==0) {
                    i = 8; 
                }
                else {
                    throw new ArgumentException(SR.GetString(SR.net_listener_scheme), "uriPrefix");
                } 
                bool inSquareBrakets = false;
                int j = i; 
                while (j0) { 
                    if (m_State==State.Started) {
                        foreach (string registeredPrefix in m_UriPrefixes.Values) { 
                            // ignore possible failures
                            InternalRemovePrefix(registeredPrefix);
                        }
                    } 
                    if(clear)
                        m_UriPrefixes.Clear(); 
                } 
            } finally {
                if(Logging.On)Logging.Exit(Logging.HttpListener, this, "RemoveAll", ""); 
            }
        }

        [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.UnmanagedCode)] 
        internal void EnsureBoundHandle()
        { 
            if (!m_RequestHandleBound) 
            {
                lock (m_InternalLock) 
                {
                    if (!m_RequestHandleBound)
                    {
                        ThreadPool.BindHandle(m_RequestQueueHandle.DangerousGetHandle()); 
                        m_RequestHandleBound = true;
                    } 
                } 
            }
        } 

        public void Start() {
            if(Logging.On)Logging.Enter(Logging.HttpListener, this, "Start", "");
            try { 
                CheckDisposed();
                if (m_State==State.Started) { 
                    return; 
                }
                m_RequestQueueHandle = SafeCloseHandle.CreateRequestQueueHandle(); 
                AddAll();
                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::.ctor() SafeCloseHandle.CreateRequestQueueHandle() returned m_RequestQueueHandle:" + m_RequestQueueHandle);
                m_State = State.Started;
            } catch (Exception exception) { 
                if(Logging.On)Logging.Exception(Logging.HttpListener, this, "Start", exception);
                throw; 
            } finally { 
                if(Logging.On)Logging.Exit(Logging.HttpListener, this, "Start", "");
            } 
        }

        public void Stop() {
            if(Logging.On)Logging.Enter(Logging.HttpListener, this, "Stop", ""); 
            try {
                CheckDisposed(); 
                if (m_State==State.Stopped) { 
                    return;
                } 
                RemoveAll(false);
                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::Stop() calling SafeCloseHandle.Close()");
                m_RequestQueueHandle.Close();
                m_RequestHandleBound = false; 
                m_State = State.Stopped;
                ClearDigestCache(); 
            } catch (Exception exception) { 
                if(Logging.On)Logging.Exception(Logging.HttpListener, this, "Stop", exception);
                throw; 
            } finally {
                if(Logging.On)Logging.Exit(Logging.HttpListener, this, "Stop", "");
            }
        } 

        public void Abort() { 
            if(Logging.On)Logging.Enter(Logging.HttpListener, this, "Abort", ""); 
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::Abort()");
 
            try {
                if (m_RequestQueueHandle!=null)
                {
                    m_RequestQueueHandle.Abort(); 
                }
                m_RequestHandleBound = false; 
                m_State = State.Closed; 
                ClearDigestCache();
            } catch (Exception exception) { 
                if(Logging.On)Logging.Exception(Logging.HttpListener, this, "Abort", exception);
                throw;
            } finally {
                if(Logging.On)Logging.Exit(Logging.HttpListener, this, "Abort", ""); 
            }
        } 
 
        public void Close() {
            if(Logging.On)Logging.Enter(Logging.HttpListener, this, "Close", ""); 
            try {
                GlobalLog.Print("HttpListenerRequest::Close()");
                ((IDisposable)this).Dispose();
            } catch (Exception exception) { 
                if(Logging.On)Logging.Exception(Logging.HttpListener, this, "Close", exception);
                throw; 
            } finally { 
                if(Logging.On)Logging.Exit(Logging.HttpListener, this, "Close", "");
            } 
        }

        // old API, now private, and helper methods
        private void Dispose(bool disposing) { 
            if(Logging.On)Logging.Enter(Logging.HttpListener, this, "Dispose", "");
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::Dispose()"); 
            try { 
                if (m_State == State.Closed){
                    return; 
                }
                Stop();
                m_RequestHandleBound = false;
                m_State = State.Closed; 
            } catch (Exception exception) {
                if(Logging.On)Logging.Exception(Logging.HttpListener, this, "Dispose", exception); 
                throw; 
            } finally {
                if(Logging.On)Logging.Exit(Logging.HttpListener, this, "Dispose", ""); 
            }
        }

        ///  
        void IDisposable.Dispose() {
            Dispose(true); 
        } 

        private uint InternalAddPrefix(string uriPrefix) { 
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::InternalAddPrefix() uriPrefix:" + uriPrefix + " calling UnsafeNclNativeMethods.HttpApi.HttpAddUrl");
            uint statusCode = 0;
            fixed (char* pUriPrefix = uriPrefix) {
                statusCode = 
                    UnsafeNclNativeMethods.HttpApi.HttpAddUrl(
                        m_RequestQueueHandle, 
                        (ushort*)pUriPrefix, 
                        null);
            } 
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::InternalAddPrefix() call to UnsafeNclNativeMethods.HttpApi.HttpAddUrl returned:" + statusCode);
            return statusCode;
        }
 
        private bool InternalRemovePrefix(string uriPrefix) {
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::InternalRemovePrefix() uriPrefix:" + uriPrefix + " calling UnsafeNclNativeMethods.HttpApi.HttpRemoveUrl"); 
            uint statusCode = 0; 
            fixed (char* pUriPrefix = uriPrefix) {
                statusCode = 
                   UnsafeNclNativeMethods.HttpApi.HttpRemoveUrl(
                        m_RequestQueueHandle,
                        (ushort*)pUriPrefix);
            } 
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::InternalRemovePrefix() call to UnsafeNclNativeMethods.HttpApi.HttpRemoveUrl returned:" + statusCode);
            if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_NOT_FOUND) 
            { 
                return false;
            } 
            return true;
        }

        private void AddAll() { 
            // go through the uri list and register for each one of them
            if (m_UriPrefixes.Count>0) { 
                foreach (string registeredPrefix in m_UriPrefixes.Values) { 
                    uint statusCode = InternalAddPrefix(registeredPrefix);
                    if (statusCode!=UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { 
                        Abort();
                        if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_ALREADY_EXISTS)
                            throw new HttpListenerException((int)statusCode, SR.GetString(SR.net_listener_already, registeredPrefix));
                        else 
                            throw new HttpListenerException((int)statusCode);
                    } 
                } 
            }
        } 

        public HttpListenerContext GetContext() {
            if(Logging.On)Logging.Enter(Logging.HttpListener, this, "GetContext", "");
 
            SyncRequestContext memoryBlob = null;
            HttpListenerContext httpContext = null; 
            bool stoleBlob = false; 

            try { 
                CheckDisposed();
                if (m_State==State.Stopped) {
                    throw new InvalidOperationException(SR.GetString(SR.net_listener_mustcall, "Start()"));
                } 
                if (m_UriPrefixes.Count==0) {
                    throw new InvalidOperationException(SR.GetString(SR.net_listener_mustcall, "AddPrefix()")); 
                } 
                uint statusCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS;
                uint size = 4096; 
                ulong requestId = 0;
                memoryBlob = new SyncRequestContext((int) size);
                for (;;) {
                    for (;;) { 
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::GetContext() calling UnsafeNclNativeMethods.HttpApi.HttpReceiveHttpRequest RequestId:" + requestId);
                        uint bytesTransferred = 0; 
                        statusCode = 
                            UnsafeNclNativeMethods.HttpApi.HttpReceiveHttpRequest(
                                m_RequestQueueHandle, 
                                requestId,
                                (uint)UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY,
                                memoryBlob.RequestBlob,
                                size, 
                                &bytesTransferred,
                                null); 
 
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::GetContext() call to UnsafeNclNativeMethods.HttpApi.HttpReceiveHttpRequest returned:" + statusCode);
                        if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_INVALID_PARAMETER && requestId != 0) { 
                            // we might get this if somebody stole our RequestId,
                            // we need to start all over again but we can reuse the buffer we just allocated
                            requestId = 0;
                            continue; 
                        }
                        else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA) 
                        { 
                            // the buffer was not big enough to fit the headers, we need
                            // to read the RequestId returned, allocate a new buffer of the required size 
                            size = bytesTransferred;
                            requestId = memoryBlob.RequestBlob->RequestId;
                            memoryBlob.Reset(checked((int) size));
                            continue; 
                        }
                        break; 
                    } 
                    if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS)
                    { 
                        // someother bad error, possible(?) return values are:
                        // ERROR_INVALID_HANDLE, ERROR_INSUFFICIENT_BUFFER, ERROR_OPERATION_ABORTED
                        throw new HttpListenerException((int)statusCode);
                    } 

                    // We need to hook up our authentication handling code here. 
                    httpContext = HandleAuthentication(memoryBlob, out stoleBlob); 
                    if (stoleBlob)
                    { 
                        // The request has been handed to the user, which means this code can't reuse the blob.  Reset it here.
                        memoryBlob = null;
                        stoleBlob = false;
                    } 
                    GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::GetContext() HandleAuthentication() returned httpContext#" + ValidationHelper.HashString(httpContext));
                    // if the request survived authentication, return it to the user 
                    if (httpContext!=null) { 
                        return httpContext;
                    } 

                    // HandleAuthentication may have cleaned this up.
                    if (memoryBlob == null)
                    { 
                        memoryBlob = new SyncRequestContext(checked((int) size));
                    } 
 
                    requestId = 0;
                } 
            } catch (Exception exception) {
                if(Logging.On)Logging.Exception(Logging.HttpListener, this, "GetContext", exception);
                throw;
            } finally { 
                if (memoryBlob != null && !stoleBlob)
                { 
                    memoryBlob.ReleasePins(); 
                    memoryBlob.Close();
                } 
                if(Logging.On)Logging.Exit(Logging.HttpListener, this, "GetContext", "HttpListenerContext#" + ValidationHelper.HashString(httpContext) + " RequestTraceIdentifier#"+httpContext.Request.RequestTraceIdentifier);
            }
        }
 
        [HostProtection(ExternalThreading=true)]
        public IAsyncResult BeginGetContext(AsyncCallback callback, object state) { 
            if(Logging.On)Logging.Enter(Logging.HttpListener, this, "BeginGetContext", ""); 
            ListenerAsyncResult asyncResult = null;
            try { 
                CheckDisposed();
                if (m_State==State.Stopped) {
                    throw new InvalidOperationException(SR.GetString(SR.net_listener_mustcall, "Start()"));
                } 
                // prepare the ListenerAsyncResult object (this will have it's own
                // event that the user can wait on for IO completion - which means we 
                // need to signal it when IO completes) 
                asyncResult = new ListenerAsyncResult(this, state, callback);
                uint statusCode = asyncResult.QueueBeginGetContext(); 
                if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS &&
                    statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING)
                {
                    // someother bad error, possible(?) return values are: 
                    // ERROR_INVALID_HANDLE, ERROR_INSUFFICIENT_BUFFER, ERROR_OPERATION_ABORTED
                    throw new HttpListenerException((int)statusCode); 
                } 
            } catch (Exception exception) {
                if(Logging.On)Logging.Exception(Logging.HttpListener, this, "BeginGetContext", exception); 
                throw;
            } finally {
                if(Logging.On)Logging.Enter(Logging.HttpListener, this, "BeginGetContext", "IAsyncResult#" + ValidationHelper.HashString(asyncResult));
            } 

            return asyncResult; 
        } 

        public HttpListenerContext EndGetContext(IAsyncResult asyncResult) { 
            if(Logging.On)Logging.Enter(Logging.HttpListener, this, "EndGetContext", "IAsyncResult#" + ValidationHelper.HashString(asyncResult));
            HttpListenerContext httpContext = null;
            try {
                CheckDisposed(); 
                if (asyncResult==null) {
                    throw new ArgumentNullException("asyncResult"); 
                } 
                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::EndGetContext() asyncResult:" + ValidationHelper.ToString(asyncResult));
                ListenerAsyncResult castedAsyncResult = asyncResult as ListenerAsyncResult; 
                if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
                    throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
                }
                if (castedAsyncResult.EndCalled) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndGetContext"));
                } 
                castedAsyncResult.EndCalled = true; 
                httpContext = castedAsyncResult.InternalWaitForCompletion() as HttpListenerContext;
                if (httpContext == null) { 
                    GlobalLog.Assert(castedAsyncResult.Result is Exception, "EndGetContext|The result is neither a HttpListenerContext nor an Exception.");
                    throw castedAsyncResult.Result as Exception;
                }
            } catch (Exception exception) { 
                if(Logging.On)Logging.Exception(Logging.HttpListener, this, "EndGetContext", exception);
                throw; 
            } finally { 
                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::EndGetContext() returning HttpListenerContext#" + ValidationHelper.ToString(httpContext));
                if(Logging.On)Logging.Enter(Logging.HttpListener, this, "EndGetContext", "HttpListenerContext#" + ValidationHelper.HashString(httpContext)+ " RequestTraceIdentifier#"+httpContext.Request.RequestTraceIdentifier); 
            }
            return httpContext;
        }
 
        [SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.UnmanagedCode)]
        [SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.ControlPrincipal)] 
        private WindowsIdentity CreateWindowsIdentity(IntPtr userToken, string type, WindowsAccountType acctType, bool isAuthenticated) 
        {
            return new WindowsIdentity(userToken, type, acctType, isAuthenticated); 
        }

        internal HttpListenerContext HandleAuthentication(RequestContextBase memoryBlob, out bool stoleBlob)
        { 
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() memoryBlob:0x" + ((IntPtr) memoryBlob.RequestBlob).ToString("x"));
 
            string challenge = null; 
            stoleBlob = false;
 
            // Some things we need right away.  Lift them out now while it's convenient.
            string verb = UnsafeNclNativeMethods.HttpApi.GetVerb(memoryBlob.RequestBlob);
            string authorizationHeader = UnsafeNclNativeMethods.HttpApi.GetKnownHeader(memoryBlob.RequestBlob, (int) HttpRequestHeader.Authorization);
            ulong connectionId = memoryBlob.RequestBlob->ConnectionId; 
            ulong requestId = memoryBlob.RequestBlob->RequestId;
 
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() authorizationHeader:" + ValidationHelper.ToString(authorizationHeader)); 

            // if the app has turned on AuthPersistence, an anonymous request might 
            // be authenticated by virtue of it coming on a connection that was
            // previously authenticated.
            // assurance that we do this only for NTLM/Negotiate is not here, but in the
            // code that caches WindowsIdentity instances in the Dictionary. 
            DisconnectAsyncResult disconnectResult = (DisconnectAsyncResult) DisconnectResults[connectionId];
            if (UnsafeConnectionNtlmAuthentication) 
            { 
                if (authorizationHeader == null)
                { 
                    WindowsPrincipal principal = disconnectResult == null ? null : disconnectResult.AuthenticatedConnection;
                    if (principal != null)
                    {
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() got principal:" + ValidationHelper.ToString(principal) + " principal.Identity.Name:" + ValidationHelper.ToString(principal.Identity.Name) + " creating request"); 
                        stoleBlob = true;
                        HttpListenerContext ntlmContext = new HttpListenerContext(this, memoryBlob); 
                        ntlmContext.SetIdentity(principal, null); 
                        ntlmContext.Request.ReleasePins();
                        return ntlmContext; 
                    }
                }
                else
                { 
                    // They sent an authorization - destroy their previous credentials.
                    GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() clearing principal cache"); 
                    if (disconnectResult != null) 
                    {
                        disconnectResult.AuthenticatedConnection = null; 
                    }
                }
            }
 
            // Figure out what schemes we're allowing, what context we have.
            stoleBlob = true; 
            HttpListenerContext httpContext = null; 
            NTAuthentication oldContext = null;
            NTAuthentication newContext = null; 
            NTAuthentication context = null;
            AuthenticationSchemes headerScheme = AuthenticationSchemes.None;
            AuthenticationSchemes authenticationScheme = AuthenticationSchemes;
            try 
            {
                // Take over handling disconnects for now. 
                if (disconnectResult != null && !disconnectResult.StartOwningDisconnectHandling()) 
                {
                    // Oops!  Just disconnected just then.  Pretend we didn't see the disconnectResult. 
                    disconnectResult = null;
                }

                // Pick out the old context now.  By default, it'll be removed in the finally, unless context is set somewhere. 
                if (disconnectResult != null)
                { 
                    oldContext = disconnectResult.Session; 
                }
 
                httpContext = new HttpListenerContext(this, memoryBlob);

                AuthenticationSelectorInfo authenticationSelector = m_AuthenticationDelegate;
                if (authenticationSelector != null) 
                {
                    try 
                    { 
                        httpContext.Request.ReleasePins();
                        authenticationScheme = authenticationSelector.Delegate(httpContext.Request); 
                        if (!authenticationSelector.AdvancedAuth &&
                            (authenticationScheme & (AuthenticationSchemes.Negotiate | AuthenticationSchemes.Ntlm | AuthenticationSchemes.Digest)) != 0)
                        {
                            throw m_SecurityException; 
                        }
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() AuthenticationSchemeSelectorDelegate() returned authenticationScheme:" + authenticationScheme); 
                    } 
                    catch (Exception exception)
                    { 
                        if (NclUtilities.IsFatal(exception)) throw;

                        if (Logging.On) Logging.PrintError(Logging.HttpListener, this, "HandleAuthentication", SR.GetString(SR.net_log_listener_delegate_exception, exception));
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() AuthenticationSchemeSelectorDelegate() returned authenticationScheme:" + authenticationScheme); 
                        SendError(requestId, HttpStatusCode.InternalServerError, null);
                        httpContext.Close(); 
                        return null; 
                    }
                } 
                else
                {
                    // We didn't give the request to the user yet, so we haven't lost control of the unmanaged blob and can
                    // continue to reuse the buffer. 
                    stoleBlob = false;
                } 
 
                // Then figure out what scheme they're trying (if any are allowed)
                int index = -1; 
                if (authorizationHeader != null && (authenticationScheme & ~AuthenticationSchemes.Anonymous) != AuthenticationSchemes.None)
                {
                    // Find the end of the scheme name.  Trust that HTTP.SYS parsed out just our header ok.
                    for (index = 0; index < authorizationHeader.Length; index++) 
                    {
                        if (authorizationHeader[index] == ' ' || authorizationHeader[index] == '\t' || 
                            authorizationHeader[index] == '\r' || authorizationHeader[index] == '\n') 
                        {
                            break; 
                        }
                    }

                    // Currently only allow one Authorization scheme/header per request. 
                    if (index < authorizationHeader.Length)
                    { 
                        if ((authenticationScheme & AuthenticationSchemes.Negotiate) != AuthenticationSchemes.None && 
                            string.Compare(authorizationHeader, 0, NegotiateClient.AuthType, 0, index, StringComparison.OrdinalIgnoreCase) == 0)
                        { 
                            headerScheme = AuthenticationSchemes.Negotiate;
                        }
                        else if ((authenticationScheme & AuthenticationSchemes.Ntlm) != AuthenticationSchemes.None &&
                            string.Compare(authorizationHeader, 0, NtlmClient.AuthType, 0, index, StringComparison.OrdinalIgnoreCase) == 0) 
                        {
                            headerScheme = AuthenticationSchemes.Ntlm; 
                        } 
                        else if ((authenticationScheme & AuthenticationSchemes.Digest) != AuthenticationSchemes.None &&
                            string.Compare(authorizationHeader, 0, DigestClient.AuthType, 0, index, StringComparison.OrdinalIgnoreCase) == 0) 
                        {
                            headerScheme = AuthenticationSchemes.Digest;
                        }
                        else if ((authenticationScheme & AuthenticationSchemes.Basic) != AuthenticationSchemes.None && 
                            string.Compare(authorizationHeader, 0, BasicClient.AuthType, 0, index, StringComparison.OrdinalIgnoreCase) == 0)
                        { 
                            headerScheme = AuthenticationSchemes.Basic; 
                        }
                        else 
                        {
                            if (Logging.On) Logging.PrintWarning(Logging.HttpListener, this, "HandleAuthentication", SR.GetString(SR.net_log_listener_unsupported_authentication_scheme, authorizationHeader , authenticationScheme));
                        }
                    } 
                }
 
                // httpError holds the error we will return if an Authorization header is present but can't be authenticated 
                HttpStatusCode httpError = HttpStatusCode.InternalServerError;
                bool error = false; 

                // See if we found an acceptable auth header
                if (headerScheme == AuthenticationSchemes.None)
                { 
                    if (Logging.On) Logging.PrintWarning(Logging.HttpListener, this, "HandleAuthentication", SR.GetString(SR.net_log_listener_unmatched_authentication_scheme, ValidationHelper.ToString(authenticationScheme), (authorizationHeader == null ? "" : authorizationHeader)));
 
                    // If anonymous is allowed, just return the context.  Otherwise go for the 401. 
                    if ((authenticationScheme & AuthenticationSchemes.Anonymous) != AuthenticationSchemes.None)
                    { 
                        if (!stoleBlob)
                        {
                            stoleBlob = true;
                            httpContext.Request.ReleasePins(); 
                        }
                        return httpContext; 
                    } 

                    httpError = HttpStatusCode.Unauthorized; 
                    httpContext.Request.DetachBlob(memoryBlob);
                    httpContext.Close();
                    httpContext = null;
                } 
                else
                { 
                    // Perform Authentication 
                    byte[] bytes = null;
                    byte[] decodedOutgoingBlob = null; 
                    string outBlob = null;

                    // Find the beginning of the blob.  Trust that HTTP.SYS parsed out just our header ok.
                    for (index++; index < authorizationHeader.Length; index++) 
                    {
                        if (authorizationHeader[index] != ' ' && authorizationHeader[index] != '\t' && 
                            authorizationHeader[index] != '\r' && authorizationHeader[index] != '\n') 
                        {
                            break; 
                        }
                    }
                    string inBlob = index < authorizationHeader.Length ? authorizationHeader.Substring(index) : "";
 
                    IPrincipal principal = null;
                    SecurityStatus statusCodeNew; 
                    GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() Performing Authentication headerScheme:" + ValidationHelper.ToString(headerScheme)); 
                    switch (headerScheme)
                    { 
                        case AuthenticationSchemes.Digest:
                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() package:WDigest headerScheme:" + headerScheme);

                            // WDigest had some weird behavior.  This is what I have discovered: 
                            // Local accounts don't work, only domain accounts.  The domain (i.e. REDMOND) is implied.  Not sure how it is chosen.
                            // If the domain is specified and the credentials are correct, it works.  If they're not (domain, username or password): 
                            //      AcceptSecurityContext (GetOutgoingDigestBlob) returns success but with a bogus 4k challenge, and 
                            //      QuerySecurityContextToken (GetContextToken) fails with NoImpersonation.
                            // If the domain isn't specified, AcceptSecurityContext returns NoAuthenticatingAuthority for a bad username, 
                            // and LogonDenied for a bad password.

                            // Also interesting is that WDigest requires us to keep a reference to the previous context, but fails if we
                            // actually pass it in!  (It't ok to pass it in for the first request, but not if nc > 1.)  For Whidbey, 
                            // we create a new context and associate it with the connection, just like NTLM, but instead of using it for
                            // the next request on the connection, we always create a new context and swap the old one out.  As long 
                            // as we keep the old one around until after we authenticate with the new one, it works.  For this reason, 
                            // we also keep these contexts around past the lifetime of the connection, so that KeepAlive=false works.
                            context = new NTAuthentication(true, NegotiationInfoClass.WDigest, null, ContextFlags.Connection); 

                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() verb:" + verb + " context.IsValidContext:" + context.IsValidContext.ToString());
                            outBlob = context.GetOutgoingDigestBlob(inBlob, verb, null, Realm, false, false, out statusCodeNew);
                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() GetOutgoingDigestBlob() returned IsCompleted:" + context.IsCompleted + " statusCodeNew:" + statusCodeNew + " outBlob:[" + outBlob + "]"); 

                            // WDigest bug: sometimes when AcceptSecurityContext returns success, it provides a bogus, empty 4k buffer. 
                            // Ignore it.  (Should find out what's going on here from WDigest people.) 
                            if (statusCodeNew == SecurityStatus.OK)
                            { 
                                outBlob = null;
                            }

                            if (context.IsValidContext) 
                            {
                                SafeCloseHandle userContext = null; 
                                try 
                                {
                                    userContext = context.GetContextToken(out statusCodeNew); 
                                    GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() GetContextToken() returned:" + statusCodeNew.ToString());
                                    if (statusCodeNew != SecurityStatus.OK)
                                    {
                                         httpError = HttpStatusFromSecurityStatus(statusCodeNew); 
                                    }
                                    else if (userContext == null) 
                                    { 
                                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() error: GetContextToken() returned:null statusCodeNew:" + statusCodeNew.ToString());
                                        httpError = HttpStatusCode.Unauthorized; 
                                    }
                                    else
                                    {
                                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() creating new WindowsIdentity() from userContext:" + userContext.DangerousGetHandle().ToString("x8")); 
                                        principal = new WindowsPrincipal(CreateWindowsIdentity(userContext.DangerousGetHandle(), DigestClient.AuthType, WindowsAccountType.Normal, true));
                                    } 
                                } 
                                finally {
                                    if (userContext!=null) { 
                                        userContext.Close();
                                    }
                                }
 
                                newContext = context;
 
                                if (outBlob != null) 
                                {
                                    challenge = DigestClient.AuthType + " " + outBlob; 
                                }
                            }
                            else
                            { 
                                httpError = HttpStatusFromSecurityStatus(statusCodeNew);
                            } 
                            break; 

                        case AuthenticationSchemes.Negotiate: 
                        case AuthenticationSchemes.Ntlm:
                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() headerScheme:" + headerScheme);
                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() returned context#" + ValidationHelper.HashString(oldContext) + " for connectionId:" + connectionId);
 
                            string package = headerScheme == AuthenticationSchemes.Ntlm ? NtlmClient.AuthType : NegotiateClient.AuthType;
                            if (oldContext != null && oldContext.Package == package) 
                            { 
                                context = oldContext;
                            } 
                            else
                            {
                                context = new NTAuthentication(true, package, null, ContextFlags.Connection);
                            } 

                            try 
                            { 
                                bytes = Convert.FromBase64String(inBlob);
                            } 
                            catch (FormatException)
                            {
                                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() FromBase64String threw a FormatException.");
                                httpError = HttpStatusCode.BadRequest; 
                                error = true;
                            } 
                            if (!error) 
                            {
                                decodedOutgoingBlob = context.GetOutgoingBlob(bytes, false, out statusCodeNew); 
                                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() GetOutgoingBlob() returned IsCompleted:" + context.IsCompleted + " statusCodeNew:" + statusCodeNew);
                                error = !context.IsValidContext;
                                if (error)
                                { 
                                    // Bug #474228: SSPI Workaround
                                    // If a client sends up a blob on the initial request, Negotiate returns SEC_E_INVALID_HANDLE 
                                    // when it should return SEC_E_INVALID_TOKEN. 
                                    if (statusCodeNew == SecurityStatus.InvalidHandle && oldContext == null && bytes != null && bytes.Length > 0)
                                    { 
                                        statusCodeNew = SecurityStatus.InvalidToken;
                                    }

                                    httpError = HttpStatusFromSecurityStatus(statusCodeNew); 
                                }
                            } 
 
                            if (decodedOutgoingBlob!=null) {
                                outBlob = Convert.ToBase64String(decodedOutgoingBlob); 
                            }

                            if (!error)
                            { 
                                if (context.IsCompleted) {
                                    SafeCloseHandle userContext = null; 
                                    try 
                                    {
                                        userContext = context.GetContextToken(out statusCodeNew); 
                                        if (statusCodeNew != SecurityStatus.OK)
                                        {
                                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() GetContextToken() failed with statusCodeNew:" + statusCodeNew.ToString());
                                            httpError = HttpStatusFromSecurityStatus(statusCodeNew); 
                                        }
                                        else 
                                        { 
                                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() creating new WindowsIdentity() from userContext:" + userContext.DangerousGetHandle().ToString("x8"));
                                            WindowsPrincipal windowsPrincipal = new WindowsPrincipal(CreateWindowsIdentity(userContext.DangerousGetHandle(), context.ProtocolName, WindowsAccountType.Normal, true)); 
                                            principal = windowsPrincipal;

                                            // if appropriate, cache this credential on this connection
                                            if (UnsafeConnectionNtlmAuthentication && context.ProtocolName == NegotiationInfoClass.NTLM) 
                                            {
                                                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() inserting principal#" + ValidationHelper.HashString(principal) + " for connectionId:" + connectionId); 
 
                                                // We may need to call WaitForDisconnect.
                                                if (disconnectResult == null) 
                                                {
                                                    RegisterForDisconnectNotification(connectionId, ref disconnectResult);
                                                }
                                                if (disconnectResult != null) 
                                                {
                                                    lock (DisconnectResults.SyncRoot) 
                                                    { 
                                                        if (UnsafeConnectionNtlmAuthentication)
                                                        { 
                                                            disconnectResult.AuthenticatedConnection = windowsPrincipal;
                                                        }
                                                    }
                                                } 
                                                else
                                                { 
                                                    // Registration failed - UnsafeConnectionNtlmAuthentication ignored. 
                                                    GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() RegisterForDisconnectNotification() failed.");
                                                } 
                                            }
                                        }
                                    }
                                    finally { 
                                        if (userContext!=null) {
                                            userContext.Close(); 
                                        } 
                                    }
                                } 
                                else
                                {
                                    // auth incomplete
                                    newContext = context; 

                                    challenge = (headerScheme==AuthenticationSchemes.Ntlm ? NtlmClient.AuthType : NegotiateClient.AuthType); 
                                    if (!String.IsNullOrEmpty(outBlob)) 
                                    {
                                        challenge += " " + outBlob; 
                                    }
                                }
                            }
                            break; 

                        case AuthenticationSchemes.Basic: 
                            try 
                            {
                                bytes = Convert.FromBase64String(inBlob); 

                                inBlob = WebHeaderCollection.HeaderEncoding.GetString(bytes, 0, bytes.Length);
                                index = inBlob.IndexOf(':');
 
                                if (index!=-1) {
                                    string userName = inBlob.Substring(0, index); 
                                    string password = inBlob.Substring(index+1); 

                                    GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() basic identity found, userName:" + userName); 
                                    principal = new GenericPrincipal(new HttpListenerBasicIdentity(userName, password), null);
                                }
                                else
                                { 
                                    httpError = HttpStatusCode.BadRequest;
                                } 
                            } 
                            catch (FormatException)
                            { 
                                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() FromBase64String threw a FormatException.");
                            }
                            break;
                    } 

                    if (principal != null) 
                    { 
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() got principal:" + ValidationHelper.ToString(principal) + " principal.Identity.Name:" + ValidationHelper.ToString(principal.Identity.Name) + " creating request");
                        httpContext.SetIdentity(principal, outBlob); 
                    }
                    else
                    {
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() handshake has failed"); 
                        if(Logging.On)Logging.PrintWarning(Logging.HttpListener, this, "HandleAuthentication", SR.GetString(SR.net_log_listener_create_valid_identity_failed));
                        httpContext.Request.DetachBlob(memoryBlob); 
                        httpContext.Close(); 
                        httpContext = null;
                    } 
                }

                // if we're not giving a request to the application, we need to send an error
                ArrayList challenges = null; 
                if (httpContext == null)
                { 
                    // If we already have a challenge, just use it.  Otherwise put a challenge for each acceptable scheme. 
                    if (challenge != null)
                    { 
                        AddChallenge(ref challenges, challenge);
                    }
                    else
                    { 
                        // We're starting over.  Any context SSPI might have wanted us to keep is useless.
                        if (newContext != null) 
                        { 
                            if (newContext == context)
                            { 
                                context = null;
                            }

                            if (newContext != oldContext) 
                            {
                                NTAuthentication toClose = newContext; 
                                newContext = null; 
                                toClose.CloseContext();
                            } 
                            else
                            {
                                newContext = null;
                            } 
                        }
 
                        // If we're sending something besides 401, do it here. 
                        if (httpError != HttpStatusCode.Unauthorized)
                        { 
                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() failed context#" + ValidationHelper.HashString(context) + " for connectionId:" + connectionId + " because of error:" + httpError.ToString());
                            SendError(requestId, httpError, null);
                            return null;
                        } 

                        challenges = BuildChallenge(authenticationScheme, connectionId, out newContext); 
                    } 
                }
 
                // Check if we need to call WaitForDisconnect, because if we do and it fails, we want to send a 500 instead.
                if (disconnectResult == null && newContext != null)
                {
                    RegisterForDisconnectNotification(connectionId, ref disconnectResult); 

                    // Failed - send 500. 
                    if (disconnectResult == null) 
                    {
                        if (newContext != null) 
                        {
                            if (newContext == context)
                            {
                                context = null; 
                            }
 
                            if (newContext != oldContext) 
                            {
                                NTAuthentication toClose = newContext; 
                                newContext = null;
                                toClose.CloseContext();
                            }
                            else 
                            {
                                newContext = null; 
                            } 
                        }
 
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() failed context#" + ValidationHelper.HashString(context) + " for connectionId:" + connectionId + " because of failed HttpWaitForDisconnect");
                        SendError(requestId, HttpStatusCode.InternalServerError, null);
                        httpContext.Request.DetachBlob(memoryBlob);
                        httpContext.Close(); 
                        return null;
                    } 
                } 

                // Update Session if necessary. 
                if (oldContext != newContext)
                {
                    if (oldContext == context)
                    { 
                        // Prevent the finally from closing this twice.
                        context = null; 
                    } 

                    NTAuthentication toClose = oldContext; 
                    oldContext = newContext;
                    disconnectResult.Session = newContext;

                    if (toClose != null) 
                    {
                        // Save digest context in digest cache, we may need it later because of 
                        // subsequest responses to the same req on the same/diff connection 
                        if ((authenticationScheme & AuthenticationSchemes.Digest) != 0)
                        { 
                            SaveDigestContext(toClose);
                        }
                        else
                        { 
                            toClose.CloseContext();
                        } 
                    } 
                }
 
                // Send the 401 here.
                if (httpContext == null)
                {
                    SendError(requestId, challenges != null && challenges.Count > 0 ? HttpStatusCode.Unauthorized : HttpStatusCode.Forbidden, challenges); 
                    GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() SendUnauthorized(Scheme:" + authenticationScheme + ")");
                    return null; 
                } 

                if (!stoleBlob) 
                {
                    stoleBlob = true;
                    httpContext.Request.ReleasePins();
                } 
                return httpContext;
            } 
            catch 
            {
                if (httpContext != null) 
                {
                    httpContext.Request.DetachBlob(memoryBlob);
                    httpContext.Close();
                } 
                if (newContext != null)
                { 
                    if (newContext == context) 
                    {
                        // Prevent the finally from closing this twice. 
                        context = null;
                    }

                    if (newContext != oldContext) 
                    {
                        NTAuthentication toClose = newContext; 
                        newContext = null; 
                        toClose.CloseContext();
                    } 
                    else
                    {
                        newContext = null;
                    } 
                }
                throw; 
            } 
            finally
            { 
                try
                {
                    // Clean up the previous context if necessary.
                    if (oldContext != null && oldContext != newContext) 
                    {
                        // Clear out Session if it wasn't already. 
                        if (newContext == null && disconnectResult != null) 
                        {
                            disconnectResult.Session = null; 
                        }

                        // Save digest context in digest cache, we may need it later because of
                        // subsequest responses to the same req on the same/diff connection 

                        if ((authenticationScheme & AuthenticationSchemes.Digest) != 0) 
                        { 
                            SaveDigestContext(oldContext);
                        } 
                        else
                        {
                            oldContext.CloseContext();
                        } 
                    }
 
                    // Delete any context created but not stored. 
                    if (context != null && oldContext != context && newContext != context)
                    { 
                        context.CloseContext();
                    }
                }
                finally 
                {
                    // Check if the connection got deleted while in this method, and clear out the hashtables if it did. 
                    // In a nested finally because if this doesn't happen, we leak. 
                    if (disconnectResult != null)
                    { 
                        disconnectResult.FinishOwningDisconnectHandling();
                    }
                }
            } 
        }
 
        private static void AddChallenge(ref ArrayList challenges, string challenge) 
        {
            if (challenge!=null) { 
                challenge = challenge.Trim();
                if (challenge.Length>0) {
                    GlobalLog.Print("HttpListener:AddChallenge() challenge:" + challenge);
                    if (challenges == null) 
                    {
                        challenges = new ArrayList(4); 
                    } 
                    challenges.Add(challenge);
                } 
            }
        }

        private ArrayList BuildChallenge(AuthenticationSchemes authenticationScheme, ulong connectionId, out NTAuthentication newContext) 
        {
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::BuildChallenge()  authenticationScheme:" + authenticationScheme.ToString()); 
            ArrayList challenges = null; 
            newContext = null;
 
            if ((authenticationScheme & AuthenticationSchemes.Negotiate) != 0)
            {
                AddChallenge(ref challenges, NegotiateClient.AuthType);
            } 

            if ((authenticationScheme & AuthenticationSchemes.Ntlm) != 0) 
            { 
                AddChallenge(ref challenges, NtlmClient.AuthType);
            } 

            if ((authenticationScheme & AuthenticationSchemes.Digest) != 0)
            {
                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::BuildChallenge() package:WDigest"); 

                NTAuthentication context = null; 
                try 
                {
                    context = new NTAuthentication(true, NegotiationInfoClass.WDigest, null, ContextFlags.Connection); 
                    SecurityStatus statusCode;
                    string outBlob = context.GetOutgoingDigestBlob(null, null, null, Realm, false, false, out statusCode);

                    GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::BuildChallenge() GetOutgoingDigestBlob() returned IsCompleted:" + context.IsCompleted + " statusCode:" + statusCode + " outBlob:[" + outBlob + "]"); 

                    if (context.IsValidContext) 
                    { 
                        newContext = context;
                    } 

                    AddChallenge(ref challenges, DigestClient.AuthType + (string.IsNullOrEmpty(outBlob) ? "" : " " + outBlob));
                }
                finally 
                {
                    if (context != null && newContext != context) 
                    { 
                        context.CloseContext();
                    } 
                }
            }

            if ((authenticationScheme & AuthenticationSchemes.Basic) != 0) 
            {
                AddChallenge(ref challenges, BasicClient.AuthType + " realm=\"" + Realm + "\""); 
            } 

            return challenges; 
        }

        private void RegisterForDisconnectNotification(ulong connectionId, ref DisconnectAsyncResult disconnectResult)
        { 
            GlobalLog.Assert(disconnectResult == null, "HttpListener#{0}::RegisterForDisconnectNotification()|Called with a disconnectResult.", ValidationHelper.HashString(this));
 
            try 
            {
                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::RegisterForDisconnectNotification() calling UnsafeNclNativeMethods.HttpApi.HttpWaitForDisconnect"); 

                DisconnectAsyncResult result = new DisconnectAsyncResult(this, connectionId);

                EnsureBoundHandle(); 
                uint statusCode = UnsafeNclNativeMethods.HttpApi.HttpWaitForDisconnect(
                    m_RequestQueueHandle, 
                    connectionId, 
                    result.NativeOverlapped);
 
                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::RegisterForDisconnectNotification() call to UnsafeNclNativeMethods.HttpApi.HttpWaitForDisconnect returned:" + statusCode);

                if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS ||
                    statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) 
                {
                    // Need to make sure it's going to get returned before adding it to the hash.  That way it'll be handled 
                    // correctly in HandleAuthentication's finally. 
                    disconnectResult = result;
                    DisconnectResults[connectionId] = disconnectResult; 
                }
            }
            catch (Win32Exception exception)
            { 
                uint statusCode = (uint) exception.NativeErrorCode;
                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::RegisterForDisconnectNotification() call to UnsafeNclNativeMethods.HttpApi.HttpWaitForDisconnect threw.  statusCode:" + statusCode); 
            } 
        }
 
        private void SendError(ulong requestId, HttpStatusCode httpStatusCode, ArrayList challenges)
        {
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::SendInternalError() requestId:" + ValidationHelper.ToString(requestId));
            UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE httpResponse = new UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE(); 
            httpResponse.Version = new UnsafeNclNativeMethods.HttpApi.HTTP_VERSION();
            httpResponse.Version.MajorVersion = (ushort)1; 
            httpResponse.Version.MinorVersion = (ushort)1; 
            httpResponse.StatusCode = (ushort)httpStatusCode;
            string statusDescription = HttpListenerResponse.GetStatusDescription((int)httpStatusCode); 
            uint DataWritten = 0;
            uint statusCode;
            byte[] byteReason = Encoding.Default.GetBytes(statusDescription);
            fixed (byte* pReason = byteReason) 
            {
                httpResponse.pReason = (sbyte*)pReason; 
                httpResponse.ReasonLength = (ushort)byteReason.Length; 

                byte[] byteContentLength = Encoding.Default.GetBytes("0"); 
                fixed (byte* pContentLength = byteContentLength)
                {
                    (&httpResponse.Headers.KnownHeaders)[(int)HttpResponseHeader.ContentLength].pRawValue = (sbyte*)pContentLength;
                    (&httpResponse.Headers.KnownHeaders)[(int)HttpResponseHeader.ContentLength].RawValueLength = (ushort)byteContentLength.Length; 

                    httpResponse.Headers.UnknownHeaderCount = checked((ushort) (challenges == null ? 0 : challenges.Count)); 
                    GCHandle[] challengeHandles = null; 
                    UnsafeNclNativeMethods.HttpApi.HTTP_UNKNOWN_HEADER[] headersArray = null;
                    GCHandle headersArrayHandle = new GCHandle(); 
                    GCHandle wwwAuthenticateHandle = new GCHandle();
                    if (httpResponse.Headers.UnknownHeaderCount > 0)
                    {
                        challengeHandles = new GCHandle[httpResponse.Headers.UnknownHeaderCount]; 
                        headersArray = new UnsafeNclNativeMethods.HttpApi.HTTP_UNKNOWN_HEADER[httpResponse.Headers.UnknownHeaderCount];
                    } 
 
                    try
                    { 
                        if (httpResponse.Headers.UnknownHeaderCount > 0)
                        {
                            headersArrayHandle = GCHandle.Alloc(headersArray, GCHandleType.Pinned);
                            httpResponse.Headers.pUnknownHeaders = (UnsafeNclNativeMethods.HttpApi.HTTP_UNKNOWN_HEADER*) Marshal.UnsafeAddrOfPinnedArrayElement(headersArray, 0); 
                            wwwAuthenticateHandle = GCHandle.Alloc(s_WwwAuthenticateBytes, GCHandleType.Pinned);
                            sbyte* wwwAuthenticate = (sbyte*) Marshal.UnsafeAddrOfPinnedArrayElement(s_WwwAuthenticateBytes, 0); 
 
                            for (int i = 0; i < challengeHandles.Length; i++)
                            { 
                                byte[] byteChallenge = Encoding.Default.GetBytes((string) challenges[i]);
                                challengeHandles[i] = GCHandle.Alloc(byteChallenge, GCHandleType.Pinned);
                                headersArray[i].pName = wwwAuthenticate;
                                headersArray[i].NameLength = (ushort) s_WwwAuthenticateBytes.Length; 
                                headersArray[i].pRawValue = (sbyte*) Marshal.UnsafeAddrOfPinnedArrayElement(byteChallenge, 0);
                                headersArray[i].RawValueLength = checked((ushort) byteChallenge.Length); 
                            } 
                        }
 
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::SendInternalError() calling UnsafeNclNativeMethods.HttpApi.HttpSendHtthttpResponse");
                        statusCode =
                            UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse(
                                m_RequestQueueHandle, 
                                requestId,
                                0, 
                                &httpResponse, 
                                null,
                                &DataWritten, 
                                SafeLocalFree.Zero,
                                0,
                                null,
                                null ); 
                    }
                    finally 
                    { 
                        if (headersArrayHandle.IsAllocated)
                        { 
                            headersArrayHandle.Free();
                        }
                        if (wwwAuthenticateHandle.IsAllocated)
                        { 
                            wwwAuthenticateHandle.Free();
                        } 
                        if (challengeHandles != null) 
                        {
                            for (int i = 0; i < challengeHandles.Length; i++) 
                            {
                                if (challengeHandles[i].IsAllocated)
                                {
                                    challengeHandles[i].Free(); 
                                }
                            } 
                        } 
                    }
                } 
            }
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::SendInternalError() call to UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse returned:" + statusCode);
            if (statusCode!=UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) {
                // if we fail to send a 401 something's seriously wrong, abort the request 
                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() SendUnauthorized() returned:" + statusCode);
                HttpListenerContext.CancelRequest(m_RequestQueueHandle, requestId); 
            } 
        }
 
        internal void CheckDisposed() {
            if (m_State==State.Closed) {
                throw new ObjectDisposedException(this.GetType().FullName);
            } 
        }
 
        // This only works for context-destroying errors. 
        private HttpStatusCode HttpStatusFromSecurityStatus(SecurityStatus status)
        { 
            if (NclUtilities.IsCredentialFailure(status))
            {
                return HttpStatusCode.Unauthorized;
            } 
            if (NclUtilities.IsClientFault(status))
            { 
                return HttpStatusCode.BadRequest; 
            }
            return HttpStatusCode.InternalServerError; 
        }

        enum State {
            Stopped, 
            Started,
            Closed, 
        } 

        private const int DigestLifetimeSeconds = 300; 
        private const int MaximumDigests = 1024;  // Must be a power of two.
        private const int MinimumDigestLifetimeSeconds = 10;

        private struct DigestContext 
        {
            internal NTAuthentication context; 
            internal int timestamp; 
        }
 
        private DigestContext[] m_SavedDigests;
        private ArrayList m_ExtraSavedDigests;
        private ArrayList m_ExtraSavedDigestsBaking;
        private int m_ExtraSavedDigestsTimestamp; 
        private int m_NewestContext;
        private int m_OldestContext; 
 
        private void SaveDigestContext(NTAuthentication digestContext)
        { 
            if (m_SavedDigests == null)
            {
                Interlocked.CompareExchange(ref m_SavedDigests, new DigestContext[MaximumDigests], null);
            } 

            // We want to actually close the contexts outside the lock. 
            NTAuthentication oldContext = null; 
            ArrayList digestsToClose = null;
            lock (m_SavedDigests) 
            {
                // If we're stopped, just throw it away.
                if (!IsListening)
                { 
                    digestContext.CloseContext();
                    return; 
                } 

                int now = ((now = Environment.TickCount) == 0 ? 1 : now); 

                m_NewestContext = (m_NewestContext + 1) & (MaximumDigests - 1);

                int oldTimestamp = m_SavedDigests[m_NewestContext].timestamp; 
                oldContext = m_SavedDigests[m_NewestContext].context;
                m_SavedDigests[m_NewestContext].timestamp = now; 
                m_SavedDigests[m_NewestContext].context = digestContext; 

                // May need to move this up. 
                if (m_OldestContext == m_NewestContext)
                {
                    m_OldestContext = (m_NewestContext + 1) & (MaximumDigests - 1);
                } 

                // Delete additional contexts older than five minutes. 
                while (unchecked(now - m_SavedDigests[m_OldestContext].timestamp) >= DigestLifetimeSeconds && m_SavedDigests[m_OldestContext].context != null) 
                {
                    if (digestsToClose == null) 
                    {
                        digestsToClose = new ArrayList();
                    }
                    digestsToClose.Add(m_SavedDigests[m_OldestContext].context); 
                    m_SavedDigests[m_OldestContext].context = null;
                    m_OldestContext = (m_OldestContext + 1) & (MaximumDigests - 1); 
                } 

                // If the old context is younger than 10 seconds, put it in the backup pile. 
                if (oldContext != null && unchecked(now - oldTimestamp) <= MinimumDigestLifetimeSeconds * 1000)
                {
                    // Use a two-tier ArrayList system to guarantee each entry lives at least 10 seconds.
                    if (m_ExtraSavedDigests == null || 
                        unchecked(now - m_ExtraSavedDigestsTimestamp) > MinimumDigestLifetimeSeconds * 1000)
                    { 
                        digestsToClose = m_ExtraSavedDigestsBaking; 
                        m_ExtraSavedDigestsBaking = m_ExtraSavedDigests;
                        m_ExtraSavedDigestsTimestamp = now; 
                        m_ExtraSavedDigests = new ArrayList();
                    }
                    m_ExtraSavedDigests.Add(oldContext);
                    oldContext = null; 
                }
            } 
 
            if (oldContext != null)
            { 
                oldContext.CloseContext();
            }
            if (digestsToClose != null)
            { 
                for (int i = 0; i < digestsToClose.Count; i++)
                { 
                    ((NTAuthentication)digestsToClose[i]).CloseContext(); 
                }
            } 
        }

        private void ClearDigestCache()
        { 
            if (m_SavedDigests == null)
            { 
                return; 
            }
 
            ArrayList[] toClose = new ArrayList[3];
            lock (m_SavedDigests)
            {
                toClose[0] = m_ExtraSavedDigestsBaking; 
                m_ExtraSavedDigestsBaking = null;
                toClose[1] = m_ExtraSavedDigests; 
                m_ExtraSavedDigests = null; 

                m_NewestContext = 0; 
                m_OldestContext = 0;

                toClose[2] = new ArrayList();
                for (int i = 0; i < MaximumDigests; i++) 
                {
                    if (m_SavedDigests[i].context != null) 
                    { 
                        toClose[2].Add(m_SavedDigests[i].context);
                        m_SavedDigests[i].context = null; 
                    }
                    m_SavedDigests[i].timestamp = 0;
                }
            } 

            for (int j = 0; j < toClose.Length; j++) 
            { 
                if (toClose[j] != null)
                { 
                    for (int k = 0; k < toClose[j].Count; k++)
                    {
                        ((NTAuthentication) toClose[j][k]).CloseContext();
                    } 
                }
            } 
        } 

        class DisconnectAsyncResult : IAsyncResult { 
            private static readonly IOCompletionCallback s_IOCallback = new IOCompletionCallback(WaitCallback);

            private ulong m_ConnectionId;
            private HttpListener m_HttpListener; 
            NativeOverlapped* m_NativeOverlapped;
            private int m_OwnershipState;   // 0 = normal, 1 = in HandleAuthentication(), 2 = disconnected, 3 = cleaned up 
 
            private WindowsPrincipal m_AuthenticatedConnection;
            private NTAuthentication m_Session; 

            internal const string NTLM = "NTLM";

            internal NativeOverlapped* NativeOverlapped{ 
                get{
                    return m_NativeOverlapped; 
                } 
            }
 
            public object AsyncState {
                get {
                    throw ExceptionHelper.PropertyNotImplementedException;
                } 
            }
            public WaitHandle AsyncWaitHandle { 
                get { 
                    throw ExceptionHelper.PropertyNotImplementedException;
                } 
            }
            public bool CompletedSynchronously {
                get {
                    throw ExceptionHelper.PropertyNotImplementedException; 
                }
            } 
            public bool IsCompleted { 
                get {
                    throw ExceptionHelper.PropertyNotImplementedException; 
                }
            }

            internal unsafe DisconnectAsyncResult(HttpListener httpListener, ulong connectionId) { 
                GlobalLog.Print("DisconnectAsyncResult#" + ValidationHelper.HashString(this) + "::.ctor() httpListener#" + ValidationHelper.HashString(httpListener) + " connectionId:" + connectionId);
                m_OwnershipState = 1; 
                m_HttpListener = httpListener; 
                m_ConnectionId = connectionId;
                Overlapped overlapped = new Overlapped(); 
                overlapped.AsyncResult = this;
                // we can call the Unsafe API here, we won't ever call user code
                m_NativeOverlapped = overlapped.UnsafePack(s_IOCallback, null);
                GlobalLog.Print("DisconnectAsyncResult#" + ValidationHelper.HashString(this) + "::.ctor() overlapped#" + ValidationHelper.HashString(overlapped) + " nativeOverlapped:" + ((IntPtr)m_NativeOverlapped).ToString("x")); 
            }
 
            internal bool StartOwningDisconnectHandling() 
            {
                int oldValue; 

                while ((oldValue = Interlocked.CompareExchange(ref m_OwnershipState, 1, 0)) == 2)
                {
                    // Must block until it equals 3 - we must be in the callback right now. 
                    Thread.SpinWait(1);
                } 
 
                GlobalLog.Assert(oldValue != 1, "DisconnectAsyncResult#{0}::HandleDisconnect()|StartOwningDisconnectHandling() called twice.", ValidationHelper.HashString(this));
                return oldValue < 2; 
            }

            internal void FinishOwningDisconnectHandling()
            { 
                // If it got disconnected, run the disconnect code.
                if (Interlocked.CompareExchange(ref m_OwnershipState, 0, 1) == 2) 
                { 
                    HandleDisconnect();
                } 
            }

            private static unsafe void WaitCallback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) {
                GlobalLog.Print("DisconnectAsyncResult::WaitCallback() errorCode:" + errorCode + " numBytes:" + numBytes + " nativeOverlapped:" + ((IntPtr)nativeOverlapped).ToString("x")); 
                // take the DisconnectAsyncResult object from the state
                Overlapped callbackOverlapped = Overlapped.Unpack(nativeOverlapped); 
                DisconnectAsyncResult asyncResult = (DisconnectAsyncResult) callbackOverlapped.AsyncResult; 
                GlobalLog.Print("DisconnectAsyncResult#" + ValidationHelper.HashString(asyncResult) + "::WaitCallback() callbackOverlapped#" + ValidationHelper.HashString(callbackOverlapped) + " m_ConnectionId:" + asyncResult.m_ConnectionId);
                Overlapped.Free(nativeOverlapped); 
                if (Interlocked.Exchange(ref asyncResult.m_OwnershipState, 2) == 0)
                {
                    asyncResult.HandleDisconnect();
                } 
            }
 
            private void HandleDisconnect() 
            {
                GlobalLog.Print("DisconnectAsyncResult#" + ValidationHelper.HashString(this) + "::HandleDisconnect() DisconnectResults#" + ValidationHelper.HashString(m_HttpListener.DisconnectResults) + " removing for m_ConnectionId:" + m_ConnectionId); 
                m_HttpListener.DisconnectResults.Remove(m_ConnectionId);
                if (m_Session != null)
                {
                    if (m_Session.Package == NegotiationInfoClass.WDigest) 
                    {
                        // VSWhidbey #497767 
                        // WDigest doesn't like having the context passed back in on the next request on a connection, but it does want 
                        // the server to keep a reference to it for as long as a client might reuse the nonce.  The heuristic we use is,
                        // keep contexts for five minutes, up to a maximum of 1024, except also keep all contexts at least 10 seconds to avoid 
                        // total DoS (where no handshakes can be completed in time).
                        m_HttpListener.SaveDigestContext(m_Session);
                    }
                    else 
                    {
                        m_Session.CloseContext(); 
                    } 
                }
 
                // Clean up the identity. This is for scenarios where identity was not cleaned up before due to
                // identity caching for unsafe ntlm authentication

                IDisposable identity = m_AuthenticatedConnection == null ? null : m_AuthenticatedConnection.Identity as IDisposable; 
                if ((identity != null) &&
                    (m_AuthenticatedConnection.Identity.AuthenticationType == NTLM) && 
                    (m_HttpListener.UnsafeConnectionNtlmAuthentication)) 
                {
                    identity.Dispose(); 
                }

                int oldValue = Interlocked.Exchange(ref m_OwnershipState, 3);
                GlobalLog.Assert(oldValue == 2, "DisconnectAsyncResult#{0}::HandleDisconnect()|Expected OwnershipState of 2, saw {1}.", ValidationHelper.HashString(this), oldValue); 
            }
 
            internal WindowsPrincipal AuthenticatedConnection 
            {
                get 
                {
                    return m_AuthenticatedConnection;
                }
 
                set
                { 
                    // The previous value can't be disposed because it may be in use by the app. 
                    m_AuthenticatedConnection = value;
                } 
            }

            internal NTAuthentication Session
            { 
                get
                { 
                    return m_Session; 
                }
 
                set
                {
                    m_Session = value;
                } 
            }
        } 
    } 

/*  Proposed Future HTTP Base Classes 
    see \ndp\mb\docs\specs\NetworkFramework\HTTPSYS\ASP.NET\stub.cs

    // System.Net exposes base abstract classes that System.Web will inherit from
 
    public abstract class BaseHttpContext {
        public virtual IPrincipal User { get; set; } 
 
        // it doesn't make sense to make these virtual because we can't override
        // and change the returned type for System.Web or people would break. 
        // the only thing we can do is to declare them normally and hide the
        // base implementation like "public new System.Web.HttpRequest Request"

        public BaseHttpRequest Request { get; } 
        public BaseHttpResponse Response { get; }
 
        // these provide plumbing to make the above two methods callable with a BaseHttpContext reference 

        protected virtual BaseHttpRequest GetRequest(); 
        protected virtual BaseHttpResponse GetResponse();
    }

    public abstract class BaseHttpRequest { 
        public virtual string[] AcceptTypes { get; }
        public virtual Encoding ContentEncoding { get; set; } 
        public virtual string ContentType { get; set; } 
        public virtual NameValueCollection Headers { get; }
        public virtual string HttpMethod { get; } 
        public virtual Stream InputStream { get; }
        public virtual bool IsAuthenticated { get; }
        public virtual bool IsLocal { get; }
        public virtual bool IsSecureConnection { get; } 
        public virtual NameValueCollection QueryString { get; }
        public virtual string RawUrl { get; } 
        public virtual Uri Url { get; } 
        public virtual Uri UrlReferrer { get; }
        public virtual string UserAgent { get; } 
        public virtual string UserHostAddress { get; }
        public virtual string UserHostName { get; }
        public virtual string[] UserLanguages { get; }
 
        // APIs that are in the base class but are new to ASP .NET
 
        public virtual long ContentLengthLong { get; } 
        public virtual bool HasEntityBody { get; }
        public virtual bool KeepAlive { get; } 
        public virtual IPEndPoint RemoteEndPoint { get; }
        public virtual IPEndPoint LocalEndPoint { get; }
    }
 
    public abstract class BaseHttpResponse {
        public virtual void AppendHeader(string name, string value); 
        public virtual void Close(); 
        public virtual Encoding ContentEncoding { get; set; }
        public virtual string ContentType { get; set; } 
        public virtual Stream OutputStream { get; }
        public virtual string RedirectLocation { get; set; }
        public virtual int StatusCode { get; set; }
        public virtual string StatusDescription { get; set; } 

        // APIs that are in the base class but are new to ASP .NET 
 
        public virtual bool KeepAlive { get; set; }
    } 
*/
}


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

//disabled until BindHandle has an overload that accepts Criticalhandles 
#pragma warning disable 618 

namespace System.Net { 
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.Specialized; 
    using System.IO;
    using System.Net; 
    using System.Net.Sockets; 
    using System.Runtime.InteropServices;
    using System.Security.Permissions; 
    using System.Text;
    using System.Threading;
    using System.ComponentModel;
    using System.Diagnostics; 
    using System.Globalization;
    using System.Security; 
    using System.Security.Principal; 
    using System.Security.Cryptography.X509Certificates;
    using Microsoft.Win32; 

    public class HttpListenerBasicIdentity : GenericIdentity
    {
        private string m_Password; 

        public HttpListenerBasicIdentity(string username, string password) : 
            base(username, BasicClient.AuthType) 
        {
            m_Password = password; 
        }

        public virtual string Password
        { 
            get
            { 
                return m_Password; 
            }
        } 
    }

    internal abstract unsafe class RequestContextBase : IDisposable
    { 
        private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* m_MemoryBlob;
        private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* m_OriginalBlobAddress; 
        private byte[] m_BackingBuffer; 

        // Must call this from derived class' constructors. 
        protected void BaseConstruction(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* requestBlob)
        {
            if (requestBlob == null)
            { 
                GC.SuppressFinalize(this);
            } 
            else 
            {
                m_MemoryBlob = requestBlob; 
            }
        }

        // ReleasePins() should be called exactly once.  It must be called before Dispose() is called, which means it must be called 
        // before an object (HttpListenerReqeust) which closes the RequestContext on demand is returned to the application.
        internal void ReleasePins() 
        { 
            GlobalLog.Assert(m_MemoryBlob != null || m_BackingBuffer == null, "RequestContextBase::ReleasePins()|ReleasePins() called twice.");
            m_OriginalBlobAddress = m_MemoryBlob; 
            UnsetBlob();
            OnReleasePins();
        }
 
        protected abstract void OnReleasePins();
 
        public void Close() 
        {
            Dispose(); 
        }

        public void Dispose()
        { 
            GlobalLog.Assert(m_MemoryBlob == null, "RequestContextBase::Dispose()|Dispose() called before ReleasePins().");
            Dispose(true); 
        } 

        protected virtual void Dispose(bool disposing) { } 

        ~RequestContextBase()
        {
            Dispose(false); 
        }
 
        internal UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* RequestBlob 
        {
            get 
            {
                GlobalLog.Assert(m_MemoryBlob != null || m_BackingBuffer == null, "RequestContextBase::Dispose()|RequestBlob requested after ReleasePins().");
                return m_MemoryBlob;
            } 
        }
 
        internal byte[] RequestBuffer 
        {
            get 
            {
                return m_BackingBuffer;
            }
        } 

        internal uint Size 
        { 
            get
            { 
                return (uint) m_BackingBuffer.Length;
            }
        }
 
        internal IntPtr OriginalBlobAddress
        { 
            get 
            {
                UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* blob = m_MemoryBlob; 
                return (IntPtr) (blob == null ? m_OriginalBlobAddress : blob);
            }
        }
 
        protected void SetBlob(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* requestBlob)
        { 
            GlobalLog.Assert(m_MemoryBlob != null || m_BackingBuffer == null, "RequestContextBase::Dispose()|SetBlob() called after ReleasePins()."); 
            if (requestBlob == null)
            { 
                UnsetBlob();
                return;
            }
 
            if (m_MemoryBlob == null)
            { 
                GC.ReRegisterForFinalize(this); 
            }
            m_MemoryBlob = requestBlob; 
        }

        protected void UnsetBlob()
        { 
            if (m_MemoryBlob != null)
            { 
                GC.SuppressFinalize(this); 
            }
            m_MemoryBlob = null; 
        }

        protected void SetBuffer(int size)
        { 
            m_BackingBuffer = size == 0 ? null : new byte[size];
        } 
    } 

    internal unsafe class AsyncRequestContext : RequestContextBase 
    {
        private NativeOverlapped* m_NativeOverlapped;
        private ListenerAsyncResult m_Result;
 
        internal AsyncRequestContext(ListenerAsyncResult result)
        { 
            m_Result = result; 
            BaseConstruction(Allocate(0));
        } 

        private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* Allocate(uint size)
        {
            uint newSize = size != 0 ? size : RequestBuffer == null ? 4096 : Size; 
            if (m_NativeOverlapped != null && newSize != RequestBuffer.Length)
            { 
                NativeOverlapped* nativeOverlapped = m_NativeOverlapped; 
                m_NativeOverlapped = null;
                Overlapped.Free(nativeOverlapped); 
            }
            if (m_NativeOverlapped == null)
            {
                SetBuffer(checked((int) newSize)); 
                Overlapped overlapped = new Overlapped();
                overlapped.AsyncResult = m_Result; 
                m_NativeOverlapped = overlapped.Pack(ListenerAsyncResult.IOCallback, RequestBuffer); 
                return (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST*) Marshal.UnsafeAddrOfPinnedArrayElement(RequestBuffer, 0);
            } 
            return RequestBlob;
        }

        internal void Reset(ulong requestId, uint size) 
        {
            SetBlob(Allocate(size)); 
            RequestBlob->RequestId = requestId; 
        }
 
        protected override void OnReleasePins()
        {
            if (m_NativeOverlapped != null)
            { 
                NativeOverlapped* nativeOverlapped = m_NativeOverlapped;
                m_NativeOverlapped = null; 
                Overlapped.Free(nativeOverlapped); 
            }
        } 

        protected override void Dispose(bool disposing)
        {
            if (m_NativeOverlapped != null) 
            {
                GlobalLog.Assert(!disposing, "AsyncRequestContext::Dispose()|Must call ReleasePins() before calling Dispose()."); 
                if (!NclUtilities.HasShutdownStarted || disposing) 
                {
                    Overlapped.Free(m_NativeOverlapped); 
                }
            }
            base.Dispose(disposing);
        } 

        internal NativeOverlapped* NativeOverlapped 
        { 
            get
            { 
                return m_NativeOverlapped;
            }
        }
    } 

    internal unsafe class SyncRequestContext : RequestContextBase 
    { 
        private GCHandle m_PinnedHandle;
 
        internal SyncRequestContext(int size)
        {
            BaseConstruction(Allocate(size));
        } 

        private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* Allocate(int size) 
        { 
            if (m_PinnedHandle.IsAllocated)
            { 
                if (RequestBuffer.Length == size)
                {
                    return RequestBlob;
                } 
                m_PinnedHandle.Free();
            } 
            SetBuffer(size); 
            if (RequestBuffer == null)
            { 
                return null;
            }
            m_PinnedHandle = GCHandle.Alloc(RequestBuffer, GCHandleType.Pinned);
            return (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST*) Marshal.UnsafeAddrOfPinnedArrayElement(RequestBuffer, 0); 
        }
 
        internal void Reset(int size) 
        {
            SetBlob(Allocate(size)); 
        }

        protected override void OnReleasePins()
        { 
            if (m_PinnedHandle.IsAllocated)
            { 
                m_PinnedHandle.Free(); 
            }
        } 

        protected override void Dispose(bool disposing)
        {
            if (m_PinnedHandle.IsAllocated) 
            {
                GlobalLog.Assert(!disposing, "AsyncRequestContext::Dispose()|Must call ReleasePins() before calling Dispose()."); 
                if (!NclUtilities.HasShutdownStarted || disposing) 
                {
                    m_PinnedHandle.Free(); 
                }
            }
            base.Dispose(disposing);
        } 
    }
 
    public sealed unsafe class HttpListener : IDisposable 
    {
        private static byte[] s_WwwAuthenticateBytes = new byte[] 
        {
            (byte) 'W', (byte) 'W', (byte) 'W', (byte) '-', (byte) 'A', (byte) 'u', (byte) 't', (byte) 'h',
            (byte) 'e', (byte) 'n', (byte) 't', (byte) 'i', (byte) 'c', (byte) 'a', (byte) 't', (byte) 'e'
        }; 

        private class AuthenticationSelectorInfo 
        { 
            private AuthenticationSchemeSelector m_SelectorDelegate;
            private bool m_CanUseAdvancedAuth; 

            internal AuthenticationSelectorInfo(AuthenticationSchemeSelector selectorDelegate, bool canUseAdvancedAuth)
            {
                m_SelectorDelegate = selectorDelegate; 
                m_CanUseAdvancedAuth = canUseAdvancedAuth;
            } 
 
            internal AuthenticationSchemeSelector Delegate
            { 
                get
                {
                    return m_SelectorDelegate;
                } 
            }
 
            internal bool AdvancedAuth 
            {
                get 
                {
                    return m_CanUseAdvancedAuth;
                }
            } 
        }
 
        private AuthenticationSelectorInfo m_AuthenticationDelegate; 
        private AuthenticationSchemes m_AuthenticationScheme = AuthenticationSchemes.Anonymous;
        private SecurityException m_SecurityException; 
        private string m_Realm;
        private SafeCloseHandle m_RequestQueueHandle;
        private bool m_RequestHandleBound;
        private State m_State; 
        private HttpListenerPrefixCollection m_Prefixes;
        private bool m_IgnoreWriteExceptions; 
        private bool m_UnsafeConnectionNtlmAuthentication; 

        private Hashtable m_DisconnectResults;         // ulong -> DisconnectAsyncResult 
        private object m_InternalLock;

        internal Hashtable m_UriPrefixes = new Hashtable();
 
        public HttpListener() {
            if(Logging.On)Logging.Enter(Logging.HttpListener, this, "HttpListener", ""); 
            if (!UnsafeNclNativeMethods.HttpApi.Supported) { 
                throw new PlatformNotSupportedException();
            } 
            m_State = State.Stopped;
            m_InternalLock = new object();
            if(Logging.On)Logging.Exit(Logging.HttpListener, this, "HttpListener", "");
        } 

        internal SafeCloseHandle RequestQueueHandle { 
            get { 
                return m_RequestQueueHandle;
            } 
        }

        public AuthenticationSchemeSelector AuthenticationSchemeSelectorDelegate {
            get { 
                AuthenticationSelectorInfo selector = m_AuthenticationDelegate;
                return selector == null ? null : selector.Delegate; 
            } 
            set {
                CheckDisposed(); 

                try
                {
                    new SecurityPermission(SecurityPermissionFlag.ControlPrincipal).Demand(); 
                    m_AuthenticationDelegate = new AuthenticationSelectorInfo(value, true);
                } 
                catch (SecurityException exception) 
                {
                    m_SecurityException = exception; 
                    m_AuthenticationDelegate = new AuthenticationSelectorInfo(value, false);
                }
            }
        } 

        public AuthenticationSchemes AuthenticationSchemes { 
            get { 
                return m_AuthenticationScheme;
            } 
            set {
                CheckDisposed();

                // Enabling certain schemes requires special permissions. 
                if ((value & (AuthenticationSchemes.Digest | AuthenticationSchemes.Negotiate | AuthenticationSchemes.Ntlm)) != 0)
                { 
                    new SecurityPermission(SecurityPermissionFlag.ControlPrincipal).Demand(); 
                }
 
                m_AuthenticationScheme = value;
            }
        }
 
        public string Realm {
            get { 
                return m_Realm; 
            }
            set { 
                CheckDisposed();
                m_Realm = value;
            }
        } 

        public static bool IsSupported { 
            get { 
                return UnsafeNclNativeMethods.HttpApi.Supported;
            } 
        }

        public bool IsListening {
            get { 
                return m_State==State.Started;
            } 
        } 

        public bool IgnoreWriteExceptions { 
            get {
                return m_IgnoreWriteExceptions;
            }
            set { 
                CheckDisposed();
                m_IgnoreWriteExceptions = value; 
            } 
        }
 
        public bool UnsafeConnectionNtlmAuthentication {
            get {
                return m_UnsafeConnectionNtlmAuthentication;
            } 

            set { 
                CheckDisposed(); 
                if (m_UnsafeConnectionNtlmAuthentication==value) {
                    return; 
                }
                lock (DisconnectResults.SyncRoot)
                {
                    if (m_UnsafeConnectionNtlmAuthentication == value) 
                    {
                        return; 
                    } 
                    m_UnsafeConnectionNtlmAuthentication = value;
                    if (!value) 
                    {
                        foreach (DisconnectAsyncResult result in DisconnectResults.Values)
                        {
                            result.AuthenticatedConnection = null; 
                        }
                    } 
                } 
            }
        } 

        private Hashtable DisconnectResults
        {
            get 
            {
                if (m_DisconnectResults == null) 
                { 
                    lock (m_InternalLock)
                    { 
                        if (m_DisconnectResults == null)
                        {
                            m_DisconnectResults = Hashtable.Synchronized(new Hashtable());
                        } 
                    }
                } 
                return m_DisconnectResults; 
            }
        } 

        internal void AddPrefix(string uriPrefix)
        {
            if(Logging.On)Logging.Enter(Logging.HttpListener, this, "AddPrefix", "uriPrefix:" + uriPrefix); 
            string registeredPrefix = null;
            try { 
                if (uriPrefix==null) { 
                    throw new ArgumentNullException("uriPrefix");
                } 
                (new WebPermission(NetworkAccess.Accept, uriPrefix)).Demand();
                CheckDisposed();
                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::AddPrefix() uriPrefix:" + uriPrefix);
                int i; 
                if (string.Compare(uriPrefix, 0, "http://", 0, 7, StringComparison.OrdinalIgnoreCase)==0) {
                    i = 7; 
                } 
                else if (string.Compare(uriPrefix, 0, "https://", 0, 8, StringComparison.OrdinalIgnoreCase)==0) {
                    i = 8; 
                }
                else {
                    throw new ArgumentException(SR.GetString(SR.net_listener_scheme), "uriPrefix");
                } 
                bool inSquareBrakets = false;
                int j = i; 
                while (j0) { 
                    if (m_State==State.Started) {
                        foreach (string registeredPrefix in m_UriPrefixes.Values) { 
                            // ignore possible failures
                            InternalRemovePrefix(registeredPrefix);
                        }
                    } 
                    if(clear)
                        m_UriPrefixes.Clear(); 
                } 
            } finally {
                if(Logging.On)Logging.Exit(Logging.HttpListener, this, "RemoveAll", ""); 
            }
        }

        [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.UnmanagedCode)] 
        internal void EnsureBoundHandle()
        { 
            if (!m_RequestHandleBound) 
            {
                lock (m_InternalLock) 
                {
                    if (!m_RequestHandleBound)
                    {
                        ThreadPool.BindHandle(m_RequestQueueHandle.DangerousGetHandle()); 
                        m_RequestHandleBound = true;
                    } 
                } 
            }
        } 

        public void Start() {
            if(Logging.On)Logging.Enter(Logging.HttpListener, this, "Start", "");
            try { 
                CheckDisposed();
                if (m_State==State.Started) { 
                    return; 
                }
                m_RequestQueueHandle = SafeCloseHandle.CreateRequestQueueHandle(); 
                AddAll();
                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::.ctor() SafeCloseHandle.CreateRequestQueueHandle() returned m_RequestQueueHandle:" + m_RequestQueueHandle);
                m_State = State.Started;
            } catch (Exception exception) { 
                if(Logging.On)Logging.Exception(Logging.HttpListener, this, "Start", exception);
                throw; 
            } finally { 
                if(Logging.On)Logging.Exit(Logging.HttpListener, this, "Start", "");
            } 
        }

        public void Stop() {
            if(Logging.On)Logging.Enter(Logging.HttpListener, this, "Stop", ""); 
            try {
                CheckDisposed(); 
                if (m_State==State.Stopped) { 
                    return;
                } 
                RemoveAll(false);
                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::Stop() calling SafeCloseHandle.Close()");
                m_RequestQueueHandle.Close();
                m_RequestHandleBound = false; 
                m_State = State.Stopped;
                ClearDigestCache(); 
            } catch (Exception exception) { 
                if(Logging.On)Logging.Exception(Logging.HttpListener, this, "Stop", exception);
                throw; 
            } finally {
                if(Logging.On)Logging.Exit(Logging.HttpListener, this, "Stop", "");
            }
        } 

        public void Abort() { 
            if(Logging.On)Logging.Enter(Logging.HttpListener, this, "Abort", ""); 
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::Abort()");
 
            try {
                if (m_RequestQueueHandle!=null)
                {
                    m_RequestQueueHandle.Abort(); 
                }
                m_RequestHandleBound = false; 
                m_State = State.Closed; 
                ClearDigestCache();
            } catch (Exception exception) { 
                if(Logging.On)Logging.Exception(Logging.HttpListener, this, "Abort", exception);
                throw;
            } finally {
                if(Logging.On)Logging.Exit(Logging.HttpListener, this, "Abort", ""); 
            }
        } 
 
        public void Close() {
            if(Logging.On)Logging.Enter(Logging.HttpListener, this, "Close", ""); 
            try {
                GlobalLog.Print("HttpListenerRequest::Close()");
                ((IDisposable)this).Dispose();
            } catch (Exception exception) { 
                if(Logging.On)Logging.Exception(Logging.HttpListener, this, "Close", exception);
                throw; 
            } finally { 
                if(Logging.On)Logging.Exit(Logging.HttpListener, this, "Close", "");
            } 
        }

        // old API, now private, and helper methods
        private void Dispose(bool disposing) { 
            if(Logging.On)Logging.Enter(Logging.HttpListener, this, "Dispose", "");
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::Dispose()"); 
            try { 
                if (m_State == State.Closed){
                    return; 
                }
                Stop();
                m_RequestHandleBound = false;
                m_State = State.Closed; 
            } catch (Exception exception) {
                if(Logging.On)Logging.Exception(Logging.HttpListener, this, "Dispose", exception); 
                throw; 
            } finally {
                if(Logging.On)Logging.Exit(Logging.HttpListener, this, "Dispose", ""); 
            }
        }

        ///  
        void IDisposable.Dispose() {
            Dispose(true); 
        } 

        private uint InternalAddPrefix(string uriPrefix) { 
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::InternalAddPrefix() uriPrefix:" + uriPrefix + " calling UnsafeNclNativeMethods.HttpApi.HttpAddUrl");
            uint statusCode = 0;
            fixed (char* pUriPrefix = uriPrefix) {
                statusCode = 
                    UnsafeNclNativeMethods.HttpApi.HttpAddUrl(
                        m_RequestQueueHandle, 
                        (ushort*)pUriPrefix, 
                        null);
            } 
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::InternalAddPrefix() call to UnsafeNclNativeMethods.HttpApi.HttpAddUrl returned:" + statusCode);
            return statusCode;
        }
 
        private bool InternalRemovePrefix(string uriPrefix) {
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::InternalRemovePrefix() uriPrefix:" + uriPrefix + " calling UnsafeNclNativeMethods.HttpApi.HttpRemoveUrl"); 
            uint statusCode = 0; 
            fixed (char* pUriPrefix = uriPrefix) {
                statusCode = 
                   UnsafeNclNativeMethods.HttpApi.HttpRemoveUrl(
                        m_RequestQueueHandle,
                        (ushort*)pUriPrefix);
            } 
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::InternalRemovePrefix() call to UnsafeNclNativeMethods.HttpApi.HttpRemoveUrl returned:" + statusCode);
            if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_NOT_FOUND) 
            { 
                return false;
            } 
            return true;
        }

        private void AddAll() { 
            // go through the uri list and register for each one of them
            if (m_UriPrefixes.Count>0) { 
                foreach (string registeredPrefix in m_UriPrefixes.Values) { 
                    uint statusCode = InternalAddPrefix(registeredPrefix);
                    if (statusCode!=UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) { 
                        Abort();
                        if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_ALREADY_EXISTS)
                            throw new HttpListenerException((int)statusCode, SR.GetString(SR.net_listener_already, registeredPrefix));
                        else 
                            throw new HttpListenerException((int)statusCode);
                    } 
                } 
            }
        } 

        public HttpListenerContext GetContext() {
            if(Logging.On)Logging.Enter(Logging.HttpListener, this, "GetContext", "");
 
            SyncRequestContext memoryBlob = null;
            HttpListenerContext httpContext = null; 
            bool stoleBlob = false; 

            try { 
                CheckDisposed();
                if (m_State==State.Stopped) {
                    throw new InvalidOperationException(SR.GetString(SR.net_listener_mustcall, "Start()"));
                } 
                if (m_UriPrefixes.Count==0) {
                    throw new InvalidOperationException(SR.GetString(SR.net_listener_mustcall, "AddPrefix()")); 
                } 
                uint statusCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS;
                uint size = 4096; 
                ulong requestId = 0;
                memoryBlob = new SyncRequestContext((int) size);
                for (;;) {
                    for (;;) { 
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::GetContext() calling UnsafeNclNativeMethods.HttpApi.HttpReceiveHttpRequest RequestId:" + requestId);
                        uint bytesTransferred = 0; 
                        statusCode = 
                            UnsafeNclNativeMethods.HttpApi.HttpReceiveHttpRequest(
                                m_RequestQueueHandle, 
                                requestId,
                                (uint)UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY,
                                memoryBlob.RequestBlob,
                                size, 
                                &bytesTransferred,
                                null); 
 
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::GetContext() call to UnsafeNclNativeMethods.HttpApi.HttpReceiveHttpRequest returned:" + statusCode);
                        if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_INVALID_PARAMETER && requestId != 0) { 
                            // we might get this if somebody stole our RequestId,
                            // we need to start all over again but we can reuse the buffer we just allocated
                            requestId = 0;
                            continue; 
                        }
                        else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA) 
                        { 
                            // the buffer was not big enough to fit the headers, we need
                            // to read the RequestId returned, allocate a new buffer of the required size 
                            size = bytesTransferred;
                            requestId = memoryBlob.RequestBlob->RequestId;
                            memoryBlob.Reset(checked((int) size));
                            continue; 
                        }
                        break; 
                    } 
                    if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS)
                    { 
                        // someother bad error, possible(?) return values are:
                        // ERROR_INVALID_HANDLE, ERROR_INSUFFICIENT_BUFFER, ERROR_OPERATION_ABORTED
                        throw new HttpListenerException((int)statusCode);
                    } 

                    // We need to hook up our authentication handling code here. 
                    httpContext = HandleAuthentication(memoryBlob, out stoleBlob); 
                    if (stoleBlob)
                    { 
                        // The request has been handed to the user, which means this code can't reuse the blob.  Reset it here.
                        memoryBlob = null;
                        stoleBlob = false;
                    } 
                    GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::GetContext() HandleAuthentication() returned httpContext#" + ValidationHelper.HashString(httpContext));
                    // if the request survived authentication, return it to the user 
                    if (httpContext!=null) { 
                        return httpContext;
                    } 

                    // HandleAuthentication may have cleaned this up.
                    if (memoryBlob == null)
                    { 
                        memoryBlob = new SyncRequestContext(checked((int) size));
                    } 
 
                    requestId = 0;
                } 
            } catch (Exception exception) {
                if(Logging.On)Logging.Exception(Logging.HttpListener, this, "GetContext", exception);
                throw;
            } finally { 
                if (memoryBlob != null && !stoleBlob)
                { 
                    memoryBlob.ReleasePins(); 
                    memoryBlob.Close();
                } 
                if(Logging.On)Logging.Exit(Logging.HttpListener, this, "GetContext", "HttpListenerContext#" + ValidationHelper.HashString(httpContext) + " RequestTraceIdentifier#"+httpContext.Request.RequestTraceIdentifier);
            }
        }
 
        [HostProtection(ExternalThreading=true)]
        public IAsyncResult BeginGetContext(AsyncCallback callback, object state) { 
            if(Logging.On)Logging.Enter(Logging.HttpListener, this, "BeginGetContext", ""); 
            ListenerAsyncResult asyncResult = null;
            try { 
                CheckDisposed();
                if (m_State==State.Stopped) {
                    throw new InvalidOperationException(SR.GetString(SR.net_listener_mustcall, "Start()"));
                } 
                // prepare the ListenerAsyncResult object (this will have it's own
                // event that the user can wait on for IO completion - which means we 
                // need to signal it when IO completes) 
                asyncResult = new ListenerAsyncResult(this, state, callback);
                uint statusCode = asyncResult.QueueBeginGetContext(); 
                if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS &&
                    statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING)
                {
                    // someother bad error, possible(?) return values are: 
                    // ERROR_INVALID_HANDLE, ERROR_INSUFFICIENT_BUFFER, ERROR_OPERATION_ABORTED
                    throw new HttpListenerException((int)statusCode); 
                } 
            } catch (Exception exception) {
                if(Logging.On)Logging.Exception(Logging.HttpListener, this, "BeginGetContext", exception); 
                throw;
            } finally {
                if(Logging.On)Logging.Enter(Logging.HttpListener, this, "BeginGetContext", "IAsyncResult#" + ValidationHelper.HashString(asyncResult));
            } 

            return asyncResult; 
        } 

        public HttpListenerContext EndGetContext(IAsyncResult asyncResult) { 
            if(Logging.On)Logging.Enter(Logging.HttpListener, this, "EndGetContext", "IAsyncResult#" + ValidationHelper.HashString(asyncResult));
            HttpListenerContext httpContext = null;
            try {
                CheckDisposed(); 
                if (asyncResult==null) {
                    throw new ArgumentNullException("asyncResult"); 
                } 
                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::EndGetContext() asyncResult:" + ValidationHelper.ToString(asyncResult));
                ListenerAsyncResult castedAsyncResult = asyncResult as ListenerAsyncResult; 
                if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
                    throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
                }
                if (castedAsyncResult.EndCalled) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndGetContext"));
                } 
                castedAsyncResult.EndCalled = true; 
                httpContext = castedAsyncResult.InternalWaitForCompletion() as HttpListenerContext;
                if (httpContext == null) { 
                    GlobalLog.Assert(castedAsyncResult.Result is Exception, "EndGetContext|The result is neither a HttpListenerContext nor an Exception.");
                    throw castedAsyncResult.Result as Exception;
                }
            } catch (Exception exception) { 
                if(Logging.On)Logging.Exception(Logging.HttpListener, this, "EndGetContext", exception);
                throw; 
            } finally { 
                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::EndGetContext() returning HttpListenerContext#" + ValidationHelper.ToString(httpContext));
                if(Logging.On)Logging.Enter(Logging.HttpListener, this, "EndGetContext", "HttpListenerContext#" + ValidationHelper.HashString(httpContext)+ " RequestTraceIdentifier#"+httpContext.Request.RequestTraceIdentifier); 
            }
            return httpContext;
        }
 
        [SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.UnmanagedCode)]
        [SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.ControlPrincipal)] 
        private WindowsIdentity CreateWindowsIdentity(IntPtr userToken, string type, WindowsAccountType acctType, bool isAuthenticated) 
        {
            return new WindowsIdentity(userToken, type, acctType, isAuthenticated); 
        }

        internal HttpListenerContext HandleAuthentication(RequestContextBase memoryBlob, out bool stoleBlob)
        { 
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() memoryBlob:0x" + ((IntPtr) memoryBlob.RequestBlob).ToString("x"));
 
            string challenge = null; 
            stoleBlob = false;
 
            // Some things we need right away.  Lift them out now while it's convenient.
            string verb = UnsafeNclNativeMethods.HttpApi.GetVerb(memoryBlob.RequestBlob);
            string authorizationHeader = UnsafeNclNativeMethods.HttpApi.GetKnownHeader(memoryBlob.RequestBlob, (int) HttpRequestHeader.Authorization);
            ulong connectionId = memoryBlob.RequestBlob->ConnectionId; 
            ulong requestId = memoryBlob.RequestBlob->RequestId;
 
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() authorizationHeader:" + ValidationHelper.ToString(authorizationHeader)); 

            // if the app has turned on AuthPersistence, an anonymous request might 
            // be authenticated by virtue of it coming on a connection that was
            // previously authenticated.
            // assurance that we do this only for NTLM/Negotiate is not here, but in the
            // code that caches WindowsIdentity instances in the Dictionary. 
            DisconnectAsyncResult disconnectResult = (DisconnectAsyncResult) DisconnectResults[connectionId];
            if (UnsafeConnectionNtlmAuthentication) 
            { 
                if (authorizationHeader == null)
                { 
                    WindowsPrincipal principal = disconnectResult == null ? null : disconnectResult.AuthenticatedConnection;
                    if (principal != null)
                    {
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() got principal:" + ValidationHelper.ToString(principal) + " principal.Identity.Name:" + ValidationHelper.ToString(principal.Identity.Name) + " creating request"); 
                        stoleBlob = true;
                        HttpListenerContext ntlmContext = new HttpListenerContext(this, memoryBlob); 
                        ntlmContext.SetIdentity(principal, null); 
                        ntlmContext.Request.ReleasePins();
                        return ntlmContext; 
                    }
                }
                else
                { 
                    // They sent an authorization - destroy their previous credentials.
                    GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() clearing principal cache"); 
                    if (disconnectResult != null) 
                    {
                        disconnectResult.AuthenticatedConnection = null; 
                    }
                }
            }
 
            // Figure out what schemes we're allowing, what context we have.
            stoleBlob = true; 
            HttpListenerContext httpContext = null; 
            NTAuthentication oldContext = null;
            NTAuthentication newContext = null; 
            NTAuthentication context = null;
            AuthenticationSchemes headerScheme = AuthenticationSchemes.None;
            AuthenticationSchemes authenticationScheme = AuthenticationSchemes;
            try 
            {
                // Take over handling disconnects for now. 
                if (disconnectResult != null && !disconnectResult.StartOwningDisconnectHandling()) 
                {
                    // Oops!  Just disconnected just then.  Pretend we didn't see the disconnectResult. 
                    disconnectResult = null;
                }

                // Pick out the old context now.  By default, it'll be removed in the finally, unless context is set somewhere. 
                if (disconnectResult != null)
                { 
                    oldContext = disconnectResult.Session; 
                }
 
                httpContext = new HttpListenerContext(this, memoryBlob);

                AuthenticationSelectorInfo authenticationSelector = m_AuthenticationDelegate;
                if (authenticationSelector != null) 
                {
                    try 
                    { 
                        httpContext.Request.ReleasePins();
                        authenticationScheme = authenticationSelector.Delegate(httpContext.Request); 
                        if (!authenticationSelector.AdvancedAuth &&
                            (authenticationScheme & (AuthenticationSchemes.Negotiate | AuthenticationSchemes.Ntlm | AuthenticationSchemes.Digest)) != 0)
                        {
                            throw m_SecurityException; 
                        }
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() AuthenticationSchemeSelectorDelegate() returned authenticationScheme:" + authenticationScheme); 
                    } 
                    catch (Exception exception)
                    { 
                        if (NclUtilities.IsFatal(exception)) throw;

                        if (Logging.On) Logging.PrintError(Logging.HttpListener, this, "HandleAuthentication", SR.GetString(SR.net_log_listener_delegate_exception, exception));
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() AuthenticationSchemeSelectorDelegate() returned authenticationScheme:" + authenticationScheme); 
                        SendError(requestId, HttpStatusCode.InternalServerError, null);
                        httpContext.Close(); 
                        return null; 
                    }
                } 
                else
                {
                    // We didn't give the request to the user yet, so we haven't lost control of the unmanaged blob and can
                    // continue to reuse the buffer. 
                    stoleBlob = false;
                } 
 
                // Then figure out what scheme they're trying (if any are allowed)
                int index = -1; 
                if (authorizationHeader != null && (authenticationScheme & ~AuthenticationSchemes.Anonymous) != AuthenticationSchemes.None)
                {
                    // Find the end of the scheme name.  Trust that HTTP.SYS parsed out just our header ok.
                    for (index = 0; index < authorizationHeader.Length; index++) 
                    {
                        if (authorizationHeader[index] == ' ' || authorizationHeader[index] == '\t' || 
                            authorizationHeader[index] == '\r' || authorizationHeader[index] == '\n') 
                        {
                            break; 
                        }
                    }

                    // Currently only allow one Authorization scheme/header per request. 
                    if (index < authorizationHeader.Length)
                    { 
                        if ((authenticationScheme & AuthenticationSchemes.Negotiate) != AuthenticationSchemes.None && 
                            string.Compare(authorizationHeader, 0, NegotiateClient.AuthType, 0, index, StringComparison.OrdinalIgnoreCase) == 0)
                        { 
                            headerScheme = AuthenticationSchemes.Negotiate;
                        }
                        else if ((authenticationScheme & AuthenticationSchemes.Ntlm) != AuthenticationSchemes.None &&
                            string.Compare(authorizationHeader, 0, NtlmClient.AuthType, 0, index, StringComparison.OrdinalIgnoreCase) == 0) 
                        {
                            headerScheme = AuthenticationSchemes.Ntlm; 
                        } 
                        else if ((authenticationScheme & AuthenticationSchemes.Digest) != AuthenticationSchemes.None &&
                            string.Compare(authorizationHeader, 0, DigestClient.AuthType, 0, index, StringComparison.OrdinalIgnoreCase) == 0) 
                        {
                            headerScheme = AuthenticationSchemes.Digest;
                        }
                        else if ((authenticationScheme & AuthenticationSchemes.Basic) != AuthenticationSchemes.None && 
                            string.Compare(authorizationHeader, 0, BasicClient.AuthType, 0, index, StringComparison.OrdinalIgnoreCase) == 0)
                        { 
                            headerScheme = AuthenticationSchemes.Basic; 
                        }
                        else 
                        {
                            if (Logging.On) Logging.PrintWarning(Logging.HttpListener, this, "HandleAuthentication", SR.GetString(SR.net_log_listener_unsupported_authentication_scheme, authorizationHeader , authenticationScheme));
                        }
                    } 
                }
 
                // httpError holds the error we will return if an Authorization header is present but can't be authenticated 
                HttpStatusCode httpError = HttpStatusCode.InternalServerError;
                bool error = false; 

                // See if we found an acceptable auth header
                if (headerScheme == AuthenticationSchemes.None)
                { 
                    if (Logging.On) Logging.PrintWarning(Logging.HttpListener, this, "HandleAuthentication", SR.GetString(SR.net_log_listener_unmatched_authentication_scheme, ValidationHelper.ToString(authenticationScheme), (authorizationHeader == null ? "" : authorizationHeader)));
 
                    // If anonymous is allowed, just return the context.  Otherwise go for the 401. 
                    if ((authenticationScheme & AuthenticationSchemes.Anonymous) != AuthenticationSchemes.None)
                    { 
                        if (!stoleBlob)
                        {
                            stoleBlob = true;
                            httpContext.Request.ReleasePins(); 
                        }
                        return httpContext; 
                    } 

                    httpError = HttpStatusCode.Unauthorized; 
                    httpContext.Request.DetachBlob(memoryBlob);
                    httpContext.Close();
                    httpContext = null;
                } 
                else
                { 
                    // Perform Authentication 
                    byte[] bytes = null;
                    byte[] decodedOutgoingBlob = null; 
                    string outBlob = null;

                    // Find the beginning of the blob.  Trust that HTTP.SYS parsed out just our header ok.
                    for (index++; index < authorizationHeader.Length; index++) 
                    {
                        if (authorizationHeader[index] != ' ' && authorizationHeader[index] != '\t' && 
                            authorizationHeader[index] != '\r' && authorizationHeader[index] != '\n') 
                        {
                            break; 
                        }
                    }
                    string inBlob = index < authorizationHeader.Length ? authorizationHeader.Substring(index) : "";
 
                    IPrincipal principal = null;
                    SecurityStatus statusCodeNew; 
                    GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() Performing Authentication headerScheme:" + ValidationHelper.ToString(headerScheme)); 
                    switch (headerScheme)
                    { 
                        case AuthenticationSchemes.Digest:
                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() package:WDigest headerScheme:" + headerScheme);

                            // WDigest had some weird behavior.  This is what I have discovered: 
                            // Local accounts don't work, only domain accounts.  The domain (i.e. REDMOND) is implied.  Not sure how it is chosen.
                            // If the domain is specified and the credentials are correct, it works.  If they're not (domain, username or password): 
                            //      AcceptSecurityContext (GetOutgoingDigestBlob) returns success but with a bogus 4k challenge, and 
                            //      QuerySecurityContextToken (GetContextToken) fails with NoImpersonation.
                            // If the domain isn't specified, AcceptSecurityContext returns NoAuthenticatingAuthority for a bad username, 
                            // and LogonDenied for a bad password.

                            // Also interesting is that WDigest requires us to keep a reference to the previous context, but fails if we
                            // actually pass it in!  (It't ok to pass it in for the first request, but not if nc > 1.)  For Whidbey, 
                            // we create a new context and associate it with the connection, just like NTLM, but instead of using it for
                            // the next request on the connection, we always create a new context and swap the old one out.  As long 
                            // as we keep the old one around until after we authenticate with the new one, it works.  For this reason, 
                            // we also keep these contexts around past the lifetime of the connection, so that KeepAlive=false works.
                            context = new NTAuthentication(true, NegotiationInfoClass.WDigest, null, ContextFlags.Connection); 

                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() verb:" + verb + " context.IsValidContext:" + context.IsValidContext.ToString());
                            outBlob = context.GetOutgoingDigestBlob(inBlob, verb, null, Realm, false, false, out statusCodeNew);
                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() GetOutgoingDigestBlob() returned IsCompleted:" + context.IsCompleted + " statusCodeNew:" + statusCodeNew + " outBlob:[" + outBlob + "]"); 

                            // WDigest bug: sometimes when AcceptSecurityContext returns success, it provides a bogus, empty 4k buffer. 
                            // Ignore it.  (Should find out what's going on here from WDigest people.) 
                            if (statusCodeNew == SecurityStatus.OK)
                            { 
                                outBlob = null;
                            }

                            if (context.IsValidContext) 
                            {
                                SafeCloseHandle userContext = null; 
                                try 
                                {
                                    userContext = context.GetContextToken(out statusCodeNew); 
                                    GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() GetContextToken() returned:" + statusCodeNew.ToString());
                                    if (statusCodeNew != SecurityStatus.OK)
                                    {
                                         httpError = HttpStatusFromSecurityStatus(statusCodeNew); 
                                    }
                                    else if (userContext == null) 
                                    { 
                                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() error: GetContextToken() returned:null statusCodeNew:" + statusCodeNew.ToString());
                                        httpError = HttpStatusCode.Unauthorized; 
                                    }
                                    else
                                    {
                                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() creating new WindowsIdentity() from userContext:" + userContext.DangerousGetHandle().ToString("x8")); 
                                        principal = new WindowsPrincipal(CreateWindowsIdentity(userContext.DangerousGetHandle(), DigestClient.AuthType, WindowsAccountType.Normal, true));
                                    } 
                                } 
                                finally {
                                    if (userContext!=null) { 
                                        userContext.Close();
                                    }
                                }
 
                                newContext = context;
 
                                if (outBlob != null) 
                                {
                                    challenge = DigestClient.AuthType + " " + outBlob; 
                                }
                            }
                            else
                            { 
                                httpError = HttpStatusFromSecurityStatus(statusCodeNew);
                            } 
                            break; 

                        case AuthenticationSchemes.Negotiate: 
                        case AuthenticationSchemes.Ntlm:
                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() headerScheme:" + headerScheme);
                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() returned context#" + ValidationHelper.HashString(oldContext) + " for connectionId:" + connectionId);
 
                            string package = headerScheme == AuthenticationSchemes.Ntlm ? NtlmClient.AuthType : NegotiateClient.AuthType;
                            if (oldContext != null && oldContext.Package == package) 
                            { 
                                context = oldContext;
                            } 
                            else
                            {
                                context = new NTAuthentication(true, package, null, ContextFlags.Connection);
                            } 

                            try 
                            { 
                                bytes = Convert.FromBase64String(inBlob);
                            } 
                            catch (FormatException)
                            {
                                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() FromBase64String threw a FormatException.");
                                httpError = HttpStatusCode.BadRequest; 
                                error = true;
                            } 
                            if (!error) 
                            {
                                decodedOutgoingBlob = context.GetOutgoingBlob(bytes, false, out statusCodeNew); 
                                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() GetOutgoingBlob() returned IsCompleted:" + context.IsCompleted + " statusCodeNew:" + statusCodeNew);
                                error = !context.IsValidContext;
                                if (error)
                                { 
                                    // Bug #474228: SSPI Workaround
                                    // If a client sends up a blob on the initial request, Negotiate returns SEC_E_INVALID_HANDLE 
                                    // when it should return SEC_E_INVALID_TOKEN. 
                                    if (statusCodeNew == SecurityStatus.InvalidHandle && oldContext == null && bytes != null && bytes.Length > 0)
                                    { 
                                        statusCodeNew = SecurityStatus.InvalidToken;
                                    }

                                    httpError = HttpStatusFromSecurityStatus(statusCodeNew); 
                                }
                            } 
 
                            if (decodedOutgoingBlob!=null) {
                                outBlob = Convert.ToBase64String(decodedOutgoingBlob); 
                            }

                            if (!error)
                            { 
                                if (context.IsCompleted) {
                                    SafeCloseHandle userContext = null; 
                                    try 
                                    {
                                        userContext = context.GetContextToken(out statusCodeNew); 
                                        if (statusCodeNew != SecurityStatus.OK)
                                        {
                                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() GetContextToken() failed with statusCodeNew:" + statusCodeNew.ToString());
                                            httpError = HttpStatusFromSecurityStatus(statusCodeNew); 
                                        }
                                        else 
                                        { 
                                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() creating new WindowsIdentity() from userContext:" + userContext.DangerousGetHandle().ToString("x8"));
                                            WindowsPrincipal windowsPrincipal = new WindowsPrincipal(CreateWindowsIdentity(userContext.DangerousGetHandle(), context.ProtocolName, WindowsAccountType.Normal, true)); 
                                            principal = windowsPrincipal;

                                            // if appropriate, cache this credential on this connection
                                            if (UnsafeConnectionNtlmAuthentication && context.ProtocolName == NegotiationInfoClass.NTLM) 
                                            {
                                                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() inserting principal#" + ValidationHelper.HashString(principal) + " for connectionId:" + connectionId); 
 
                                                // We may need to call WaitForDisconnect.
                                                if (disconnectResult == null) 
                                                {
                                                    RegisterForDisconnectNotification(connectionId, ref disconnectResult);
                                                }
                                                if (disconnectResult != null) 
                                                {
                                                    lock (DisconnectResults.SyncRoot) 
                                                    { 
                                                        if (UnsafeConnectionNtlmAuthentication)
                                                        { 
                                                            disconnectResult.AuthenticatedConnection = windowsPrincipal;
                                                        }
                                                    }
                                                } 
                                                else
                                                { 
                                                    // Registration failed - UnsafeConnectionNtlmAuthentication ignored. 
                                                    GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() RegisterForDisconnectNotification() failed.");
                                                } 
                                            }
                                        }
                                    }
                                    finally { 
                                        if (userContext!=null) {
                                            userContext.Close(); 
                                        } 
                                    }
                                } 
                                else
                                {
                                    // auth incomplete
                                    newContext = context; 

                                    challenge = (headerScheme==AuthenticationSchemes.Ntlm ? NtlmClient.AuthType : NegotiateClient.AuthType); 
                                    if (!String.IsNullOrEmpty(outBlob)) 
                                    {
                                        challenge += " " + outBlob; 
                                    }
                                }
                            }
                            break; 

                        case AuthenticationSchemes.Basic: 
                            try 
                            {
                                bytes = Convert.FromBase64String(inBlob); 

                                inBlob = WebHeaderCollection.HeaderEncoding.GetString(bytes, 0, bytes.Length);
                                index = inBlob.IndexOf(':');
 
                                if (index!=-1) {
                                    string userName = inBlob.Substring(0, index); 
                                    string password = inBlob.Substring(index+1); 

                                    GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() basic identity found, userName:" + userName); 
                                    principal = new GenericPrincipal(new HttpListenerBasicIdentity(userName, password), null);
                                }
                                else
                                { 
                                    httpError = HttpStatusCode.BadRequest;
                                } 
                            } 
                            catch (FormatException)
                            { 
                                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() FromBase64String threw a FormatException.");
                            }
                            break;
                    } 

                    if (principal != null) 
                    { 
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() got principal:" + ValidationHelper.ToString(principal) + " principal.Identity.Name:" + ValidationHelper.ToString(principal.Identity.Name) + " creating request");
                        httpContext.SetIdentity(principal, outBlob); 
                    }
                    else
                    {
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() handshake has failed"); 
                        if(Logging.On)Logging.PrintWarning(Logging.HttpListener, this, "HandleAuthentication", SR.GetString(SR.net_log_listener_create_valid_identity_failed));
                        httpContext.Request.DetachBlob(memoryBlob); 
                        httpContext.Close(); 
                        httpContext = null;
                    } 
                }

                // if we're not giving a request to the application, we need to send an error
                ArrayList challenges = null; 
                if (httpContext == null)
                { 
                    // If we already have a challenge, just use it.  Otherwise put a challenge for each acceptable scheme. 
                    if (challenge != null)
                    { 
                        AddChallenge(ref challenges, challenge);
                    }
                    else
                    { 
                        // We're starting over.  Any context SSPI might have wanted us to keep is useless.
                        if (newContext != null) 
                        { 
                            if (newContext == context)
                            { 
                                context = null;
                            }

                            if (newContext != oldContext) 
                            {
                                NTAuthentication toClose = newContext; 
                                newContext = null; 
                                toClose.CloseContext();
                            } 
                            else
                            {
                                newContext = null;
                            } 
                        }
 
                        // If we're sending something besides 401, do it here. 
                        if (httpError != HttpStatusCode.Unauthorized)
                        { 
                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() failed context#" + ValidationHelper.HashString(context) + " for connectionId:" + connectionId + " because of error:" + httpError.ToString());
                            SendError(requestId, httpError, null);
                            return null;
                        } 

                        challenges = BuildChallenge(authenticationScheme, connectionId, out newContext); 
                    } 
                }
 
                // Check if we need to call WaitForDisconnect, because if we do and it fails, we want to send a 500 instead.
                if (disconnectResult == null && newContext != null)
                {
                    RegisterForDisconnectNotification(connectionId, ref disconnectResult); 

                    // Failed - send 500. 
                    if (disconnectResult == null) 
                    {
                        if (newContext != null) 
                        {
                            if (newContext == context)
                            {
                                context = null; 
                            }
 
                            if (newContext != oldContext) 
                            {
                                NTAuthentication toClose = newContext; 
                                newContext = null;
                                toClose.CloseContext();
                            }
                            else 
                            {
                                newContext = null; 
                            } 
                        }
 
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() failed context#" + ValidationHelper.HashString(context) + " for connectionId:" + connectionId + " because of failed HttpWaitForDisconnect");
                        SendError(requestId, HttpStatusCode.InternalServerError, null);
                        httpContext.Request.DetachBlob(memoryBlob);
                        httpContext.Close(); 
                        return null;
                    } 
                } 

                // Update Session if necessary. 
                if (oldContext != newContext)
                {
                    if (oldContext == context)
                    { 
                        // Prevent the finally from closing this twice.
                        context = null; 
                    } 

                    NTAuthentication toClose = oldContext; 
                    oldContext = newContext;
                    disconnectResult.Session = newContext;

                    if (toClose != null) 
                    {
                        // Save digest context in digest cache, we may need it later because of 
                        // subsequest responses to the same req on the same/diff connection 
                        if ((authenticationScheme & AuthenticationSchemes.Digest) != 0)
                        { 
                            SaveDigestContext(toClose);
                        }
                        else
                        { 
                            toClose.CloseContext();
                        } 
                    } 
                }
 
                // Send the 401 here.
                if (httpContext == null)
                {
                    SendError(requestId, challenges != null && challenges.Count > 0 ? HttpStatusCode.Unauthorized : HttpStatusCode.Forbidden, challenges); 
                    GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() SendUnauthorized(Scheme:" + authenticationScheme + ")");
                    return null; 
                } 

                if (!stoleBlob) 
                {
                    stoleBlob = true;
                    httpContext.Request.ReleasePins();
                } 
                return httpContext;
            } 
            catch 
            {
                if (httpContext != null) 
                {
                    httpContext.Request.DetachBlob(memoryBlob);
                    httpContext.Close();
                } 
                if (newContext != null)
                { 
                    if (newContext == context) 
                    {
                        // Prevent the finally from closing this twice. 
                        context = null;
                    }

                    if (newContext != oldContext) 
                    {
                        NTAuthentication toClose = newContext; 
                        newContext = null; 
                        toClose.CloseContext();
                    } 
                    else
                    {
                        newContext = null;
                    } 
                }
                throw; 
            } 
            finally
            { 
                try
                {
                    // Clean up the previous context if necessary.
                    if (oldContext != null && oldContext != newContext) 
                    {
                        // Clear out Session if it wasn't already. 
                        if (newContext == null && disconnectResult != null) 
                        {
                            disconnectResult.Session = null; 
                        }

                        // Save digest context in digest cache, we may need it later because of
                        // subsequest responses to the same req on the same/diff connection 

                        if ((authenticationScheme & AuthenticationSchemes.Digest) != 0) 
                        { 
                            SaveDigestContext(oldContext);
                        } 
                        else
                        {
                            oldContext.CloseContext();
                        } 
                    }
 
                    // Delete any context created but not stored. 
                    if (context != null && oldContext != context && newContext != context)
                    { 
                        context.CloseContext();
                    }
                }
                finally 
                {
                    // Check if the connection got deleted while in this method, and clear out the hashtables if it did. 
                    // In a nested finally because if this doesn't happen, we leak. 
                    if (disconnectResult != null)
                    { 
                        disconnectResult.FinishOwningDisconnectHandling();
                    }
                }
            } 
        }
 
        private static void AddChallenge(ref ArrayList challenges, string challenge) 
        {
            if (challenge!=null) { 
                challenge = challenge.Trim();
                if (challenge.Length>0) {
                    GlobalLog.Print("HttpListener:AddChallenge() challenge:" + challenge);
                    if (challenges == null) 
                    {
                        challenges = new ArrayList(4); 
                    } 
                    challenges.Add(challenge);
                } 
            }
        }

        private ArrayList BuildChallenge(AuthenticationSchemes authenticationScheme, ulong connectionId, out NTAuthentication newContext) 
        {
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::BuildChallenge()  authenticationScheme:" + authenticationScheme.ToString()); 
            ArrayList challenges = null; 
            newContext = null;
 
            if ((authenticationScheme & AuthenticationSchemes.Negotiate) != 0)
            {
                AddChallenge(ref challenges, NegotiateClient.AuthType);
            } 

            if ((authenticationScheme & AuthenticationSchemes.Ntlm) != 0) 
            { 
                AddChallenge(ref challenges, NtlmClient.AuthType);
            } 

            if ((authenticationScheme & AuthenticationSchemes.Digest) != 0)
            {
                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::BuildChallenge() package:WDigest"); 

                NTAuthentication context = null; 
                try 
                {
                    context = new NTAuthentication(true, NegotiationInfoClass.WDigest, null, ContextFlags.Connection); 
                    SecurityStatus statusCode;
                    string outBlob = context.GetOutgoingDigestBlob(null, null, null, Realm, false, false, out statusCode);

                    GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::BuildChallenge() GetOutgoingDigestBlob() returned IsCompleted:" + context.IsCompleted + " statusCode:" + statusCode + " outBlob:[" + outBlob + "]"); 

                    if (context.IsValidContext) 
                    { 
                        newContext = context;
                    } 

                    AddChallenge(ref challenges, DigestClient.AuthType + (string.IsNullOrEmpty(outBlob) ? "" : " " + outBlob));
                }
                finally 
                {
                    if (context != null && newContext != context) 
                    { 
                        context.CloseContext();
                    } 
                }
            }

            if ((authenticationScheme & AuthenticationSchemes.Basic) != 0) 
            {
                AddChallenge(ref challenges, BasicClient.AuthType + " realm=\"" + Realm + "\""); 
            } 

            return challenges; 
        }

        private void RegisterForDisconnectNotification(ulong connectionId, ref DisconnectAsyncResult disconnectResult)
        { 
            GlobalLog.Assert(disconnectResult == null, "HttpListener#{0}::RegisterForDisconnectNotification()|Called with a disconnectResult.", ValidationHelper.HashString(this));
 
            try 
            {
                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::RegisterForDisconnectNotification() calling UnsafeNclNativeMethods.HttpApi.HttpWaitForDisconnect"); 

                DisconnectAsyncResult result = new DisconnectAsyncResult(this, connectionId);

                EnsureBoundHandle(); 
                uint statusCode = UnsafeNclNativeMethods.HttpApi.HttpWaitForDisconnect(
                    m_RequestQueueHandle, 
                    connectionId, 
                    result.NativeOverlapped);
 
                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::RegisterForDisconnectNotification() call to UnsafeNclNativeMethods.HttpApi.HttpWaitForDisconnect returned:" + statusCode);

                if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS ||
                    statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) 
                {
                    // Need to make sure it's going to get returned before adding it to the hash.  That way it'll be handled 
                    // correctly in HandleAuthentication's finally. 
                    disconnectResult = result;
                    DisconnectResults[connectionId] = disconnectResult; 
                }
            }
            catch (Win32Exception exception)
            { 
                uint statusCode = (uint) exception.NativeErrorCode;
                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::RegisterForDisconnectNotification() call to UnsafeNclNativeMethods.HttpApi.HttpWaitForDisconnect threw.  statusCode:" + statusCode); 
            } 
        }
 
        private void SendError(ulong requestId, HttpStatusCode httpStatusCode, ArrayList challenges)
        {
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::SendInternalError() requestId:" + ValidationHelper.ToString(requestId));
            UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE httpResponse = new UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE(); 
            httpResponse.Version = new UnsafeNclNativeMethods.HttpApi.HTTP_VERSION();
            httpResponse.Version.MajorVersion = (ushort)1; 
            httpResponse.Version.MinorVersion = (ushort)1; 
            httpResponse.StatusCode = (ushort)httpStatusCode;
            string statusDescription = HttpListenerResponse.GetStatusDescription((int)httpStatusCode); 
            uint DataWritten = 0;
            uint statusCode;
            byte[] byteReason = Encoding.Default.GetBytes(statusDescription);
            fixed (byte* pReason = byteReason) 
            {
                httpResponse.pReason = (sbyte*)pReason; 
                httpResponse.ReasonLength = (ushort)byteReason.Length; 

                byte[] byteContentLength = Encoding.Default.GetBytes("0"); 
                fixed (byte* pContentLength = byteContentLength)
                {
                    (&httpResponse.Headers.KnownHeaders)[(int)HttpResponseHeader.ContentLength].pRawValue = (sbyte*)pContentLength;
                    (&httpResponse.Headers.KnownHeaders)[(int)HttpResponseHeader.ContentLength].RawValueLength = (ushort)byteContentLength.Length; 

                    httpResponse.Headers.UnknownHeaderCount = checked((ushort) (challenges == null ? 0 : challenges.Count)); 
                    GCHandle[] challengeHandles = null; 
                    UnsafeNclNativeMethods.HttpApi.HTTP_UNKNOWN_HEADER[] headersArray = null;
                    GCHandle headersArrayHandle = new GCHandle(); 
                    GCHandle wwwAuthenticateHandle = new GCHandle();
                    if (httpResponse.Headers.UnknownHeaderCount > 0)
                    {
                        challengeHandles = new GCHandle[httpResponse.Headers.UnknownHeaderCount]; 
                        headersArray = new UnsafeNclNativeMethods.HttpApi.HTTP_UNKNOWN_HEADER[httpResponse.Headers.UnknownHeaderCount];
                    } 
 
                    try
                    { 
                        if (httpResponse.Headers.UnknownHeaderCount > 0)
                        {
                            headersArrayHandle = GCHandle.Alloc(headersArray, GCHandleType.Pinned);
                            httpResponse.Headers.pUnknownHeaders = (UnsafeNclNativeMethods.HttpApi.HTTP_UNKNOWN_HEADER*) Marshal.UnsafeAddrOfPinnedArrayElement(headersArray, 0); 
                            wwwAuthenticateHandle = GCHandle.Alloc(s_WwwAuthenticateBytes, GCHandleType.Pinned);
                            sbyte* wwwAuthenticate = (sbyte*) Marshal.UnsafeAddrOfPinnedArrayElement(s_WwwAuthenticateBytes, 0); 
 
                            for (int i = 0; i < challengeHandles.Length; i++)
                            { 
                                byte[] byteChallenge = Encoding.Default.GetBytes((string) challenges[i]);
                                challengeHandles[i] = GCHandle.Alloc(byteChallenge, GCHandleType.Pinned);
                                headersArray[i].pName = wwwAuthenticate;
                                headersArray[i].NameLength = (ushort) s_WwwAuthenticateBytes.Length; 
                                headersArray[i].pRawValue = (sbyte*) Marshal.UnsafeAddrOfPinnedArrayElement(byteChallenge, 0);
                                headersArray[i].RawValueLength = checked((ushort) byteChallenge.Length); 
                            } 
                        }
 
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::SendInternalError() calling UnsafeNclNativeMethods.HttpApi.HttpSendHtthttpResponse");
                        statusCode =
                            UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse(
                                m_RequestQueueHandle, 
                                requestId,
                                0, 
                                &httpResponse, 
                                null,
                                &DataWritten, 
                                SafeLocalFree.Zero,
                                0,
                                null,
                                null ); 
                    }
                    finally 
                    { 
                        if (headersArrayHandle.IsAllocated)
                        { 
                            headersArrayHandle.Free();
                        }
                        if (wwwAuthenticateHandle.IsAllocated)
                        { 
                            wwwAuthenticateHandle.Free();
                        } 
                        if (challengeHandles != null) 
                        {
                            for (int i = 0; i < challengeHandles.Length; i++) 
                            {
                                if (challengeHandles[i].IsAllocated)
                                {
                                    challengeHandles[i].Free(); 
                                }
                            } 
                        } 
                    }
                } 
            }
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::SendInternalError() call to UnsafeNclNativeMethods.HttpApi.HttpSendHttpResponse returned:" + statusCode);
            if (statusCode!=UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS) {
                // if we fail to send a 401 something's seriously wrong, abort the request 
                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() SendUnauthorized() returned:" + statusCode);
                HttpListenerContext.CancelRequest(m_RequestQueueHandle, requestId); 
            } 
        }
 
        internal void CheckDisposed() {
            if (m_State==State.Closed) {
                throw new ObjectDisposedException(this.GetType().FullName);
            } 
        }
 
        // This only works for context-destroying errors. 
        private HttpStatusCode HttpStatusFromSecurityStatus(SecurityStatus status)
        { 
            if (NclUtilities.IsCredentialFailure(status))
            {
                return HttpStatusCode.Unauthorized;
            } 
            if (NclUtilities.IsClientFault(status))
            { 
                return HttpStatusCode.BadRequest; 
            }
            return HttpStatusCode.InternalServerError; 
        }

        enum State {
            Stopped, 
            Started,
            Closed, 
        } 

        private const int DigestLifetimeSeconds = 300; 
        private const int MaximumDigests = 1024;  // Must be a power of two.
        private const int MinimumDigestLifetimeSeconds = 10;

        private struct DigestContext 
        {
            internal NTAuthentication context; 
            internal int timestamp; 
        }
 
        private DigestContext[] m_SavedDigests;
        private ArrayList m_ExtraSavedDigests;
        private ArrayList m_ExtraSavedDigestsBaking;
        private int m_ExtraSavedDigestsTimestamp; 
        private int m_NewestContext;
        private int m_OldestContext; 
 
        private void SaveDigestContext(NTAuthentication digestContext)
        { 
            if (m_SavedDigests == null)
            {
                Interlocked.CompareExchange(ref m_SavedDigests, new DigestContext[MaximumDigests], null);
            } 

            // We want to actually close the contexts outside the lock. 
            NTAuthentication oldContext = null; 
            ArrayList digestsToClose = null;
            lock (m_SavedDigests) 
            {
                // If we're stopped, just throw it away.
                if (!IsListening)
                { 
                    digestContext.CloseContext();
                    return; 
                } 

                int now = ((now = Environment.TickCount) == 0 ? 1 : now); 

                m_NewestContext = (m_NewestContext + 1) & (MaximumDigests - 1);

                int oldTimestamp = m_SavedDigests[m_NewestContext].timestamp; 
                oldContext = m_SavedDigests[m_NewestContext].context;
                m_SavedDigests[m_NewestContext].timestamp = now; 
                m_SavedDigests[m_NewestContext].context = digestContext; 

                // May need to move this up. 
                if (m_OldestContext == m_NewestContext)
                {
                    m_OldestContext = (m_NewestContext + 1) & (MaximumDigests - 1);
                } 

                // Delete additional contexts older than five minutes. 
                while (unchecked(now - m_SavedDigests[m_OldestContext].timestamp) >= DigestLifetimeSeconds && m_SavedDigests[m_OldestContext].context != null) 
                {
                    if (digestsToClose == null) 
                    {
                        digestsToClose = new ArrayList();
                    }
                    digestsToClose.Add(m_SavedDigests[m_OldestContext].context); 
                    m_SavedDigests[m_OldestContext].context = null;
                    m_OldestContext = (m_OldestContext + 1) & (MaximumDigests - 1); 
                } 

                // If the old context is younger than 10 seconds, put it in the backup pile. 
                if (oldContext != null && unchecked(now - oldTimestamp) <= MinimumDigestLifetimeSeconds * 1000)
                {
                    // Use a two-tier ArrayList system to guarantee each entry lives at least 10 seconds.
                    if (m_ExtraSavedDigests == null || 
                        unchecked(now - m_ExtraSavedDigestsTimestamp) > MinimumDigestLifetimeSeconds * 1000)
                    { 
                        digestsToClose = m_ExtraSavedDigestsBaking; 
                        m_ExtraSavedDigestsBaking = m_ExtraSavedDigests;
                        m_ExtraSavedDigestsTimestamp = now; 
                        m_ExtraSavedDigests = new ArrayList();
                    }
                    m_ExtraSavedDigests.Add(oldContext);
                    oldContext = null; 
                }
            } 
 
            if (oldContext != null)
            { 
                oldContext.CloseContext();
            }
            if (digestsToClose != null)
            { 
                for (int i = 0; i < digestsToClose.Count; i++)
                { 
                    ((NTAuthentication)digestsToClose[i]).CloseContext(); 
                }
            } 
        }

        private void ClearDigestCache()
        { 
            if (m_SavedDigests == null)
            { 
                return; 
            }
 
            ArrayList[] toClose = new ArrayList[3];
            lock (m_SavedDigests)
            {
                toClose[0] = m_ExtraSavedDigestsBaking; 
                m_ExtraSavedDigestsBaking = null;
                toClose[1] = m_ExtraSavedDigests; 
                m_ExtraSavedDigests = null; 

                m_NewestContext = 0; 
                m_OldestContext = 0;

                toClose[2] = new ArrayList();
                for (int i = 0; i < MaximumDigests; i++) 
                {
                    if (m_SavedDigests[i].context != null) 
                    { 
                        toClose[2].Add(m_SavedDigests[i].context);
                        m_SavedDigests[i].context = null; 
                    }
                    m_SavedDigests[i].timestamp = 0;
                }
            } 

            for (int j = 0; j < toClose.Length; j++) 
            { 
                if (toClose[j] != null)
                { 
                    for (int k = 0; k < toClose[j].Count; k++)
                    {
                        ((NTAuthentication) toClose[j][k]).CloseContext();
                    } 
                }
            } 
        } 

        class DisconnectAsyncResult : IAsyncResult { 
            private static readonly IOCompletionCallback s_IOCallback = new IOCompletionCallback(WaitCallback);

            private ulong m_ConnectionId;
            private HttpListener m_HttpListener; 
            NativeOverlapped* m_NativeOverlapped;
            private int m_OwnershipState;   // 0 = normal, 1 = in HandleAuthentication(), 2 = disconnected, 3 = cleaned up 
 
            private WindowsPrincipal m_AuthenticatedConnection;
            private NTAuthentication m_Session; 

            internal const string NTLM = "NTLM";

            internal NativeOverlapped* NativeOverlapped{ 
                get{
                    return m_NativeOverlapped; 
                } 
            }
 
            public object AsyncState {
                get {
                    throw ExceptionHelper.PropertyNotImplementedException;
                } 
            }
            public WaitHandle AsyncWaitHandle { 
                get { 
                    throw ExceptionHelper.PropertyNotImplementedException;
                } 
            }
            public bool CompletedSynchronously {
                get {
                    throw ExceptionHelper.PropertyNotImplementedException; 
                }
            } 
            public bool IsCompleted { 
                get {
                    throw ExceptionHelper.PropertyNotImplementedException; 
                }
            }

            internal unsafe DisconnectAsyncResult(HttpListener httpListener, ulong connectionId) { 
                GlobalLog.Print("DisconnectAsyncResult#" + ValidationHelper.HashString(this) + "::.ctor() httpListener#" + ValidationHelper.HashString(httpListener) + " connectionId:" + connectionId);
                m_OwnershipState = 1; 
                m_HttpListener = httpListener; 
                m_ConnectionId = connectionId;
                Overlapped overlapped = new Overlapped(); 
                overlapped.AsyncResult = this;
                // we can call the Unsafe API here, we won't ever call user code
                m_NativeOverlapped = overlapped.UnsafePack(s_IOCallback, null);
                GlobalLog.Print("DisconnectAsyncResult#" + ValidationHelper.HashString(this) + "::.ctor() overlapped#" + ValidationHelper.HashString(overlapped) + " nativeOverlapped:" + ((IntPtr)m_NativeOverlapped).ToString("x")); 
            }
 
            internal bool StartOwningDisconnectHandling() 
            {
                int oldValue; 

                while ((oldValue = Interlocked.CompareExchange(ref m_OwnershipState, 1, 0)) == 2)
                {
                    // Must block until it equals 3 - we must be in the callback right now. 
                    Thread.SpinWait(1);
                } 
 
                GlobalLog.Assert(oldValue != 1, "DisconnectAsyncResult#{0}::HandleDisconnect()|StartOwningDisconnectHandling() called twice.", ValidationHelper.HashString(this));
                return oldValue < 2; 
            }

            internal void FinishOwningDisconnectHandling()
            { 
                // If it got disconnected, run the disconnect code.
                if (Interlocked.CompareExchange(ref m_OwnershipState, 0, 1) == 2) 
                { 
                    HandleDisconnect();
                } 
            }

            private static unsafe void WaitCallback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) {
                GlobalLog.Print("DisconnectAsyncResult::WaitCallback() errorCode:" + errorCode + " numBytes:" + numBytes + " nativeOverlapped:" + ((IntPtr)nativeOverlapped).ToString("x")); 
                // take the DisconnectAsyncResult object from the state
                Overlapped callbackOverlapped = Overlapped.Unpack(nativeOverlapped); 
                DisconnectAsyncResult asyncResult = (DisconnectAsyncResult) callbackOverlapped.AsyncResult; 
                GlobalLog.Print("DisconnectAsyncResult#" + ValidationHelper.HashString(asyncResult) + "::WaitCallback() callbackOverlapped#" + ValidationHelper.HashString(callbackOverlapped) + " m_ConnectionId:" + asyncResult.m_ConnectionId);
                Overlapped.Free(nativeOverlapped); 
                if (Interlocked.Exchange(ref asyncResult.m_OwnershipState, 2) == 0)
                {
                    asyncResult.HandleDisconnect();
                } 
            }
 
            private void HandleDisconnect() 
            {
                GlobalLog.Print("DisconnectAsyncResult#" + ValidationHelper.HashString(this) + "::HandleDisconnect() DisconnectResults#" + ValidationHelper.HashString(m_HttpListener.DisconnectResults) + " removing for m_ConnectionId:" + m_ConnectionId); 
                m_HttpListener.DisconnectResults.Remove(m_ConnectionId);
                if (m_Session != null)
                {
                    if (m_Session.Package == NegotiationInfoClass.WDigest) 
                    {
                        // VSWhidbey #497767 
                        // WDigest doesn't like having the context passed back in on the next request on a connection, but it does want 
                        // the server to keep a reference to it for as long as a client might reuse the nonce.  The heuristic we use is,
                        // keep contexts for five minutes, up to a maximum of 1024, except also keep all contexts at least 10 seconds to avoid 
                        // total DoS (where no handshakes can be completed in time).
                        m_HttpListener.SaveDigestContext(m_Session);
                    }
                    else 
                    {
                        m_Session.CloseContext(); 
                    } 
                }
 
                // Clean up the identity. This is for scenarios where identity was not cleaned up before due to
                // identity caching for unsafe ntlm authentication

                IDisposable identity = m_AuthenticatedConnection == null ? null : m_AuthenticatedConnection.Identity as IDisposable; 
                if ((identity != null) &&
                    (m_AuthenticatedConnection.Identity.AuthenticationType == NTLM) && 
                    (m_HttpListener.UnsafeConnectionNtlmAuthentication)) 
                {
                    identity.Dispose(); 
                }

                int oldValue = Interlocked.Exchange(ref m_OwnershipState, 3);
                GlobalLog.Assert(oldValue == 2, "DisconnectAsyncResult#{0}::HandleDisconnect()|Expected OwnershipState of 2, saw {1}.", ValidationHelper.HashString(this), oldValue); 
            }
 
            internal WindowsPrincipal AuthenticatedConnection 
            {
                get 
                {
                    return m_AuthenticatedConnection;
                }
 
                set
                { 
                    // The previous value can't be disposed because it may be in use by the app. 
                    m_AuthenticatedConnection = value;
                } 
            }

            internal NTAuthentication Session
            { 
                get
                { 
                    return m_Session; 
                }
 
                set
                {
                    m_Session = value;
                } 
            }
        } 
    } 

/*  Proposed Future HTTP Base Classes 
    see \ndp\mb\docs\specs\NetworkFramework\HTTPSYS\ASP.NET\stub.cs

    // System.Net exposes base abstract classes that System.Web will inherit from
 
    public abstract class BaseHttpContext {
        public virtual IPrincipal User { get; set; } 
 
        // it doesn't make sense to make these virtual because we can't override
        // and change the returned type for System.Web or people would break. 
        // the only thing we can do is to declare them normally and hide the
        // base implementation like "public new System.Web.HttpRequest Request"

        public BaseHttpRequest Request { get; } 
        public BaseHttpResponse Response { get; }
 
        // these provide plumbing to make the above two methods callable with a BaseHttpContext reference 

        protected virtual BaseHttpRequest GetRequest(); 
        protected virtual BaseHttpResponse GetResponse();
    }

    public abstract class BaseHttpRequest { 
        public virtual string[] AcceptTypes { get; }
        public virtual Encoding ContentEncoding { get; set; } 
        public virtual string ContentType { get; set; } 
        public virtual NameValueCollection Headers { get; }
        public virtual string HttpMethod { get; } 
        public virtual Stream InputStream { get; }
        public virtual bool IsAuthenticated { get; }
        public virtual bool IsLocal { get; }
        public virtual bool IsSecureConnection { get; } 
        public virtual NameValueCollection QueryString { get; }
        public virtual string RawUrl { get; } 
        public virtual Uri Url { get; } 
        public virtual Uri UrlReferrer { get; }
        public virtual string UserAgent { get; } 
        public virtual string UserHostAddress { get; }
        public virtual string UserHostName { get; }
        public virtual string[] UserLanguages { get; }
 
        // APIs that are in the base class but are new to ASP .NET
 
        public virtual long ContentLengthLong { get; } 
        public virtual bool HasEntityBody { get; }
        public virtual bool KeepAlive { get; } 
        public virtual IPEndPoint RemoteEndPoint { get; }
        public virtual IPEndPoint LocalEndPoint { get; }
    }
 
    public abstract class BaseHttpResponse {
        public virtual void AppendHeader(string name, string value); 
        public virtual void Close(); 
        public virtual Encoding ContentEncoding { get; set; }
        public virtual string ContentType { get; set; } 
        public virtual Stream OutputStream { get; }
        public virtual string RedirectLocation { get; set; }
        public virtual int StatusCode { get; set; }
        public virtual string StatusDescription { get; set; } 

        // APIs that are in the base class but are new to ASP .NET 
 
        public virtual bool KeepAlive { get; set; }
    } 
*/
}


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

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