Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.ServiceModel.Activation / System / ServiceModel / Activation / HostedHttpContext.cs
1 //----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //----------------------------------------------------------------------------
4 namespace System.ServiceModel.Activation
5 {
6     using System.Collections.Generic;
7     using System.Diagnostics;
8     using System.Globalization;
9     using System.IO;
10     using System.Net;
11     using System.Net.Http;
12     using System.Net.Http.Headers;
13     using System.Net.WebSockets;
14     using System.Runtime;
15     using System.Security;
16     using System.Security.Authentication.ExtendedProtection;
17     using System.Security.Permissions;
18     using System.ServiceModel;
19     using System.ServiceModel.Channels;
20     using System.ServiceModel.Diagnostics;
21     using System.ServiceModel.Security;
22     using System.Threading;
23     using System.Threading.Tasks;
24     using System.Web;
25     using System.Web.Management;
26     using System.Web.WebSockets;
27
28     class HostedHttpContext : HttpRequestContext
29     {
30         HostedRequestContainer requestContainer;
31         HostedHttpRequestAsyncResult result;
32         TaskCompletionSource<object> webSocketWaitingTask;
33         RemoteEndpointMessageProperty remoteEndpointMessageProperty;
34         TaskCompletionSource<WebSocketContext> webSocketContextTaskSource;
35
36         int impersonationReleased = 0;
37
38         public HostedHttpContext(HttpChannelListener listener, HostedHttpRequestAsyncResult result)
39             : base(listener, null, result.EventTraceActivity)
40         {
41             AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
42
43             this.result = result;
44             result.AddRefForImpersonation();
45         }
46
47         public override string HttpMethod
48         {
49             get
50             {
51                 return result.GetHttpMethod();
52             }
53         }
54
55         internal void CompleteWithException(Exception ex)
56         {
57             Fx.Assert(ex != null, "ex should not be null.");
58             this.result.CompleteOperation(ex);
59         }
60
61         protected override SecurityMessageProperty OnProcessAuthentication()
62         {
63             return Listener.ProcessAuthentication(this.result);
64         }
65
66         protected override HttpStatusCode ValidateAuthentication()
67         {
68             return Listener.ValidateAuthentication(this.result);
69         }
70
71         // Accessing the headers of an already replied HttpRequest instance causes an Access Violation in hosted mode.
72         // In one-way scenarios, reply happens before the user gets the message. That's why we are disabling all access
73         // to HostedRequestContainer (CSDMain 34014).
74         void CloseHostedRequestContainer()
75         {
76             // RequestContext.RequestMessage property can throw rather than create a message.
77             // This means we never created a message and never cached the IIS properties.
78             // At this point the user may return a reply, so requestContainer is allowed to be null.
79             if (this.requestContainer != null)
80             {
81                 this.requestContainer.Close();
82                 this.requestContainer = null;
83             }
84         }
85
86         protected override Task<WebSocketContext> AcceptWebSocketCore(HttpResponseMessage response, string protocol)
87         {
88             this.BeforeAcceptWebSocket(response);
89             this.webSocketContextTaskSource = new TaskCompletionSource<WebSocketContext>();
90             this.result.Application.Context.AcceptWebSocketRequest(PostAcceptWebSocket, new AspNetWebSocketOptions() { SubProtocol = protocol });
91             this.result.OnReplySent();
92             return this.webSocketContextTaskSource.Task;
93         }
94
95         protected override void OnAcceptWebSocketSuccess(WebSocketContext context, HttpRequestMessage requestMessage)
96         {
97             // ASP.NET owns the WebSocket object and needs it during the cleanup process. We should not dispose the WebSocket in WCF layer.
98             base.OnAcceptWebSocketSuccess(context, this.remoteEndpointMessageProperty, null, false, requestMessage);
99         }
100
101         void BeforeAcceptWebSocket(HttpResponseMessage response)
102         {
103             this.SetRequestContainer(new HostedRequestContainer(this.result));
104             string address = string.Empty;
105             int port = 0;
106
107             if (this.requestContainer.TryGetAddressAndPort(out address, out port))
108             {
109                 this.remoteEndpointMessageProperty = new RemoteEndpointMessageProperty(address, port);
110             }
111
112             this.CloseHostedRequestContainer();
113
114             HostedHttpContext.AppendHeaderFromHttpResponseMessageToResponse(response, this.result);
115         }
116
117         Task PostAcceptWebSocket(AspNetWebSocketContext context)
118         {
119             this.webSocketWaitingTask = new TaskCompletionSource<object>();
120             this.WebSocketChannel.Closed += new EventHandler(this.FinishWebSocketWaitingTask);
121             this.webSocketContextTaskSource.SetResult(context);
122             return webSocketWaitingTask.Task;
123         }
124
125         static void AppendHeaderFromHttpResponseMessageToResponse(HttpResponseMessage response, HostedHttpRequestAsyncResult result)
126         {
127             HostedHttpContext.AppendHeaderToResponse(response.Headers, result);
128             if (response.Content != null)
129             {
130                 HostedHttpContext.AppendHeaderToResponse(response.Content.Headers, result);
131             }
132         }
133
134         static void AppendHeaderToResponse(HttpHeaders headers, HostedHttpRequestAsyncResult result)
135         {
136             foreach (KeyValuePair<string, IEnumerable<string>> header in headers)
137             {
138                 foreach (string value in header.Value)
139                 {
140                     result.AppendHeader(header.Key, value);
141                 }
142             }
143         }
144
145         void FinishWebSocketWaitingTask(object sender, EventArgs args)
146         {
147             this.webSocketWaitingTask.TrySetResult(null);
148         }
149
150         public override bool IsWebSocketRequest
151         {
152             get
153             {
154                 return this.result.IsWebSocketRequest;
155             }
156         }
157
158         protected override void OnReply(Message message, TimeSpan timeout)
159         {
160             this.CloseHostedRequestContainer();
161             base.OnReply(message, timeout);
162         }
163
164         protected override IAsyncResult OnBeginReply(
165             Message message, TimeSpan timeout, AsyncCallback callback, object state)
166         {
167             this.CloseHostedRequestContainer();
168             return base.OnBeginReply(message, timeout, callback, state);
169         }
170
171         protected override void OnAbort()
172         {
173             base.OnAbort();
174             result.Abort();
175         }
176
177         protected override void Cleanup()
178         {
179             base.Cleanup();
180
181             if (Interlocked.Increment(ref this.impersonationReleased) == 1)
182             {
183                 this.result.ReleaseImpersonation();
184             }
185         }
186
187         protected override HttpInput GetHttpInput()
188         {
189             return new HostedHttpInput(this);
190         }
191
192         public override HttpOutput GetHttpOutput(Message message)
193         {
194             HttpInput httpInput = this.GetHttpInput(false);
195
196             // work around http.sys keep alive bug with chunked requests, see MB 49676, this is fixed in Vista
197             if ((httpInput != null && httpInput.ContentLength == -1 && !OSEnvironmentHelper.IsVistaOrGreater) || !this.KeepAliveEnabled)
198             {
199                 result.SetConnectionClose();
200             }
201
202             ICompressedMessageEncoder compressedMessageEncoder = this.Listener.MessageEncoderFactory.Encoder as ICompressedMessageEncoder;
203             if (compressedMessageEncoder != null && compressedMessageEncoder.CompressionEnabled)
204             {
205                 string acceptEncoding = this.result.GetAcceptEncoding();
206                 compressedMessageEncoder.AddCompressedMessageProperties(message, acceptEncoding);
207             }
208
209             return new HostedRequestHttpOutput(result, Listener, message, this);
210         }
211
212         protected override void OnClose(TimeSpan timeout)
213         {
214             base.OnClose(timeout);
215             result.OnReplySent();
216         }
217
218         void SetRequestContainer(HostedRequestContainer requestContainer)
219         {
220             this.requestContainer = requestContainer;
221         }
222
223         class HostedHttpInput : HttpInput
224         {
225             int contentLength;
226             string contentType;
227             HostedHttpContext hostedHttpContext;
228             byte[] preReadBuffer;
229
230             public HostedHttpInput(HostedHttpContext hostedHttpContext)
231                 : base(hostedHttpContext.Listener, true, hostedHttpContext.Listener.IsChannelBindingSupportEnabled)
232             {
233                 AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
234
235                 this.hostedHttpContext = hostedHttpContext;
236
237                 EnvelopeVersion envelopeVersion = hostedHttpContext.Listener.MessageEncoderFactory.Encoder.MessageVersion.Envelope;
238
239                 // MB#29602, perf optimization
240                 if (envelopeVersion == EnvelopeVersion.Soap11)
241                 {
242                     // For soap 1.1, use headers collection to get content-type since we need to pull in the headers 
243                     // collection for SOAP-Action anyways
244                     this.contentType = hostedHttpContext.result.GetContentType();
245                 }
246                 else
247                 {
248                     // For soap 1.2, the we pull the action header from the content-type, so don't access the headers
249                     // and just use the typed property. For other versions, we shouldn't need the headers up front.
250                     this.contentType = hostedHttpContext.result.GetContentTypeFast();
251                 }
252
253                 this.contentLength = hostedHttpContext.result.GetContentLength();
254
255                 // MB#34947: System.Web signals chunked as 0 as well so the only way we can
256                 // differentiate is by reading ahead
257                 if (this.contentLength == 0)
258                 {
259                     preReadBuffer = hostedHttpContext.result.GetPrereadBuffer(ref this.contentLength);
260                 }
261             }
262
263             public override long ContentLength
264             {
265                 get
266                 {
267                     return this.contentLength;
268                 }
269             }
270
271             protected override string ContentTypeCore
272             {
273                 get
274                 {
275                     return this.contentType;
276                 }
277             }
278
279             protected override bool HasContent
280             {
281                 get { return (this.preReadBuffer != null || this.ContentLength > 0); }
282             }
283
284             protected override string SoapActionHeader
285             {
286                 get
287                 {
288                     return hostedHttpContext.result.GetSoapAction();
289                 }
290             }
291
292             protected override ChannelBinding ChannelBinding
293             {
294                 get
295                 {
296                     return ChannelBindingUtility.DuplicateToken(hostedHttpContext.result.GetChannelBinding());
297                 }
298             }
299
300             protected override void AddProperties(Message message)
301             {
302                 HostedRequestContainer requestContainer = new HostedRequestContainer(this.hostedHttpContext.result);
303
304                 HttpRequestMessageProperty requestProperty = new HttpRequestMessageProperty(requestContainer);
305
306                 requestProperty.Method = this.hostedHttpContext.HttpMethod;
307
308                 // Uri.Query always includes the '?'
309                 if (this.hostedHttpContext.result.RequestUri.Query.Length > 1)
310                 {
311                     requestProperty.QueryString = this.hostedHttpContext.result.RequestUri.Query.Substring(1);
312                 }
313
314                 message.Properties.Add(HttpRequestMessageProperty.Name, requestProperty);
315
316                 message.Properties.Add(HostingMessageProperty.Name, CreateMessagePropertyFromHostedResult(this.hostedHttpContext.result));
317                 message.Properties.Via = this.hostedHttpContext.result.RequestUri;
318
319                 RemoteEndpointMessageProperty remoteEndpointProperty = new RemoteEndpointMessageProperty(requestContainer);
320                 message.Properties.Add(RemoteEndpointMessageProperty.Name, remoteEndpointProperty);
321
322                 this.hostedHttpContext.SetRequestContainer(requestContainer);
323             }
324
325             public override void ConfigureHttpRequestMessage(HttpRequestMessage message)
326             {
327                 message.Method = new HttpMethod(this.hostedHttpContext.result.GetHttpMethod());
328                 message.RequestUri = this.hostedHttpContext.result.RequestUri;
329                 foreach (string webHeaderKey in this.hostedHttpContext.result.Application.Context.Request.Headers.Keys)
330                 {
331                     message.AddHeader(webHeaderKey, this.hostedHttpContext.result.Application.Context.Request.Headers[webHeaderKey]);
332                 }
333
334                 HostedRequestContainer requestContainer = new HostedRequestContainer(this.hostedHttpContext.result);
335                 RemoteEndpointMessageProperty remoteEndpointProperty = new RemoteEndpointMessageProperty(requestContainer);
336                 message.Properties.Add(RemoteEndpointMessageProperty.Name, remoteEndpointProperty);
337             }
338
339             [Fx.Tag.SecurityNote(Critical = "Calls critical .ctor(HostedImpersonationContext)",
340                 Safe = "Only accepts the incoming context from HostedHttpRequestAsyncResult which stores the context in a critical field")]
341             [SecuritySafeCritical]
342             static HostingMessageProperty CreateMessagePropertyFromHostedResult(HostedHttpRequestAsyncResult result)
343             {
344                 return new HostingMessageProperty(result);
345             }
346
347             protected override Stream GetInputStream()
348             {
349                 if (this.preReadBuffer != null)
350                 {
351                     return new HostedInputStream(this.hostedHttpContext, this.preReadBuffer);
352                 }
353                 else
354                 {
355                     return new HostedInputStream(this.hostedHttpContext);
356                 }
357             }
358
359             class HostedInputStream : HttpDelayedAcceptStream
360             {
361                 HostedHttpRequestAsyncResult result;
362
363                 public HostedInputStream(HostedHttpContext hostedContext)
364                     : base(hostedContext.result.GetInputStream())
365                 {
366                     AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
367                     this.result = hostedContext.result;
368                 }
369
370                 public HostedInputStream(HostedHttpContext hostedContext, byte[] preReadBuffer)
371                     : base(new PreReadStream(hostedContext.result.GetInputStream(), preReadBuffer))
372                 {
373                     AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
374                     this.result = hostedContext.result;
375                 }
376
377                 public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
378                 {
379                     if (!this.result.TryStartStreamedRead())
380                     {
381                         throw FxTrace.Exception.AsError(new CommunicationObjectAbortedException(SR.RequestContextAborted));
382                     }
383
384                     bool throwing = true;
385
386                     try
387                     {
388                         IAsyncResult result = base.BeginRead(buffer, offset, count, callback, state);
389                         throwing = false;
390                         return result;
391                     }
392                     catch (HttpException hostedException)
393                     {
394                         throw FxTrace.Exception.AsError(CreateCommunicationException(hostedException));
395                     }
396                     finally
397                     {
398                         if (throwing)
399                         {
400                             this.result.SetStreamedReadFinished();
401                         }
402                     }
403                 }
404
405                 public override int EndRead(IAsyncResult result)
406                 {
407                     try
408                     {
409                         return base.EndRead(result);
410                     }
411                     catch (HttpException hostedException)
412                     {
413                         throw FxTrace.Exception.AsError(CreateCommunicationException(hostedException));
414                     }
415                     finally
416                     {
417                         this.result.SetStreamedReadFinished();
418                     }
419                 }
420
421                 public override int Read(byte[] buffer, int offset, int count)
422                 {
423                     if (!this.result.TryStartStreamedRead())
424                     {
425                         throw FxTrace.Exception.AsError(new CommunicationObjectAbortedException(SR.RequestContextAborted));
426                     }
427
428                     try
429                     {
430                         return base.Read(buffer, offset, count);
431                     }
432                     catch (HttpException hostedException)
433                     {
434                         throw FxTrace.Exception.AsError(CreateCommunicationException(hostedException));
435                     }
436                     finally
437                     {
438                         this.result.SetStreamedReadFinished();
439                     }
440                 }
441
442                 // Wraps HttpException as inner exception in CommunicationException or ProtocolException (which derives from CommunicationException)
443                 static Exception CreateCommunicationException(HttpException hostedException)
444                 {
445                     if (hostedException.WebEventCode == WebEventCodes.RuntimeErrorPostTooLarge)
446                     {
447                         // This HttpException is thrown if greater than httpRuntime/maxRequestLength bytes have been read from the stream.
448                         // Note that this code path can only be hit when GetBufferedInputStream() is called in HostedHttpRequestAsyncResult.GetInputStream(), which only
449                         // happens when an Http Module which is executed before the WCF Http Handler has accessed the request stream via GetBufferedInputStream().
450                         // This is the only case that throws because GetBufferlessInputStream(true) ignores maxRequestLength, and InputStream property throws when invoked, not when stream is read.
451                         return HttpInput.CreateHttpProtocolException(SR.Hosting_MaxRequestLengthExceeded, HttpStatusCode.RequestEntityTooLarge, null, hostedException);
452                     }
453                     else
454                     {
455                         // This HttpException is thrown if client disconnects and a read operation is invoked on the stream.
456                         return new CommunicationException(hostedException.Message, hostedException);
457                     }
458
459                 }
460             }
461         }
462
463         class HostedRequestHttpOutput : HttpOutput
464         {
465             HostedHttpRequestAsyncResult result;
466             HostedHttpContext context;
467             string mimeVersion;
468             string contentType;
469             int statusCode;
470             bool isSettingMimeHeader = false;
471             bool isSettingContentType = false;
472
473             public HostedRequestHttpOutput(HostedHttpRequestAsyncResult result, IHttpTransportFactorySettings settings,
474                 Message message, HostedHttpContext context)
475                 : base(settings, message, false, false)
476             {
477                 AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
478
479                 this.result = result;
480                 this.context = context;
481
482                 if (TransferModeHelper.IsResponseStreamed(settings.TransferMode))
483                     result.SetTransferModeToStreaming();
484
485                 if (message.IsFault)
486                 {
487                     this.statusCode = (int)HttpStatusCode.InternalServerError;
488                 }
489                 else
490                 {
491                     this.statusCode = (int)HttpStatusCode.OK;
492                 }
493             }
494
495             protected override Stream GetOutputStream()
496             {
497                 return new HostedResponseOutputStream(this.result, this.context);
498             }
499
500             protected override void AddHeader(string name, string value)
501             {
502                 this.result.AppendHeader(name, value);
503             }
504
505             protected override void AddMimeVersion(string version)
506             {
507                 if (!isSettingMimeHeader)
508                 {
509                     this.mimeVersion = version;
510                 }
511                 else
512                 {
513                     this.result.AppendHeader(HttpChannelUtilities.MIMEVersionHeader, this.mimeVersion);
514                 }
515             }
516
517             protected override void SetContentType(string contentType)
518             {
519                 if (!this.isSettingContentType)
520                 {
521                     this.contentType = contentType;
522                 }
523                 else
524                 {
525                     this.result.SetContentType(contentType);
526                 }
527             }
528
529             protected override void SetContentEncoding(string contentEncoding)
530             {
531                 this.result.AppendHeader(HttpChannelUtilities.ContentEncodingHeader, contentEncoding);
532             }
533
534             protected override void SetContentLength(int contentLength)
535             {
536                 this.result.AppendHeader("content-length", contentLength.ToString(CultureInfo.InvariantCulture));
537             }
538
539             protected override void SetStatusCode(HttpStatusCode statusCode)
540             {
541                 this.result.SetStatusCode((int)statusCode);
542             }
543
544             protected override void SetStatusDescription(string statusDescription)
545             {
546                 this.result.SetStatusDescription(statusDescription);
547             }
548
549             protected override bool PrepareHttpSend(Message message)
550             {
551                 bool retValue = base.PrepareHttpSend(message);
552                 object property;
553
554                 bool httpMethodIsHead = string.Compare(this.context.HttpMethod, "HEAD", StringComparison.OrdinalIgnoreCase) == 0;
555                 if (httpMethodIsHead)
556                 {
557                     retValue = true;
558                 }
559
560                 if (message.Properties.TryGetValue(HttpResponseMessageProperty.Name, out property))
561                 {
562                     HttpResponseMessageProperty responseProperty = (HttpResponseMessageProperty)property;
563
564                     if (responseProperty.SuppressPreamble)
565                     {
566                         return retValue || responseProperty.SuppressEntityBody;
567                     }
568
569                     this.SetStatusCode(responseProperty.StatusCode);
570                     if (responseProperty.StatusDescription != null)
571                     {
572                         this.SetStatusDescription(responseProperty.StatusDescription);
573                     }
574
575                     WebHeaderCollection responseHeaders = responseProperty.Headers;
576                     for (int i = 0; i < responseHeaders.Count; i++)
577                     {
578                         string name = responseHeaders.Keys[i];
579                         string value = responseHeaders[i];
580                         if (string.Compare(name, "content-type", StringComparison.OrdinalIgnoreCase) == 0)
581                         {
582                             this.contentType = value;
583                         }
584                         else if (string.Compare(name, HttpChannelUtilities.MIMEVersionHeader, StringComparison.OrdinalIgnoreCase) == 0)
585                         {
586                             this.mimeVersion = value;
587                         }
588                         else if (string.Compare(name, "content-length", StringComparison.OrdinalIgnoreCase) == 0)
589                         {
590                             int contentLength = -1;
591                             if (httpMethodIsHead &&
592                                 int.TryParse(value, out contentLength))
593                             {
594                                 this.SetContentLength(contentLength);
595                             }
596                         }
597                         else
598                         {
599                             this.AddHeader(name, value);
600                         }
601                     }
602                     if (responseProperty.SuppressEntityBody)
603                     {
604                         contentType = null;
605                         retValue = true;
606                     }
607                 }
608
609                 else
610                 {
611                     this.SetStatusCode((HttpStatusCode)statusCode);
612                 }
613
614                 if (contentType != null && contentType.Length != 0)
615                 {
616                     if (this.CanSendCompressedResponses)
617                     {
618                         string contentEncoding;
619                         if (HttpChannelUtilities.GetHttpResponseTypeAndEncodingForCompression(ref contentType, out contentEncoding))
620                         {
621                             result.SetContentEncoding(contentEncoding);
622                         }
623                     }
624
625                     this.isSettingContentType = true;
626                     this.SetContentType(contentType);
627                 }
628
629                 if (this.mimeVersion != null)
630                 {
631                     this.isSettingMimeHeader = true;
632                     this.AddMimeVersion(this.mimeVersion);
633                 }
634
635                 return retValue;
636             }
637
638             protected override void PrepareHttpSendCore(HttpResponseMessage message)
639             {
640                 result.SetStatusCode((int)message.StatusCode);
641                 if (message.ReasonPhrase != null)
642                 {
643                     result.SetStatusDescription(message.ReasonPhrase);
644                 }
645                 HostedHttpContext.AppendHeaderFromHttpResponseMessageToResponse(message, this.result);
646             }
647
648             class HostedResponseOutputStream : BytesReadPositionStream
649             {
650                 HostedHttpContext context;
651                 HostedHttpRequestAsyncResult result;
652
653                 public HostedResponseOutputStream(HostedHttpRequestAsyncResult result, HostedHttpContext context)
654                     : base(result.GetOutputStream())
655                 {
656                     this.context = context;
657                     this.result = result;
658                 }
659
660                 public override void Close()
661                 {
662                     try
663                     {
664                         base.Close();
665                     }
666                     catch (Exception e)
667                     {
668                         CheckWrapThrow(e);
669                         throw;
670                     }
671                     finally
672                     {
673                         result.OnReplySent();
674                     }
675                 }
676
677                 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
678                 {
679                     try
680                     {
681                         return base.BeginWrite(buffer, offset, count, callback, state);
682                     }
683                     catch (Exception e)
684                     {
685                         CheckWrapThrow(e);
686                         throw;
687                     }
688                 }
689
690                 public override void EndWrite(IAsyncResult result)
691                 {
692                     try
693                     {
694                         base.EndWrite(result);
695                     }
696                     catch (Exception e)
697                     {
698                         CheckWrapThrow(e);
699                         throw;
700                     }
701                 }
702
703                 public override void Write(byte[] buffer, int offset, int count)
704                 {
705                     try
706                     {
707                         base.Write(buffer, offset, count);
708                     }
709                     catch (Exception e)
710                     {
711                         CheckWrapThrow(e);
712                         throw;
713                     }
714                 }
715
716                 void CheckWrapThrow(Exception e)
717                 {
718                     if (!Fx.IsFatal(e))
719                     {
720                         if (e is HttpException)
721                         {
722                             if (this.context.Aborted)
723                             {
724                                 throw FxTrace.Exception.AsError(
725                                     new CommunicationObjectAbortedException(SR.RequestContextAborted, e));
726                             }
727                             else
728                             {
729                                 throw FxTrace.Exception.AsError(new CommunicationException(e.Message, e));
730                             }
731                         }
732                         else if (this.context.Aborted)
733                         {
734                             // See VsWhidbey (594450)
735                             if (DiagnosticUtility.ShouldTraceError)
736                             {
737                                 TraceUtility.TraceEvent(TraceEventType.Error, TraceCode.RequestContextAbort, SR.TraceCodeRequestContextAbort, this, e);
738                             }
739
740                             throw FxTrace.Exception.AsError(new CommunicationObjectAbortedException(SR.RequestContextAborted));
741                         }
742                     }
743                 }
744             }
745         }
746
747         class HostedRequestContainer : RemoteEndpointMessageProperty.IRemoteEndpointProvider, HttpRequestMessageProperty.IHttpHeaderProvider
748         {
749             volatile bool isClosed;
750             HostedHttpRequestAsyncResult result;
751             object thisLock;
752
753             public HostedRequestContainer(HostedHttpRequestAsyncResult result)
754             {
755                 AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
756
757                 this.result = result;
758                 this.thisLock = new object();
759             }
760
761             object ThisLock
762             {
763                 get
764                 {
765                     return this.thisLock;
766                 }
767             }
768
769             // IIS properties are not valid once the reply occurs.
770             // Close invalidates all access to these properties.
771             public void Close()
772             {
773                 lock (this.ThisLock)
774                 {
775                     this.isClosed = true;
776                 }
777             }
778
779
780             [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects",
781                 Safe = "Does not leak control or mutable/harmful data, no potential for harm")]
782             [SecuritySafeCritical]
783             void HttpRequestMessageProperty.IHttpHeaderProvider.CopyHeaders(WebHeaderCollection headers)
784             {
785                 if (!this.isClosed)
786                 {
787                     lock (this.ThisLock)
788                     {
789                         if (!this.isClosed)
790                         {
791                             HttpChannelUtilities.CopyHeadersToNameValueCollection(this.result.Application.Request.Headers, headers);                            
792                         }
793                     }
794                 }
795             }
796
797             [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects",
798                 Safe = "Does not leak control or mutable/harmful data, no potential for harm")]
799             [SecuritySafeCritical]
800             string RemoteEndpointMessageProperty.IRemoteEndpointProvider.GetAddress()
801             {
802                 if (!this.isClosed)
803                 {
804                     lock (this.ThisLock)
805                     {
806                         if (!this.isClosed)
807                         {
808                             return this.result.Application.Request.UserHostAddress;
809                         }
810                     }
811                 }
812                 return string.Empty;
813             }
814
815
816             [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects",
817                 Safe = "Does not leak control or mutable/harmful data, no potential for harm")]
818             [SecuritySafeCritical]
819             int RemoteEndpointMessageProperty.IRemoteEndpointProvider.GetPort()
820             {
821                 int port = 0;
822
823                 if (!this.isClosed)
824                 {
825                     lock (this.ThisLock)
826                     {
827                         if (!this.isClosed)
828                         {
829                             string remotePort = this.result.Application.Request.ServerVariables["REMOTE_PORT"];
830                             if (string.IsNullOrEmpty(remotePort) || !int.TryParse(remotePort, out port))
831                             {
832                                 port = 0;
833                             }
834                         }
835                     }
836                 }
837
838                 return port;
839             }
840
841             [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects",
842                 Safe = "Does not leak control or mutable/harmful data, no potential for harm")]
843             [SecuritySafeCritical]
844             public bool TryGetAddressAndPort(out string address, out int port)
845             {
846                 address = string.Empty;
847                 port = 0;
848
849                 if (!this.isClosed)
850                 {
851                     lock (this.ThisLock)
852                     {
853                         if (!this.isClosed)
854                         {
855                             address = this.result.Application.Request.UserHostAddress;
856
857                             IServiceProvider provider = (IServiceProvider)result.Application.Context;
858                             port = GetRemotePort(provider);
859                             return true;
860                         }
861                     }
862                 }
863                 return false;
864             }
865
866             [Fx.Tag.SecurityNote(Critical = "Asserts UnmanagedCode to get the HttpWorkerRequest.", Safe = "Only returns the remote port, doesn't leak the HttpWorkerRequest.")]
867             [SecuritySafeCritical]
868             [SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
869             static int GetRemotePort(IServiceProvider provider)
870             {
871                 return ((HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest))).GetRemotePort();
872             }
873         }
874     }
875 }