Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.ServiceModel / System / ServiceModel / Channels / HttpChannelHelpers.cs
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4 namespace System.ServiceModel.Channels
5 {
6     using System.Collections.Generic;
7     using System.Collections.Specialized;
8     using System.Diagnostics;
9     using System.Globalization;
10     using System.IO;
11     using System.Net;
12     using System.Net.Http;
13     using System.Net.Http.Headers;
14     using System.Net.Mime;
15     using System.Net.Security;
16     using System.Net.Sockets;
17     using System.Reflection;
18     using System.Runtime;
19     using System.Runtime.CompilerServices;
20     using System.Runtime.Diagnostics;
21     using System.Security.Authentication.ExtendedProtection;
22     using System.Security.Principal;
23     using System.ServiceModel;
24     using System.ServiceModel.Activation;
25     using System.ServiceModel.Diagnostics;
26     using System.ServiceModel.Diagnostics.Application;
27     using System.ServiceModel.Security;
28     using System.ServiceModel.Security.Tokens;
29     using System.Text;
30     using System.Threading;
31     using System.Threading.Tasks;
32     using System.Xml;
33
34     // abstract out the common functionality of an "HttpInput"
35     abstract class HttpInput
36     {
37         const string multipartRelatedMediaType = "multipart/related";
38         const string startInfoHeaderParam = "start-info";
39         const string defaultContentType = "application/octet-stream";
40
41         BufferManager bufferManager;
42         bool isRequest;
43         MessageEncoder messageEncoder;
44         IHttpTransportFactorySettings settings;
45         bool streamed;
46         WebException webException;
47         Stream inputStream;
48         bool enableChannelBinding;
49         bool errorGettingInputStream;
50
51         protected HttpInput(IHttpTransportFactorySettings settings, bool isRequest, bool enableChannelBinding)
52         {
53             this.settings = settings;
54             this.bufferManager = settings.BufferManager;
55             this.messageEncoder = settings.MessageEncoderFactory.Encoder;
56             this.webException = null;
57             this.isRequest = isRequest;
58             this.inputStream = null;
59             this.enableChannelBinding = enableChannelBinding;
60
61             if (isRequest)
62             {
63                 this.streamed = TransferModeHelper.IsRequestStreamed(settings.TransferMode);
64             }
65             else
66             {
67                 this.streamed = TransferModeHelper.IsResponseStreamed(settings.TransferMode);
68             }
69         }
70
71         internal static HttpInput CreateHttpInput(HttpWebResponse httpWebResponse, IHttpTransportFactorySettings settings, ChannelBinding channelBinding)
72         {
73             return new WebResponseHttpInput(httpWebResponse, settings, channelBinding);
74         }
75
76         internal WebException WebException
77         {
78             get { return webException; }
79             set { webException = value; }
80         }
81
82         // Note: This method will return null in the case where throwOnError is false, and a non-fatal error occurs.
83         // Please exercice caution when passing in throwOnError = false.  This should basically only be done in error
84         // code paths, or code paths where there is very good reason that you would not want this method to throw.
85         // When passing in throwOnError = false, please handle the case where this method returns null.
86         public Stream GetInputStream(bool throwOnError)
87         {
88             if (inputStream == null && (throwOnError || !this.errorGettingInputStream))
89             {
90                 try
91                 {
92                     inputStream = GetInputStream();
93                     this.errorGettingInputStream = false;
94                 }
95                 catch (Exception e)
96                 {
97                     this.errorGettingInputStream = true;
98                     if (throwOnError || Fx.IsFatal(e))
99                     {
100                         throw;
101                     }
102
103                     DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
104                 }
105             }
106
107             return inputStream;
108         }
109
110         // -1 if chunked
111         public abstract long ContentLength { get; }
112         protected abstract string ContentTypeCore { get; }
113         protected abstract bool HasContent { get; }
114         protected abstract string SoapActionHeader { get; }
115         protected abstract Stream GetInputStream();
116         protected virtual ChannelBinding ChannelBinding { get { return null; } }
117
118         protected string ContentType
119         {
120             get
121             {
122                 string contentType = ContentTypeCore;
123
124                 if (string.IsNullOrEmpty(contentType))
125                 {
126                     return defaultContentType;
127                 }
128
129                 return contentType;
130             }
131         }
132
133         void ThrowMaxReceivedMessageSizeExceeded()
134         {
135             if (TD.MaxReceivedMessageSizeExceededIsEnabled())
136             {
137                 TD.MaxReceivedMessageSizeExceeded(SR.GetString(SR.MaxReceivedMessageSizeExceeded, settings.MaxReceivedMessageSize));
138             }
139
140             if (isRequest)
141             {
142                 ThrowHttpProtocolException(SR.GetString(SR.MaxReceivedMessageSizeExceeded, settings.MaxReceivedMessageSize), HttpStatusCode.RequestEntityTooLarge);
143             }
144             else
145             {
146                 string message = SR.GetString(SR.MaxReceivedMessageSizeExceeded, settings.MaxReceivedMessageSize);
147                 Exception inner = new QuotaExceededException(message);
148                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(message, inner));
149             }
150         }
151
152         Message DecodeBufferedMessage(ArraySegment<byte> buffer, Stream inputStream)
153         {
154             try
155             {
156                 // if we're chunked, make sure we've consumed the whole body
157                 if (ContentLength == -1 && buffer.Count == settings.MaxReceivedMessageSize)
158                 {
159                     byte[] extraBuffer = new byte[1];
160                     int extraReceived = inputStream.Read(extraBuffer, 0, 1);
161                     if (extraReceived > 0)
162                     {
163                         ThrowMaxReceivedMessageSizeExceeded();
164                     }
165                 }
166
167                 try
168                 {
169                     return messageEncoder.ReadMessage(buffer, bufferManager, ContentType);
170                 }
171                 catch (XmlException xmlException)
172                 {
173                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
174                         new ProtocolException(SR.GetString(SR.MessageXmlProtocolError), xmlException));
175                 }
176             }
177             finally
178             {
179                 inputStream.Close();
180             }
181         }
182
183         Message ReadBufferedMessage(Stream inputStream)
184         {
185             ArraySegment<byte> messageBuffer = GetMessageBuffer();
186             byte[] buffer = messageBuffer.Array;
187             int offset = 0;
188             int count = messageBuffer.Count;
189
190             while (count > 0)
191             {
192                 int bytesRead = inputStream.Read(buffer, offset, count);
193                 if (bytesRead == 0) // EOF 
194                 {
195                     if (ContentLength != -1)
196                     {
197                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
198                             new ProtocolException(SR.GetString(SR.HttpContentLengthIncorrect)));
199                     }
200
201                     break;
202                 }
203                 count -= bytesRead;
204                 offset += bytesRead;
205             }
206
207             return DecodeBufferedMessage(new ArraySegment<byte>(buffer, 0, offset), inputStream);
208         }
209
210         Message ReadChunkedBufferedMessage(Stream inputStream)
211         {
212             try
213             {
214                 return messageEncoder.ReadMessage(inputStream, bufferManager, settings.MaxBufferSize, ContentType);
215             }
216             catch (XmlException xmlException)
217             {
218                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
219                     new ProtocolException(SR.GetString(SR.MessageXmlProtocolError), xmlException));
220             }
221         }
222
223         Message ReadStreamedMessage(Stream inputStream)
224         {
225             MaxMessageSizeStream maxMessageSizeStream = new MaxMessageSizeStream(inputStream, settings.MaxReceivedMessageSize);
226
227             try
228             {
229                 return messageEncoder.ReadMessage(maxMessageSizeStream, settings.MaxBufferSize, ContentType);
230             }
231             catch (XmlException xmlException)
232             {
233                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
234                     new ProtocolException(SR.GetString(SR.MessageXmlProtocolError), xmlException));
235             }
236         }
237
238         protected abstract void AddProperties(Message message);
239
240         void ApplyChannelBinding(Message message)
241         {
242             if (this.enableChannelBinding)
243             {
244                 ChannelBindingUtility.TryAddToMessage(this.ChannelBinding, message, true);
245             }
246         }
247
248         // makes sure that appropriate HTTP level headers are included in the received Message
249         Exception ProcessHttpAddressing(Message message)
250         {
251             Exception result = null;
252             AddProperties(message);
253
254             // check if user is receiving WS-1 messages
255             if (message.Version.Addressing == AddressingVersion.None)
256             {
257                 bool actionAbsent = false;
258                 try
259                 {
260                     actionAbsent = (message.Headers.Action == null);
261                 }
262                 catch (XmlException e)
263                 {
264                     DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
265                 }
266                 catch (CommunicationException e)
267                 {
268                     DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
269                 }
270
271                 if (!actionAbsent)
272                 {
273                     result = new ProtocolException(SR.GetString(SR.HttpAddressingNoneHeaderOnWire,
274                         XD.AddressingDictionary.Action.Value));
275                 }
276
277                 bool toAbsent = false;
278                 try
279                 {
280                     toAbsent = (message.Headers.To == null);
281                 }
282                 catch (XmlException e)
283                 {
284                     DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
285                 }
286                 catch (CommunicationException e)
287                 {
288                     DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
289                 }
290
291                 if (!toAbsent)
292                 {
293                     result = new ProtocolException(SR.GetString(SR.HttpAddressingNoneHeaderOnWire,
294                         XD.AddressingDictionary.To.Value));
295                 }
296                 message.Headers.To = message.Properties.Via;
297             }
298
299             if (isRequest)
300             {
301                 string action = null;
302
303                 if (message.Version.Envelope == EnvelopeVersion.Soap11)
304                 {
305                     action = SoapActionHeader;
306                 }
307                 else if (message.Version.Envelope == EnvelopeVersion.Soap12 && !String.IsNullOrEmpty(ContentType))
308                 {
309                     ContentType parsedContentType = new ContentType(ContentType);
310
311                     if (parsedContentType.MediaType == multipartRelatedMediaType && parsedContentType.Parameters.ContainsKey(startInfoHeaderParam))
312                     {
313                         // fix to grab action from start-info as stated in RFC2387
314                         action = new ContentType(parsedContentType.Parameters[startInfoHeaderParam]).Parameters["action"];
315                     }
316                     if (action == null)
317                     {
318                         // only if we can't find an action inside start-info
319                         action = parsedContentType.Parameters["action"];
320                     }
321                 }
322
323                 if (action != null)
324                 {
325                     action = UrlUtility.UrlDecode(action, Encoding.UTF8);
326
327                     if (action.Length >= 2 && action[0] == '"' && action[action.Length - 1] == '"')
328                     {
329                         action = action.Substring(1, action.Length - 2);
330                     }
331
332                     if (message.Version.Addressing == AddressingVersion.None)
333                     {
334                         message.Headers.Action = action;
335                     }
336
337                     try
338                     {
339
340                         if (action.Length > 0 && string.Compare(message.Headers.Action, action, StringComparison.Ordinal) != 0)
341                         {
342                             result = new ActionMismatchAddressingException(SR.GetString(SR.HttpSoapActionMismatchFault,
343                                 message.Headers.Action, action), message.Headers.Action, action);
344                         }
345
346                     }
347                     catch (XmlException e)
348                     {
349                         DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
350                     }
351                     catch (CommunicationException e)
352                     {
353                         DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
354                     }
355                 }
356             }
357
358             ApplyChannelBinding(message);
359
360             if (DiagnosticUtility.ShouldUseActivity)
361             {
362                 TraceUtility.TransferFromTransport(message);
363             }
364             if (DiagnosticUtility.ShouldTraceInformation)
365             {
366                 TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.MessageReceived, SR.GetString(SR.TraceCodeMessageReceived),
367                     MessageTransmitTraceRecord.CreateReceiveTraceRecord(message), this, null, message);
368             }
369
370             // MessageLogger doesn't log AddressingVersion.None in the encoder since we want to make sure we log 
371             // as much of the message as possible. Here we log after stamping the addressing information
372             if (MessageLogger.LoggingEnabled && message.Version.Addressing == AddressingVersion.None)
373             {
374                 MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportReceive | MessageLoggingSource.LastChance);
375             }
376
377             return result;
378         }
379
380         void ValidateContentType()
381         {
382             if (!HasContent)
383                 return;
384
385             if (string.IsNullOrEmpty(ContentType))
386             {
387                 if (MessageLogger.ShouldLogMalformed)
388                 {
389                     // We pass in throwOnError = false below so that the exception which is eventually thrown is the ProtocolException below, with Http status code 415 "UnsupportedMediaType"
390                     Stream stream = this.GetInputStream(false);
391                     if (stream != null)
392                     {
393                         MessageLogger.LogMessage(stream, MessageLoggingSource.Malformed);
394                     }
395                 }
396                 ThrowHttpProtocolException(SR.GetString(SR.HttpContentTypeHeaderRequired), HttpStatusCode.UnsupportedMediaType, HttpChannelUtilities.StatusDescriptionStrings.HttpContentTypeMissing);
397             }
398             if (!messageEncoder.IsContentTypeSupported(ContentType))
399             {
400                 if (MessageLogger.ShouldLogMalformed)
401                 {
402                     // We pass in throwOnError = false below so that the exception which is eventually thrown is the ProtocolException below, with Http status code 415 "UnsupportedMediaType"
403                     Stream stream = this.GetInputStream(false);
404                     if (stream != null)
405                     {
406                         MessageLogger.LogMessage(stream, MessageLoggingSource.Malformed);
407                     }
408                 }
409                 string statusDescription = string.Format(CultureInfo.InvariantCulture, HttpChannelUtilities.StatusDescriptionStrings.HttpContentTypeMismatch, ContentType, messageEncoder.ContentType);
410                 ThrowHttpProtocolException(SR.GetString(SR.ContentTypeMismatch, ContentType, messageEncoder.ContentType), HttpStatusCode.UnsupportedMediaType, statusDescription);
411             }
412         }
413
414         public IAsyncResult BeginParseIncomingMessage(AsyncCallback callback, object state)
415         {
416             return this.BeginParseIncomingMessage(null, callback, state);
417         }
418
419         public IAsyncResult BeginParseIncomingMessage(HttpRequestMessage httpRequestMessage, AsyncCallback callback, object state)
420         {            
421             bool throwing = true;
422             try
423             {
424                 IAsyncResult result = new ParseMessageAsyncResult(httpRequestMessage, this, callback, state);
425                 throwing = false;
426                 return result;
427             }
428             finally
429             {
430                 if (throwing)
431                 {
432                     Close();
433                 }
434             }
435         }
436
437         public Message EndParseIncomingMessage(IAsyncResult result, out Exception requestException)
438         {
439             bool throwing = true;
440             try
441             {
442                 Message message = ParseMessageAsyncResult.End(result, out requestException);
443                 throwing = false;
444                 return message;
445             }
446             finally
447             {
448                 if (throwing)
449                 {
450                     Close();
451                 }
452             }
453         }
454
455         public HttpRequestMessageHttpInput CreateHttpRequestMessageInput()
456         {
457             HttpRequestMessage message = new HttpRequestMessage();
458
459             if (this.HasContent)
460             {
461                 message.Content = new StreamContent(new MaxMessageSizeStream(this.GetInputStream(true), this.settings.MaxReceivedMessageSize));
462             }
463
464             HttpChannelUtilities.EnsureHttpRequestMessageContentNotNull(message);
465
466             this.ConfigureHttpRequestMessage(message);
467             ChannelBinding channelBinding = this.enableChannelBinding ? this.ChannelBinding : null;
468             return new HttpRequestMessageHttpInput(message, this.settings, this.enableChannelBinding, channelBinding);
469         }
470
471         public abstract void ConfigureHttpRequestMessage(HttpRequestMessage message);
472
473         public Message ParseIncomingMessage(out Exception requestException)
474         {
475             return this.ParseIncomingMessage(null, out requestException);
476         }
477
478         public Message ParseIncomingMessage(HttpRequestMessage httpRequestMessage, out Exception requestException)
479         {
480             Message message = null;
481             requestException = null;
482             bool throwing = true;
483             try
484             {
485                 ValidateContentType();
486
487                 ServiceModelActivity activity = null;
488                 if (DiagnosticUtility.ShouldUseActivity &&
489                     ((ServiceModelActivity.Current == null) ||
490                      (ServiceModelActivity.Current.ActivityType != ActivityType.ProcessAction)))
491                 {
492                     activity = ServiceModelActivity.CreateBoundedActivity(true);
493                 }
494                 using (activity)
495                 {
496                     if (DiagnosticUtility.ShouldUseActivity && activity != null)
497                     {
498                         // Only update the Start identifier if the activity is not null.
499                         ServiceModelActivity.Start(activity, SR.GetString(SR.ActivityProcessingMessage, TraceUtility.RetrieveMessageNumber()), ActivityType.ProcessMessage);
500                     }
501
502                     if (!this.HasContent)
503                     {
504                         if (this.messageEncoder.MessageVersion == MessageVersion.None)
505                         {
506                             message = new NullMessage();
507                         }
508                         else
509                         {
510                             return null;
511                         }
512                     }
513                     else
514                     {
515                         Stream stream = this.GetInputStream(true);
516                         if (streamed)
517                         {
518                             message = ReadStreamedMessage(stream);
519                         }
520                         else if (this.ContentLength == -1)
521                         {
522                             message = ReadChunkedBufferedMessage(stream);
523                         }
524                         else
525                         {
526                             if (httpRequestMessage == null)
527                             {
528                                 message = ReadBufferedMessage(stream);
529                             }
530                             else
531                             {
532                                 message = ReadBufferedMessage(httpRequestMessage);
533                             }
534                         }
535                     }
536
537                     requestException = ProcessHttpAddressing(message);
538
539                     throwing = false;
540                     return message;
541                 }
542             }
543             finally
544             {
545                 if (throwing)
546                 {
547                     Close();
548                 }
549             }
550         }
551
552         Message ReadBufferedMessage(HttpRequestMessage httpRequestMessage)
553         {
554             Fx.Assert(httpRequestMessage != null, "httpRequestMessage cannot be null.");
555
556             Message message;
557             using (HttpContent currentContent = httpRequestMessage.Content)
558             {
559                 int length = (int)this.ContentLength;
560                 byte[] buffer = this.bufferManager.TakeBuffer(length);
561                 bool success = false;
562                 try
563                 {
564                     MemoryStream ms = new MemoryStream(buffer);
565                     currentContent.CopyToAsync(ms).Wait<CommunicationException>();
566                     httpRequestMessage.Content = new ByteArrayContent(buffer, 0, length);
567
568                     foreach (var header in currentContent.Headers)
569                     {
570                         httpRequestMessage.Content.Headers.Add(header.Key, header.Value);
571                     }
572
573                     // 
574
575                     message = this.messageEncoder.ReadMessage(new ArraySegment<byte>(buffer, 0, length), this.bufferManager, this.ContentType);
576                     success = true;
577                 }
578                 finally
579                 {
580                     if (!success)
581                     {
582                         // We don't have to return it in success case since the buffer will be returned to bufferManager when the message is disposed.
583                         this.bufferManager.ReturnBuffer(buffer);
584                     }
585                 }
586             }
587             return message;
588         }
589
590         void ThrowHttpProtocolException(string message, HttpStatusCode statusCode)
591         {
592             ThrowHttpProtocolException(message, statusCode, null);
593         }
594
595         void ThrowHttpProtocolException(string message, HttpStatusCode statusCode, string statusDescription)
596         {
597             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateHttpProtocolException(message, statusCode, statusDescription, webException));
598         }
599
600         internal static ProtocolException CreateHttpProtocolException(string message, HttpStatusCode statusCode, string statusDescription, Exception innerException)
601         {
602             ProtocolException exception = new ProtocolException(message, innerException);
603             exception.Data.Add(HttpChannelUtilities.HttpStatusCodeExceptionKey, statusCode);
604             if (statusDescription != null && statusDescription.Length > 0)
605             {
606                 exception.Data.Add(HttpChannelUtilities.HttpStatusDescriptionExceptionKey, statusDescription);
607             }
608
609             return exception;
610         }
611
612         protected virtual void Close()
613         {
614         }
615
616         ArraySegment<byte> GetMessageBuffer()
617         {
618             long count = ContentLength;
619             int bufferSize;
620
621             if (count > settings.MaxReceivedMessageSize)
622             {
623                 ThrowMaxReceivedMessageSizeExceeded();
624             }
625
626             bufferSize = (int)count;
627
628             return new ArraySegment<byte>(bufferManager.TakeBuffer(bufferSize), 0, bufferSize);
629         }
630
631         class ParseMessageAsyncResult : TraceAsyncResult
632         {
633             ArraySegment<byte> buffer;
634             int count;
635             int offset;
636             HttpInput httpInput;
637             Stream inputStream;
638             Message message;
639             Exception requestException = null;
640             HttpRequestMessage httpRequestMessage;            
641             static AsyncCallback onRead = Fx.ThunkCallback(new AsyncCallback(OnRead));
642
643             public ParseMessageAsyncResult(
644                 HttpRequestMessage httpRequestMessage,
645                 HttpInput httpInput,
646                 AsyncCallback callback,
647                 object state)
648                 : base(callback, state)
649             {
650                 this.httpInput = httpInput;
651                 this.httpRequestMessage = httpRequestMessage;
652                 this.BeginParse();
653             }
654
655             void BeginParse()
656             {
657                 httpInput.ValidateContentType();
658                 this.inputStream = httpInput.GetInputStream(true);
659
660                 if (!httpInput.HasContent)
661                 {
662                     if (httpInput.messageEncoder.MessageVersion == MessageVersion.None)
663                     {
664                         this.message = new NullMessage();
665                     }
666                     else
667                     {
668                         base.Complete(true);
669                         return;
670                     }
671                 }
672                 else if (httpInput.streamed || httpInput.ContentLength == -1)
673                 {
674                     if (httpInput.streamed)
675                     {
676                         this.message = httpInput.ReadStreamedMessage(inputStream);
677                     }
678                     else
679                     {
680                         this.message = httpInput.ReadChunkedBufferedMessage(inputStream);
681                     }
682                 }
683
684                 if (this.message != null)
685                 {
686                     this.requestException = httpInput.ProcessHttpAddressing(this.message);
687                     base.Complete(true);
688                     return;
689                 }
690
691                 AsyncCompletionResult result;
692                 if (httpRequestMessage == null)
693                 {
694                     result = this.DecodeBufferedMessageAsync();
695                 }
696                 else
697                 {
698                     result = this.DecodeBufferedHttpRequestMessageAsync();
699                 }
700
701                 if (result == AsyncCompletionResult.Completed)
702                 {
703                     base.Complete(true);
704                 }
705             }
706
707             AsyncCompletionResult DecodeBufferedMessageAsync()
708             {
709                 this.buffer = this.httpInput.GetMessageBuffer();
710                 this.count = this.buffer.Count;
711                 this.offset = 0;
712
713                 IAsyncResult result = inputStream.BeginRead(buffer.Array, offset, count, onRead, this);
714                 if (result.CompletedSynchronously)
715                 {
716                     if (ContinueReading(inputStream.EndRead(result)))
717                     {
718                         return AsyncCompletionResult.Completed;
719                     }
720                 }
721
722                 return AsyncCompletionResult.Queued;
723             }
724
725             bool ContinueReading(int bytesRead)
726             {
727                 while (true)
728                 {
729                     if (bytesRead == 0) // EOF
730                     {
731                         break;
732                     }
733                     else
734                     {
735                         offset += bytesRead;
736                         count -= bytesRead;
737                         if (count <= 0)
738                         {
739                             break;
740                         }
741                         else
742                         {
743                             IAsyncResult result = inputStream.BeginRead(buffer.Array, offset, count, onRead, this);
744                             if (!result.CompletedSynchronously)
745                             {
746                                 return false;
747                             }
748
749                             bytesRead = inputStream.EndRead(result);
750                         }
751                     }
752                 }
753
754                 using (DiagnosticUtility.ShouldUseActivity ? ServiceModelActivity.BoundOperation(this.CallbackActivity) : null)
755                 {
756                     using (ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity ? ServiceModelActivity.CreateBoundedActivity(true) : null)
757                     {
758                         if (DiagnosticUtility.ShouldUseActivity)
759                         {
760                             ServiceModelActivity.Start(activity, SR.GetString(SR.ActivityProcessingMessage, TraceUtility.RetrieveMessageNumber()), ActivityType.ProcessMessage);
761                         }
762
763                         this.message = this.httpInput.DecodeBufferedMessage(new ArraySegment<byte>(buffer.Array, 0, offset), inputStream);
764                         this.requestException = this.httpInput.ProcessHttpAddressing(this.message);
765                     }
766                     return true;
767                 }
768             }
769
770             static void OnRead(IAsyncResult result)
771             {
772                 if (result.CompletedSynchronously)
773                     return;
774
775                 ParseMessageAsyncResult thisPtr = (ParseMessageAsyncResult)result.AsyncState;
776
777                 Exception completionException = null;
778                 bool completeSelf;
779                 try
780                 {
781                     completeSelf = thisPtr.ContinueReading(thisPtr.inputStream.EndRead(result));
782                 }
783 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
784                 catch (Exception e)
785                 {
786                     if (Fx.IsFatal(e))
787                     {
788                         throw;
789                     }
790
791                     completeSelf = true;
792                     completionException = e;
793                 }
794
795                 if (completeSelf)
796                 {
797                     thisPtr.Complete(false, completionException);
798                 }
799             }
800
801             public static Message End(IAsyncResult result, out Exception requestException)
802             {
803                 ParseMessageAsyncResult thisPtr = AsyncResult.End<ParseMessageAsyncResult>(result);
804                 requestException = thisPtr.requestException;
805                 return thisPtr.message;
806             }
807
808             AsyncCompletionResult DecodeBufferedHttpRequestMessageAsync()
809             {
810                 // Need to consider moving this to async implemenation for HttpContent reading.(CSDMAIN: 229108)
811                 this.message = this.httpInput.ReadBufferedMessage(this.httpRequestMessage);
812                 this.requestException = this.httpInput.ProcessHttpAddressing(this.message);
813                 return AsyncCompletionResult.Completed;
814             }
815         }
816
817         class WebResponseHttpInput : HttpInput
818         {
819             HttpWebResponse httpWebResponse;
820             byte[] preReadBuffer;
821             ChannelBinding channelBinding;
822             bool hasContent;
823
824             public WebResponseHttpInput(HttpWebResponse httpWebResponse, IHttpTransportFactorySettings settings, ChannelBinding channelBinding)
825                 : base(settings, false, channelBinding != null)
826             {
827                 this.channelBinding = channelBinding;
828                 this.httpWebResponse = httpWebResponse;
829                 if (this.httpWebResponse.ContentLength == -1)
830                 {
831                     this.preReadBuffer = new byte[1];
832
833                     if (this.httpWebResponse.GetResponseStream().Read(preReadBuffer, 0, 1) == 0)
834                     {
835                         this.preReadBuffer = null;
836                     }
837                 }
838
839                 this.hasContent = (this.preReadBuffer != null || this.httpWebResponse.ContentLength > 0);
840                 if (!this.hasContent)
841                 {
842                     // Close the response stream to avoid leaking the connection.
843                     this.httpWebResponse.GetResponseStream().Close();
844                 }
845             }
846
847             protected override ChannelBinding ChannelBinding
848             {
849                 get
850                 {
851                     return this.channelBinding;
852                 }
853             }
854
855             public override long ContentLength
856             {
857                 get
858                 {
859                     return httpWebResponse.ContentLength;
860                 }
861             }
862
863             protected override string ContentTypeCore
864             {
865                 get
866                 {
867                     return httpWebResponse.ContentType;
868                 }
869             }
870
871             protected override bool HasContent
872             {
873                 get { return this.hasContent; }
874             }
875
876             protected override string SoapActionHeader
877             {
878                 get
879                 {
880                     return httpWebResponse.Headers["SOAPAction"];
881                 }
882             }
883
884             protected override void AddProperties(Message message)
885             {
886                 HttpResponseMessageProperty responseProperty = new HttpResponseMessageProperty(httpWebResponse.Headers);
887                 responseProperty.StatusCode = httpWebResponse.StatusCode;
888                 responseProperty.StatusDescription = httpWebResponse.StatusDescription;
889                 message.Properties.Add(HttpResponseMessageProperty.Name, responseProperty);
890                 message.Properties.Via = message.Version.Addressing.AnonymousUri;
891             }
892
893             public override void ConfigureHttpRequestMessage(HttpRequestMessage message)
894             {
895                 // HTTP pipeline for client side is not implemented yet
896                 // DCR CSDMain 216853 is tracking this
897                 // This API is never going to be called in current stack
898                 Fx.Assert(false, "HTTP pipeline for client is not implemented yet. This method should not be called.");
899                 throw FxTrace.Exception.AsError(new NotSupportedException());
900             }
901
902             protected override void Close()
903             {
904                 try
905                 {
906                     httpWebResponse.Close();
907                 }
908                 catch (Exception exception)
909                 {
910                     if (Fx.IsFatal(exception))
911                         throw;
912
913                     DiagnosticUtility.TraceHandledException(exception, TraceEventType.Error);
914                 }
915             }
916
917             protected override Stream GetInputStream()
918             {
919                 Fx.Assert(this.HasContent, "this.HasContent must be true.");
920                 if (this.preReadBuffer != null)
921                 {
922                     return new WebResponseInputStream(httpWebResponse, preReadBuffer);
923                 }
924                 else
925                 {
926                     return new WebResponseInputStream(httpWebResponse);
927                 }
928             }
929
930             class WebResponseInputStream : DetectEofStream
931             {
932                 // in order to avoid ----ing kernel buffers, we throttle our reads. http.sys
933                 // deals with this fine, but System.Net doesn't do any such throttling.
934                 const int maxSocketRead = 64 * 1024;
935                 HttpWebResponse webResponse;
936                 bool responseClosed;
937
938                 public WebResponseInputStream(HttpWebResponse httpWebResponse)
939                     : base(httpWebResponse.GetResponseStream())
940                 {
941                     this.webResponse = httpWebResponse;
942                 }
943
944                 public WebResponseInputStream(HttpWebResponse httpWebResponse, byte[] prereadBuffer)
945                     : base(new PreReadStream(httpWebResponse.GetResponseStream(), prereadBuffer))
946                 {
947                     this.webResponse = httpWebResponse;
948                 }
949
950
951                 public override void Close()
952                 {
953                     base.Close();
954                     CloseResponse();
955                 }
956
957                 protected override void OnReceivedEof()
958                 {
959                     base.OnReceivedEof();
960                     CloseResponse();
961                 }
962
963                 void CloseResponse()
964                 {
965                     if (responseClosed)
966                     {
967                         return;
968                     }
969
970                     responseClosed = true;
971                     this.webResponse.Close();
972                 }
973
974                 public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
975                 {
976                     try
977                     {
978                         return BaseStream.BeginRead(buffer, offset, Math.Min(count, maxSocketRead), callback, state);
979                     }
980                     catch (IOException ioException)
981                     {
982                         throw this.CreateResponseIOException(ioException);
983                     }
984                     catch (ObjectDisposedException objectDisposedException)
985                     {
986                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(objectDisposedException.Message, objectDisposedException));
987                     }
988                     catch (WebException webException)
989                     {
990                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateResponseWebException(webException, this.webResponse));
991                     }
992                 }
993
994                 public override int EndRead(IAsyncResult result)
995                 {
996                     try
997                     {
998                         return BaseStream.EndRead(result);
999                     }
1000                     catch (IOException ioException)
1001                     {
1002                         throw this.CreateResponseIOException(ioException);
1003                     }
1004                     catch (ObjectDisposedException objectDisposedException)
1005                     {
1006                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(objectDisposedException.Message, objectDisposedException));
1007                     }
1008                     catch (WebException webException)
1009                     {
1010                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateResponseWebException(webException, this.webResponse));
1011                     }
1012                 }
1013
1014                 public override int Read(byte[] buffer, int offset, int count)
1015                 {
1016                     try
1017                     {
1018                         return BaseStream.Read(buffer, offset, Math.Min(count, maxSocketRead));
1019                     }
1020                     catch (ObjectDisposedException objectDisposedException)
1021                     {
1022                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(objectDisposedException.Message, objectDisposedException));
1023                     }
1024                     catch (IOException ioException)
1025                     {
1026                         throw this.CreateResponseIOException(ioException);
1027                     }
1028                     catch (WebException webException)
1029                     {
1030                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateResponseWebException(webException, this.webResponse));
1031                     }
1032                 }
1033
1034
1035                 public override int ReadByte()
1036                 {
1037                     try
1038                     {
1039                         return BaseStream.ReadByte();
1040                     }
1041                     catch (ObjectDisposedException objectDisposedException)
1042                     {
1043                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(objectDisposedException.Message, objectDisposedException));
1044                     }
1045                     catch (IOException ioException)
1046                     {
1047                         throw this.CreateResponseIOException(ioException);
1048                     }
1049                     catch (WebException webException)
1050                     {
1051                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateResponseWebException(webException, this.webResponse));
1052                     }
1053                 }
1054
1055                 private Exception CreateResponseIOException(IOException ioException)
1056                 {
1057                     TimeSpan timeSpan = this.CanTimeout ? TimeoutHelper.FromMilliseconds(this.ReadTimeout) : TimeSpan.MaxValue;
1058
1059                     return DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateResponseIOException(ioException, timeSpan));
1060                 } 
1061
1062             }
1063         }
1064     }
1065
1066     // abstract out the common functionality of an "HttpOutput"
1067     abstract class HttpOutput
1068     {
1069         const string DefaultMimeVersion = "1.0";
1070
1071         HttpAbortReason abortReason;
1072         bool isDisposed;
1073         bool isRequest;
1074         Message message;
1075         IHttpTransportFactorySettings settings;
1076         byte[] bufferToRecycle;
1077         BufferManager bufferManager;
1078         MessageEncoder messageEncoder;
1079         bool streamed;
1080         static Action<object> onStreamSendTimeout;
1081         string mtomBoundary;
1082         Stream outputStream;
1083         bool supportsConcurrentIO;
1084         EventTraceActivity eventTraceActivity;
1085         bool canSendCompressedResponses;
1086
1087         protected HttpOutput(IHttpTransportFactorySettings settings, Message message, bool isRequest, bool supportsConcurrentIO)
1088         {
1089             this.settings = settings;
1090             this.message = message;
1091             this.isRequest = isRequest;
1092             this.bufferManager = settings.BufferManager;
1093             this.messageEncoder = settings.MessageEncoderFactory.Encoder;
1094             ICompressedMessageEncoder compressedMessageEncoder = this.messageEncoder as ICompressedMessageEncoder;
1095             this.canSendCompressedResponses = compressedMessageEncoder != null && compressedMessageEncoder.CompressionEnabled;
1096             if (isRequest)
1097             {
1098                 this.streamed = TransferModeHelper.IsRequestStreamed(settings.TransferMode);
1099             }
1100             else
1101             {
1102                 this.streamed = TransferModeHelper.IsResponseStreamed(settings.TransferMode);
1103             }
1104             this.supportsConcurrentIO = supportsConcurrentIO;
1105
1106             if (FxTrace.Trace.IsEnd2EndActivityTracingEnabled)
1107             {
1108                 this.eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(message);
1109             }
1110         }
1111
1112         protected virtual bool IsChannelBindingSupportEnabled { get { return false; } }
1113         protected virtual ChannelBinding ChannelBinding { get { return null; } }
1114
1115         protected void Abort()
1116         {
1117             Abort(HttpAbortReason.Aborted);
1118         }
1119
1120         public virtual void Abort(HttpAbortReason reason)
1121         {
1122             if (isDisposed)
1123             {
1124                 return;
1125             }
1126
1127             this.abortReason = reason;
1128
1129             TraceRequestResponseAborted(reason);
1130
1131             CleanupBuffer();
1132         }
1133
1134         private void TraceRequestResponseAborted(HttpAbortReason reason)
1135         {
1136             if (isRequest)
1137             {
1138                 if (TD.HttpChannelRequestAbortedIsEnabled())
1139                 {
1140                     TD.HttpChannelRequestAborted(this.eventTraceActivity);
1141                 }
1142             }
1143             else if (TD.HttpChannelResponseAbortedIsEnabled())
1144             {
1145                 TD.HttpChannelResponseAborted(this.eventTraceActivity);
1146             }
1147
1148             if (DiagnosticUtility.ShouldTraceWarning)
1149             {
1150                 TraceUtility.TraceEvent(TraceEventType.Warning,
1151                                         isRequest ? TraceCode.HttpChannelRequestAborted : TraceCode.HttpChannelResponseAborted,
1152                                         isRequest ? SR.GetString(SR.TraceCodeHttpChannelRequestAborted) : SR.GetString(SR.TraceCodeHttpChannelResponseAborted),
1153                                         this.message);
1154             }
1155         }
1156
1157         public void Close()
1158         {
1159             if (isDisposed)
1160             {
1161                 return;
1162             }
1163
1164             try
1165             {
1166                 if (this.outputStream != null)
1167                 {
1168                     outputStream.Close();
1169                 }
1170             }
1171             finally
1172             {
1173                 CleanupBuffer();
1174             }
1175         }
1176
1177         void CleanupBuffer()
1178         {
1179             byte[] bufferToRecycleSnapshot = Interlocked.Exchange<byte[]>(ref this.bufferToRecycle, null);
1180             if (bufferToRecycleSnapshot != null)
1181             {
1182                 bufferManager.ReturnBuffer(bufferToRecycleSnapshot);
1183             }
1184
1185             isDisposed = true;
1186         }
1187
1188         protected abstract void AddMimeVersion(string version);
1189         protected abstract void AddHeader(string name, string value);
1190         protected abstract void SetContentType(string contentType);
1191         protected abstract void SetContentEncoding(string contentEncoding);
1192         protected abstract void SetStatusCode(HttpStatusCode statusCode);
1193         protected abstract void SetStatusDescription(string statusDescription);
1194         protected virtual bool CleanupChannelBinding { get { return true; } }
1195         protected virtual void SetContentLength(int contentLength)
1196         {
1197         }
1198
1199         protected virtual string HttpMethod { get { return null; } }
1200
1201         public virtual ChannelBinding TakeChannelBinding()
1202         {
1203             return null;
1204         }
1205
1206         private void ApplyChannelBinding()
1207         {
1208             if (this.IsChannelBindingSupportEnabled)
1209             {
1210                 ChannelBindingUtility.TryAddToMessage(this.ChannelBinding, this.message, this.CleanupChannelBinding);
1211             }
1212         }
1213
1214         protected abstract Stream GetOutputStream();
1215
1216         protected virtual bool WillGetOutputStreamCompleteSynchronously
1217         {
1218             get { return true; }
1219         }
1220
1221         protected bool CanSendCompressedResponses
1222         {
1223             get { return this.canSendCompressedResponses; }
1224         }
1225
1226         protected virtual IAsyncResult BeginGetOutputStream(AsyncCallback callback, object state)
1227         {
1228             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
1229         }
1230
1231         protected virtual Stream EndGetOutputStream(IAsyncResult result)
1232         {
1233             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
1234         }
1235
1236         public void ConfigureHttpResponseMessage(Message message, HttpResponseMessage httpResponseMessage, HttpResponseMessageProperty responseProperty)
1237         {
1238             HttpChannelUtilities.EnsureHttpResponseMessageContentNotNull(httpResponseMessage);
1239
1240             string action = message.Headers.Action;
1241
1242             if (message.Version.Addressing == AddressingVersion.None)
1243             {
1244                 if (MessageLogger.LogMessagesAtTransportLevel)
1245                 {
1246                     message.Properties.Add(AddressingProperty.Name, new AddressingProperty(message.Headers));
1247                 }
1248
1249                 message.Headers.Action = null;
1250                 message.Headers.To = null;
1251             }
1252
1253             bool httpResponseMessagePropertyFound = responseProperty != null;
1254
1255             string contentType = null;
1256             if (message.Version == MessageVersion.None && httpResponseMessagePropertyFound && !string.IsNullOrEmpty(responseProperty.Headers[HttpResponseHeader.ContentType]))
1257             {
1258                 contentType = responseProperty.Headers[HttpResponseHeader.ContentType];
1259                 responseProperty.Headers.Remove(HttpResponseHeader.ContentType);
1260                 if (!messageEncoder.IsContentTypeSupported(contentType))
1261                 {
1262                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1263                         new ProtocolException(SR.GetString(SR.ResponseContentTypeNotSupported,
1264                         contentType)));
1265                 }
1266             }
1267
1268             if (string.IsNullOrEmpty(contentType))
1269             {
1270                 MtomMessageEncoder mtomMessageEncoder = messageEncoder as MtomMessageEncoder;
1271                 if (mtomMessageEncoder == null)
1272                 {
1273                     contentType = messageEncoder.ContentType;
1274                 }
1275                 else
1276                 {
1277                     contentType = mtomMessageEncoder.GetContentType(out this.mtomBoundary);
1278                     // For MTOM messages, add a MIME version header
1279                     httpResponseMessage.Headers.Add(HttpChannelUtilities.MIMEVersionHeader, DefaultMimeVersion);
1280                 }
1281             }
1282
1283             if (isRequest && FxTrace.Trace.IsEnd2EndActivityTracingEnabled)
1284             {
1285                 EnsureEventTraceActivity(message);
1286             }
1287
1288             if (this.CanSendCompressedResponses)
1289             {
1290                 string contentEncoding;
1291                 string compressionContentType = contentType;
1292                 if (HttpChannelUtilities.GetHttpResponseTypeAndEncodingForCompression(ref compressionContentType, out contentEncoding))
1293                 {
1294                     contentType = compressionContentType;
1295                     this.SetContentEncoding(contentEncoding);
1296                 }
1297             }
1298
1299             if (httpResponseMessage.Content != null && !string.IsNullOrEmpty(contentType))
1300             {
1301                 MediaTypeHeaderValue mediaTypeHeaderValue;
1302                 if (!MediaTypeHeaderValue.TryParse(contentType, out mediaTypeHeaderValue))
1303                 {
1304                     throw FxTrace.Exception.Argument("contentType", SR.GetString(SR.InvalidContentTypeError, contentType));
1305                 }
1306                 httpResponseMessage.Content.Headers.ContentType = mediaTypeHeaderValue;
1307             }
1308
1309             bool httpMethodIsHead = string.Compare(this.HttpMethod, "HEAD", StringComparison.OrdinalIgnoreCase) == 0;
1310
1311             if (httpMethodIsHead ||
1312                 httpResponseMessagePropertyFound && responseProperty.SuppressEntityBody)
1313             {
1314                 httpResponseMessage.Content.Headers.ContentLength = 0;
1315                 httpResponseMessage.Content.Headers.ContentType = null;
1316             }
1317
1318             if (httpResponseMessagePropertyFound)
1319             {
1320                 httpResponseMessage.StatusCode = responseProperty.StatusCode;
1321                 if (responseProperty.StatusDescription != null)
1322                 {
1323                     responseProperty.StatusDescription = responseProperty.StatusDescription;
1324                 }
1325
1326                 foreach (string key in responseProperty.Headers.AllKeys)
1327                 {
1328                     httpResponseMessage.AddHeader(key, responseProperty.Headers[key]);
1329                 }
1330             }
1331
1332             if (!message.IsEmpty)
1333             {
1334                 using (HttpContent content = httpResponseMessage.Content)
1335                 {
1336                     if (this.streamed)
1337                     {
1338                         IStreamedMessageEncoder streamedMessageEncoder = this.messageEncoder as IStreamedMessageEncoder;
1339                         Stream stream = null;
1340                         if (streamedMessageEncoder != null)
1341                         {
1342                             stream = streamedMessageEncoder.GetResponseMessageStream(message);
1343                         }
1344
1345                         if (stream != null)
1346                         {
1347                             httpResponseMessage.Content = new StreamContent(stream);
1348                         }
1349                         else
1350                         {
1351                             httpResponseMessage.Content = new OpaqueContent(this.messageEncoder, message, this.mtomBoundary);
1352                         }
1353                     }
1354                     else
1355                     {
1356                         // HttpOutputByteArrayContent assumes responsibility for returning the buffer to the bufferManager. 
1357                         ArraySegment<byte> messageBytes = this.SerializeBufferedMessage(message, false);
1358                         httpResponseMessage.Content = new HttpOutputByteArrayContent(messageBytes.Array, messageBytes.Offset, messageBytes.Count, this.bufferManager);
1359                     }
1360
1361                     httpResponseMessage.Content.Headers.Clear();
1362                     foreach (var header in content.Headers)
1363                     {
1364                         httpResponseMessage.Content.Headers.Add(header.Key, header.Value);
1365                     }
1366                 }
1367             }
1368         }
1369
1370         protected virtual bool PrepareHttpSend(Message message)
1371         {
1372             string action = message.Headers.Action;
1373
1374             if (message.Version.Addressing == AddressingVersion.None)
1375             {
1376                 if (MessageLogger.LogMessagesAtTransportLevel)
1377                 {
1378                     message.Properties.Add(AddressingProperty.Name, new AddressingProperty(message.Headers));
1379                 }
1380
1381                 message.Headers.Action = null;
1382                 message.Headers.To = null;
1383             }
1384
1385             string contentType = null;
1386
1387             if (message.Version == MessageVersion.None)
1388             {
1389                 object property = null;
1390                 if (message.Properties.TryGetValue(HttpResponseMessageProperty.Name, out property))
1391                 {
1392                     HttpResponseMessageProperty responseProperty = (HttpResponseMessageProperty)property;
1393                     if (!string.IsNullOrEmpty(responseProperty.Headers[HttpResponseHeader.ContentType]))
1394                     {
1395                         contentType = responseProperty.Headers[HttpResponseHeader.ContentType];
1396                         if (!messageEncoder.IsContentTypeSupported(contentType))
1397                         {
1398                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1399                                 new ProtocolException(SR.GetString(SR.ResponseContentTypeNotSupported,
1400                                 contentType)));
1401                         }
1402                     }
1403                 }
1404             }
1405
1406             if (string.IsNullOrEmpty(contentType))
1407             {
1408                 MtomMessageEncoder mtomMessageEncoder = messageEncoder as MtomMessageEncoder;
1409                 if (mtomMessageEncoder == null)
1410                 {
1411                     contentType = messageEncoder.ContentType;
1412                 }
1413                 else
1414                 {
1415                     contentType = mtomMessageEncoder.GetContentType(out this.mtomBoundary);
1416                     // For MTOM messages, add a MIME version header
1417                     AddMimeVersion("1.0");
1418                 }
1419             }
1420
1421             if (isRequest && FxTrace.Trace.IsEnd2EndActivityTracingEnabled)
1422             {
1423                 EnsureEventTraceActivity(message);
1424             }
1425
1426             SetContentType(contentType);
1427             return message is NullMessage;
1428         }
1429
1430         protected bool PrepareHttpSend(HttpResponseMessage httpResponseMessage)
1431         {
1432             this.PrepareHttpSendCore(httpResponseMessage);
1433             return HttpChannelUtilities.IsEmpty(httpResponseMessage);
1434         }
1435
1436         protected abstract void PrepareHttpSendCore(HttpResponseMessage message);
1437
1438         private static void EnsureEventTraceActivity(Message message)
1439         {
1440             //We need to send this only if there is no message id. 
1441             if (message.Headers.MessageId == null)
1442             {
1443                 EventTraceActivity eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(message);
1444                 if (eventTraceActivity == null)
1445                 {
1446                     //Whoops no activity on the message yet.                         
1447                     eventTraceActivity = new EventTraceActivity();
1448                     EventTraceActivityHelper.TryAttachActivity(message, eventTraceActivity);
1449                 }
1450
1451                 HttpRequestMessageProperty httpProperties;
1452                 if (!message.Properties.TryGetValue<HttpRequestMessageProperty>(HttpRequestMessageProperty.Name, out httpProperties))
1453                 {
1454                     httpProperties = new HttpRequestMessageProperty();
1455                     message.Properties.Add(HttpRequestMessageProperty.Name, httpProperties);
1456                 }
1457                 httpProperties.Headers.Add(EventTraceActivity.Name, Convert.ToBase64String(eventTraceActivity.ActivityId.ToByteArray()));
1458             }
1459         }
1460
1461         ArraySegment<byte> SerializeBufferedMessage(Message message)
1462         {
1463             // by default, the HttpOutput should own the buffer and clean it up
1464             return SerializeBufferedMessage(message, true);
1465         }
1466
1467         ArraySegment<byte> SerializeBufferedMessage(Message message, bool shouldRecycleBuffer)
1468         {
1469             ArraySegment<byte> result;
1470
1471             MtomMessageEncoder mtomMessageEncoder = messageEncoder as MtomMessageEncoder;
1472             if (mtomMessageEncoder == null)
1473             {
1474                 result = messageEncoder.WriteMessage(message, int.MaxValue, bufferManager);
1475             }
1476             else
1477             {
1478                 result = mtomMessageEncoder.WriteMessage(message, int.MaxValue, bufferManager, 0, this.mtomBoundary);
1479             }
1480
1481             if (shouldRecycleBuffer)
1482             {
1483                 // Only set this.bufferToRecycle if the HttpOutput owns the buffer, we will clean it up upon httpOutput.Close()
1484                 // Otherwise, caller of SerializeBufferedMessage assumes responsiblity for returning the buffer to the buffer pool
1485             this.bufferToRecycle = result.Array;
1486             }
1487             return result;
1488         }
1489
1490         Stream GetWrappedOutputStream()
1491         {
1492             const int ChunkSize = 32768;    // buffer size used for synchronous writes
1493             const int BufferSize = 16384;   // buffer size used for asynchronous writes
1494             const int BufferCount = 4;      // buffer count used for asynchronous writes
1495
1496             // Writing an HTTP request chunk has a high fixed cost, so use BufferedStream to avoid writing 
1497             // small ones. 
1498             return this.supportsConcurrentIO ? (Stream)new BufferedOutputAsyncStream(this.outputStream, BufferSize, BufferCount) : new BufferedStream(this.outputStream, ChunkSize);
1499         }
1500
1501         void WriteStreamedMessage(TimeSpan timeout)
1502         {
1503             this.outputStream = GetWrappedOutputStream();
1504
1505             // Since HTTP streams don't support timeouts, we can't just use TimeoutStream here. 
1506             // Rather, we need to run a timer to bound the overall operation
1507             if (onStreamSendTimeout == null)
1508             {
1509                 onStreamSendTimeout = new Action<object>(OnStreamSendTimeout);
1510             }
1511             IOThreadTimer sendTimer = new IOThreadTimer(onStreamSendTimeout, this, true);
1512             sendTimer.Set(timeout);
1513
1514             try
1515             {
1516                 MtomMessageEncoder mtomMessageEncoder = messageEncoder as MtomMessageEncoder;
1517                 if (mtomMessageEncoder == null)
1518                 {
1519                     messageEncoder.WriteMessage(this.message, this.outputStream);
1520                 }
1521                 else
1522                 {
1523                     mtomMessageEncoder.WriteMessage(this.message, this.outputStream, this.mtomBoundary);
1524                 }
1525
1526                 if (this.supportsConcurrentIO)
1527                 {
1528                     this.outputStream.Close();
1529                 }
1530             }
1531             finally
1532             {
1533                 sendTimer.Cancel();
1534             }
1535         }
1536
1537         static void OnStreamSendTimeout(object state)
1538         {
1539             HttpOutput thisPtr = (HttpOutput)state;
1540             thisPtr.Abort(HttpAbortReason.TimedOut);
1541         }
1542
1543         IAsyncResult BeginWriteStreamedMessage(HttpResponseMessage httpResponseMessage, TimeSpan timeout, AsyncCallback callback, object state)
1544         {
1545             return new WriteStreamedMessageAsyncResult(timeout, this, httpResponseMessage, callback, state);
1546         }
1547
1548         void EndWriteStreamedMessage(IAsyncResult result)
1549         {
1550             WriteStreamedMessageAsyncResult.End(result);
1551         }
1552
1553         class HttpOutputByteArrayContent : ByteArrayContent
1554         {
1555             BufferManager bufferManager;
1556             volatile bool cleaned = false;
1557             ArraySegment<byte> content;
1558
1559             public HttpOutputByteArrayContent(byte[] content, int offset, int count, BufferManager bufferManager)
1560                 : base(content, offset, count)
1561             {
1562                 Fx.Assert(bufferManager != null, "bufferManager should not be null");
1563                 Fx.Assert(content != null, "content should not be null");
1564                 this.content = new ArraySegment<byte>(content, offset, count);
1565                 this.bufferManager = bufferManager;
1566             }
1567
1568             public ArraySegment<byte> Content
1569             {
1570                 get
1571                 {
1572                     return this.content;
1573                 }
1574             }
1575
1576             protected override Task<Stream> CreateContentReadStreamAsync()
1577             {
1578                 return base.CreateContentReadStreamAsync().ContinueWith<Stream>(t => 
1579                     new HttpOutputByteArrayContentStream(t.Result, this));
1580             }
1581
1582             protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
1583             {
1584                 return base.SerializeToStreamAsync(stream, context).ContinueWith(t =>
1585                     {
1586                         this.Cleanup();
1587                         HttpChannelUtilities.HandleContinueWithTask(t);
1588                     });
1589             }
1590
1591             void Cleanup()
1592             {
1593                 if (!cleaned)
1594                 {
1595                     lock (this)
1596                     {
1597                         if (!cleaned)
1598                         {
1599                             cleaned = true;
1600                             this.bufferManager.ReturnBuffer(this.content.Array);
1601                         }
1602                     }
1603                 }
1604             }
1605
1606             class HttpOutputByteArrayContentStream : DelegatingStream
1607             {
1608                 HttpOutputByteArrayContent content;
1609
1610                 public HttpOutputByteArrayContentStream(Stream innerStream, HttpOutputByteArrayContent content)
1611                     : base(innerStream)
1612                 {
1613                     this.content = content;
1614                 }
1615
1616                 public override void Close()
1617                 {
1618                     base.Close();
1619                     this.content.Cleanup();
1620                 }
1621             }
1622         }
1623
1624         class WriteStreamedMessageAsyncResult : AsyncResult
1625         {
1626             HttpOutput httpOutput;
1627             IOThreadTimer sendTimer;
1628             static AsyncCallback onWriteStreamedMessage = Fx.ThunkCallback(OnWriteStreamedMessage);
1629             HttpResponseMessage httpResponseMessage;
1630
1631             public WriteStreamedMessageAsyncResult(TimeSpan timeout, HttpOutput httpOutput, HttpResponseMessage httpResponseMessage, AsyncCallback callback, object state)
1632                 : base(callback, state)
1633             {
1634                 this.httpResponseMessage = httpResponseMessage;
1635                 this.httpOutput = httpOutput;
1636                 httpOutput.outputStream = httpOutput.GetWrappedOutputStream();
1637
1638                 // Since HTTP streams don't support timeouts, we can't just use TimeoutStream here. 
1639                 // Rather, we need to run a timer to bound the overall operation
1640                 if (onStreamSendTimeout == null)
1641                 {
1642                     onStreamSendTimeout = new Action<object>(OnStreamSendTimeout);
1643                 }
1644                 this.SetTimer(timeout);
1645
1646                 bool completeSelf = false;
1647                 bool throwing = true;
1648
1649                 try
1650                 {
1651                     completeSelf = HandleWriteStreamedMessage(null);
1652                     throwing = false;
1653                 }
1654                 finally
1655                 {
1656                     if (completeSelf || throwing)
1657                     {
1658                         this.sendTimer.Cancel();
1659                     }
1660                 }
1661
1662                 if (completeSelf)
1663                 {
1664                     this.Complete(true);
1665                 }
1666             }
1667
1668             bool HandleWriteStreamedMessage(IAsyncResult result)
1669             {
1670                 if (this.httpResponseMessage == null)
1671                 {
1672                     if (result == null)
1673                     {
1674                         MtomMessageEncoder mtomMessageEncoder = httpOutput.messageEncoder as MtomMessageEncoder;
1675                         if (mtomMessageEncoder == null)
1676                         {
1677                             result = httpOutput.messageEncoder.BeginWriteMessage(httpOutput.message, httpOutput.outputStream, onWriteStreamedMessage, this);
1678                         }
1679                         else
1680                         {
1681                             result = mtomMessageEncoder.BeginWriteMessage(httpOutput.message, httpOutput.outputStream, httpOutput.mtomBoundary, onWriteStreamedMessage, this);
1682                         }
1683
1684                         if (!result.CompletedSynchronously)
1685                         {
1686                             return false;
1687                         }
1688                     }
1689
1690                     httpOutput.messageEncoder.EndWriteMessage(result);
1691
1692                     if (this.httpOutput.supportsConcurrentIO)
1693                     {
1694                         httpOutput.outputStream.Close();
1695                     }
1696
1697                     return true;
1698                 }
1699                 else
1700                 {
1701                     OpaqueContent content = this.httpResponseMessage.Content as OpaqueContent;
1702                     if (result == null)
1703                     {
1704                         Fx.Assert(this.httpResponseMessage.Content != null, "httpOutput.httpResponseMessage.Content should not be null.");
1705
1706                         if (content != null)
1707                         {
1708                             result = content.BeginWriteToStream(httpOutput.outputStream, onWriteStreamedMessage, this);
1709                         }
1710                         else
1711                         {
1712                             result = this.httpResponseMessage.Content.CopyToAsync(httpOutput.outputStream).AsAsyncResult(onWriteStreamedMessage, this);
1713                         }
1714
1715                         if (!result.CompletedSynchronously)
1716                         {
1717                             return false;
1718                         }
1719                     }
1720
1721                     if (content != null)
1722                     {
1723                         content.EndWriteToStream(result);
1724                     }
1725
1726                     if (this.httpOutput.supportsConcurrentIO)
1727                     {
1728                         httpOutput.outputStream.Close();
1729                     }
1730
1731                     return true;
1732                 }
1733             }
1734
1735             static void OnWriteStreamedMessage(IAsyncResult result)
1736             {
1737                 if (result.CompletedSynchronously)
1738                 {
1739                     return;
1740                 }
1741
1742                 WriteStreamedMessageAsyncResult thisPtr = (WriteStreamedMessageAsyncResult)result.AsyncState;
1743                 Exception completionException = null;
1744                 bool completeSelf = false;
1745
1746                 try
1747                 {
1748                     completeSelf = thisPtr.HandleWriteStreamedMessage(result);
1749                 }
1750                 catch (Exception ex)
1751                 {
1752                     if (Fx.IsFatal(ex))
1753                     {
1754                         throw;
1755                     }
1756                     completeSelf = true;
1757                     completionException = ex;
1758                 }
1759
1760                 if (completeSelf)
1761                 {
1762                     thisPtr.sendTimer.Cancel();
1763                     thisPtr.Complete(false, completionException);
1764                 }
1765             }
1766
1767             void SetTimer(TimeSpan timeout)
1768             {
1769                 Fx.Assert(this.sendTimer == null, "SetTimer should only be called once");
1770
1771                 this.sendTimer = new IOThreadTimer(onStreamSendTimeout, this.httpOutput, true);
1772                 this.sendTimer.Set(timeout);
1773             }
1774
1775             public static void End(IAsyncResult result)
1776             {
1777                 AsyncResult.End<WriteStreamedMessageAsyncResult>(result);
1778             }
1779         }
1780
1781         public IAsyncResult BeginSend(HttpResponseMessage httpResponseMessage, TimeSpan timeout, AsyncCallback callback, object state)
1782         {
1783             Fx.Assert(httpResponseMessage != null, "httpResponseMessage should not be null.");
1784             return this.BeginSendCore(httpResponseMessage, timeout, callback, state);
1785         }
1786
1787         public IAsyncResult BeginSend(TimeSpan timeout, AsyncCallback callback, object state)
1788         {
1789             return this.BeginSendCore(null, timeout, callback, state);
1790         }
1791
1792         IAsyncResult BeginSendCore(HttpResponseMessage httpResponseMessage, TimeSpan timeout, AsyncCallback callback, object state)
1793         {
1794             bool throwing = true;
1795             try
1796             {
1797                 bool suppressEntityBody;
1798                 if (httpResponseMessage != null)
1799                 {
1800                     suppressEntityBody = this.PrepareHttpSend(httpResponseMessage);
1801                 }
1802                 else
1803                 {
1804                     suppressEntityBody = PrepareHttpSend(message);
1805                 }
1806
1807                 this.TraceHttpSendStart();
1808                 IAsyncResult result = new SendAsyncResult(this, httpResponseMessage, suppressEntityBody, timeout, callback, state);
1809                 throwing = false;
1810                 return result;
1811             }
1812             finally
1813             {
1814                 if (throwing)
1815                 {
1816                     Abort();
1817                 }
1818             }
1819         }
1820
1821         private void TraceHttpSendStart()
1822         {
1823             if (TD.HttpSendMessageStartIsEnabled())
1824             {
1825                 if (streamed)
1826                 {
1827                     TD.HttpSendStreamedMessageStart(this.eventTraceActivity);
1828                 }
1829                 else
1830                 {
1831                     TD.HttpSendMessageStart(this.eventTraceActivity);
1832                 }
1833             }
1834         }
1835
1836         public virtual void EndSend(IAsyncResult result)
1837         {
1838             bool throwing = true;
1839             try
1840             {
1841                 SendAsyncResult.End(result);
1842                 throwing = false;
1843             }
1844             finally
1845             {
1846                 if (throwing)
1847                 {
1848                     Abort();
1849                 }
1850             }
1851         }
1852
1853         void LogMessage()
1854         {
1855             if (MessageLogger.LogMessagesAtTransportLevel)
1856             {
1857                 MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportSend);
1858             }
1859         }
1860
1861         public void Send(HttpResponseMessage httpResponseMessage, TimeSpan timeout)
1862         {
1863             bool suppressEntityBody = this.PrepareHttpSend(httpResponseMessage);
1864
1865             TraceHttpSendStart();
1866
1867             if (suppressEntityBody)
1868             {
1869                 // requests can't always support an output stream (for GET, etc)
1870                 if (!isRequest)
1871                 {
1872                     outputStream = GetOutputStream();
1873                 }
1874                 else
1875                 {
1876                     this.SetContentLength(0);
1877                     LogMessage();
1878                 }
1879             }
1880             else if (streamed)
1881             {
1882                 outputStream = this.GetOutputStream();
1883                 ApplyChannelBinding();
1884
1885                 OpaqueContent content = httpResponseMessage.Content as OpaqueContent;
1886                 if (content != null)
1887                 {
1888                     content.WriteToStream(this.outputStream);
1889                 }
1890                 else
1891                 {
1892                     if (!httpResponseMessage.Content.CopyToAsync(this.outputStream).Wait<CommunicationException>(timeout))
1893                     {
1894                         throw FxTrace.Exception.AsError(new TimeoutException(SR.GetString(SR.TimeoutOnSend, timeout)));
1895                     }
1896                 }
1897             }
1898             else
1899             {
1900                 if (this.IsChannelBindingSupportEnabled)
1901                 {
1902                     //need to get the Channel binding token (CBT), apply channel binding info to the message and then write the message                    
1903                     //CBT is only enabled when message security is in the stack, which also requires an HTTP entity body, so we 
1904                     //should be safe to always get the stream.
1905                     outputStream = this.GetOutputStream();
1906
1907                     ApplyChannelBinding();
1908
1909                     ArraySegment<byte> buffer = SerializeBufferedMessage(httpResponseMessage);
1910
1911                     Fx.Assert(buffer.Count != 0, "We should always have an entity body in this case...");
1912                     outputStream.Write(buffer.Array, buffer.Offset, buffer.Count);
1913                 }
1914                 else
1915                 {
1916                     ArraySegment<byte> buffer = SerializeBufferedMessage(httpResponseMessage);
1917                     SetContentLength(buffer.Count);
1918
1919                     // requests can't always support an output stream (for GET, etc)
1920                     if (!isRequest || buffer.Count > 0)
1921                     {
1922                         outputStream = this.GetOutputStream();
1923                         outputStream.Write(buffer.Array, buffer.Offset, buffer.Count);
1924                     }
1925                 }
1926             }
1927
1928             TraceSend();
1929         }
1930
1931         ArraySegment<byte> SerializeBufferedMessage(HttpResponseMessage httpResponseMessage)
1932         {
1933             HttpOutputByteArrayContent content = httpResponseMessage.Content as HttpOutputByteArrayContent;
1934             if (content == null)
1935             {
1936                 byte[] byteArray = httpResponseMessage.Content.ReadAsByteArrayAsync().Result;
1937                 return new ArraySegment<byte>(byteArray, 0, byteArray.Length);
1938             }
1939             else
1940             {
1941                 return content.Content;
1942             }
1943         }
1944
1945         public void Send(TimeSpan timeout)
1946         {
1947             bool suppressEntityBody = PrepareHttpSend(message);
1948
1949             TraceHttpSendStart();
1950
1951             if (suppressEntityBody)
1952             {
1953                 // requests can't always support an output stream (for GET, etc)
1954                 if (!isRequest)
1955                 {
1956                     outputStream = GetOutputStream();
1957                 }
1958                 else
1959                 {
1960                     this.SetContentLength(0);
1961                     LogMessage();
1962                 }
1963             }
1964             else if (streamed)
1965             {
1966                 outputStream = GetOutputStream();
1967                 ApplyChannelBinding();
1968                 WriteStreamedMessage(timeout);
1969             }
1970             else
1971             {
1972                 if (this.IsChannelBindingSupportEnabled)
1973                 {
1974                     //need to get the Channel binding token (CBT), apply channel binding info to the message and then write the message                    
1975                     //CBT is only enabled when message security is in the stack, which also requires an HTTP entity body, so we 
1976                     //should be safe to always get the stream.
1977                     outputStream = GetOutputStream();
1978
1979                     ApplyChannelBinding();
1980
1981                     ArraySegment<byte> buffer = SerializeBufferedMessage(message);
1982
1983                     Fx.Assert(buffer.Count != 0, "We should always have an entity body in this case...");
1984                     outputStream.Write(buffer.Array, buffer.Offset, buffer.Count);
1985                 }
1986                 else
1987                 {
1988                     ArraySegment<byte> buffer = SerializeBufferedMessage(message);
1989                     SetContentLength(buffer.Count);
1990
1991                     // requests can't always support an output stream (for GET, etc)
1992                     if (!isRequest || buffer.Count > 0)
1993                     {
1994                         outputStream = GetOutputStream();
1995                         outputStream.Write(buffer.Array, buffer.Offset, buffer.Count);
1996                     }
1997                 }
1998             }
1999
2000             TraceSend();
2001         }
2002
2003         void TraceSend()
2004         {
2005             if (DiagnosticUtility.ShouldTraceInformation)
2006             {
2007                 TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.MessageSent, SR.GetString(SR.TraceCodeMessageSent),
2008                     new MessageTraceRecord(this.message), this, null);
2009             }
2010
2011             if (TD.HttpSendStopIsEnabled())
2012             {
2013                 TD.HttpSendStop(this.eventTraceActivity);
2014             }
2015         }
2016
2017         class SendAsyncResult : AsyncResult
2018         {
2019             HttpOutput httpOutput;
2020             static AsyncCallback onGetOutputStream;
2021             static Action<object> onWriteStreamedMessageLater;
2022             static AsyncCallback onWriteStreamedMessage;
2023             static AsyncCallback onWriteBody;
2024             bool suppressEntityBody;
2025             ArraySegment<byte> buffer;
2026             TimeoutHelper timeoutHelper;
2027             HttpResponseMessage httpResponseMessage;
2028
2029             public SendAsyncResult(HttpOutput httpOutput, HttpResponseMessage httpResponseMessage, bool suppressEntityBody, TimeSpan timeout, AsyncCallback callback, object state)
2030                 : base(callback, state)
2031             {
2032                 this.httpOutput = httpOutput;
2033                 this.httpResponseMessage = httpResponseMessage;
2034                 this.suppressEntityBody = suppressEntityBody;
2035
2036                 if (suppressEntityBody)
2037                 {
2038                     if (httpOutput.isRequest)
2039                     {
2040                         httpOutput.SetContentLength(0);
2041                         this.httpOutput.TraceSend();
2042                         this.httpOutput.LogMessage();
2043                         base.Complete(true);
2044                         return;
2045                     }
2046                 }
2047
2048                 this.timeoutHelper = new TimeoutHelper(timeout);
2049                 Send();
2050             }
2051
2052             void Send()
2053             {
2054                 if (httpOutput.IsChannelBindingSupportEnabled)
2055                 {
2056                     SendWithChannelBindingToken();
2057                 }
2058                 else
2059                 {
2060                     SendWithoutChannelBindingToken();
2061                 }
2062             }
2063
2064             void SendWithoutChannelBindingToken()
2065             {
2066                 if (!suppressEntityBody && !httpOutput.streamed)
2067                 {
2068                     if (this.httpResponseMessage != null)
2069                     {
2070                         buffer = httpOutput.SerializeBufferedMessage(this.httpResponseMessage);
2071                     }
2072                     else
2073                     {
2074                         buffer = httpOutput.SerializeBufferedMessage(httpOutput.message);
2075                     }
2076
2077                     httpOutput.SetContentLength(buffer.Count);
2078                 }
2079
2080
2081                 if (this.httpOutput.WillGetOutputStreamCompleteSynchronously)
2082                 {
2083                     httpOutput.outputStream = httpOutput.GetOutputStream();
2084                 }
2085                 else
2086                 {
2087                     if (onGetOutputStream == null)
2088                     {
2089                         onGetOutputStream = Fx.ThunkCallback(new AsyncCallback(OnGetOutputStream));
2090                     }
2091
2092                     IAsyncResult result = httpOutput.BeginGetOutputStream(onGetOutputStream, this);
2093
2094                     if (!result.CompletedSynchronously)
2095                         return;
2096
2097                     httpOutput.outputStream = httpOutput.EndGetOutputStream(result);
2098                 }
2099
2100                 if (WriteMessage(true))
2101                 {
2102                     this.httpOutput.TraceSend();
2103                     base.Complete(true);
2104                 }
2105             }
2106
2107             void SendWithChannelBindingToken()
2108             {
2109                 if (this.httpOutput.WillGetOutputStreamCompleteSynchronously)
2110                 {
2111                     httpOutput.outputStream = httpOutput.GetOutputStream();
2112                     httpOutput.ApplyChannelBinding();
2113                 }
2114                 else
2115                 {
2116                     if (onGetOutputStream == null)
2117                     {
2118                         onGetOutputStream = Fx.ThunkCallback(new AsyncCallback(OnGetOutputStream));
2119                     }
2120
2121                     IAsyncResult result = httpOutput.BeginGetOutputStream(onGetOutputStream, this);
2122
2123                     if (!result.CompletedSynchronously)
2124                         return;
2125
2126                     httpOutput.outputStream = httpOutput.EndGetOutputStream(result);
2127                     httpOutput.ApplyChannelBinding();
2128                 }
2129
2130                 if (!httpOutput.streamed)
2131                 {
2132                     if (this.httpResponseMessage != null)
2133                     {
2134                         buffer = httpOutput.SerializeBufferedMessage(this.httpResponseMessage);
2135                     }
2136                     else
2137                     {
2138                         buffer = httpOutput.SerializeBufferedMessage(httpOutput.message);
2139                     }
2140
2141                     httpOutput.SetContentLength(buffer.Count);
2142                 }
2143
2144                 if (WriteMessage(true))
2145                 {
2146                     this.httpOutput.TraceSend();
2147                     base.Complete(true);
2148                 }
2149             }
2150
2151             bool WriteMessage(bool isStillSynchronous)
2152             {
2153                 if (suppressEntityBody)
2154                 {
2155                     return true;
2156                 }
2157                 if (httpOutput.streamed)
2158                 {
2159                     if (isStillSynchronous)
2160                     {
2161                         if (onWriteStreamedMessageLater == null)
2162                         {
2163                             onWriteStreamedMessageLater = new Action<object>(OnWriteStreamedMessageLater);
2164                         }
2165                         ActionItem.Schedule(onWriteStreamedMessageLater, this);
2166                         return false;
2167                     }
2168                     else
2169                     {
2170                         return WriteStreamedMessage();
2171                     }
2172                 }
2173                 else
2174                 {
2175                     if (onWriteBody == null)
2176                     {
2177                         onWriteBody = Fx.ThunkCallback(new AsyncCallback(OnWriteBody));
2178                     }
2179
2180                     IAsyncResult writeResult =
2181                         httpOutput.outputStream.BeginWrite(buffer.Array, buffer.Offset, buffer.Count, onWriteBody, this);
2182
2183                     if (!writeResult.CompletedSynchronously)
2184                     {
2185                         return false;
2186                     }
2187
2188                     CompleteWriteBody(writeResult);
2189                 }
2190
2191                 return true;
2192             }
2193
2194             bool WriteStreamedMessage()
2195             {
2196                 // return a bool to determine if we are sync. 
2197
2198                 if (onWriteStreamedMessage == null)
2199                 {
2200                     onWriteStreamedMessage = Fx.ThunkCallback(OnWriteStreamedMessage);
2201                 }
2202
2203                 return HandleWriteStreamedMessage(null); // completed synchronously
2204             }
2205
2206             bool HandleWriteStreamedMessage(IAsyncResult result)
2207             {
2208                 if (result == null)
2209                 {
2210                     result = httpOutput.BeginWriteStreamedMessage(this.httpResponseMessage, timeoutHelper.RemainingTime(), onWriteStreamedMessage, this);
2211                     if (!result.CompletedSynchronously)
2212                     {
2213                         return false;
2214                     }
2215                 }
2216
2217                 httpOutput.EndWriteStreamedMessage(result);
2218                 return true;
2219             }
2220
2221             static void OnWriteStreamedMessage(IAsyncResult result)
2222             {
2223                 if (result.CompletedSynchronously)
2224                 {
2225                     return;
2226                 }
2227
2228                 SendAsyncResult thisPtr = (SendAsyncResult)result.AsyncState;
2229                 Exception completionException = null;
2230                 bool completeSelf = false;
2231
2232                 try
2233                 {
2234                     completeSelf = thisPtr.HandleWriteStreamedMessage(result);
2235                 }
2236                 catch (Exception ex)
2237                 {
2238                     if (Fx.IsFatal(ex))
2239                     {
2240                         throw;
2241                     }
2242                     completeSelf = true;
2243                     completionException = ex;
2244                 }
2245
2246                 if (completeSelf)
2247                 {
2248                     if (completionException != null)
2249                     {
2250                         thisPtr.httpOutput.TraceSend();
2251                     }
2252                     thisPtr.Complete(false, completionException);
2253                 }
2254             }
2255
2256             void CompleteWriteBody(IAsyncResult result)
2257             {
2258                 httpOutput.outputStream.EndWrite(result);
2259             }
2260
2261             public static void End(IAsyncResult result)
2262             {
2263                 AsyncResult.End<SendAsyncResult>(result);
2264             }
2265
2266             static void OnGetOutputStream(IAsyncResult result)
2267             {
2268                 if (result.CompletedSynchronously)
2269                     return;
2270
2271                 SendAsyncResult thisPtr = (SendAsyncResult)result.AsyncState;
2272
2273                 Exception completionException = null;
2274                 bool completeSelf = false;
2275                 try
2276                 {
2277                     thisPtr.httpOutput.outputStream = thisPtr.httpOutput.EndGetOutputStream(result);
2278                     thisPtr.httpOutput.ApplyChannelBinding();
2279
2280                     if (!thisPtr.httpOutput.streamed && thisPtr.httpOutput.IsChannelBindingSupportEnabled)
2281                     {
2282                         thisPtr.buffer = thisPtr.httpOutput.SerializeBufferedMessage(thisPtr.httpOutput.message);
2283                         thisPtr.httpOutput.SetContentLength(thisPtr.buffer.Count);
2284                     }
2285
2286                     if (thisPtr.WriteMessage(false))
2287                     {
2288                         thisPtr.httpOutput.TraceSend();
2289                         completeSelf = true;
2290                     }
2291                 }
2292 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
2293                 catch (Exception e)
2294                 {
2295                     if (Fx.IsFatal(e))
2296                     {
2297                         throw;
2298                     }
2299                     completeSelf = true;
2300                     completionException = e;
2301                 }
2302                 if (completeSelf)
2303                 {
2304                     thisPtr.Complete(false, completionException);
2305                 }
2306             }
2307
2308             static void OnWriteStreamedMessageLater(object state)
2309             {
2310                 SendAsyncResult thisPtr = (SendAsyncResult)state;
2311
2312                 bool completeSelf = false;
2313                 Exception completionException = null;
2314                 try
2315                 {
2316                     completeSelf = thisPtr.WriteStreamedMessage();
2317                 }
2318 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
2319                 catch (Exception e)
2320                 {
2321                     if (Fx.IsFatal(e))
2322                     {
2323                         throw;
2324                     }
2325                     completeSelf = true;
2326                     completionException = e;
2327                 }
2328
2329                 if (completeSelf)
2330                 {
2331                     if (completionException != null)
2332                     {
2333                         thisPtr.httpOutput.TraceSend();
2334                     }
2335                     thisPtr.Complete(false, completionException);
2336                 }
2337             }
2338
2339             static void OnWriteBody(IAsyncResult result)
2340             {
2341                 if (result.CompletedSynchronously)
2342                     return;
2343
2344                 SendAsyncResult thisPtr = (SendAsyncResult)result.AsyncState;
2345
2346                 Exception completionException = null;
2347                 try
2348                 {
2349                     thisPtr.CompleteWriteBody(result);
2350                     thisPtr.httpOutput.TraceSend();
2351                 }
2352 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
2353                 catch (Exception e)
2354                 {
2355                     if (Fx.IsFatal(e))
2356                     {
2357                         throw;
2358                     }
2359                     completionException = e;
2360                 }
2361                 thisPtr.Complete(false, completionException);
2362             }
2363         }
2364
2365         internal static HttpOutput CreateHttpOutput(HttpWebRequest httpWebRequest, IHttpTransportFactorySettings settings, Message message, bool enableChannelBindingSupport)
2366         {
2367             return new WebRequestHttpOutput(httpWebRequest, settings, message, enableChannelBindingSupport);
2368         }
2369
2370         internal static HttpOutput CreateHttpOutput(HttpListenerResponse httpListenerResponse, IHttpTransportFactorySettings settings, Message message, string httpMethod)
2371         {
2372             return new ListenerResponseHttpOutput(httpListenerResponse, settings, message, httpMethod);
2373         }
2374
2375         class WebRequestHttpOutput : HttpOutput
2376         {
2377             HttpWebRequest httpWebRequest;
2378             ChannelBinding channelBindingToken;
2379             bool enableChannelBindingSupport;
2380
2381             public WebRequestHttpOutput(HttpWebRequest httpWebRequest, IHttpTransportFactorySettings settings, Message message, bool enableChannelBindingSupport)
2382                 : base(settings, message, true, false)
2383             {
2384                 this.httpWebRequest = httpWebRequest;
2385                 this.enableChannelBindingSupport = enableChannelBindingSupport;
2386             }
2387
2388             public override void Abort(HttpAbortReason abortReason)
2389             {
2390                 httpWebRequest.Abort();
2391                 base.Abort(abortReason);
2392             }
2393
2394             protected override void AddMimeVersion(string version)
2395             {
2396                 httpWebRequest.Headers[HttpChannelUtilities.MIMEVersionHeader] = version;
2397             }
2398
2399             protected override void AddHeader(string name, string value)
2400             {
2401                 httpWebRequest.Headers.Add(name, value);
2402             }
2403
2404             protected override void SetContentType(string contentType)
2405             {
2406                 httpWebRequest.ContentType = contentType;
2407             }
2408
2409             protected override void SetContentEncoding(string contentEncoding)
2410             {
2411                 this.httpWebRequest.Headers.Add(HttpChannelUtilities.ContentEncodingHeader, contentEncoding);
2412             }
2413
2414             protected override void SetContentLength(int contentLength)
2415             {
2416                 if (contentLength == 0 // work around whidbey issue with setting ContentLength - (see MB36881)
2417                     && !this.enableChannelBindingSupport) //When ChannelBinding is enabled, content length isn't supported
2418                 {
2419                     httpWebRequest.ContentLength = contentLength;
2420                 }
2421             }
2422
2423             protected override void SetStatusCode(HttpStatusCode statusCode)
2424             {
2425             }
2426
2427             protected override void SetStatusDescription(string statusDescription)
2428             {
2429             }
2430
2431             protected override bool WillGetOutputStreamCompleteSynchronously
2432             {
2433                 get { return false; }
2434             }
2435
2436             protected override bool IsChannelBindingSupportEnabled
2437             {
2438                 get
2439                 {
2440                     return this.enableChannelBindingSupport;
2441                 }
2442             }
2443
2444             protected override ChannelBinding ChannelBinding
2445             {
2446                 get
2447                 {
2448                     return this.channelBindingToken;
2449                 }
2450             }
2451
2452             protected override bool CleanupChannelBinding
2453             {
2454                 get
2455                 {
2456                     //client side channel binding token will be attached to the inbound response message also, so
2457                     //we need to not clean up the CBT object for this HttpOutput object.
2458                     return false;
2459                 }
2460             }
2461
2462             //Used to allow the channel binding object to be transferred to the 
2463             //WebResponseHttpInput object.
2464             public override ChannelBinding TakeChannelBinding()
2465             {
2466                 ChannelBinding result = this.channelBindingToken;
2467                 this.channelBindingToken = null;
2468                 return result;
2469             }
2470
2471             protected override Stream GetOutputStream()
2472             {
2473                 try
2474                 {
2475                     Stream outputStream;
2476                     if (this.IsChannelBindingSupportEnabled)
2477                     {
2478                         TransportContext context;
2479                         outputStream = httpWebRequest.GetRequestStream(out context);
2480                         this.channelBindingToken = ChannelBindingUtility.GetToken(context);
2481                     }
2482                     else
2483                     {
2484                         outputStream = httpWebRequest.GetRequestStream();
2485                     }
2486
2487                     outputStream = new WebRequestOutputStream(outputStream, httpWebRequest, this);
2488
2489                     return outputStream;
2490                 }
2491                 catch (WebException webException)
2492                 {
2493                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestWebException(webException, httpWebRequest, abortReason));
2494                 }
2495             }
2496
2497             protected override IAsyncResult BeginGetOutputStream(AsyncCallback callback, object state)
2498             {
2499                 return new GetOutputStreamAsyncResult(httpWebRequest, this, callback, state);
2500             }
2501
2502             protected override Stream EndGetOutputStream(IAsyncResult result)
2503             {
2504                 return GetOutputStreamAsyncResult.End(result, out this.channelBindingToken);
2505             }
2506
2507             protected override bool PrepareHttpSend(Message message)
2508             {
2509                 bool wasContentTypeSet = false;
2510
2511                 string action = message.Headers.Action;
2512
2513                 if (action != null)
2514                 {
2515                     //This code is calling UrlPathEncode due to MessageBus bug 53362.
2516                     //After reviewing this decision, we
2517                     //feel that this was probably the wrong thing to do because UrlPathEncode
2518                     //doesn't escape some characters like '+', '%', etc.  The real issue behind 
2519                     //bug 53362 may have been as simple as being encoded multiple times on the client
2520                     //but being decoded one time on the server.  Calling UrlEncode would correctly
2521                     //escape these characters, but since we don't want to break any customers and no
2522                     //customers have complained, we will leave this as is for now...
2523                     action = string.Format(CultureInfo.InvariantCulture, "\"{0}\"", UrlUtility.UrlPathEncode(action));
2524                 }
2525
2526                 bool suppressEntityBody = base.PrepareHttpSend(message);
2527
2528                 object property;
2529                 if (message.Properties.TryGetValue(HttpRequestMessageProperty.Name, out property))
2530                 {
2531                     HttpRequestMessageProperty requestProperty = (HttpRequestMessageProperty)property;
2532                     httpWebRequest.Method = requestProperty.Method;
2533                     // Query string was applied in HttpChannelFactory.ApplyManualAddressing
2534                     WebHeaderCollection requestHeaders = requestProperty.Headers;
2535                     suppressEntityBody = suppressEntityBody || requestProperty.SuppressEntityBody;
2536                     for (int i = 0; i < requestHeaders.Count; i++)
2537                     {
2538                         string name = requestHeaders.Keys[i];
2539                         string value = requestHeaders[i];
2540                         if (string.Compare(name, "accept", StringComparison.OrdinalIgnoreCase) == 0)
2541                         {
2542                             httpWebRequest.Accept = value;
2543                         }
2544                         else if (string.Compare(name, "connection", StringComparison.OrdinalIgnoreCase) == 0)
2545                         {
2546                             if (value.IndexOf("keep-alive", StringComparison.OrdinalIgnoreCase) != -1)
2547                             {
2548                                 httpWebRequest.KeepAlive = true;
2549                             }
2550                             else
2551                             {
2552                                 httpWebRequest.Connection = value;
2553                             }
2554                         }
2555                         else if (string.Compare(name, "SOAPAction", StringComparison.OrdinalIgnoreCase) == 0)
2556                         {
2557                             if (action == null)
2558                             {
2559                                 action = value;
2560                             }
2561                             else
2562                             {
2563                                 if (value.Length > 0 && string.Compare(value, action, StringComparison.Ordinal) != 0)
2564                                 {
2565                                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
2566                                         new ProtocolException(SR.GetString(SR.HttpSoapActionMismatch, action, value)));
2567                                 }
2568                             }
2569                         }
2570                         else if (string.Compare(name, "content-length", StringComparison.OrdinalIgnoreCase) == 0)
2571                         {
2572                             // this will be taken care of by System.Net when we write to the content
2573                         }
2574                         else if (string.Compare(name, "content-type", StringComparison.OrdinalIgnoreCase) == 0)
2575                         {
2576                             httpWebRequest.ContentType = value;
2577                             wasContentTypeSet = true;
2578                         }
2579                         else if (string.Compare(name, "expect", StringComparison.OrdinalIgnoreCase) == 0)
2580                         {
2581                             if (value.ToUpperInvariant().IndexOf("100-CONTINUE", StringComparison.OrdinalIgnoreCase) != -1)
2582                             {
2583                                 httpWebRequest.ServicePoint.Expect100Continue = true;
2584                             }
2585                             else
2586                             {
2587                                 httpWebRequest.Expect = value;
2588                             }
2589                         }
2590                         else if (string.Compare(name, "host", StringComparison.OrdinalIgnoreCase) == 0)
2591                         {
2592                             // this should be controlled through Via
2593                         }
2594                         else if (string.Compare(name, "referer", StringComparison.OrdinalIgnoreCase) == 0)
2595                         {
2596                             // referrer is proper spelling, but referer is the what is in the protocol.
2597                             httpWebRequest.Referer = value;
2598                         }
2599                         else if (string.Compare(name, "transfer-encoding", StringComparison.OrdinalIgnoreCase) == 0)
2600                         {
2601                             if (value.ToUpperInvariant().IndexOf("CHUNKED", StringComparison.OrdinalIgnoreCase) != -1)
2602                             {
2603                                 httpWebRequest.SendChunked = true;
2604                             }
2605                             else
2606                             {
2607                                 httpWebRequest.TransferEncoding = value;
2608                             }
2609                         }
2610                         else if (string.Compare(name, "user-agent", StringComparison.OrdinalIgnoreCase) == 0)
2611                         {
2612                             httpWebRequest.UserAgent = value;
2613                         }
2614                         else if (string.Compare(name, "if-modified-since", StringComparison.OrdinalIgnoreCase) == 0)
2615                         {
2616                             DateTime modifiedSinceDate;
2617                             if (DateTime.TryParse(value, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.AssumeLocal, out modifiedSinceDate))
2618                             {
2619                                 httpWebRequest.IfModifiedSince = modifiedSinceDate;
2620                             }
2621                             else
2622                             {
2623                                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
2624                                     new ProtocolException(SR.GetString(SR.HttpIfModifiedSinceParseError, value)));
2625                             }
2626                         }
2627                         else if (string.Compare(name, "date", StringComparison.OrdinalIgnoreCase) == 0)
2628                         {
2629                             // this will be taken care of by System.Net when we make the request
2630                         }
2631                         else if (string.Compare(name, "proxy-connection", StringComparison.OrdinalIgnoreCase) == 0)
2632                         {
2633                             // set by System.Net if using a proxy.
2634                         }
2635                         else if (string.Compare(name, "range", StringComparison.OrdinalIgnoreCase) == 0)
2636                         {
2637                             // we don't support ranges in v1.
2638                         }
2639                         else
2640                         {
2641                             httpWebRequest.Headers.Add(name, value);
2642                         }
2643                     }
2644                 }
2645
2646                 if (action != null)
2647                 {
2648                     if (message.Version.Envelope == EnvelopeVersion.Soap11)
2649                     {
2650                         httpWebRequest.Headers["SOAPAction"] = action;
2651                     }
2652                     else if (message.Version.Envelope == EnvelopeVersion.Soap12)
2653                     {
2654                         if (message.Version.Addressing == AddressingVersion.None)
2655                         {
2656                             bool shouldSetContentType = true;
2657                             if (wasContentTypeSet)
2658                             {
2659                                 if (httpWebRequest.ContentType.Contains("action")
2660                                     || httpWebRequest.ContentType.ToUpperInvariant().IndexOf("ACTION", StringComparison.OrdinalIgnoreCase) != -1)
2661                                 {
2662                                     try
2663                                     {
2664                                         ContentType parsedContentType = new ContentType(httpWebRequest.ContentType);
2665                                         if (parsedContentType.Parameters.ContainsKey("action"))
2666                                         {
2667                                             string value = string.Format(CultureInfo.InvariantCulture, "\"{0}\"", parsedContentType.Parameters["action"]);
2668                                             if (string.Compare(value, action, StringComparison.Ordinal) != 0)
2669                                             {
2670                                                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
2671                                                     new ProtocolException(SR.GetString(SR.HttpSoapActionMismatchContentType, action, value)));
2672                                             }
2673                                             shouldSetContentType = false;
2674                                         }
2675                                     }
2676                                     catch (FormatException formatException)
2677                                     {
2678                                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
2679                                             new ProtocolException(SR.GetString(SR.HttpContentTypeFormatException, formatException.Message, httpWebRequest.ContentType), formatException));
2680                                     }
2681                                 }
2682                             }
2683
2684                             if (shouldSetContentType)
2685                             {
2686                                 httpWebRequest.ContentType = string.Format(CultureInfo.InvariantCulture, "{0}; action={1}", httpWebRequest.ContentType, action);
2687                             }
2688                         }
2689                     }
2690                     else if (message.Version.Envelope != EnvelopeVersion.None)
2691                     {
2692                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
2693                             new ProtocolException(SR.GetString(SR.EnvelopeVersionUnknown,
2694                             message.Version.Envelope.ToString())));
2695                     }
2696                 }
2697
2698                 // since we don't get the output stream in send when retVal == true, 
2699                 // we need to disable chunking for some verbs (DELETE/PUT)
2700                 if (suppressEntityBody)
2701                 {
2702                     httpWebRequest.SendChunked = false;
2703                 }
2704                 else if (this.IsChannelBindingSupportEnabled)
2705                 {
2706                     //force chunked upload since the length of the message is unknown before encoding.
2707                     httpWebRequest.SendChunked = true;
2708                 }
2709
2710                 return suppressEntityBody;
2711             }
2712
2713             protected override void PrepareHttpSendCore(HttpResponseMessage message)
2714             {
2715                 // HTTP pipeline for client side is not implemented yet
2716                 // DCR CSDMain 216853 is tracking this
2717                 Fx.Assert(false, "HTTP pipeline for client is not implemented yet. This method should not be called.");
2718             }
2719
2720             class GetOutputStreamAsyncResult : AsyncResult
2721             {
2722                 static AsyncCallback onGetRequestStream = Fx.ThunkCallback(new AsyncCallback(OnGetRequestStream));
2723                 HttpOutput httpOutput;
2724                 HttpWebRequest httpWebRequest;
2725                 Stream outputStream;
2726                 ChannelBinding channelBindingToken;
2727
2728                 public GetOutputStreamAsyncResult(HttpWebRequest httpWebRequest, HttpOutput httpOutput, AsyncCallback callback, object state)
2729                     : base(callback, state)
2730                 {
2731                     this.httpWebRequest = httpWebRequest;
2732                     this.httpOutput = httpOutput;
2733
2734                     IAsyncResult result = null;
2735                     try
2736                     {
2737                         result = httpWebRequest.BeginGetRequestStream(onGetRequestStream, this);
2738                     }
2739                     catch (WebException webException)
2740                     {
2741                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestWebException(webException, httpWebRequest, httpOutput.abortReason));
2742                     }
2743
2744                     if (result.CompletedSynchronously)
2745                     {
2746                         CompleteGetRequestStream(result);
2747                         base.Complete(true);
2748                     }
2749                 }
2750
2751                 void CompleteGetRequestStream(IAsyncResult result)
2752                 {
2753                     try
2754                     {
2755                         TransportContext context;
2756                         this.outputStream = new WebRequestOutputStream(httpWebRequest.EndGetRequestStream(result, out context), httpWebRequest, this.httpOutput);
2757                         this.channelBindingToken = ChannelBindingUtility.GetToken(context);
2758                     }
2759                     catch (WebException webException)
2760                     {
2761                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestWebException(webException, httpWebRequest, httpOutput.abortReason));
2762                     }
2763                 }
2764
2765                 public static Stream End(IAsyncResult result, out ChannelBinding channelBindingToken)
2766                 {
2767                     GetOutputStreamAsyncResult thisPtr = AsyncResult.End<GetOutputStreamAsyncResult>(result);
2768                     channelBindingToken = thisPtr.channelBindingToken;
2769                     return thisPtr.outputStream;
2770                 }
2771
2772                 static void OnGetRequestStream(IAsyncResult result)
2773                 {
2774                     if (result.CompletedSynchronously)
2775                         return;
2776
2777                     GetOutputStreamAsyncResult thisPtr = (GetOutputStreamAsyncResult)result.AsyncState;
2778
2779                     Exception completionException = null;
2780                     try
2781                     {
2782                         thisPtr.CompleteGetRequestStream(result);
2783                     }
2784 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
2785                     catch (Exception e)
2786                     {
2787                         if (Fx.IsFatal(e))
2788                         {
2789                             throw;
2790                         }
2791                         completionException = e;
2792                     }
2793                     thisPtr.Complete(false, completionException);
2794                 }
2795             }
2796
2797             class WebRequestOutputStream : BytesReadPositionStream
2798             {
2799                 HttpWebRequest httpWebRequest;
2800                 HttpOutput httpOutput;
2801                 int bytesSent = 0;
2802
2803                 public WebRequestOutputStream(Stream requestStream, HttpWebRequest httpWebRequest, HttpOutput httpOutput)
2804                     : base(requestStream)
2805                 {
2806                     this.httpWebRequest = httpWebRequest;
2807                     this.httpOutput = httpOutput;
2808                 }
2809
2810                 public override void Close()
2811                 {
2812                     try
2813                     {
2814                         base.Close();
2815                     }
2816                     catch (ObjectDisposedException objectDisposedException)
2817                     {
2818                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestCanceledException(objectDisposedException, httpWebRequest, httpOutput.abortReason));
2819                     }
2820                     catch (IOException ioException)
2821                     {
2822                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestIOException(ioException, httpWebRequest));
2823                     }
2824                     catch (WebException webException)
2825                     {
2826                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestWebException(webException, httpWebRequest, httpOutput.abortReason));
2827                     }
2828                 }
2829
2830                 public override long Position
2831                 {
2832                     get
2833                     {
2834                         return bytesSent;
2835                     }
2836                     set
2837                     {
2838                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SeekNotSupported)));
2839                     }
2840                 }
2841
2842                 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
2843                 {
2844                     this.bytesSent += count;
2845                     try
2846                     {
2847                         return base.BeginWrite(buffer, offset, count, callback, state);
2848                     }
2849                     catch (ObjectDisposedException objectDisposedException)
2850                     {
2851                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestCanceledException(objectDisposedException, httpWebRequest, httpOutput.abortReason));
2852                     }
2853                     catch (IOException ioException)
2854                     {
2855                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestIOException(ioException, httpWebRequest));
2856                     }
2857                     catch (WebException webException)
2858                     {
2859                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestWebException(webException, httpWebRequest, httpOutput.abortReason));
2860                     }
2861                 }
2862
2863                 public override void EndWrite(IAsyncResult result)
2864                 {
2865                     try
2866                     {
2867                         base.EndWrite(result);
2868                     }
2869                     catch (ObjectDisposedException objectDisposedException)
2870                     {
2871                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestCanceledException(objectDisposedException, httpWebRequest, httpOutput.abortReason));
2872                     }
2873                     catch (IOException ioException)
2874                     {
2875                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestIOException(ioException, httpWebRequest));
2876                     }
2877                     catch (WebException webException)
2878                     {
2879                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestWebException(webException, httpWebRequest, httpOutput.abortReason));
2880                     }
2881                 }
2882
2883                 public override void Write(byte[] buffer, int offset, int count)
2884                 {
2885                     try
2886                     {
2887                         base.Write(buffer, offset, count);
2888                     }
2889                     catch (ObjectDisposedException objectDisposedException)
2890                     {
2891                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestCanceledException(objectDisposedException, httpWebRequest, httpOutput.abortReason));
2892                     }
2893                     catch (IOException ioException)
2894                     {
2895                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestIOException(ioException, httpWebRequest));
2896                     }
2897                     catch (WebException webException)
2898                     {
2899                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(HttpChannelUtilities.CreateRequestWebException(webException, httpWebRequest, httpOutput.abortReason));
2900                     }
2901                     this.bytesSent += count;
2902                 }
2903             }
2904         }
2905
2906         class ListenerResponseHttpOutput : HttpOutput
2907         {
2908             HttpListenerResponse listenerResponse;
2909             string httpMethod;
2910
2911             [System.Diagnostics.CodeAnalysis.SuppressMessage(FxCop.Category.Usage, "CA2214", Justification = "No one else is inhiriting from this class.")]
2912             public ListenerResponseHttpOutput(HttpListenerResponse listenerResponse, IHttpTransportFactorySettings settings, Message message, string httpMethod)
2913                 : base(settings, message, false, true)
2914             {
2915                 this.listenerResponse = listenerResponse;
2916                 this.httpMethod = httpMethod;
2917
2918                 if (message.IsFault)
2919                 {
2920                     this.SetStatusCode(HttpStatusCode.InternalServerError);
2921                 }
2922                 else
2923                 {
2924                     this.SetStatusCode(HttpStatusCode.OK);
2925                 }
2926             }
2927
2928             protected override string HttpMethod
2929             {
2930                 get { return this.httpMethod; }
2931             }
2932
2933             public override void Abort(HttpAbortReason abortReason)
2934             {
2935                 listenerResponse.Abort();
2936                 base.Abort(abortReason);
2937             }
2938
2939             protected override void AddMimeVersion(string version)
2940             {
2941                 listenerResponse.Headers[HttpChannelUtilities.MIMEVersionHeader] = version;
2942             }
2943
2944             protected override bool PrepareHttpSend(Message message)
2945             {
2946                 bool result = base.PrepareHttpSend(message);
2947
2948                 if (this.CanSendCompressedResponses)
2949                 {
2950                     string contentType = this.listenerResponse.ContentType;
2951                     string contentEncoding;
2952                     if (HttpChannelUtilities.GetHttpResponseTypeAndEncodingForCompression(ref contentType, out contentEncoding))
2953                     {
2954                         if (contentType != this.listenerResponse.ContentType)
2955                         {
2956                             this.SetContentType(contentType);
2957                         }
2958                         this.SetContentEncoding(contentEncoding);
2959                     }
2960                 }
2961
2962                 HttpResponseMessageProperty responseProperty = message.Properties.GetValue<HttpResponseMessageProperty>(HttpResponseMessageProperty.Name, true);
2963                 bool httpResponseMessagePropertyFound = responseProperty != null;
2964                 bool httpMethodIsHead = string.Compare(this.httpMethod, "HEAD", StringComparison.OrdinalIgnoreCase) == 0;
2965
2966                 if (httpMethodIsHead ||
2967                     httpResponseMessagePropertyFound && responseProperty.SuppressEntityBody)
2968                 {
2969                     result = true;
2970                     this.SetContentLength(0);
2971                     this.SetContentType(null);
2972                     listenerResponse.SendChunked = false;
2973                 }
2974
2975                 if (httpResponseMessagePropertyFound)
2976                 {
2977                     this.SetStatusCode(responseProperty.StatusCode);
2978                     if (responseProperty.StatusDescription != null)
2979                     {
2980                         this.SetStatusDescription(responseProperty.StatusDescription);
2981                     }
2982
2983                     WebHeaderCollection responseHeaders = responseProperty.Headers;
2984                     for (int i = 0; i < responseHeaders.Count; i++)
2985                     {
2986                         string name = responseHeaders.Keys[i];
2987                         string value = responseHeaders[i];
2988                         if (string.Compare(name, "content-length", StringComparison.OrdinalIgnoreCase) == 0)
2989                         {
2990                             int contentLength = -1;
2991                             if (httpMethodIsHead &&
2992                                 int.TryParse(value, out contentLength))
2993                             {
2994                                 this.SetContentLength(contentLength);
2995                             }
2996                             // else
2997                             //this will be taken care of by System.Net when we write to the content
2998                         }
2999                         else if (string.Compare(name, "content-type", StringComparison.OrdinalIgnoreCase) == 0)
3000                         {
3001                             if (httpMethodIsHead ||
3002                                 !responseProperty.SuppressEntityBody)
3003                             {
3004                                 this.SetContentType(value);
3005                             }
3006                         }
3007                         else if (string.Compare(name, "Connection", StringComparison.OrdinalIgnoreCase) == 0 &&
3008                                  value != null &&
3009                                  string.Compare(value.Trim(), "close", StringComparison.OrdinalIgnoreCase) == 0 &&
3010                                  !LocalAppContextSwitches.DisableExplicitConnectionCloseHeader)
3011                         {
3012                             // HttpListenerResponse will not serialize the Connection:close header
3013                             // if its KeepAlive is true.  So in the case where a service has explicitly
3014                             // added Connection:close (not added by default) set KeepAlive to false.
3015                             // This will cause HttpListenerResponse to add its own Connection:close header
3016                             // and to serialize it properly.  We do not add a redundant header here.
3017                             this.listenerResponse.KeepAlive = false;
3018                         }
3019                         else
3020                         {
3021                             this.AddHeader(name, value);
3022                         }
3023                     }
3024                 }
3025
3026                 return result;
3027             }
3028
3029             protected override void PrepareHttpSendCore(HttpResponseMessage message)
3030             {
3031                 this.listenerResponse.StatusCode = (int)message.StatusCode;
3032                 if (message.ReasonPhrase != null)
3033                 {
3034                     this.listenerResponse.StatusDescription = message.ReasonPhrase;
3035                 }
3036                 HttpChannelUtilities.CopyHeaders(message, AddHeader);
3037             }
3038
3039             protected override void AddHeader(string name, string value)
3040             {
3041                 if (string.Compare(name, "WWW-Authenticate", StringComparison.OrdinalIgnoreCase) == 0)
3042                 {
3043                     listenerResponse.AddHeader(name, value);
3044                 }
3045                 else
3046                 {
3047                     listenerResponse.AppendHeader(name, value);
3048                 }
3049             }
3050
3051             protected override void SetContentType(string contentType)
3052             {
3053                 listenerResponse.ContentType = contentType;
3054             }
3055
3056             protected override void SetContentEncoding(string contentEncoding)
3057             {
3058                 this.listenerResponse.AddHeader(HttpChannelUtilities.ContentEncodingHeader, contentEncoding);
3059             }
3060
3061             protected override void SetContentLength(int contentLength)
3062             {
3063                 listenerResponse.ContentLength64 = contentLength;
3064             }
3065
3066             protected override void SetStatusCode(HttpStatusCode statusCode)
3067             {
3068                 listenerResponse.StatusCode = (int)statusCode;
3069             }
3070
3071             protected override void SetStatusDescription(string statusDescription)
3072             {
3073                 listenerResponse.StatusDescription = statusDescription;
3074             }
3075
3076             protected override Stream GetOutputStream()
3077             {
3078                 return new ListenerResponseOutputStream(listenerResponse);
3079             }
3080
3081             class ListenerResponseOutputStream : BytesReadPositionStream
3082             {
3083                 public ListenerResponseOutputStream(HttpListenerResponse listenerResponse)
3084                     : base(listenerResponse.OutputStream)
3085                 {
3086                 }
3087
3088                 public override void Close()
3089                 {
3090                     try
3091                     {
3092                         base.Close();
3093                     }
3094                     catch (HttpListenerException listenerException)
3095                     {
3096                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
3097                             HttpChannelUtilities.CreateCommunicationException(listenerException));
3098                     }
3099                 }
3100
3101                 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
3102                 {
3103                     try
3104                     {
3105                         return base.BeginWrite(buffer, offset, count, callback, state);
3106                     }
3107                     catch (HttpListenerException listenerException)
3108                     {
3109                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
3110                             HttpChannelUtilities.CreateCommunicationException(listenerException));
3111                     }
3112                     catch (ApplicationException applicationException)
3113                     {
3114                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
3115                             new CommunicationObjectAbortedException(SR.GetString(SR.HttpResponseAborted),
3116                             applicationException));
3117                     }
3118                 }
3119
3120                 public override void EndWrite(IAsyncResult result)
3121                 {
3122                     try
3123                     {
3124                         base.EndWrite(result);
3125                     }
3126                     catch (HttpListenerException listenerException)
3127                     {
3128                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
3129                             HttpChannelUtilities.CreateCommunicationException(listenerException));
3130                     }
3131                     catch (ApplicationException applicationException)
3132                     {
3133                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
3134                             new CommunicationObjectAbortedException(SR.GetString(SR.HttpResponseAborted),
3135                             applicationException));
3136                     }
3137                 }
3138
3139                 public override void Write(byte[] buffer, int offset, int count)
3140                 {
3141                     try
3142                     {
3143                         base.Write(buffer, offset, count);
3144                     }
3145                     catch (HttpListenerException listenerException)
3146                     {
3147                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
3148                             HttpChannelUtilities.CreateCommunicationException(listenerException));
3149                     }
3150                     catch (ApplicationException applicationException)
3151                     {
3152                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
3153                             new CommunicationObjectAbortedException(SR.GetString(SR.HttpResponseAborted),
3154                             applicationException));
3155                     }
3156                 }
3157             }
3158         }
3159     }
3160
3161     enum HttpAbortReason
3162     {
3163         None,
3164         Aborted,
3165         TimedOut
3166     }
3167
3168     delegate void AddHeaderDelegate(string headerName, string headerValue);
3169
3170     static class HttpChannelUtilities
3171     {
3172         internal static class StatusDescriptionStrings
3173         {
3174             internal const string HttpContentTypeMissing = "Missing Content Type";
3175             internal const string HttpContentTypeMismatch = "Cannot process the message because the content type '{0}' was not the expected type '{1}'.";
3176             internal const string HttpStatusServiceActivationException = "System.ServiceModel.ServiceActivationException";
3177         }
3178
3179         internal static class ObsoleteDescriptionStrings
3180         {
3181             internal const string PropertyObsoleteUseAllowCookies = "This property is obsolete. To enable Http CookieContainer, use the AllowCookies property instead.";
3182             internal const string TypeObsoleteUseAllowCookies = "This type is obsolete. To enable the Http CookieContainer, use the AllowCookies property on the http binding or on the HttpTransportBindingElement.";
3183         }
3184
3185         internal const string HttpStatusCodeKey = "HttpStatusCode";
3186         internal const string HttpStatusCodeExceptionKey = "System.ServiceModel.Channels.HttpInput.HttpStatusCode";
3187         internal const string HttpStatusDescriptionExceptionKey = "System.ServiceModel.Channels.HttpInput.HttpStatusDescription";
3188
3189         internal const int ResponseStreamExcerptSize = 1024;
3190
3191         internal const string MIMEVersionHeader = "MIME-Version";
3192
3193         internal const string ContentEncodingHeader = "Content-Encoding";
3194         internal const string AcceptEncodingHeader = "Accept-Encoding";
3195
3196         private const string ContentLengthHeader = "Content-Length";
3197         private static readonly HashSet<string> httpContentHeaders = new HashSet<string>()
3198             {
3199                 "Allow", "Content-Encoding", "Content-Language", "Content-Location", "Content-MD5",
3200                 "Content-Range", "Expires", "Last-Modified", "Content-Type", ContentLengthHeader
3201             };
3202
3203         static bool allReferencedAssembliesLoaded = false;
3204
3205         public static Exception CreateCommunicationException(HttpListenerException listenerException)
3206         {
3207             switch (listenerException.NativeErrorCode)
3208             {
3209                 case UnsafeNativeMethods.ERROR_NO_TRACKING_SERVICE:
3210                     return new CommunicationException(SR.GetString(SR.HttpNoTrackingService, listenerException.Message), listenerException);
3211
3212                 case UnsafeNativeMethods.ERROR_NETNAME_DELETED:
3213                     return new CommunicationException(SR.GetString(SR.HttpNetnameDeleted, listenerException.Message), listenerException);
3214
3215                 case UnsafeNativeMethods.ERROR_INVALID_HANDLE:
3216                     return new CommunicationObjectAbortedException(SR.GetString(SR.HttpResponseAborted), listenerException);
3217
3218                 case UnsafeNativeMethods.ERROR_NOT_ENOUGH_MEMORY:
3219                 case UnsafeNativeMethods.ERROR_OUTOFMEMORY:
3220                 case UnsafeNativeMethods.ERROR_NO_SYSTEM_RESOURCES:
3221                     return new InsufficientMemoryException(SR.GetString(SR.InsufficentMemory), listenerException);
3222
3223                 default:
3224                     return new CommunicationException(listenerException.Message, listenerException);
3225             }
3226         }
3227
3228         public static void EnsureHttpRequestMessageContentNotNull(HttpRequestMessage httpRequestMessage)
3229         {
3230             if (httpRequestMessage.Content == null)
3231             {
3232                 httpRequestMessage.Content = new ByteArrayContent(EmptyArray<byte>.Instance);
3233             }
3234         }
3235
3236         public static void EnsureHttpResponseMessageContentNotNull(HttpResponseMessage httpResponseMessage)
3237         {
3238             if (httpResponseMessage.Content == null)
3239             {
3240                 httpResponseMessage.Content = new ByteArrayContent(EmptyArray<byte>.Instance);
3241             }
3242         }
3243
3244         public static bool IsEmpty(HttpResponseMessage httpResponseMessage)
3245         {
3246             return httpResponseMessage.Content == null
3247                || (httpResponseMessage.Content.Headers.ContentLength.HasValue && httpResponseMessage.Content.Headers.ContentLength.Value == 0);
3248         }
3249
3250         internal static void HandleContinueWithTask(Task task)
3251         {
3252             HandleContinueWithTask(task, null);
3253         }
3254
3255         internal static void HandleContinueWithTask(Task task, Action<Exception> exceptionHandler)
3256         {
3257             if (task.IsFaulted)
3258             {
3259                 if (exceptionHandler == null)
3260                 {
3261                     throw FxTrace.Exception.AsError<FaultException>(task.Exception);
3262                 }
3263                 else
3264                 {
3265                     exceptionHandler.Invoke(task.Exception);
3266                 }
3267             }
3268             else if (task.IsCanceled)
3269             {
3270                 throw FxTrace.Exception.AsError(new TimeoutException(SR.GetString(SR.TaskCancelledError)));
3271             }
3272         }
3273
3274         public static void AbortRequest(HttpWebRequest request)
3275         {
3276             request.Abort();
3277         }
3278
3279         public static void SetRequestTimeout(HttpWebRequest request, TimeSpan timeout)
3280         {
3281             int millisecondsTimeout = TimeoutHelper.ToMilliseconds(timeout);
3282             if (millisecondsTimeout == 0)
3283             {
3284                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(SR.GetString(
3285                     SR.HttpRequestTimedOut, request.RequestUri, timeout)));
3286             }
3287             request.Timeout = millisecondsTimeout;
3288             request.ReadWriteTimeout = millisecondsTimeout;
3289         }
3290
3291         public static void AddReplySecurityProperty(HttpChannelFactory<IRequestChannel> factory, HttpWebRequest webRequest,
3292             HttpWebResponse webResponse, Message replyMessage)
3293         {
3294             SecurityMessageProperty securityProperty = factory.CreateReplySecurityProperty(webRequest, webResponse);
3295             if (securityProperty != null)
3296             {
3297                 replyMessage.Properties.Security = securityProperty;
3298             }
3299         }
3300
3301         public static void CopyHeaders(HttpRequestMessage request, AddHeaderDelegate addHeader)
3302         {
3303             HttpChannelUtilities.CopyHeaders(request.Headers, addHeader);
3304             if (request.Content != null)
3305             {
3306                 HttpChannelUtilities.CopyHeaders(request.Content.Headers, addHeader);
3307             }
3308         }
3309
3310         public static void CopyHeaders(HttpResponseMessage response, AddHeaderDelegate addHeader)
3311         {
3312             HttpChannelUtilities.CopyHeaders(response.Headers, addHeader);
3313             if (response.Content != null)
3314             {
3315                 HttpChannelUtilities.CopyHeaders(response.Content.Headers, addHeader);
3316             }
3317         }
3318
3319         static void CopyHeaders(HttpHeaders headers, AddHeaderDelegate addHeader)
3320         {
3321             foreach (KeyValuePair<string, IEnumerable<string>> header in headers)
3322             {
3323                 foreach (string value in header.Value)
3324                 {
3325                     TryAddToCollection(addHeader, header.Key, value);                    
3326                 }
3327             }
3328         }
3329
3330         public static void CopyHeaders(NameValueCollection headers, AddHeaderDelegate addHeader)
3331         {
3332             //this nested loop logic was copied from NameValueCollection.Add(NameValueCollection)
3333             int count = headers.Count;
3334             for (int i = 0; i < count; i++)
3335             {
3336                 string key = headers.GetKey(i);
3337
3338                 string[] values = headers.GetValues(i);
3339                 if (values != null)
3340                 {
3341                     for (int j = 0; j < values.Length; j++)
3342                     {
3343                         TryAddToCollection(addHeader, key, values[j]);
3344                     }
3345                 }
3346                 else
3347                 {
3348                     addHeader(key, null);
3349                 }
3350             }
3351         }
3352
3353         public static void CopyHeadersToNameValueCollection(NameValueCollection headers, NameValueCollection destination)
3354         {
3355             CopyHeaders(headers, destination.Add); 
3356         }
3357
3358         [System.Diagnostics.CodeAnalysis.SuppressMessage(FxCop.Category.ReliabilityBasic, "Reliability104",
3359                             Justification = "The exceptions are traced already.")]
3360         static void TryAddToCollection(AddHeaderDelegate addHeader, string headerName, string value)
3361         {
3362             try
3363             {
3364                 addHeader(headerName, value);
3365             }
3366             catch (ArgumentException ex)
3367             {
3368                 string encodedValue = null;
3369                 if (TryEncodeHeaderValueAsUri(headerName, value, out encodedValue))
3370                 {
3371                     //note: if the hosthame of a referer header contains illegal chars, we will still throw from here
3372                     //because Uri will not fix this up for us, which is ok. The request will get rejected in the error code path.
3373                     addHeader(headerName, encodedValue);
3374                 }
3375                 else
3376                 {
3377                     // In self-hosted scenarios, some of the headers like Content-Length cannot be added directly.
3378                     // It will throw ArgumentException instead.
3379                     FxTrace.Exception.AsInformation(ex);
3380                 }
3381             }
3382         }
3383
3384         static bool TryEncodeHeaderValueAsUri(string headerName, string value, out string result)
3385         {
3386             result = null;
3387             //Internet Explorer will send the referrer header on the wire in unicode without encoding it
3388             //this will cause errors when added to a WebHeaderCollection.  This is a workaround for sharepoint, 
3389             //but will only work for WebHosted Scenarios.
3390             if (String.Compare(headerName, "Referer", StringComparison.OrdinalIgnoreCase) == 0)
3391             {
3392                 Uri uri;
3393                 if (Uri.TryCreate(value, UriKind.RelativeOrAbsolute, out uri))
3394                 {
3395                     if (uri.IsAbsoluteUri)
3396                     {
3397                         result = uri.AbsoluteUri;
3398                     }
3399                     else
3400                     {
3401                         result = uri.GetComponents(UriComponents.SerializationInfoString, UriFormat.UriEscaped);
3402                     }
3403                     return true;
3404                 }                
3405             }
3406             return false;
3407         }
3408
3409         //
3410         internal static Type GetTypeFromAssembliesInCurrentDomain(string typeString)
3411         {
3412             Type type = Type.GetType(typeString, false);
3413             if (null == type)
3414             {
3415                 if (!allReferencedAssembliesLoaded)
3416                 {
3417                     allReferencedAssembliesLoaded = true;
3418                     AspNetEnvironment.Current.EnsureAllReferencedAssemblyLoaded();
3419                 }
3420
3421                 Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
3422                 for (int i = 0; i < assemblies.Length; i++)
3423                 {
3424                     type = assemblies[i].GetType(typeString, false);
3425                     if (null != type)
3426                     {
3427                         break;
3428                     }
3429                 }
3430             }
3431
3432             return type;
3433         }
3434
3435         public static NetworkCredential GetCredential(AuthenticationSchemes authenticationScheme,
3436             SecurityTokenProviderContainer credentialProvider, TimeSpan timeout,
3437             out TokenImpersonationLevel impersonationLevel, out AuthenticationLevel authenticationLevel)
3438         {
3439             impersonationLevel = TokenImpersonationLevel.None;
3440             authenticationLevel = AuthenticationLevel.None;
3441
3442             NetworkCredential result = null;
3443
3444             if (authenticationScheme != AuthenticationSchemes.Anonymous)
3445             {
3446                 result = GetCredentialCore(authenticationScheme, credentialProvider, timeout, out impersonationLevel, out authenticationLevel);
3447             }
3448
3449             return result;
3450         }
3451
3452         [MethodImpl(MethodImplOptions.NoInlining)]
3453         static NetworkCredential GetCredentialCore(AuthenticationSchemes authenticationScheme,
3454             SecurityTokenProviderContainer credentialProvider, TimeSpan timeout,
3455             out TokenImpersonationLevel impersonationLevel, out AuthenticationLevel authenticationLevel)
3456         {
3457             impersonationLevel = TokenImpersonationLevel.None;
3458             authenticationLevel = AuthenticationLevel.None;
3459
3460             NetworkCredential result = null;
3461
3462             switch (authenticationScheme)
3463             {
3464                 case AuthenticationSchemes.Basic:
3465                     result = TransportSecurityHelpers.GetUserNameCredential(credentialProvider, timeout);
3466                     impersonationLevel = TokenImpersonationLevel.Delegation;
3467                     break;
3468
3469                 case AuthenticationSchemes.Digest:
3470                     result = TransportSecurityHelpers.GetSspiCredential(credentialProvider, timeout,
3471                         out impersonationLevel, out authenticationLevel);
3472
3473                     HttpChannelUtilities.ValidateDigestCredential(ref result, impersonationLevel);
3474                     break;
3475
3476                 case AuthenticationSchemes.Negotiate:
3477                     result = TransportSecurityHelpers.GetSspiCredential(credentialProvider, timeout,
3478                         out impersonationLevel, out authenticationLevel);
3479                     break;
3480
3481                 case AuthenticationSchemes.Ntlm:
3482                     result = TransportSecurityHelpers.GetSspiCredential(credentialProvider, timeout,
3483                         out impersonationLevel, out authenticationLevel);
3484                     if (authenticationLevel == AuthenticationLevel.MutualAuthRequired)
3485                     {
3486                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
3487                             new InvalidOperationException(SR.GetString(SR.CredentialDisallowsNtlm)));
3488                     }
3489                     break;
3490
3491                 default:
3492                     // The setter for this property should prevent this.
3493                     throw Fx.AssertAndThrow("GetCredential: Invalid authentication scheme");
3494             }
3495
3496             return result;
3497         }
3498
3499
3500         public static HttpWebResponse ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)
3501         {
3502             HttpWebResponse response = null;
3503
3504             if (webException.Status == WebExceptionStatus.Success ||
3505                 webException.Status == WebExceptionStatus.ProtocolError)
3506             {
3507                 response = (HttpWebResponse)webException.Response;
3508             }
3509
3510             if (response == null)
3511             {
3512                 Exception convertedException = ConvertWebException(webException, request, abortReason);
3513
3514                 if (convertedException != null)
3515                 {
3516                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(convertedException);
3517                 }
3518
3519                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(webException.Message,
3520                     webException));
3521             }
3522
3523             if (response.StatusCode == HttpStatusCode.NotFound)
3524             {
3525                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new EndpointNotFoundException(SR.GetString(SR.EndpointNotFound, request.RequestUri.AbsoluteUri), webException));
3526             }
3527
3528             if (response.StatusCode == HttpStatusCode.ServiceUnavailable)
3529             {
3530                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ServerTooBusyException(SR.GetString(SR.HttpServerTooBusy, request.RequestUri.AbsoluteUri), webException));
3531             }
3532
3533             if (response.StatusCode == HttpStatusCode.UnsupportedMediaType)
3534             {
3535                 string statusDescription = response.StatusDescription;
3536                 if (!string.IsNullOrEmpty(statusDescription))
3537                 {
3538                     if (string.Compare(statusDescription, HttpChannelUtilities.StatusDescriptionStrings.HttpContentTypeMissing, StringComparison.OrdinalIgnoreCase) == 0)
3539                     {
3540                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(SR.GetString(SR.MissingContentType, request.RequestUri), webException));
3541                     }
3542                 }
3543                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(SR.GetString(SR.FramingContentTypeMismatch, request.ContentType, request.RequestUri), webException));
3544             }
3545
3546             if (response.StatusCode == HttpStatusCode.GatewayTimeout)
3547             {
3548                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(webException.Message, webException));
3549             }
3550
3551             // if http.sys has a request queue on the TCP port, then if the path fails to match it will send
3552             // back "<h1>Bad Request (Invalid Hostname)</h1>" in the body of a 400 response.
3553             // See code at \\index1\sddnsrv\net\http\sys\httprcv.c for details
3554             if (response.StatusCode == HttpStatusCode.BadRequest)
3555             {
3556                 const string httpSysRequestQueueNotFound = "<h1>Bad Request (Invalid Hostname)</h1>";
3557                 const string httpSysRequestQueueNotFoundVista = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\"http://www.w3.org/TR/html4/strict.dtd\">\r\n<HTML><HEAD><TITLE>Bad Request</TITLE>\r\n<META HTTP-EQUIV=\"Content-Type\" Content=\"text/html; charset=us-ascii\"></HEAD>\r\n<BODY><h2>Bad Request - Invalid Hostname</h2>\r\n<hr><p>HTTP Error 400. The request hostname is invalid.</p>\r\n</BODY></HTML>\r\n";
3558                 string notFoundTestString = null;
3559
3560                 if (response.ContentLength == httpSysRequestQueueNotFound.Length)
3561                 {
3562                     notFoundTestString = httpSysRequestQueueNotFound;
3563                 }
3564                 else if (response.ContentLength == httpSysRequestQueueNotFoundVista.Length)
3565                 {
3566                     notFoundTestString = httpSysRequestQueueNotFoundVista;
3567                 }
3568
3569                 if (notFoundTestString != null)
3570                 {
3571                     Stream responseStream = response.GetResponseStream();
3572                     byte[] responseBytes = new byte[notFoundTestString.Length];
3573                     int bytesRead = responseStream.Read(responseBytes, 0, responseBytes.Length);
3574
3575                     // since the response is buffered by System.Net (it's an error response), we should have read
3576                     // the amount we were expecting
3577                     if (bytesRead == notFoundTestString.Length
3578                         && notFoundTestString == UTF8Encoding.ASCII.GetString(responseBytes))
3579                     {
3580                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new EndpointNotFoundException(SR.GetString(SR.EndpointNotFound, request.RequestUri.AbsoluteUri), webException));
3581                     }
3582                 }
3583             }
3584
3585             return response;
3586         }
3587
3588         public static Exception ConvertWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)
3589         {
3590             switch (webException.Status)
3591             {
3592                 case WebExceptionStatus.ConnectFailure:
3593                 case WebExceptionStatus.NameResolutionFailure:
3594                 case WebExceptionStatus.ProxyNameResolutionFailure:
3595                     return new EndpointNotFoundException(SR.GetString(SR.EndpointNotFound, request.RequestUri.AbsoluteUri), webException);
3596                 case WebExceptionStatus.SecureChannelFailure:
3597                     return new SecurityNegotiationException(SR.GetString(SR.SecureChannelFailure, request.RequestUri.Authority), webException);
3598                 case WebExceptionStatus.TrustFailure:
3599                     return new SecurityNegotiationException(SR.GetString(SR.TrustFailure, request.RequestUri.Authority), webException);
3600                 case WebExceptionStatus.Timeout:
3601                     return new TimeoutException(CreateRequestTimedOutMessage(request), webException);
3602                 case WebExceptionStatus.ReceiveFailure:
3603                     return new CommunicationException(SR.GetString(SR.HttpReceiveFailure, request.RequestUri), webException);
3604                 case WebExceptionStatus.SendFailure:
3605                     return new CommunicationException(SR.GetString(SR.HttpSendFailure, request.RequestUri), webException);
3606                 case WebExceptionStatus.RequestCanceled:
3607                     return CreateRequestCanceledException(webException, request, abortReason);
3608                 case WebExceptionStatus.ProtocolError:
3609                     HttpWebResponse response = (HttpWebResponse)webException.Response;
3610                     Fx.Assert(response != null, "'response' MUST NOT be NULL for WebExceptionStatus=='ProtocolError'.");
3611                     if (response.StatusCode == HttpStatusCode.InternalServerError &&
3612                         string.Compare(response.StatusDescription, HttpChannelUtilities.StatusDescriptionStrings.HttpStatusServiceActivationException, StringComparison.OrdinalIgnoreCase) == 0)
3613                     {
3614                         return new ServiceActivationException(SR.GetString(SR.Hosting_ServiceActivationFailed, request.RequestUri));
3615                     }
3616                     else
3617                     {
3618                         return null;
3619                     }
3620                 default:
3621                     return null;
3622             }
3623         }
3624
3625         public static Exception CreateResponseIOException(IOException ioException, TimeSpan receiveTimeout)
3626         {
3627             if (ioException.InnerException is SocketException)
3628             {
3629                 return SocketConnection.ConvertTransferException((SocketException)ioException.InnerException, receiveTimeout, ioException);
3630             }
3631
3632             return new CommunicationException(SR.GetString(SR.HttpTransferError, ioException.Message), ioException);
3633         }
3634
3635         public static Exception CreateResponseWebException(WebException webException, HttpWebResponse response)
3636         {
3637             switch (webException.Status)
3638             {
3639                 case WebExceptionStatus.RequestCanceled:
3640                     return TraceResponseException(new CommunicationObjectAbortedException(SR.GetString(SR.HttpRequestAborted, response.ResponseUri), webException));
3641                 case WebExceptionStatus.ConnectionClosed:
3642                     return TraceResponseException(new CommunicationException(webException.Message, webException));
3643                 case WebExceptionStatus.Timeout:
3644                     return TraceResponseException(new TimeoutException(SR.GetString(SR.HttpResponseTimedOut, response.ResponseUri,
3645                         TimeSpan.FromMilliseconds(response.GetResponseStream().ReadTimeout)), webException));
3646                 default:
3647                     return CreateUnexpectedResponseException(webException, response);
3648             }
3649         }
3650
3651         public static Exception CreateRequestCanceledException(Exception webException, HttpWebRequest request, HttpAbortReason abortReason)
3652         {
3653             switch (abortReason)
3654             {
3655                 case HttpAbortReason.Aborted:
3656                     return new CommunicationObjectAbortedException(SR.GetString(SR.HttpRequestAborted, request.RequestUri), webException);
3657                 case HttpAbortReason.TimedOut:
3658                     return new TimeoutException(CreateRequestTimedOutMessage(request), webException);
3659                 default:
3660                     return new CommunicationException(SR.GetString(SR.HttpTransferError, webException.Message), webException);
3661             }
3662         }
3663
3664         public static Exception CreateRequestIOException(IOException ioException, HttpWebRequest request)
3665         {
3666             return CreateRequestIOException(ioException, request, null);
3667         }
3668
3669         public static Exception CreateRequestIOException(IOException ioException, HttpWebRequest request, Exception originalException)
3670         {
3671             Exception exception = originalException == null ? ioException : originalException;
3672
3673             if (ioException.InnerException is SocketException)
3674             {
3675                 return SocketConnection.ConvertTransferException((SocketException)ioException.InnerException, TimeSpan.FromMilliseconds(request.Timeout), exception);
3676             }
3677
3678             return new CommunicationException(SR.GetString(SR.HttpTransferError, exception.Message), exception);
3679         }
3680
3681         static string CreateRequestTimedOutMessage(HttpWebRequest request)
3682         {
3683             return SR.GetString(SR.HttpRequestTimedOut, request.RequestUri, TimeSpan.FromMilliseconds(request.Timeout));
3684         }
3685
3686         public static Exception CreateRequestWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)
3687         {
3688             Exception convertedException = ConvertWebException(webException, request, abortReason);
3689
3690             if (webException.Response != null)
3691             {
3692                 //free the connection for use by another request
3693                 webException.Response.Close();
3694             }
3695
3696             if (convertedException != null)
3697             {
3698                 return convertedException;
3699             }
3700
3701             if (webException.InnerException is IOException)
3702             {
3703                 return CreateRequestIOException((IOException)webException.InnerException, request, webException);
3704             }
3705
3706             if (webException.InnerException is SocketException)
3707             {
3708                 return SocketConnectionInitiator.ConvertConnectException((SocketException)webException.InnerException, request.RequestUri, TimeSpan.MaxValue, webException);
3709             }
3710
3711             return new EndpointNotFoundException(SR.GetString(SR.EndpointNotFound, request.RequestUri.AbsoluteUri), webException);
3712         }
3713
3714         static Exception CreateUnexpectedResponseException(WebException responseException, HttpWebResponse response)
3715         {
3716             string statusDescription = response.StatusDescription;
3717             if (string.IsNullOrEmpty(statusDescription))
3718                 statusDescription = response.StatusCode.ToString();
3719
3720             return TraceResponseException(
3721                 new ProtocolException(SR.GetString(SR.UnexpectedHttpResponseCode,
3722                 (int)response.StatusCode, statusDescription), responseException));
3723         }
3724
3725         public static Exception CreateNullReferenceResponseException(NullReferenceException nullReferenceException)
3726         {
3727             return TraceResponseException(
3728                 new ProtocolException(SR.GetString(SR.NullReferenceOnHttpResponse), nullReferenceException));
3729         }
3730
3731         static string GetResponseStreamString(HttpWebResponse webResponse, out int bytesRead)
3732         {
3733             Stream responseStream = webResponse.GetResponseStream();
3734
3735             long bufferSize = webResponse.ContentLength;
3736
3737             if (bufferSize < 0 || bufferSize > ResponseStreamExcerptSize)
3738             {
3739                 bufferSize = ResponseStreamExcerptSize;
3740             }
3741
3742             byte[] responseBuffer = DiagnosticUtility.Utility.AllocateByteArray(checked((int)bufferSize));
3743             bytesRead = responseStream.Read(responseBuffer, 0, (int)bufferSize);
3744             responseStream.Close();
3745
3746             return System.Text.Encoding.UTF8.GetString(responseBuffer, 0, bytesRead);
3747         }
3748
3749         static Exception TraceResponseException(Exception exception)
3750         {
3751             if (DiagnosticUtility.ShouldTraceError)
3752             {
3753                 TraceUtility.TraceEvent(TraceEventType.Error, TraceCode.HttpChannelUnexpectedResponse, SR.GetString(SR.TraceCodeHttpChannelUnexpectedResponse), (object)null, exception);
3754             }
3755
3756             return exception;
3757         }
3758
3759         static bool ValidateEmptyContent(HttpWebResponse response)
3760         {
3761             bool responseIsEmpty = true;
3762
3763             if (response.ContentLength > 0)
3764             {
3765                 responseIsEmpty = false;
3766             }
3767             else if (response.ContentLength == -1) // chunked 
3768             {
3769                 Stream responseStream = response.GetResponseStream();
3770                 byte[] testBuffer = new byte[1];
3771                 responseIsEmpty = (responseStream.Read(testBuffer, 0, 1) != 1);
3772             }
3773
3774             return responseIsEmpty;
3775         }
3776
3777         static void ValidateAuthentication(HttpWebRequest request, HttpWebResponse response,
3778             WebException responseException, HttpChannelFactory<IRequestChannel> factory)
3779         {
3780             if (response.StatusCode == HttpStatusCode.Unauthorized)
3781             {
3782                 string message = SR.GetString(SR.HttpAuthorizationFailed, factory.AuthenticationScheme,
3783                     response.Headers[HttpResponseHeader.WwwAuthenticate]);
3784                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
3785                     TraceResponseException(new MessageSecurityException(message, responseException)));
3786             }
3787
3788             if (response.StatusCode == HttpStatusCode.Forbidden)
3789             {
3790                 string message = SR.GetString(SR.HttpAuthorizationForbidden, factory.AuthenticationScheme);
3791                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
3792                     TraceResponseException(new MessageSecurityException(message, responseException)));
3793             }
3794
3795             if ((request.AuthenticationLevel == AuthenticationLevel.MutualAuthRequired) &&
3796                 !response.IsMutuallyAuthenticated)
3797             {
3798                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
3799                     TraceResponseException(new SecurityNegotiationException(SR.GetString(SR.HttpMutualAuthNotSatisfied),
3800                     responseException)));
3801             }
3802         }
3803
3804         public static void ValidateDigestCredential(ref NetworkCredential credential, TokenImpersonationLevel impersonationLevel)
3805         {
3806             // this is a work-around to VSWhidbey#470545 (Since the service always uses Impersonation,
3807             // we mitigate EOP by preemtively not allowing Identification)
3808             if (!SecurityUtils.IsDefaultNetworkCredential(credential))
3809             {
3810                 // With a non-default credential, Digest will not honor a client impersonation constraint of 
3811                 // TokenImpersonationLevel.Identification.
3812                 if (!TokenImpersonationLevelHelper.IsGreaterOrEqual(impersonationLevel,
3813                     TokenImpersonationLevel.Impersonation))
3814                 {
3815                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(
3816                         SR.DigestExplicitCredsImpersonationLevel, impersonationLevel)));
3817                 }
3818             }
3819         }
3820
3821         // only valid response codes are 500 (if it's a fault) or 200 (iff it's a response message)
3822         public static HttpInput ValidateRequestReplyResponse(HttpWebRequest request, HttpWebResponse response,
3823             HttpChannelFactory<IRequestChannel> factory, WebException responseException, ChannelBinding channelBinding)
3824         {
3825             ValidateAuthentication(request, response, responseException, factory);
3826
3827             HttpInput httpInput = null;
3828
3829             // We will close the HttpWebResponse if we got an error code betwen 200 and 300 and 
3830             // 1) an exception was thrown out or 
3831             // 2) it's an empty message and we are using SOAP.
3832             // For responses with status code above 300, System.Net will close the underlying connection so we don't need to worry about that.
3833             if ((200 <= (int)response.StatusCode && (int)response.StatusCode < 300) || response.StatusCode == HttpStatusCode.InternalServerError)
3834             {
3835                 if (response.StatusCode == HttpStatusCode.InternalServerError
3836                     && string.Compare(response.StatusDescription, HttpChannelUtilities.StatusDescriptionStrings.HttpStatusServiceActivationException, StringComparison.OrdinalIgnoreCase) == 0)
3837                 {
3838                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ServiceActivationException(SR.GetString(SR.Hosting_ServiceActivationFailed, request.RequestUri)));
3839                 }
3840                 else
3841                 {
3842                     bool throwing = true;
3843                     try
3844                     {
3845                         if (string.IsNullOrEmpty(response.ContentType))
3846                         {
3847                             if (!ValidateEmptyContent(response))
3848                             {
3849                                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(TraceResponseException(
3850                                     new ProtocolException(
3851                                         SR.GetString(SR.HttpContentTypeHeaderRequired),
3852                                         responseException)));
3853                             }
3854                         }
3855                         else if (response.ContentLength != 0)
3856                         {
3857                             MessageEncoder encoder = factory.MessageEncoderFactory.Encoder;
3858                             if (!encoder.IsContentTypeSupported(response.ContentType))
3859                             {
3860                                 int bytesRead;
3861                                 String responseExcerpt = GetResponseStreamString(response, out bytesRead);
3862
3863                                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(TraceResponseException(
3864                                     new ProtocolException(
3865                                         SR.GetString(
3866                                             SR.ResponseContentTypeMismatch,
3867                                             response.ContentType,
3868                                             encoder.ContentType,
3869                                             bytesRead,
3870                                             responseExcerpt), responseException)));
3871
3872                             }
3873
3874                             httpInput = HttpInput.CreateHttpInput(response, factory, channelBinding);
3875                             httpInput.WebException = responseException;
3876                         }
3877
3878                         throwing = false;
3879                     }
3880                     finally
3881                     {
3882                         if (throwing)
3883                         {
3884                             response.Close();
3885                         }
3886                     }
3887                 }
3888
3889                 if (httpInput == null)
3890                 {
3891                     if (factory.MessageEncoderFactory.MessageVersion == MessageVersion.None)
3892                     {
3893                         httpInput = HttpInput.CreateHttpInput(response, factory, channelBinding);
3894                         httpInput.WebException = responseException;
3895                     }
3896                     else
3897                     {
3898                         // In this case, we got a response with
3899                         // 1) status code between 200 and 300
3900                         // 2) Non-empty Content Type string
3901                         // 3) Zero content length
3902                         // Since we are trying to use SOAP here, the message seems to be malicious and we should
3903                         // just close the response directly.
3904                         response.Close();
3905                     }
3906                 }
3907             }
3908             else
3909             {
3910                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateUnexpectedResponseException(responseException, response));
3911             }
3912
3913             return httpInput;
3914         }
3915
3916         public static bool GetHttpResponseTypeAndEncodingForCompression(ref string contentType, out string contentEncoding)
3917         {
3918             contentEncoding = null;
3919             bool isSession = false;
3920             bool isDeflate = false;
3921
3922             if (string.Equals(BinaryVersion.GZipVersion1.ContentType, contentType, StringComparison.OrdinalIgnoreCase) ||
3923                 (isSession = string.Equals(BinaryVersion.GZipVersion1.SessionContentType, contentType, StringComparison.OrdinalIgnoreCase)) ||
3924                 (isDeflate = (string.Equals(BinaryVersion.DeflateVersion1.ContentType, contentType, StringComparison.OrdinalIgnoreCase) ||
3925                 (isSession = string.Equals(BinaryVersion.DeflateVersion1.SessionContentType, contentType, StringComparison.OrdinalIgnoreCase)))))
3926             {
3927                 contentType = isSession ? BinaryVersion.Version1.SessionContentType : BinaryVersion.Version1.ContentType;
3928                 contentEncoding = isDeflate ? MessageEncoderCompressionHandler.DeflateContentEncoding : MessageEncoderCompressionHandler.GZipContentEncoding;
3929                 return true;
3930             }
3931             return false;
3932         }
3933     }
3934
3935     abstract class HttpDelayedAcceptStream : DetectEofStream
3936     {
3937         HttpOutput httpOutput;
3938         bool isHttpOutputClosed;
3939
3940         /// <summary>
3941         /// Indicates whether the HttpOutput should be closed when this stream is closed. In the streamed case, 
3942         /// we�ll leave the HttpOutput opened (and it will be closed by the HttpRequestContext, so we won't leak it).
3943         /// </summary>
3944         bool closeHttpOutput;
3945
3946         // sometimes we can't flush the HTTP output until we're done reading the end of the 
3947         // incoming stream of the HTTP input
3948         protected HttpDelayedAcceptStream(Stream stream)
3949             : base(stream)
3950         {
3951         }
3952
3953         public bool EnableDelayedAccept(HttpOutput output, bool closeHttpOutput)
3954         {
3955             if (IsAtEof)
3956             {
3957                 return false;
3958             }
3959
3960             this.closeHttpOutput = closeHttpOutput;
3961             this.httpOutput = output;
3962             return true;
3963         }
3964
3965         protected override void OnReceivedEof()
3966         {
3967             if (this.closeHttpOutput)
3968             {
3969                 CloseHttpOutput();
3970             }
3971         }
3972
3973         public override void Close()
3974         {
3975             if (this.closeHttpOutput)
3976             {
3977                 CloseHttpOutput();
3978             }
3979
3980             base.Close();
3981         }
3982
3983         void CloseHttpOutput()
3984         {
3985             if (this.httpOutput != null && !this.isHttpOutputClosed)
3986             {
3987                 this.httpOutput.Close();
3988                 this.isHttpOutputClosed = true;
3989             }
3990         }
3991     }
3992
3993     abstract class BytesReadPositionStream : DelegatingStream
3994     {
3995         int bytesSent = 0;
3996
3997         protected BytesReadPositionStream(Stream stream)
3998             : base(stream)
3999         {
4000         }
4001
4002         public override long Position
4003         {
4004             get
4005             {
4006                 return bytesSent;
4007             }
4008             set
4009             {
4010                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.SeekNotSupported)));
4011             }
4012         }
4013
4014         public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
4015         {
4016             this.bytesSent += count;
4017             return BaseStream.BeginWrite(buffer, offset, count, callback, state);
4018         }
4019
4020         public override void Write(byte[] buffer, int offset, int count)
4021         {
4022             BaseStream.Write(buffer, offset, count);
4023             this.bytesSent += count;
4024         }
4025
4026         public override void WriteByte(byte value)
4027         {
4028             BaseStream.WriteByte(value);
4029             this.bytesSent++;
4030         }
4031     }
4032
4033     class PreReadStream : DelegatingStream
4034     {
4035         byte[] preReadBuffer;
4036
4037         public PreReadStream(Stream stream, byte[] preReadBuffer)
4038             : base(stream)
4039         {
4040             this.preReadBuffer = preReadBuffer;
4041         }
4042
4043         bool ReadFromBuffer(byte[] buffer, int offset, int count, out int bytesRead)
4044         {
4045             if (this.preReadBuffer != null)
4046             {
4047                 if (buffer == null)
4048                 {
4049                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("buffer");
4050                 }
4051
4052                 if (offset >= buffer.Length)
4053                 {
4054                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", offset,
4055                         SR.GetString(SR.OffsetExceedsBufferBound, buffer.Length - 1)));
4056                 }
4057
4058                 if (count < 0)
4059                 {
4060                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", count,
4061                         SR.GetString(SR.ValueMustBeNonNegative)));
4062                 }
4063
4064                 if (count == 0)
4065                 {
4066                     bytesRead = 0;
4067                 }
4068                 else
4069                 {
4070                     buffer[offset] = this.preReadBuffer[0];
4071                     this.preReadBuffer = null;
4072                     bytesRead = 1;
4073                 }
4074
4075                 return true;
4076             }
4077
4078             bytesRead = -1;
4079             return false;
4080         }
4081
4082         public override int Read(byte[] buffer, int offset, int count)
4083         {
4084             int bytesRead;
4085             if (ReadFromBuffer(buffer, offset, count, out bytesRead))
4086             {
4087                 return bytesRead;
4088             }
4089
4090             return base.Read(buffer, offset, count);
4091         }
4092
4093         public override int ReadByte()
4094         {
4095             if (this.preReadBuffer != null)
4096             {
4097                 byte[] tempBuffer = new byte[1];
4098                 int bytesRead;
4099                 if (ReadFromBuffer(tempBuffer, 0, 1, out bytesRead))
4100                 {
4101                     return tempBuffer[0];
4102                 }
4103             }
4104             return base.ReadByte();
4105         }
4106
4107         public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
4108         {
4109             int bytesRead;
4110             if (ReadFromBuffer(buffer, offset, count, out bytesRead))
4111             {
4112                 return new CompletedAsyncResult<int>(bytesRead, callback, state);
4113             }
4114
4115             return base.BeginRead(buffer, offset, count, callback, state);
4116         }
4117
4118         public override int EndRead(IAsyncResult result)
4119         {
4120             if (result is CompletedAsyncResult<int>)
4121             {
4122                 return CompletedAsyncResult<int>.End(result);
4123             }
4124             else
4125             {
4126                 return base.EndRead(result);
4127             }
4128         }
4129     }
4130
4131     class HttpRequestMessageHttpInput : HttpInput, HttpRequestMessageProperty.IHttpHeaderProvider
4132     {
4133         const string SoapAction = "SOAPAction";
4134         HttpRequestMessage httpRequestMessage;
4135         ChannelBinding channelBinding;
4136
4137         public HttpRequestMessageHttpInput(HttpRequestMessage httpRequestMessage, IHttpTransportFactorySettings settings, bool enableChannelBinding, ChannelBinding channelBinding)
4138             : base(settings, true, enableChannelBinding)
4139         {
4140             this.httpRequestMessage = httpRequestMessage;
4141             this.channelBinding = channelBinding;
4142         }
4143
4144         public override long ContentLength
4145         {
4146             get
4147             {
4148                 if (this.httpRequestMessage.Content.Headers.ContentLength == null)
4149                 {
4150                     // Chunked transfer mode
4151                     return -1;
4152                 }
4153
4154                 return this.httpRequestMessage.Content.Headers.ContentLength.Value;
4155             }
4156         }
4157
4158         protected override ChannelBinding ChannelBinding
4159         {
4160             get
4161             {
4162                 return this.channelBinding;
4163             }
4164         }
4165
4166         public HttpRequestMessage HttpRequestMessage
4167         {
4168             get { return this.httpRequestMessage; }
4169         }
4170
4171         protected override bool HasContent
4172         {
4173             get
4174             {
4175                 // In Chunked transfer mode, the ContentLength header is null
4176                 // Otherwise we just rely on the ContentLength header
4177                 return this.httpRequestMessage.Content.Headers.ContentLength == null || this.httpRequestMessage.Content.Headers.ContentLength.Value > 0;
4178             }
4179         }
4180
4181         protected override string ContentTypeCore
4182         {
4183             get
4184             {
4185                 if (!this.HasContent)
4186                 {
4187                     return null;
4188                 }
4189
4190                 return this.httpRequestMessage.Content.Headers.ContentType == null ? null : this.httpRequestMessage.Content.Headers.ContentType.MediaType;
4191             }
4192         }
4193
4194         public override void ConfigureHttpRequestMessage(HttpRequestMessage message)
4195         {
4196             throw FxTrace.Exception.AsError(new InvalidOperationException());
4197         }
4198
4199         protected override Stream GetInputStream()
4200         {
4201             if (this.httpRequestMessage.Content == null)
4202             {
4203                 return Stream.Null;
4204             }
4205
4206             return this.httpRequestMessage.Content.ReadAsStreamAsync().Result;
4207         }
4208
4209         protected override void AddProperties(Message message)
4210         {
4211             HttpRequestMessageProperty requestProperty = new HttpRequestMessageProperty(this.httpRequestMessage);
4212             message.Properties.Add(HttpRequestMessageProperty.Name, requestProperty);
4213             message.Properties.Via = this.httpRequestMessage.RequestUri;
4214
4215             foreach (KeyValuePair<string, object> property in this.httpRequestMessage.Properties)
4216             {
4217                 message.Properties.Add(property.Key, property.Value);
4218             }
4219
4220             this.httpRequestMessage.Properties.Clear();
4221         }
4222
4223         protected override string SoapActionHeader
4224         {
4225             get
4226             {
4227                 IEnumerable<string> values;
4228                 if (this.httpRequestMessage.Headers.TryGetValues(SoapAction, out values))
4229                 {
4230                     foreach (string headerValue in values)
4231                     {
4232                         return headerValue;
4233                     }
4234                 }
4235
4236                 return null;
4237             }
4238         }
4239
4240         public void CopyHeaders(WebHeaderCollection headers)
4241         {
4242             // No special-casing for the "WWW-Authenticate" header required here,
4243             // because this method is only called for the incoming request
4244             // and the WWW-Authenticate header is a header only applied to responses.
4245             HttpChannelUtilities.CopyHeaders(this.httpRequestMessage, headers.Add);
4246         }        
4247
4248         internal void SetHttpRequestMessage(HttpRequestMessage httpRequestMessage)
4249         {
4250             Fx.Assert(httpRequestMessage != null, "httpRequestMessage should not be null.");
4251             this.httpRequestMessage = httpRequestMessage;
4252         }
4253     }
4254 }