HttpChannelHelpers.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Channels / HttpChannelHelpers.cs / 3 / HttpChannelHelpers.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------
namespace System.ServiceModel.Channels
{ 
    using System.Collections;
    using System.ServiceModel; 
    using System.ServiceModel.Activation; 
    using System.ServiceModel.Description;
    using System.Collections.Generic; 
    using System.Diagnostics;
    using System.Globalization;
    using System.IO;
    using System.Net; 
    using System.Net.Mime;
    using System.Net.Security; 
    using System.IdentityModel.Claims; 
    using System.IdentityModel.Policy;
    using System.IdentityModel.Selectors; 
    using System.Security.Principal;
    using System.ServiceModel.Diagnostics;
    using System.ServiceModel.Security;
    using System.ServiceModel.Security.Tokens; 
    using System.Text;
    using System.Threading; 
    using System.Web; 
    using System.Web.Hosting;
    using System.Net.Sockets; 
    using System.Xml;
    using System.Runtime.CompilerServices;
    using System.Security;
 
    // abstract out the common functionality of an "HttpInput"
    abstract class HttpInput 
    { 
        const string multipartRelatedMediaType = "multipart/related";
        const string startInfoHeaderParam = "start-info"; 

        BufferManager bufferManager;
        bool isRequest;
        MessageEncoder messageEncoder; 
        IHttpTransportFactorySettings settings;
        bool streamed; 
        WebException webException; 
        Stream inputStream;
 
        protected HttpInput(IHttpTransportFactorySettings settings, bool isRequest)
        {
            this.settings = settings;
            this.bufferManager = settings.BufferManager; 
            this.messageEncoder = settings.MessageEncoderFactory.Encoder;
            this.webException = null; 
            this.isRequest = isRequest; 
            this.inputStream = null;
 

            if (isRequest)
            {
                this.streamed = TransferModeHelper.IsRequestStreamed(settings.TransferMode); 
            }
            else 
            { 
                this.streamed = TransferModeHelper.IsResponseStreamed(settings.TransferMode);
            } 
        }

        internal static HttpInput CreateHttpInput(HttpWebResponse httpWebResponse, IHttpTransportFactorySettings settings)
        { 
            return new WebResponseHttpInput(httpWebResponse, settings);
        } 
 
        internal WebException WebException
        { 
            get { return webException; }
            set { webException = value; }
        }
 
        internal Stream InputStream
        { 
            get 
            {
                if (inputStream == null) 
                {
                    inputStream = GetInputStream();
                }
                return inputStream; 
            }
        } 
 
        // -1 if chunked
        public abstract long ContentLength { get; } 
        protected abstract string ContentType { get; }
        protected abstract bool HasContent { get; }
        protected abstract string SoapActionHeader { get; }
        protected abstract Stream GetInputStream(); 

        void ThrowMaxReceivedMessageSizeExceeded() 
        { 
            if (isRequest)
            { 
                ThrowHttpProtocolException(SR.GetString(SR.MaxReceivedMessageSizeExceeded, settings.MaxReceivedMessageSize), HttpStatusCode.BadRequest);
            }
            else
            { 
                string message = SR.GetString(SR.MaxReceivedMessageSizeExceeded, settings.MaxReceivedMessageSize);
                Exception inner = new QuotaExceededException(message); 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(message, inner)); 
            }
        } 

        Message DecodeBufferedMessage(ArraySegment buffer, Stream inputStream)
        {
            try 
            {
                // if we're chunked, make sure we've consumed the whole body 
                if (ContentLength == -1 && buffer.Count == settings.MaxReceivedMessageSize) 
                {
                    byte[] extraBuffer = new byte[1]; 
                    int extraReceived = inputStream.Read(extraBuffer, 0, 1);
                    if (extraReceived > 0)
                    {
                        ThrowMaxReceivedMessageSizeExceeded(); 
                    }
                } 
 
                try
                { 
                    return messageEncoder.ReadMessage(buffer, bufferManager, ContentType);
                }
                catch (XmlException xmlException)
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new ProtocolException(SR.GetString(SR.MessageXmlProtocolError), xmlException)); 
                } 
            }
            finally 
            {
                inputStream.Close();
            }
        } 

        Message ReadBufferedMessage(Stream inputStream) 
        { 
            ArraySegment messageBuffer = GetMessageBuffer();
            byte[] buffer = messageBuffer.Array; 
            int offset = 0;
            int count = messageBuffer.Count;

            while (count > 0) 
            {
                int bytesRead = inputStream.Read(buffer, offset, count); 
                if (bytesRead == 0) // EOF 
                {
                    if (ContentLength != -1) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                            new ProtocolException(SR.GetString(SR.HttpContentLengthIncorrect)));
                    } 

                    break; 
                } 
                count -= bytesRead;
                offset += bytesRead; 
            }

            return DecodeBufferedMessage(new ArraySegment(buffer, 0, offset), inputStream);
        } 

        Message ReadChunkedBufferedMessage(Stream inputStream) 
        { 
            try
            { 
                return messageEncoder.ReadMessage(inputStream, bufferManager, settings.MaxBufferSize, ContentType);
            }
            catch (XmlException xmlException)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new ProtocolException(SR.GetString(SR.MessageXmlProtocolError), xmlException)); 
            } 
        }
 
        Message ReadStreamedMessage(Stream inputStream)
        {
            MaxMessageSizeStream maxMessageSizeStream = new MaxMessageSizeStream(inputStream, settings.MaxReceivedMessageSize);
 
            Stream drainingStream = new DrainOnCloseStream(maxMessageSizeStream);
            try 
            { 
                return messageEncoder.ReadMessage(drainingStream, settings.MaxBufferSize, ContentType);
            } 
            catch (XmlException xmlException)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new ProtocolException(SR.GetString(SR.MessageXmlProtocolError), xmlException)); 
            }
        } 
 
        protected abstract void AddProperties(Message message);
 
        // makes sure that appropriate HTTP level headers are included in the received Message
        Exception ProcessHttpAddressing(Message message)
        {
            Exception result = null; 
            AddProperties(message);
 
            // check if user is receiving WS-1 messages 
            if (message.Version.Addressing == AddressingVersion.None)
            { 
                bool actionAbsent = false;
                try
                {
                    actionAbsent = (message.Headers.Action == null); 
                }
                catch (XmlException e) 
                { 
                    if (DiagnosticUtility.ShouldTraceInformation)
                    { 
                        DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information);
                    }
                }
                catch (CommunicationException e) 
                {
                    if (DiagnosticUtility.ShouldTraceInformation) 
                    { 
                        DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information);
                    } 
                }

                if (!actionAbsent)
                { 
                    result = new ProtocolException(SR.GetString(SR.HttpAddressingNoneHeaderOnWire,
                        XD.AddressingDictionary.Action.Value)); 
                } 

                bool toAbsent = false; 
                try
                {
                    toAbsent = (message.Headers.To == null);
                } 
                catch (XmlException e)
                { 
                    if (DiagnosticUtility.ShouldTraceInformation) 
                    {
                        DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); 
                    }
                }
                catch (CommunicationException e)
                { 
                    if (DiagnosticUtility.ShouldTraceInformation)
                    { 
                        DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); 
                    }
                } 

                if (!toAbsent)
                {
                    result = new ProtocolException(SR.GetString(SR.HttpAddressingNoneHeaderOnWire, 
                        XD.AddressingDictionary.To.Value));
                } 
                message.Headers.To = message.Properties.Via; 
            }
 
            if (isRequest)
            {
                string action = null;
 
                if (message.Version.Envelope == EnvelopeVersion.Soap11)
                { 
                    action = SoapActionHeader; 
                }
                else if (message.Version.Envelope == EnvelopeVersion.Soap12 && !String.IsNullOrEmpty(ContentType)) 
                {
                    ContentType parsedContentType = new ContentType(ContentType);

                    if (parsedContentType.MediaType == multipartRelatedMediaType && parsedContentType.Parameters.ContainsKey(startInfoHeaderParam)) 
                    {
                        // fix to grab action from start-info as stated in RFC2387 
                        action = new ContentType(parsedContentType.Parameters[startInfoHeaderParam]).Parameters["action"]; 
                    }
                    if (action == null) 
                    {
                        // only if we can't find an action inside start-info
                        action = parsedContentType.Parameters["action"];
                    } 
                }
 
                if (action != null) 
                {
                    action = UrlUtility.UrlDecode(action, Encoding.UTF8); 

                    if (action.Length >= 2 && action[0] == '"' && action[action.Length - 1] == '"')
                    {
                        action = action.Substring(1, action.Length - 2); 
                    }
 
                    if (message.Version.Addressing == AddressingVersion.None) 
                    {
                        message.Headers.Action = action; 
                    }

                    try
                    { 

                        if (action.Length > 0 && string.Compare(message.Headers.Action, action, StringComparison.Ordinal) != 0) 
                        { 
                            result = new ActionMismatchAddressingException(SR.GetString(SR.HttpSoapActionMismatchFault,
                                message.Headers.Action, action), message.Headers.Action, action); 
                        }

                    }
                    catch (XmlException e) 
                    {
                        if (DiagnosticUtility.ShouldTraceInformation) 
                        { 
                            DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information);
                        } 
                    }
                    catch (CommunicationException e)
                    {
                        if (DiagnosticUtility.ShouldTraceInformation) 
                        {
                            DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); 
                        } 
                    }
                } 
            }

            if (DiagnosticUtility.ShouldUseActivity)
            { 
                TraceUtility.TransferFromTransport(message);
            } 
            if (DiagnosticUtility.ShouldTraceInformation) 
            {
                TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.MessageReceived, 
                    MessageTransmitTraceRecord.CreateReceiveTraceRecord(message), this, null, message);
            }
            // MessageLogger doesn't log AddressingVersion.None in the encoder since we want to make sure we log
            // as much of the message as possible. Here we log after stamping the addressing information 
            if (MessageLogger.LoggingEnabled && message.Version.Addressing == AddressingVersion.None)
            { 
                MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportReceive | MessageLoggingSource.LastChance); 
            }
 
            return result;
        }

        void ValidateContentType() 
        {
            if (!HasContent) 
                return; 

            if (string.IsNullOrEmpty(ContentType)) 
            {
                if (MessageLogger.ShouldLogMalformed)
                {
                    MessageLogger.LogMessage(this.InputStream, MessageLoggingSource.Malformed); 
                }
                ThrowHttpProtocolException(SR.GetString(SR.HttpContentTypeHeaderRequired), HttpStatusCode.UnsupportedMediaType, HttpChannelUtilities.StatusDescriptionStrings.HttpContentTypeMissing); 
            } 
            if (!messageEncoder.IsContentTypeSupported(ContentType))
            { 
                if (MessageLogger.ShouldLogMalformed)
                {
                    MessageLogger.LogMessage(this.InputStream, MessageLoggingSource.Malformed);
                } 
                string statusDescription = string.Format(CultureInfo.InvariantCulture, HttpChannelUtilities.StatusDescriptionStrings.HttpContentTypeMismatch, ContentType, messageEncoder.ContentType);
                ThrowHttpProtocolException(SR.GetString(SR.ContentTypeMismatch, ContentType, messageEncoder.ContentType), HttpStatusCode.UnsupportedMediaType, statusDescription); 
            } 
        }
 
        public IAsyncResult BeginParseIncomingMessage(AsyncCallback callback, object state)
        {
            bool throwing = true;
            try 
            {
                IAsyncResult result = new ParseMessageAsyncResult(this, callback, state); 
                throwing = false; 
                return result;
            } 
            finally
            {
                if (throwing)
                { 
                    Close();
                } 
            } 
        }
 
        public Message EndParseIncomingMessage(IAsyncResult result, out Exception requestException)
        {
            bool throwing = true;
            try 
            {
                Message message = ParseMessageAsyncResult.End(result, out requestException); 
                throwing = false; 
                return message;
            } 
            finally
            {
                if (throwing)
                { 
                    Close();
                } 
            } 
        }
 
        public Message ParseIncomingMessage(out Exception requestException)
        {
            Message message = null;
            requestException = null; 
            bool throwing = true;
            try 
            { 
                ValidateContentType();
 
                ServiceModelActivity activity = null;
                if (DiagnosticUtility.ShouldUseActivity &&
                    ((ServiceModelActivity.Current == null) ||
                     (ServiceModelActivity.Current.ActivityType != ActivityType.ProcessAction))) 
                {
                    activity = ServiceModelActivity.CreateBoundedActivity(true); 
                } 
                using (activity)
                { 
                    if (DiagnosticUtility.ShouldUseActivity && activity != null)
                    {
                        // Only update the Start identifier if the activity is not null.
                        ServiceModelActivity.Start(activity, SR.GetString(SR.ActivityProcessingMessage, TraceUtility.RetrieveMessageNumber()), ActivityType.ProcessMessage); 
                    }
 
                    if (!this.HasContent) 
                    {
                        if (this.messageEncoder.MessageVersion == MessageVersion.None) 
                        {
                            message = new NullMessage();
                        }
                        else 
                        {
                            return null; 
                        } 
                    }
                    else if (streamed) 
                    {
                        message = ReadStreamedMessage(InputStream);
                    }
                    else if (ContentLength == -1) 
                    {
                        message = ReadChunkedBufferedMessage(InputStream); 
                    } 
                    else
                    { 
                        message = ReadBufferedMessage(InputStream);
                    }

                    requestException = ProcessHttpAddressing(message); 

                    throwing = false; 
                    return message; 
                }
            } 
            finally
            {
                if (throwing)
                { 
                    Close();
                } 
            } 

        } 

        void ThrowHttpProtocolException(string message, HttpStatusCode statusCode)
        {
            ThrowHttpProtocolException(message, statusCode, null); 
        }
 
        void ThrowHttpProtocolException(string message, HttpStatusCode statusCode, string statusDescription) 
        {
            ProtocolException exception = new ProtocolException(message, webException); 
            exception.Data.Add(HttpChannelUtilities.HttpStatusCodeExceptionKey, statusCode);
            if (statusDescription != null && statusDescription.Length > 0)
            {
                exception.Data.Add(HttpChannelUtilities.HttpStatusDescriptionExceptionKey, statusDescription); 
            }
 
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exception); 
        }
 
        protected virtual void Close()
        {
        }
 
        ArraySegment GetMessageBuffer()
        { 
            long count = ContentLength; 
            int bufferSize;
 
            if (count > settings.MaxReceivedMessageSize)
            {
                ThrowMaxReceivedMessageSizeExceeded();
            } 

            bufferSize = (int)count; 
 
            return new ArraySegment(bufferManager.TakeBuffer(bufferSize), 0, bufferSize);
        } 

        class ParseMessageAsyncResult : TraceAsyncResult
        {
            ArraySegment buffer; 
            int count;
            int offset; 
            HttpInput httpInput; 
            Stream inputStream;
            Message message; 
            Exception requestException = null;
            static AsyncCallback onRead = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnRead));

            public ParseMessageAsyncResult(HttpInput httpInput, AsyncCallback callback, object state) 
                : base(callback, state)
            { 
                this.httpInput = httpInput; 
                httpInput.ValidateContentType();
                this.inputStream = httpInput.InputStream; 

                if (!httpInput.HasContent)
                {
                    if (httpInput.messageEncoder.MessageVersion == MessageVersion.None) 
                    {
                        this.message = new NullMessage(); 
                    } 
                    else
                    { 
                        base.Complete(true);
                        return;
                    }
                } 
                else if (httpInput.streamed || httpInput.ContentLength == -1)
                { 
                    if (httpInput.streamed) 
                    {
                        this.message = httpInput.ReadStreamedMessage(inputStream); 
                    }
                    else
                    {
                        this.message = httpInput.ReadChunkedBufferedMessage(inputStream); 
                    }
                } 
 
                if (this.message != null)
                { 
                    this.requestException = httpInput.ProcessHttpAddressing(this.message);
                    base.Complete(true);
                    return;
                } 

                this.buffer = httpInput.GetMessageBuffer(); 
                this.count = this.buffer.Count; 
                this.offset = 0;
 
                IAsyncResult result = inputStream.BeginRead(buffer.Array, offset, count, onRead, this);
                if (result.CompletedSynchronously)
                {
                    if (ContinueReading(inputStream.EndRead(result))) 
                    {
                        base.Complete(true); 
                    } 
                }
            } 

            bool ContinueReading(int bytesRead)
            {
                while (true) 
                {
                    if (bytesRead == 0) // EOF 
                    { 
                        break;
                    } 
                    else
                    {
                        offset += bytesRead;
                        count -= bytesRead; 
                        if (count <= 0)
                        { 
                            break; 
                        }
                        else 
                        {
                            IAsyncResult result = inputStream.BeginRead(buffer.Array, offset, count, onRead, this);
                            if (!result.CompletedSynchronously)
                            { 
                                return false;
                            } 
 
                            bytesRead = inputStream.EndRead(result);
                        } 
                    }
                }

                using (ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity ? ServiceModelActivity.CreateBoundedActivity(true) : null) 
                {
                    if (DiagnosticUtility.ShouldUseActivity) 
                    { 
                        ServiceModelActivity.Start(activity, SR.GetString(SR.ActivityProcessingMessage, TraceUtility.RetrieveMessageNumber()), ActivityType.ProcessMessage);
                    } 
                    this.message = httpInput.DecodeBufferedMessage(new ArraySegment(buffer.Array, 0, offset), inputStream);
                    this.requestException = httpInput.ProcessHttpAddressing(this.message);
                }
                return true; 
            }
 
            static void OnRead(IAsyncResult result) 
            {
                if (result.CompletedSynchronously) 
                    return;

                ParseMessageAsyncResult thisPtr = (ParseMessageAsyncResult)result.AsyncState;
 
                Exception completionException = null;
                bool completeSelf; 
                try 
                {
                    completeSelf = thisPtr.ContinueReading(thisPtr.inputStream.EndRead(result)); 
                }
#pragma warning suppress 56500 // [....], transferring exception to another thread
                catch (Exception e)
                { 
                    if (DiagnosticUtility.IsFatal(e))
                    { 
                        throw; 
                    }
 
                    completeSelf = true;
                    completionException = e;
                }
                if (completeSelf) 
                {
                    thisPtr.Complete(false, completionException); 
                } 
            }
 
            public static Message End(IAsyncResult result, out Exception requestException)
            {
                ParseMessageAsyncResult thisPtr = AsyncResult.End(result);
                requestException = thisPtr.requestException; 
                return thisPtr.message;
            } 
        } 

        class WebResponseHttpInput : HttpInput 
        {
            HttpWebResponse httpWebResponse;
            byte[] preReadBuffer;
 
            public WebResponseHttpInput(HttpWebResponse httpWebResponse, IHttpTransportFactorySettings settings)
                : base(settings, false) 
            { 
                this.httpWebResponse = httpWebResponse;
                if (this.httpWebResponse.ContentLength == -1) 
                {
                    this.preReadBuffer = new byte[1];

                    if (this.httpWebResponse.GetResponseStream().Read(preReadBuffer, 0, 1) == 0) 
                    {
                          this.preReadBuffer = null; 
                    } 
                 }
            } 

            public override long ContentLength
            {
                get 
                {
                    return httpWebResponse.ContentLength; 
                } 
            }
 
            protected override string ContentType
            {
                get
                { 
                    return httpWebResponse.ContentType;
                } 
            } 

            protected override bool HasContent 
            {
                get { return (this.preReadBuffer != null || this.ContentLength > 0); }
            }
 
            protected override string SoapActionHeader
            { 
                get 
                {
                    return httpWebResponse.Headers["SOAPAction"]; 
                }
            }

            protected override void AddProperties(Message message) 
            {
                HttpResponseMessageProperty responseProperty = new HttpResponseMessageProperty(httpWebResponse.Headers); 
                responseProperty.StatusCode = httpWebResponse.StatusCode; 
                responseProperty.StatusDescription = httpWebResponse.StatusDescription;
                message.Properties.Add(HttpResponseMessageProperty.Name, responseProperty); 
                message.Properties.Via = message.Version.Addressing.AnonymousUri;

            }
 
            protected override void Close()
            { 
                try 
                {
                    httpWebResponse.Close(); 
                }
                catch (Exception exception)
                {
                    if (DiagnosticUtility.IsFatal(exception)) 
                        throw;
 
                    DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Error); 
                }
            } 

            protected override Stream GetInputStream()
            {
                if (this.preReadBuffer != null) 
                {
                    return new WebResponseInputStream(httpWebResponse, preReadBuffer); 
                } 
                else
                { 
                    return new WebResponseInputStream(httpWebResponse);
                }
            }
 
            class WebResponseInputStream : DetectEofStream
            { 
                // in order to avoid removing kernel buffers, we throttle our reads. http.sys 
                // deals with this fine, but System.Net doesn't do any such throttling.
                const int maxSocketRead = 64 * 1024; 
                HttpWebResponse webResponse;
                bool responseClosed;

                public WebResponseInputStream(HttpWebResponse httpWebResponse) 
                    : base(httpWebResponse.GetResponseStream())
                { 
                    this.webResponse = httpWebResponse; 
                }
 
                public WebResponseInputStream(HttpWebResponse httpWebResponse, byte[] prereadBuffer)
                    : base(new PreReadStream(httpWebResponse.GetResponseStream(), prereadBuffer))
                {
                    this.webResponse = httpWebResponse; 
                }
 
 
                public override void Close()
                { 
                    base.Close();
                    CloseResponse();
                }
 
                protected override void OnReceivedEof()
                { 
                    base.OnReceivedEof(); 
                    CloseResponse();
                } 

                void CloseResponse()
                {
                    if (responseClosed) 
                    {
                        return; 
                    } 

                    responseClosed = true; 
                    this.webResponse.Close();
                }

                public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) 
                {
                    try 
                    { 
                        return BaseStream.BeginRead(buffer, offset, Math.Min(count, maxSocketRead), callback, state);
                    } 
                    catch (IOException ioException)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateResponseIOException(ioException, TimeoutHelper.FromMilliseconds(this.ReadTimeout)));
                    } 
                    catch (ObjectDisposedException objectDisposedException)
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(objectDisposedException.Message, objectDisposedException)); 
                    }
                    catch (WebException webException) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateResponseWebException(webException, this.webResponse));
                    }
                } 

                public override int EndRead(IAsyncResult result) 
                { 
                    try
                    { 
                        return BaseStream.EndRead(result);
                    }
                    catch (IOException ioException)
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateResponseIOException(ioException, TimeoutHelper.FromMilliseconds(this.ReadTimeout)));
                    } 
                    catch (ObjectDisposedException objectDisposedException) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(objectDisposedException.Message, objectDisposedException)); 
                    }
                    catch (WebException webException)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateResponseWebException(webException, this.webResponse)); 
                    }
                } 
 
                public override int Read(byte[] buffer, int offset, int count)
                { 
                    try
                    {
                        return BaseStream.Read(buffer, offset, Math.Min(count, maxSocketRead));
                    } 
                    catch (ObjectDisposedException objectDisposedException)
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(objectDisposedException.Message, objectDisposedException)); 
                    }
                    catch (IOException ioException) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateResponseIOException(ioException, TimeoutHelper.FromMilliseconds(this.ReadTimeout)));
                    }
                    catch (WebException webException) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateResponseWebException(webException, this.webResponse)); 
                    } 
                }
 

                public override int ReadByte()
                {
                    try 
                    {
                        return BaseStream.ReadByte(); 
                    } 
                    catch (ObjectDisposedException objectDisposedException)
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(objectDisposedException.Message, objectDisposedException));
                    }
                    catch (IOException ioException)
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateResponseIOException(ioException, TimeoutHelper.FromMilliseconds(this.ReadTimeout)));
                    } 
                    catch (WebException webException) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateResponseWebException(webException, this.webResponse)); 
                    }
                }
            }
        } 
    }
 
    // abstract out the common functionality of an "HttpOutput" 
    abstract class HttpOutput
    { 
        const string MIMEVersionHeader = "MIME-Version";

        HttpAbortReason abortReason;
        bool isDisposed; 
        bool isRequest;
        Message message; 
        IHttpTransportFactorySettings settings; 
        byte[] bufferToRecycle;
        BufferManager bufferManager; 
        MessageEncoder messageEncoder;
        bool streamed;
        static WaitCallback onStreamSendTimeout;
        string mtomBoundary; 
        Stream outputStream;
        bool supportsConcurrentIO; 
 
        private HttpOutput(IHttpTransportFactorySettings settings, Message message, bool isRequest, bool supportsConcurrentIO)
        { 
            this.settings = settings;
            this.message = message;
            this.isRequest = isRequest;
            this.bufferManager = settings.BufferManager; 
            this.messageEncoder = settings.MessageEncoderFactory.Encoder;
            if (isRequest) 
            { 
                this.streamed = TransferModeHelper.IsRequestStreamed(settings.TransferMode);
            } 
            else
            {
                this.streamed = TransferModeHelper.IsResponseStreamed(settings.TransferMode);
            } 
            this.supportsConcurrentIO = supportsConcurrentIO;
        } 
 
        protected void Abort()
        { 
            Abort(HttpAbortReason.Aborted);
        }

        public virtual void Abort(HttpAbortReason reason) 
        {
            if (isDisposed) 
            { 
                return;
            } 

            this.abortReason = reason;
            if (DiagnosticUtility.ShouldTraceWarning)
            { 
                TraceUtility.TraceEvent(TraceEventType.Warning,
                                        isRequest ? TraceCode.HttpChannelRequestAborted : TraceCode.HttpChannelResponseAborted, 
                                        this.message); 
            }
 
            CleanupBuffer();
        }

        public void Close() 
        {
            if (isDisposed) 
            { 
                return;
            } 

            if (this.outputStream != null)
            {
                outputStream.Close(); 
            }
 
            CleanupBuffer(); 
        }
 
        void CleanupBuffer()
        {
            if (bufferToRecycle != null)
            { 
                bufferManager.ReturnBuffer(bufferToRecycle);
                bufferToRecycle = null; 
            } 

            isDisposed = true; 
        }

        protected abstract void AddMimeVersion(string version);
        protected abstract void SetContentType(string contentType); 
        protected virtual void SetContentLength(int contentLength)
        { 
        } 

        protected abstract Stream GetOutputStream(); 

        protected virtual bool WillGetOutputStreamCompleteSynchronously
        {
            get { return true; } 
        }
 
        protected virtual IAsyncResult BeginGetOutputStream(AsyncCallback callback, object state) 
        {
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); 
        }

        protected virtual Stream EndGetOutputStream(IAsyncResult result)
        { 
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
        } 
 
        protected virtual bool PrepareHttpSend(Message message)
        { 
            string action = message.Headers.Action;

            if (message.Version.Addressing == AddressingVersion.None)
            { 
                if (MessageLogger.LogMessagesAtTransportLevel)
                { 
                    message.Properties.Add(AddressingProperty.Name, new AddressingProperty(message.Headers)); 
                }
 
                message.Headers.Action = null;
                message.Headers.To = null;
            }
 
            string contentType = null;
 
            if (message.Version == MessageVersion.None) 
            {
                object property = null; 
                if (message.Properties.TryGetValue(HttpResponseMessageProperty.Name, out property))
                {
                    HttpResponseMessageProperty responseProperty = (HttpResponseMessageProperty)property;
                    if (!string.IsNullOrEmpty(responseProperty.Headers[HttpResponseHeader.ContentType])) 
                    {
                        contentType = responseProperty.Headers[HttpResponseHeader.ContentType]; 
                        if (!messageEncoder.IsContentTypeSupported(contentType)) 
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                                new ProtocolException(SR.GetString(SR.ResponseContentTypeNotSupported,
                                contentType)));
                        }
                    } 
                }
            } 
 
            if (string.IsNullOrEmpty(contentType))
            { 
                MtomMessageEncoder mtomMessageEncoder = messageEncoder as MtomMessageEncoder;
                if (mtomMessageEncoder == null)
                {
                    contentType = messageEncoder.ContentType; 
                }
                else 
                { 
                    contentType = mtomMessageEncoder.GetContentType(out this.mtomBoundary);
                    // For MTOM messages, add a MIME version header 
                    AddMimeVersion("1.0");
                }
            }
 
            SetContentType(contentType);
            return message is NullMessage; 
        } 

        ArraySegment SerializeBufferedMessage(Message message) 
        {
            ArraySegment result;
            MtomMessageEncoder mtomMessageEncoder = messageEncoder as MtomMessageEncoder;
            if (mtomMessageEncoder == null) 
            {
                result = messageEncoder.WriteMessage(message, int.MaxValue, bufferManager); 
            } 
            else
            { 
                result = mtomMessageEncoder.WriteMessage(message, int.MaxValue, bufferManager, 0, this.mtomBoundary);
            }

            this.bufferToRecycle = result.Array; 
            return result;
        } 
 

        void WriteStreamedMessage(TimeSpan timeout) 
        {
            const int ChunkSize = 32768;    // buffer size used for synchronous writes
            const int BufferSize = 16384;   // buffer size used for asynchronous writes
            const int BufferCount = 4;      // buffer count used for asynchronous writes 

            // Writing an HTTP request chunk has a high fixed cost, so use BufferedStream to avoid writing 
            // small ones. 
            this.outputStream = this.supportsConcurrentIO ? (Stream)new BufferedOutputAsyncStream(this.outputStream, BufferSize, BufferCount) : new BufferedStream(this.outputStream, ChunkSize);
 
            // Since HTTP streams don't support timeouts, we can't just use TimeoutStream here.
            // Rather, we need to run a timer to bound the overall operation
            if (onStreamSendTimeout == null)
            { 
                onStreamSendTimeout = new WaitCallback(OnStreamSendTimeout);
            } 
            IOThreadTimer sendTimer = new IOThreadTimer(onStreamSendTimeout, this, true); 
            sendTimer.Set(timeout);
 
            try
            {
                MtomMessageEncoder mtomMessageEncoder = messageEncoder as MtomMessageEncoder;
                if (mtomMessageEncoder == null) 
                {
                    messageEncoder.WriteMessage(this.message, this.outputStream); 
                } 
                else
                { 
                    mtomMessageEncoder.WriteMessage(this.message, this.outputStream, this.mtomBoundary);
                }
            }
            finally 
            {
                sendTimer.Cancel(); 
            } 
        }
 
        static void OnStreamSendTimeout(object state)
        {
            HttpOutput thisPtr = (HttpOutput)state;
            thisPtr.Abort(HttpAbortReason.TimedOut); 
        }
 
        public virtual IAsyncResult BeginSend(TimeSpan timeout, AsyncCallback callback, object state) 
        {
            bool throwing = true; 
            try
            {
                bool suppressEntityBody = PrepareHttpSend(message);
                IAsyncResult result = new SendAsyncResult(this, suppressEntityBody, timeout, callback, state); 
                throwing = false;
                return result; 
            } 
            finally
            { 
                if (throwing)
                {
                    Abort();
                } 
            }
        } 
 
        public virtual void EndSend(IAsyncResult result)
        { 
            bool throwing = true;
            try
            {
                SendAsyncResult.End(result); 
                throwing = false;
            } 
            finally 
            {
                if (throwing) 
                {
                    Abort();
                }
            } 
        }
 
        void LogMessage() 
        {
            if (MessageLogger.LogMessagesAtTransportLevel) 
            {
                MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportSend);
            }
        } 

        public virtual void Send(TimeSpan timeout) 
        { 
            bool suppressEntityBody = PrepareHttpSend(message);
 
            if (suppressEntityBody)
            {
                SetContentLength(0);
                // requests can't always support an output stream (for GET, etc) 
                if (!isRequest)
                { 
                    outputStream = GetOutputStream(); 
                }
                else 
                {
                    LogMessage();
                }
            } 
            else if (streamed)
            { 
                outputStream = GetOutputStream(); 
                WriteStreamedMessage(timeout);
            } 
            else
            {
                ArraySegment buffer = SerializeBufferedMessage(message);
                SetContentLength(buffer.Count); 

                // requests can't always support an output stream (for GET, etc) 
                if (!isRequest || buffer.Count > 0) 
                {
                    outputStream = GetOutputStream(); 
                    outputStream.Write(buffer.Array, buffer.Offset, buffer.Count);
                }
            }
 
            TraceSend();
        } 
 
        void TraceSend()
        { 
            if (DiagnosticUtility.ShouldTraceInformation)
            {
                TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.MessageSent,
                    new MessageTraceRecord(this.message), this, null); 
            }
        } 
 
        class SendAsyncResult : AsyncResult
        { 
            HttpOutput httpOutput;
            static AsyncCallback onGetOutputStream;
            static WaitCallback onWriteStreamedMessage;
            static AsyncCallback onWriteBody; 
            bool suppressEntityBody;
            ArraySegment buffer; 
            TimeoutHelper timeoutHelper; 

            public SendAsyncResult(HttpOutput httpOutput, bool suppressEntityBody, TimeSpan timeout, AsyncCallback callback, object state) 
                : base(callback, state)
            {
                this.httpOutput = httpOutput;
                this.suppressEntityBody = suppressEntityBody; 

                if (suppressEntityBody) 
                { 
                    httpOutput.SetContentLength(0);
 
                    if (httpOutput.isRequest)
                    {
                        this.httpOutput.TraceSend();
                        this.httpOutput.LogMessage(); 
                        base.Complete(true);
                        return; 
                    } 
                }
 
                if (!suppressEntityBody && !httpOutput.streamed)
                {
                    buffer = httpOutput.SerializeBufferedMessage(httpOutput.message);
                    httpOutput.SetContentLength(buffer.Count); 
                }
 
                this.timeoutHelper = new TimeoutHelper(timeout); 
                if (this.httpOutput.WillGetOutputStreamCompleteSynchronously)
                { 
                    httpOutput.outputStream = httpOutput.GetOutputStream();
                }
                else
                { 
                    if (onGetOutputStream == null)
                    { 
                        onGetOutputStream = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnGetOutputStream)); 
                    }
 
                    IAsyncResult result = httpOutput.BeginGetOutputStream(onGetOutputStream, this);

                    if (!result.CompletedSynchronously)
                        return; 

                    httpOutput.outputStream = httpOutput.EndGetOutputStream(result); 
                } 

                if (WriteMessage(true)) 
                {
                    this.httpOutput.TraceSend();
                    base.Complete(true);
                } 
            }
 
            bool WriteMessage(bool isStillSynchronous) 
            {
                if (suppressEntityBody) 
                {
                    return true;
                }
                if (httpOutput.streamed) 
                {
                    if (isStillSynchronous) 
                    { 
                        if (onWriteStreamedMessage == null)
                        { 
                            onWriteStreamedMessage = new WaitCallback(OnWriteStreamedMessage);
                        }
                        IOThreadScheduler.ScheduleCallback(onWriteStreamedMessage, this);
                        return false; 
                    }
                    else 
                    { 
                        WriteStreamedMessage();
                    } 
                }
                else
                {
                    if (onWriteBody == null) 
                    {
                        onWriteBody = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnWriteBody)); 
                    } 

                    IAsyncResult writeResult = 
                        httpOutput.outputStream.BeginWrite(buffer.Array, buffer.Offset, buffer.Count, onWriteBody, this);

                    if (!writeResult.CompletedSynchronously)
                    { 
                        return false;
                    } 
 
                    CompleteWriteBody(writeResult);
                } 

                return true;
            }
 
            void WriteStreamedMessage()
            { 
                httpOutput.WriteStreamedMessage(timeoutHelper.RemainingTime()); 
            }
 
            void CompleteWriteBody(IAsyncResult result)
            {
                httpOutput.outputStream.EndWrite(result);
            } 

            public static void End(IAsyncResult result) 
            { 
                AsyncResult.End(result);
            } 

            static void OnGetOutputStream(IAsyncResult result)
            {
                if (result.CompletedSynchronously) 
                    return;
 
                SendAsyncResult thisPtr = (SendAsyncResult)result.AsyncState; 

                Exception completionException = null; 
                bool completeSelf = false;
                try
                {
                    thisPtr.httpOutput.outputStream = thisPtr.httpOutput.EndGetOutputStream(result); 
                    if (thisPtr.WriteMessage(false))
                    { 
                        thisPtr.httpOutput.TraceSend(); 
                        completeSelf = true;
                    } 
                }
#pragma warning suppress 56500 // [....], transferring exception to another thread
                catch (Exception e)
                { 
                    if (DiagnosticUtility.IsFatal(e))
                    { 
                        throw; 
                    }
                    completeSelf = true; 
                    completionException = e;
                }
                if (completeSelf)
                { 
                    thisPtr.Complete(false, completionException);
                } 
            } 

            static void OnWriteStreamedMessage(object state) 
            {
                SendAsyncResult thisPtr = (SendAsyncResult)state;

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

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

                SendAsyncResult thisPtr = (SendAsyncResult)result.AsyncState; 

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

        internal static HttpOutput CreateHttpOutput(HttpWebRequest httpWebRequest, IHttpTransportFactorySettings settings, Message message)
        { 
            return new WebRequestHttpOutput(httpWebRequest, settings, message);
        } 
 
        internal static HttpOutput CreateHttpOutput(HttpListenerResponse httpListenerResponse, IHttpTransportFactorySettings settings, Message message)
        { 
            return new ListenerResponseHttpOutput(httpListenerResponse, settings, message);
        }

        internal static HttpOutput CreateHttpOutput(HostedHttpRequestAsyncResult result, IHttpTransportFactorySettings settings, Message message, HostedHttpContext context) 
        {
            return new HostedRequestHttpOutput(result, settings, message, context); 
        } 

        class WebRequestHttpOutput : HttpOutput 
        {
            HttpWebRequest httpWebRequest;

            public WebRequestHttpOutput(HttpWebRequest httpWebRequest, IHttpTransportFactorySettings settings, Message message) 
                : base(settings, message, true, false)
            { 
                this.httpWebRequest = httpWebRequest; 
            }
 
            public override void Abort(HttpAbortReason abortReason)
            {
                httpWebRequest.Abort();
                base.Abort(abortReason); 
            }
 
            protected override void AddMimeVersion(string version) 
            {
                httpWebRequest.Headers[MIMEVersionHeader] = version; 
            }

            protected override void SetContentType(string contentType)
            { 
                httpWebRequest.ContentType = contentType;
            } 
 
            protected override void SetContentLength(int contentLength)
            { 
                // work around whidbey issue with setting ContentLength - (see MB36881)
                if (contentLength == 0)
                {
                    httpWebRequest.ContentLength = contentLength; 
                }
            } 
 
            protected override bool WillGetOutputStreamCompleteSynchronously
            { 
                get { return false; }
            }

            protected override Stream GetOutputStream() 
            {
                try 
                { 
                    return new WebRequestOutputStream(httpWebRequest.GetRequestStream(), httpWebRequest, this);
                } 
                catch (WebException webException)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestWebException(webException, httpWebRequest, abortReason));
                } 
            }
 
            protected override IAsyncResult BeginGetOutputStream(AsyncCallback callback, object state) 
            {
                return new GetOutputStreamAsyncResult(httpWebRequest, this, callback, state); 
            }

            protected override Stream EndGetOutputStream(IAsyncResult result)
            { 
                return GetOutputStreamAsyncResult.End(result);
            } 
 
            protected override bool PrepareHttpSend(Message message)
            { 
                bool wasContentTypeSet = false;

                string action = message.Headers.Action;
 
                if (action != null)
                { 
                    //This code is calling UrlPathEncode due to MessageBus bug 53362. 
                    //After reviewing this decision, we
                    //feel that this was probably the wrong thing to do because UrlPathEncode 
                    //doesn't escape some characters like '+', '%', etc.  The real issue behind
                    //bug 53362 may have been as simple as being encoded multiple times on the client
                    //but being decoded one time on the server.  Calling UrlEncode would correctly
                    //escape these characters, but since we don't want to break any customers and no 
                    //customers have complained, we will leave this as is for now...
                    action = string.Format(CultureInfo.InvariantCulture, "\"{0}\"", UrlUtility.UrlPathEncode(action)); 
                } 

                bool retValue = base.PrepareHttpSend(message); 

                object property;
                if (message.Properties.TryGetValue(HttpRequestMessageProperty.Name, out property))
                { 
                    HttpRequestMessageProperty requestProperty = (HttpRequestMessageProperty)property;
                    httpWebRequest.Method = requestProperty.Method; 
                    // Query string was applied in HttpChannelFactory.ApplyManualAddressing 
                    WebHeaderCollection requestHeaders = requestProperty.Headers;
                    retValue = retValue || requestProperty.SuppressEntityBody; 
                    for (int i = 0; i < requestHeaders.Count; i++)
                    {
                        string name = requestHeaders.Keys[i];
                        string value = requestHeaders[i]; 
                        if (string.Compare(name, "accept", StringComparison.OrdinalIgnoreCase) == 0)
                        { 
                            httpWebRequest.Accept = value; 
                        }
                        else if (string.Compare(name, "connection", StringComparison.OrdinalIgnoreCase) == 0) 
                        {
                            if (value.IndexOf("keep-alive", StringComparison.OrdinalIgnoreCase) != -1)
                            {
                                httpWebRequest.KeepAlive = true; 
                            }
                            else 
                            { 
                                httpWebRequest.Connection = value;
                            } 
                        }
                        else if (string.Compare(name, "SOAPAction", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            if (action == null) 
                            {
                                action = value; 
                            } 
                            else
                            { 
                                if (value.Length > 0 && string.Compare(value, action, StringComparison.Ordinal) != 0)
                                {
                                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                                        new ProtocolException(SR.GetString(SR.HttpSoapActionMismatch, action, value))); 
                                }
                            } 
                        } 
                        else if (string.Compare(name, "content-length", StringComparison.OrdinalIgnoreCase) == 0)
                        { 
                            // this will be taken care of by System.Net when we write to the content
                        }
                        else if (string.Compare(name, "content-type", StringComparison.OrdinalIgnoreCase) == 0)
                        { 
                            httpWebRequest.ContentType = value;
                            wasContentTypeSet = true; 
                        } 
                        else if (string.Compare(name, "expect", StringComparison.OrdinalIgnoreCase) == 0)
                        { 
                            if (value.ToUpperInvariant().IndexOf("100-CONTINUE", StringComparison.OrdinalIgnoreCase) != -1)
                            {
                                httpWebRequest.ServicePoint.Expect100Continue = true;
                            } 
                            else
                            { 
                                httpWebRequest.Expect = value; 
                            }
                        } 
                        else if (string.Compare(name, "host", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            // this should be controlled through Via
                        } 
                        else if (string.Compare(name, "referer", StringComparison.OrdinalIgnoreCase) == 0)
                        { 
                            // referrer is proper spelling, but referer is the what is in the protocol. 
                            httpWebRequest.Referer = value;
                        } 
                        else if (string.Compare(name, "transfer-encoding", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            if (value.ToUpperInvariant().IndexOf("CHUNKED", StringComparison.OrdinalIgnoreCase) != -1)
                            { 
                                httpWebRequest.SendChunked = true;
                            } 
                            else 
                            {
                                httpWebRequest.TransferEncoding = value; 
                            }
                        }
                        else if (string.Compare(name, "user-agent", StringComparison.OrdinalIgnoreCase) == 0)
                        { 
                            httpWebRequest.UserAgent = value;
                        } 
                        else if (string.Compare(name, "if-modified-since", StringComparison.OrdinalIgnoreCase) == 0) 
                        {
                            DateTime modifiedSinceDate; 
                            if (DateTime.TryParse(value, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.AssumeLocal, out modifiedSinceDate))
                            {
                                httpWebRequest.IfModifiedSince = modifiedSinceDate;
                            } 
                            else
                            { 
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                                    new ProtocolException(SR.GetString(SR.HttpIfModifiedSinceParseError, value)));
                            } 
                        }
                        else if (string.Compare(name, "date", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            // this will be taken care of by System.Net when we make the request 
                        }
                        else if (string.Compare(name, "proxy-connection", StringComparison.OrdinalIgnoreCase) == 0) 
                        { 
                            // set by System.Net if using a proxy.
                        } 
                        else if (string.Compare(name, "range", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            // we don't support ranges in v1.
                        } 
                        else
                        { 
                            httpWebRequest.Headers.Add(name, value); 
                        }
                    } 
                }

                if (action != null)
                { 
                    if (message.Version.Envelope == EnvelopeVersion.Soap11)
                    { 
                        httpWebRequest.Headers["SOAPAction"] = action; 
                    }
                    else if (message.Version.Envelope == EnvelopeVersion.Soap12) 
                    {
                        if (message.Version.Addressing == AddressingVersion.None)
                        {
                            bool shouldSetContentType = true; 
                            if (wasContentTypeSet)
                            { 
                                if (httpWebRequest.ContentType.Contains("action") 
                                    || httpWebRequest.ContentType.ToUpperInvariant().IndexOf("ACTION", StringComparison.OrdinalIgnoreCase) != -1)
                                { 
                                    try
                                    {
                                        ContentType parsedContentType = new ContentType(httpWebRequest.ContentType);
                                        if (parsedContentType.Parameters.ContainsKey("action")) 
                                        {
                                            string value = string.Format(CultureInfo.InvariantCulture, "\"{0}\"", parsedContentType.Parameters["action"]); 
                                            if (string.Compare(value, action, StringComparison.Ordinal) != 0) 
                                            {
                                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                                                    new ProtocolException(SR.GetString(SR.HttpSoapActionMismatchContentType, action, value)));
                                            }
                                            shouldSetContentType = false;
                                        } 
                                    }
                                    catch (FormatException formatException) 
                                    { 
                                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                                            new ProtocolException(SR.GetString(SR.HttpContentTypeFormatException, formatException.Message, httpWebRequest.ContentType), formatException)); 
                                    }
                                }
                            }
 
                            if (shouldSetContentType)
                            { 
                                httpWebRequest.ContentType = string.Format(CultureInfo.InvariantCulture, "{0}; action={1}", httpWebRequest.ContentType, action); 
                            }
                        } 
                    }
                    else if (message.Version.Envelope != EnvelopeVersion.None)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                            new ProtocolException(SR.GetString(SR.EnvelopeVersionUnknown,
                            message.Version.Envelope.ToString()))); 
                    } 
                }
 
                // since we don't get the output stream in send when retVal == true,
                // we need to disable chunking for some verbs (DELETE/PUT)
                if (retValue)
                { 
                    httpWebRequest.SendChunked = false;
                } 
 
                return retValue;
            } 

            class GetOutputStreamAsyncResult : AsyncResult
            {
                static AsyncCallback onGetRequestStream = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnGetRequestStream)); 
                HttpOutput httpOutput;
                HttpWebRequest httpWebRequest; 
                Stream outputStream; 

                public GetOutputStreamAsyncResult(HttpWebRequest httpWebRequest, HttpOutput httpOutput, AsyncCallback callback, object state) 
                    : base(callback, state)
                {
                    this.httpWebRequest = httpWebRequest;
                    this.httpOutput = httpOutput; 

                    IAsyncResult result = null; 
                    try 
                    {
                        result = httpWebRequest.BeginGetRequestStream(onGetRequestStream, this); 
                    }
                    catch (WebException webException)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestWebException(webException, httpWebRequest, httpOutput.abortReason)); 
                    }
 
                    if (result.CompletedSynchronously) 
                    {
                        CompleteGetRequestStream(result); 
                        base.Complete(true);
                    }
                }
 
                void CompleteGetRequestStream(IAsyncResult result)
                { 
                    try 
                    {
                        this.outputStream = new WebRequestOutputStream(httpWebRequest.EndGetRequestStream(result), httpWebRequest, this.httpOutput); 
                    }
                    catch (WebException webException)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestWebException(webException, httpWebRequest, httpOutput.abortReason)); 
                    }
                } 
 
                public static Stream End(IAsyncResult result)
                { 
                    GetOutputStreamAsyncResult thisPtr = AsyncResult.End(result);
                    return thisPtr.outputStream;
                }
 
                static void OnGetRequestStream(IAsyncResult result)
                { 
                    if (result.CompletedSynchronously) 
                        return;
 
                    GetOutputStreamAsyncResult thisPtr = (GetOutputStreamAsyncResult)result.AsyncState;

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

            class WebRequestOutputStream : BytesReadPositionStream
            { 
                HttpWebRequest httpWebRequest;
                HttpOutput httpOutput; 
                int bytesSent = 0; 

                public WebRequestOutputStream(Stream requestStream, HttpWebRequest httpWebRequest, HttpOutput httpOutput) 
                    : base(requestStream)
                {
                    this.httpWebRequest = httpWebRequest;
                    this.httpOutput = httpOutput; 
                }
 
                public override void Close() 
                {
                    try 
                    {
                        base.Close();
                    }
                    catch (ObjectDisposedException objectDisposedException) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestCanceledException(objectDisposedException, httpWebRequest, httpOutput.abortReason)); 
                    } 
                    catch (IOException ioException)
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestIOException(ioException, httpWebRequest));
                    }
                    catch (WebException webException)
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestWebException(webException, httpWebRequest, httpOutput.abortReason));
                    } 
                } 

                public override long Position 
                {
                    get
                    {
                        return bytesSent; 
                    }
                    set 
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SeekNotSupported)));
                    } 
                }

                public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
                { 
                    this.bytesSent += count;
                    try 
                    { 
                        return base.BeginWrite(buffer, offset, count, callback, state);
                    } 
                    catch (ObjectDisposedException objectDisposedException)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestCanceledException(objectDisposedException, httpWebRequest, httpOutput.abortReason));
                    } 
                    catch (IOException ioException)
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestIOException(ioException, httpWebRequest)); 
                    }
                    catch (WebException webException) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestWebException(webException, httpWebRequest, httpOutput.abortReason));
                    }
                } 

                public override void EndWrite(IAsyncResult result) 
                { 
                    try
                    { 
                        base.EndWrite(result);
                    }
                    catch (ObjectDisposedException objectDisposedException)
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestCanceledException(objectDisposedException, httpWebRequest, httpOutput.abortReason));
                    } 
                    catch (IOException ioException) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestIOException(ioException, httpWebRequest)); 
                    }
                    catch (WebException webException)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestWebException(webException, httpWebRequest, httpOutput.abortReason)); 
                    }
                } 
 
                public override void Write(byte[] buffer, int offset, int count)
                { 
                    try
                    {
                        base.Write(buffer, offset, count);
                    } 
                    catch (ObjectDisposedException objectDisposedException)
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestCanceledException(objectDisposedException, httpWebRequest, httpOutput.abortReason)); 
                    }
                    catch (IOException ioException) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestIOException(ioException, httpWebRequest));
                    }
                    catch (WebException webException) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestWebException(webException, httpWebRequest, httpOutput.abortReason)); 
                    } 
                    this.bytesSent += count;
                } 
            }
        }

        class ListenerResponseHttpOutput : HttpOutput 
        {
            HttpListenerResponse listenerResponse; 
 
            public ListenerResponseHttpOutput(HttpListenerResponse listenerResponse, IHttpTransportFactorySettings settings, Message message)
                : base(settings, message, false, true) 
            {
                this.listenerResponse = listenerResponse;

                if (message.IsFault) 
                {
                    this.listenerResponse.StatusCode = (int)HttpStatusCode.InternalServerError; 
                } 
                else
                { 
                    this.listenerResponse.StatusCode = (int)HttpStatusCode.OK;
                }
            }
 
            public override void Abort(HttpAbortReason abortReason)
            { 
                listenerResponse.Abort(); 
                base.Abort(abortReason);
            } 

            protected override void AddMimeVersion(string version)
            {
                listenerResponse.Headers[MIMEVersionHeader] = version; 
            }
 
            protected override bool PrepareHttpSend(Message message) 
            {
                bool result = base.PrepareHttpSend(message); 

                object property;
                if (message.Properties.TryGetValue(HttpResponseMessageProperty.Name, out property))
                { 
                    HttpResponseMessageProperty responseProperty = (HttpResponseMessageProperty)property;
                    listenerResponse.StatusCode = (int)responseProperty.StatusCode; 
                    if (responseProperty.StatusDescription != null) 
                    {
                        listenerResponse.StatusDescription = responseProperty.StatusDescription; 
                    }

                    WebHeaderCollection responseHeaders = responseProperty.Headers;
                    for (int i = 0; i < responseHeaders.Count; i++) 
                    {
                        string name = responseHeaders.Keys[i]; 
                        string value = responseHeaders[i]; 
                        if (string.Compare(name, "content-length", StringComparison.OrdinalIgnoreCase) == 0)
                        { 
                            // this will be taken care of by System.Net when we write to the content
                        }
                        else if (string.Compare(name, "content-type", StringComparison.OrdinalIgnoreCase) == 0)
                        { 
                            listenerResponse.ContentType = value;
                        } 
                        else 
                        {
                            listenerResponse.AppendHeader(name, value); 
                        }
                    }

                    if (responseProperty.SuppressEntityBody) 
                    {
                        listenerResponse.ContentLength64 = 0; 
                        listenerResponse.ContentType = null; 
                        result = true;
                    } 
                }

                return result;
            } 

            protected override void SetContentType(string contentType) 
            { 
                listenerResponse.ContentType = contentType;
            } 

            protected override void SetContentLength(int contentLength)
            {
                listenerResponse.ContentLength64 = contentLength; 
            }
 
            protected override Stream GetOutputStream() 
            {
                return new ListenerResponseOutputStream(listenerResponse); 
            }

            class ListenerResponseOutputStream : BytesReadPositionStream
            { 
                public ListenerResponseOutputStream(HttpListenerResponse listenerResponse)
                    : base(listenerResponse.OutputStream) 
                { 
                }
 
                public override void Close()
                {
                    try
                    { 
                        base.Close();
                    } 
                    catch (HttpListenerException listenerException) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                            HttpChannelUtilities.CreateCommunicationException(listenerException));
                    }
                }
 
                public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
                { 
                    try 
                    {
                        return base.BeginWrite(buffer, offset, count, callback, state); 
                    }
                    catch (HttpListenerException listenerException)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                            HttpChannelUtilities.CreateCommunicationException(listenerException));
                    } 
                    catch (ApplicationException applicationException) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                            new CommunicationObjectAbortedException(SR.GetString(SR.HttpResponseAborted),
                            applicationException));
                    }
                } 

                public override void EndWrite(IAsyncResult result) 
                { 
                    try
                    { 
                        base.EndWrite(result);
                    }
                    catch (HttpListenerException listenerException)
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                            HttpChannelUtilities.CreateCommunicationException(listenerException)); 
                    } 
                    catch (ApplicationException applicationException)
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                            new CommunicationObjectAbortedException(SR.GetString(SR.HttpResponseAborted),
                            applicationException));
                    } 
                }
 
                public override void Write(byte[] buffer, int offset, int count) 
                {
                    try 
                    {
                        base.Write(buffer, offset, count);
                    }
                    catch (HttpListenerException listenerException) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                            HttpChannelUtilities.CreateCommunicationException(listenerException)); 
                    }
                    catch (ApplicationException applicationException) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                            new CommunicationObjectAbortedException(SR.GetString(SR.HttpResponseAborted),
                            applicationException)); 
                    }
                } 
            } 
        }
 
        class HostedRequestHttpOutput : HttpOutput
        {
            HostedHttpRequestAsyncResult result;
            HostedHttpContext context; 
            string contentType;
            string mimeVersion; 
            int statusCode; 

            public HostedRequestHttpOutput(HostedHttpRequestAsyncResult result, IHttpTransportFactorySettings settings, 
                Message message, HostedHttpContext context)
                : base(settings, message, false, false)
            {
                this.result = result; 
                this.context = context;
 
                if (TransferModeHelper.IsResponseStreamed(settings.TransferMode)) 
                    result.SetTransferModeToStreaming();
 
                if (message.IsFault)
                    this.statusCode = (int)HttpStatusCode.InternalServerError;
                else
                    this.statusCode = (int)HttpStatusCode.OK; 

 
            } 

            protected override Stream GetOutputStream() 
            {
                return new HostedResponseOutputStream(this.result, this.context);
            }
 

            protected override void AddMimeVersion(string version) 
            { 
                this.mimeVersion = version;
            } 

            protected override void SetContentType(string contentType)
            {
                this.contentType = contentType; 
            }
 
            protected override bool PrepareHttpSend(Message message) 
            {
                bool retValue = base.PrepareHttpSend(message); 

                object property;
                if (message.Properties.TryGetValue(HttpResponseMessageProperty.Name, out property))
                { 
                    HttpResponseMessageProperty responseProperty = (HttpResponseMessageProperty)property;
                    result.SetStatusCode((int)responseProperty.StatusCode); 
                    if (responseProperty.StatusDescription != null) 
                    {
                        result.SetStatusDescription(responseProperty.StatusDescription); 
                    }

                    WebHeaderCollection responseHeaders = responseProperty.Headers;
                    for (int i = 0; i < responseHeaders.Count; i++) 
                    {
                        string name = responseHeaders.Keys[i]; 
                        string value = responseHeaders[i]; 
                        if (string.Compare(name, "content-type", StringComparison.OrdinalIgnoreCase) == 0)
                        { 
                            this.contentType = value;
                        }
                        else if (string.Compare(name, MIMEVersionHeader, StringComparison.OrdinalIgnoreCase) == 0)
                        { 
                            this.mimeVersion = value;
                        } 
                        else if (string.Compare(name, "content-length", StringComparison.OrdinalIgnoreCase) == 0) 
                        {
                            // this will be taken care of by System.Net when we write to the content 
                        }
                        else
                        {
                            result.AppendHeader(name, value); 
                        }
                    } 
 
                    if (responseProperty.SuppressEntityBody)
                    { 
                        contentType = null;
                        retValue = true;
                    }
                } 
                else
                { 
                    result.SetStatusCode(statusCode); 
                }
 
                if (contentType != null && contentType.Length != 0)
                {
                    result.SetContentType(contentType);
                } 

                if (mimeVersion != null) 
                { 
                    result.AppendHeader(MIMEVersionHeader, mimeVersion);
                } 

                return retValue;
            }
 
            class HostedResponseOutputStream : BytesReadPositionStream
            { 
                HostedHttpContext context; 
                HostedHttpRequestAsyncResult result;
 
                public HostedResponseOutputStream(HostedHttpRequestAsyncResult result, HostedHttpContext context)
                    : base(result.GetOutputStream())
                {
                    this.context = context; 
                    this.result = result;
                } 
 
                public override void Close()
                { 
                    try
                    {
                        base.Close();
                    } 
                    catch (Exception e)
                    { 
                        CheckWrapThrow(e); 
                        throw;
                    } 
                    finally
                    {
                        result.OnReplySent();
                    } 
                }
 
                public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) 
                {
                    try 
                    {
                        return base.BeginWrite(buffer, offset, count, callback, state);
                    }
                    catch (Exception e) 
                    {
                        CheckWrapThrow(e); 
                        throw; 
                    }
                } 

                public override void EndWrite(IAsyncResult result)
                {
                    try 
                    {
                        base.EndWrite(result); 
                    } 
                    catch (Exception e)
                    { 
                        CheckWrapThrow(e);
                        throw;
                    }
                } 

                public override void Write(byte[] buffer, int offset, int count) 
                { 
                    try
                    { 
                        base.Write(buffer, offset, count);
                    }
                    catch (Exception e)
                    { 
                        CheckWrapThrow(e);
                        throw; 
                    } 
                }
 
                private void CheckWrapThrow(Exception e)
                {
                    if (!DiagnosticUtility.IsFatal(e))
                    { 
                        if (e is HttpException)
                        { 
                            if (this.context.Aborted) 
                            {
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                                    new CommunicationObjectAbortedException(SR.GetString(SR.RequestContextAborted), e));
                            }
                            else
                            { 
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                                    new CommunicationException(e.Message, e)); 
                            } 
                        }
                        else if (this.context.Aborted) 
                        {
                            // See VsWhidbey (594450)
                            if (DiagnosticUtility.ShouldTraceError)
                            { 
                                TraceUtility.TraceEvent(
                                    TraceEventType.Error, TraceCode.RequestContextAbort, 
                                    this, e); 
                            }
 
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                                    new CommunicationObjectAbortedException(SR.GetString(SR.RequestContextAborted)));
                        }
 
                    }
                } 
            } 
        }
    } 

    enum HttpAbortReason
    {
        None, 
        Aborted,
        TimedOut 
    } 

    static class HttpChannelUtilities 
    {
        internal static class StatusDescriptionStrings
        {
            internal const string HttpContentTypeMissing = "Missing Content Type"; 
            internal const string HttpContentTypeMismatch = "Cannot process the message because the content type '{0}' was not the expected type '{1}'.";
            internal const string HttpStatusServiceActivationException = "System.ServiceModel.ServiceActivationException"; 
        } 

        internal const string HttpStatusCodeExceptionKey = "System.ServiceModel.Channels.HttpInput.HttpStatusCode"; 
        internal const string HttpStatusDescriptionExceptionKey = "System.ServiceModel.Channels.HttpInput.HttpStatusDescription";

        internal const int ResponseStreamExcerptSize = 1024;
 
        public static Exception CreateCommunicationException(HttpListenerException listenerException)
        { 
            switch (listenerException.NativeErrorCode) 
            {
                case UnsafeNativeMethods.ERROR_NO_TRACKING_SERVICE: 
                    return new CommunicationException(SR.GetString(SR.HttpNoTrackingService, listenerException.Message), listenerException);

                case UnsafeNativeMethods.ERROR_NETNAME_DELETED:
                    return new CommunicationException(SR.GetString(SR.HttpNetnameDeleted, listenerException.Message), listenerException); 

                case UnsafeNativeMethods.ERROR_INVALID_HANDLE: 
                    return new CommunicationObjectAbortedException(SR.GetString(SR.HttpResponseAborted), listenerException); 

                case UnsafeNativeMethods.ERROR_NOT_ENOUGH_MEMORY: 
                case UnsafeNativeMethods.ERROR_OUTOFMEMORY:
                case UnsafeNativeMethods.ERROR_NO_SYSTEM_RESOURCES:
                    return new InsufficientMemoryException(SR.GetString(SR.InsufficentMemory), listenerException);
 
                default:
                    return new CommunicationException(listenerException.Message, listenerException); 
            } 
        }
 
        public static void AbortRequest(HttpWebRequest request)
        {
            request.Abort();
        } 

        public static void SetRequestTimeout(HttpWebRequest request, TimeSpan timeout) 
        { 
            int millisecondsTimeout = TimeoutHelper.ToMilliseconds(timeout);
            if (millisecondsTimeout == 0) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(SR.GetString(
                    SR.HttpRequestTimedOut, request.RequestUri, timeout)));
            } 
            request.Timeout = millisecondsTimeout;
            request.ReadWriteTimeout = millisecondsTimeout; 
        } 

        public static void AddReplySecurityProperty(HttpChannelFactory factory, HttpWebRequest webRequest, 
            HttpWebResponse webResponse, Message replyMessage)
        {
            SecurityMessageProperty securityProperty = factory.CreateReplySecurityProperty(webRequest, webResponse);
            if (securityProperty != null) 
            {
                replyMessage.Properties.Security = securityProperty; 
            } 
        }
 

        public static NetworkCredential GetCredential(AuthenticationSchemes authenticationScheme,
            SecurityTokenProviderContainer credentialProvider, TimeSpan timeout,
            out TokenImpersonationLevel impersonationLevel, out AuthenticationLevel authenticationLevel) 
        {
            impersonationLevel = TokenImpersonationLevel.None; 
            authenticationLevel = AuthenticationLevel.None; 

            NetworkCredential result = null; 

            if (authenticationScheme != AuthenticationSchemes.Anonymous)
            {
                result = GetCredentialCore(authenticationScheme, credentialProvider, timeout, out impersonationLevel, out authenticationLevel); 
            }
 
            return result; 
        }
 
        [MethodImpl(MethodImplOptions.NoInlining)]
        static NetworkCredential GetCredentialCore(AuthenticationSchemes authenticationScheme,
            SecurityTokenProviderContainer credentialProvider, TimeSpan timeout,
            out TokenImpersonationLevel impersonationLevel, out AuthenticationLevel authenticationLevel) 
        {
            impersonationLevel = TokenImpersonationLevel.None; 
            authenticationLevel = AuthenticationLevel.None; 

            NetworkCredential result = null; 

            switch (authenticationScheme)
            {
                case AuthenticationSchemes.Basic: 
                    result = TransportSecurityHelpers.GetUserNameCredential(credentialProvider, timeout);
                    impersonationLevel = TokenImpersonationLevel.Delegation; 
                    break; 

                case AuthenticationSchemes.Digest: 
                    result = TransportSecurityHelpers.GetSspiCredential(credentialProvider, timeout,
                        out impersonationLevel, out authenticationLevel);

                    HttpChannelUtilities.ValidateDigestCredential(ref result, impersonationLevel); 
                    break;
 
                case AuthenticationSchemes.Negotiate: 
                    result = TransportSecurityHelpers.GetSspiCredential(credentialProvider, timeout,
                        out impersonationLevel, out authenticationLevel); 
                    break;

                case AuthenticationSchemes.Ntlm:
                    result = TransportSecurityHelpers.GetSspiCredential(credentialProvider, timeout, 
                        out impersonationLevel, out authenticationLevel);
                    if (authenticationLevel == AuthenticationLevel.MutualAuthRequired) 
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                            new InvalidOperationException(SR.GetString(SR.CredentialDisallowsNtlm))); 
                    }
                    break;

                default: 
                    // The setter for this property should prevent this.
                    DiagnosticUtility.DebugAssert("GetCredential: Invalid authentication scheme"); 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false); 
            }
 
            return result;
        }

 
        public static HttpWebResponse ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)
        { 
            HttpWebResponse response = null; 

            switch (webException.Status) 
            {
                case WebExceptionStatus.Success:
                case WebExceptionStatus.ProtocolError:
                    response = (HttpWebResponse)webException.Response; 
                    break;
                case WebExceptionStatus.ConnectFailure: 
                case WebExceptionStatus.NameResolutionFailure: 
                case WebExceptionStatus.ProxyNameResolutionFailure:
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                        new EndpointNotFoundException(SR.GetString(SR.EndpointNotFound, request.RequestUri.AbsoluteUri), webException));
                case WebExceptionStatus.SecureChannelFailure:
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new SecurityNegotiationException(SR.GetString(SR.SecureChannelFailure, request.RequestUri.Authority), webException)); 
                case WebExceptionStatus.TrustFailure:
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                        new SecurityNegotiationException(SR.GetString(SR.TrustFailure, request.RequestUri.Authority), webException)); 
                case WebExceptionStatus.Timeout:
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                        new TimeoutException(CreateRequestTimedOutMessage(request), webException));
                case WebExceptionStatus.ReceiveFailure:
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new CommunicationException(SR.GetString(SR.HttpReceiveFailure, request.RequestUri), webException)); 
                case WebExceptionStatus.SendFailure:
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                        new CommunicationException(SR.GetString(SR.HttpSendFailure, request.RequestUri), webException)); 
                case WebExceptionStatus.RequestCanceled:
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                        CreateRequestCanceledException(webException, request, abortReason));
                default:
                    break;
            } 

            if (response == null) 
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(webException.Message,
                    webException)); 
            }

            if (response.StatusCode == HttpStatusCode.NotFound)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new EndpointNotFoundException(SR.GetString(SR.EndpointNotFound, request.RequestUri.AbsoluteUri), webException));
            } 
 
            if (response.StatusCode == HttpStatusCode.ServiceUnavailable)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ServerTooBusyException(SR.GetString(SR.HttpServerTooBusy, request.RequestUri.AbsoluteUri), webException));
            }

            if (response.StatusCode == HttpStatusCode.UnsupportedMediaType) 
            {
                string statusDescription = response.StatusDescription; 
                if (!string.IsNullOrEmpty(statusDescription)) 
                {
                    if (string.Compare(statusDescription, HttpChannelUtilities.StatusDescriptionStrings.HttpContentTypeMissing, StringComparison.OrdinalIgnoreCase) == 0) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(SR.GetString(SR.MissingContentType, request.RequestUri), webException));
                    }
                } 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(SR.GetString(SR.FramingContentTypeMismatch, request.ContentType, request.RequestUri), webException));
            } 
 
            if (response.StatusCode == HttpStatusCode.GatewayTimeout)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(webException.Message, webException));
            }

            // if http.sys has a request queue on the TCP port, then if the path fails to match it will send 
            // back "

Bad Request (Invalid Hostname)

" in the body of a 400 response. // See code at \\index1\sddnsrv\net\http\sys\httprcv.c for details if (response.StatusCode == HttpStatusCode.BadRequest) { const string httpSysRequestQueueNotFound = "

Bad Request (Invalid Hostname)

"; const string httpSysRequestQueueNotFoundVista = "\r\nBad Request\r\n\r\n

Bad Request - Invalid Hostname

\r\n

HTTP Error 400. The request hostname is invalid.

\r\n\r\n"; string notFoundTestString = null; if (response.ContentLength == httpSysRequestQueueNotFound.Length) { notFoundTestString = httpSysRequestQueueNotFound; } else if (response.ContentLength == httpSysRequestQueueNotFoundVista.Length) { notFoundTestString = httpSysRequestQueueNotFoundVista; } if (notFoundTestString != null) { Stream responseStream = response.GetResponseStream(); byte[] responseBytes = new byte[notFoundTestString.Length]; int bytesRead = responseStream.Read(responseBytes, 0, responseBytes.Length); // since the response is buffered by System.Net (it's an error response), we should have read // the amount we were expecting if (bytesRead == notFoundTestString.Length && notFoundTestString == UTF8Encoding.ASCII.GetString(responseBytes)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new EndpointNotFoundException(SR.GetString(SR.EndpointNotFound, request.RequestUri.AbsoluteUri), webException)); } } } return response; } public static Exception CreateResponseIOException(IOException ioException, TimeSpan receiveTimeout) { if (ioException.InnerException is SocketException) { return SocketConnection.ConvertTransferException((SocketException)ioException.InnerException, receiveTimeout, ioException); } return new CommunicationException(SR.GetString(SR.HttpTransferError, ioException.Message), ioException); } public static Exception CreateResponseWebException(WebException webException, HttpWebResponse response) { switch (webException.Status) { case WebExceptionStatus.RequestCanceled: return TraceResponseException(new CommunicationObjectAbortedException(SR.GetString(SR.HttpRequestAborted, response.ResponseUri), webException)); case WebExceptionStatus.ConnectionClosed: return TraceResponseException(new CommunicationException(webException.Message, webException)); case WebExceptionStatus.Timeout: return TraceResponseException(new TimeoutException(SR.GetString(SR.HttpResponseTimedOut, response.ResponseUri, TimeSpan.FromMilliseconds(response.GetResponseStream().ReadTimeout)), webException)); default: return CreateUnexpectedResponseException(webException, response); } } public static Exception CreateRequestCanceledException(Exception webException, HttpWebRequest request, HttpAbortReason abortReason) { switch (abortReason) { case HttpAbortReason.Aborted: return new CommunicationObjectAbortedException(SR.GetString(SR.HttpRequestAborted, request.RequestUri), webException); case HttpAbortReason.TimedOut: return new TimeoutException(CreateRequestTimedOutMessage(request), webException); default: return new CommunicationException(SR.GetString(SR.HttpTransferError, webException.Message), webException); } } public static Exception CreateRequestIOException(IOException ioException, HttpWebRequest request) { return CreateRequestIOException(ioException, request, null); } public static Exception CreateRequestIOException(IOException ioException, HttpWebRequest request, Exception originalException) { Exception exception = originalException == null ? ioException : originalException; if (ioException.InnerException is SocketException) { return SocketConnection.ConvertTransferException((SocketException)ioException.InnerException, TimeSpan.FromMilliseconds(request.Timeout), exception); } return new CommunicationException(SR.GetString(SR.HttpTransferError, exception.Message), exception); } static string CreateRequestTimedOutMessage(HttpWebRequest request) { return SR.GetString(SR.HttpRequestTimedOut, request.RequestUri, TimeSpan.FromMilliseconds(request.Timeout)); } public static Exception CreateRequestWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason) { if (webException.Status == WebExceptionStatus.Timeout) { return new TimeoutException(CreateRequestTimedOutMessage(request), webException); } if (webException.Status == WebExceptionStatus.RequestCanceled) { return CreateRequestCanceledException(webException, request, abortReason); } if (webException.InnerException is IOException) { return CreateRequestIOException((IOException)webException.InnerException, request, webException); } if (webException.InnerException is SocketException) { return SocketConnectionInitiator.ConvertConnectException((SocketException)webException.InnerException, request.RequestUri, TimeSpan.MaxValue, webException); } return new EndpointNotFoundException(SR.GetString(SR.EndpointNotFound, request.RequestUri.AbsoluteUri), webException); } static Exception CreateUnexpectedResponseException(WebException responseException, HttpWebResponse response) { string statusDescription = response.StatusDescription; if (string.IsNullOrEmpty(statusDescription)) statusDescription = response.StatusCode.ToString(); return TraceResponseException( new ProtocolException(SR.GetString(SR.UnexpectedHttpResponseCode, (int)response.StatusCode, statusDescription), responseException)); } public static Exception CreateNullReferenceResponseException(NullReferenceException nullReferenceException) { return TraceResponseException( new ProtocolException(SR.GetString(SR.NullReferenceOnHttpResponse), nullReferenceException)); } static string GetResponseStreamString(HttpWebResponse webResponse, out int bytesRead) { Stream responseStream = webResponse.GetResponseStream(); long bufferSize = webResponse.ContentLength; if (bufferSize < 0 || bufferSize > ResponseStreamExcerptSize) { bufferSize = ResponseStreamExcerptSize; } byte[] responseBuffer = DiagnosticUtility.Utility.AllocateByteArray(checked((int)bufferSize)); bytesRead = responseStream.Read(responseBuffer, 0, (int)bufferSize); responseStream.Close(); return System.Text.Encoding.UTF8.GetString(responseBuffer, 0, bytesRead); } static Exception TraceResponseException(Exception exception) { if (DiagnosticUtility.ShouldTraceError) { TraceUtility.TraceEvent(TraceEventType.Error, TraceCode.HttpChannelUnexpectedResponse, (object)null, exception); } return exception; } static bool ValidateEmptyContent(HttpWebResponse response) { bool responseIsEmpty = true; if (response.ContentLength > 0) { responseIsEmpty = false; } else if (response.ContentLength == -1) // chunked { Stream responseStream = response.GetResponseStream(); byte[] testBuffer = new byte[1]; responseIsEmpty = (responseStream.Read(testBuffer, 0, 1) != 1); } return responseIsEmpty; } static void ValidateAuthentication(HttpWebRequest request, HttpWebResponse response, WebException responseException, HttpChannelFactory factory) { if (response.StatusCode == HttpStatusCode.Unauthorized) { string message = SR.GetString(SR.HttpAuthorizationFailed, factory.AuthenticationScheme, response.Headers[HttpResponseHeader.WwwAuthenticate]); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( TraceResponseException(new MessageSecurityException(message, responseException))); } if (response.StatusCode == HttpStatusCode.Forbidden) { string message = SR.GetString(SR.HttpAuthorizationForbidden, factory.AuthenticationScheme); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( TraceResponseException(new MessageSecurityException(message, responseException))); } if ((request.AuthenticationLevel == AuthenticationLevel.MutualAuthRequired) && !response.IsMutuallyAuthenticated) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( TraceResponseException(new SecurityNegotiationException(SR.GetString(SR.HttpMutualAuthNotSatisfied), responseException))); } } public static void ValidateDigestCredential(ref NetworkCredential credential, TokenImpersonationLevel impersonationLevel) { // this is a work-around to VSWhidbey#470545 (Since the service always uses Impersonation, // we mitigate EOP by preemtively not allowing Identification) if (!SecurityUtils.IsDefaultNetworkCredential(credential)) { // With a non-default credential, Digest will not honor a client impersonation constraint of // TokenImpersonationLevel.Identification. if (!TokenImpersonationLevelHelper.IsGreaterOrEqual(impersonationLevel, TokenImpersonationLevel.Impersonation)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString( SR.DigestExplicitCredsImpersonationLevel, impersonationLevel))); } } } // only valid response codes are 500 (if it's a fault) or 200 (iff it's a response message) public static HttpInput ValidateRequestReplyResponse(HttpWebRequest request, HttpWebResponse response, HttpChannelFactory factory, WebException responseException) { ValidateAuthentication(request, response, responseException, factory); HttpInput httpInput = null; if ((200 <= (int)response.StatusCode && (int)response.StatusCode < 300) || response.StatusCode == HttpStatusCode.InternalServerError) { if (response.StatusCode == HttpStatusCode.InternalServerError && string.Compare(response.StatusDescription, HttpChannelUtilities.StatusDescriptionStrings.HttpStatusServiceActivationException, StringComparison.OrdinalIgnoreCase) == 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ServiceActivationException(SR.GetString(SR.Hosting_ServiceActivationFailed, request.RequestUri))); } else if (string.IsNullOrEmpty(response.ContentType)) { if (!ValidateEmptyContent(response)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(TraceResponseException( new ProtocolException( SR.GetString(SR.HttpContentTypeHeaderRequired), responseException))); } } else if (response.ContentLength != 0) { MessageEncoder encoder = factory.MessageEncoderFactory.Encoder; if (!encoder.IsContentTypeSupported(response.ContentType)) { int bytesRead; String responseExcerpt = GetResponseStreamString(response, out bytesRead); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(TraceResponseException( new ProtocolException( SR.GetString( SR.ResponseContentTypeMismatch, response.ContentType, encoder.ContentType, bytesRead, responseExcerpt), responseException))); } httpInput = HttpInput.CreateHttpInput(response, factory); httpInput.WebException = responseException; } if (httpInput == null && factory.MessageEncoderFactory.MessageVersion == MessageVersion.None) { httpInput = HttpInput.CreateHttpInput(response, factory); httpInput.WebException = responseException; } } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateUnexpectedResponseException(responseException, response)); } return httpInput; } } class DrainOnCloseStream : DetectEofStream { public DrainOnCloseStream(MaxMessageSizeStream innerStream) : base(innerStream) { } public override void Close() { if (!base.IsAtEof) { // Drain remaining bytes (the underlying stream bounds this to MaxReceivedMessageSize as per our ctor) const int dummyBufferSize = 2048; byte[] dummy = DiagnosticUtility.Utility.AllocateByteArray(dummyBufferSize); while (!base.IsAtEof) { // don't need the return value, base stream is monitoring for EOF base.Read(dummy, 0, dummy.Length); } } base.Close(); } } abstract class HttpDelayedAcceptStream : DetectEofStream { HttpOutput httpOutput; // sometimes we can't flush the HTTP output until we're done reading the end of the // incoming stream of the HTTP input protected HttpDelayedAcceptStream(Stream stream) : base(stream) { } public bool EnableDelayedAccept(HttpOutput output) { if (IsAtEof) { return false; } this.httpOutput = output; return true; } protected override void OnReceivedEof() { if (this.httpOutput != null) { this.httpOutput.Close(); } } } abstract class BytesReadPositionStream : DelegatingStream { int bytesSent = 0; protected BytesReadPositionStream(Stream stream) : base(stream) { } public override long Position { get { return bytesSent; } set { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SeekNotSupported))); } } public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { this.bytesSent += count; return BaseStream.BeginWrite(buffer, offset, count, callback, state); } public override void Write(byte[] buffer, int offset, int count) { BaseStream.Write(buffer, offset, count); this.bytesSent += count; } public override void WriteByte(byte value) { BaseStream.WriteByte(value); this.bytesSent++; } } class PreReadStream : DelegatingStream { byte[] preReadBuffer; public PreReadStream(Stream stream, byte[] preReadBuffer) : base(stream) { this.preReadBuffer = preReadBuffer; } bool ReadFromBuffer(byte[] buffer, int offset, int count, out int bytesRead) { if (this.preReadBuffer != null) { if (buffer == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("buffer"); } if (offset >= buffer.Length) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", offset, SR.GetString(SR.OffsetExceedsBufferBound, buffer.Length - 1))); } if (count < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", count, SR.GetString(SR.ValueMustBeNonNegative))); } if (count == 0) { bytesRead = 0; } else { buffer[offset] = this.preReadBuffer[0]; this.preReadBuffer = null; bytesRead = 1; } return true; } bytesRead = -1; return false; } public override int Read(byte[] buffer, int offset, int count) { int bytesRead; if (ReadFromBuffer(buffer, offset, count, out bytesRead)) { return bytesRead; } return base.Read(buffer, offset, count); } public override int ReadByte() { if (this.preReadBuffer != null) { byte[] tempBuffer = new byte[1]; int bytesRead; if (ReadFromBuffer(tempBuffer, 0, 1, out bytesRead)) { return tempBuffer[0]; } } return base.ReadByte(); } public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { int bytesRead; if (ReadFromBuffer(buffer, offset, count, out bytesRead)) { return new TypedCompletedAsyncResult(bytesRead, callback, state); } return base.BeginRead(buffer, offset, count, callback, state); } public override int EndRead(IAsyncResult result) { if (result is TypedCompletedAsyncResult) { return TypedCompletedAsyncResult.End(result); } else { return base.EndRead(result); } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.

Link Menu

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