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(ArraySegmentbuffer, 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\nBad Request - Invalid Hostname
\r\nHTTP 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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- FixedSOMPageConstructor.cs
- AffineTransform3D.cs
- PageBreakRecord.cs
- Signature.cs
- FtpCachePolicyElement.cs
- XamlStream.cs
- FixedSOMSemanticBox.cs
- MenuAdapter.cs
- StringKeyFrameCollection.cs
- ApplicationDirectoryMembershipCondition.cs
- DbParameterCollectionHelper.cs
- UrlPropertyAttribute.cs
- IntPtr.cs
- ReadOnlyHierarchicalDataSourceView.cs
- RewritingValidator.cs
- MultilineStringConverter.cs
- Int32EqualityComparer.cs
- DCSafeHandle.cs
- XmlnsDefinitionAttribute.cs
- IsolatedStorageFilePermission.cs
- GridViewColumnHeader.cs
- IdentityElement.cs
- ColumnHeaderConverter.cs
- WhitespaceRuleReader.cs
- AvTraceFormat.cs
- AssociationTypeEmitter.cs
- NavigationPropertyEmitter.cs
- XmlSchemaValidator.cs
- CopyAttributesAction.cs
- GridProviderWrapper.cs
- RelOps.cs
- BadImageFormatException.cs
- BaseTemplateParser.cs
- JapaneseLunisolarCalendar.cs
- WindowsTokenRoleProvider.cs
- StorageModelBuildProvider.cs
- WindowsSlider.cs
- QualifiedCellIdBoolean.cs
- TabRenderer.cs
- StringAnimationUsingKeyFrames.cs
- EntityProxyFactory.cs
- NativeMethods.cs
- ValidationError.cs
- Block.cs
- ResourceAssociationType.cs
- DataGridViewRowHeaderCell.cs
- PagerSettings.cs
- SqlClientWrapperSmiStreamChars.cs
- StyleSelector.cs
- RealizationContext.cs
- CharacterHit.cs
- DetailsViewActionList.cs
- DeploymentExceptionMapper.cs
- ChannelAcceptor.cs
- DirectoryInfo.cs
- BitmapEffectInputData.cs
- BaseCodePageEncoding.cs
- Stacktrace.cs
- CheckBoxDesigner.cs
- StreamUpdate.cs
- util.cs
- CodeMethodReturnStatement.cs
- SqlDeflator.cs
- FixedSOMPage.cs
- WebPartMenu.cs
- TypedMessageConverter.cs
- AudioStateChangedEventArgs.cs
- Cell.cs
- BinaryReader.cs
- AppearanceEditorPart.cs
- TimeZone.cs
- RemoteCryptoDecryptRequest.cs
- SessionStateContainer.cs
- _OSSOCK.cs
- GraphicsContext.cs
- DeviceFiltersSection.cs
- BrowserDefinitionCollection.cs
- ControlPaint.cs
- Pen.cs
- ErrorView.xaml.cs
- StreamUpgradeBindingElement.cs
- MsmqVerifier.cs
- CounterCreationDataCollection.cs
- WorkerRequest.cs
- DocComment.cs
- SplitterCancelEvent.cs
- BindingMemberInfo.cs
- __Filters.cs
- ReadWriteObjectLock.cs
- EdmRelationshipRoleAttribute.cs
- SafeCryptoHandles.cs
- WebPartConnectionsCloseVerb.cs
- SerializationInfo.cs
- WhitespaceSignificantCollectionAttribute.cs
- BinaryOperationBinder.cs
- ObjectHelper.cs
- WindowsTab.cs
- WebPartConnectionsDisconnectVerb.cs
- ListenerServiceInstallComponent.cs
- JoinQueryOperator.cs