//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ namespace System.ServiceModel.Activation { using System.Diagnostics; using System.Globalization; using System.IO; using System.Net; using System.Runtime; using System.Runtime.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security; using System.Security.Authentication.ExtendedProtection; using System.Security.Cryptography.X509Certificates; using System.Security.Permissions; using System.Security.Principal; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Activation.Configuration; using System.ServiceModel.Activation.Diagnostics; using System.Threading; using System.Web; using System.Web.Management; using System.Web.Routing; using TD2 = System.ServiceModel.Diagnostics.Application.TD; class HostedHttpRequestAsyncResult : AsyncResult, HttpChannelListener.IHttpAuthenticationContext { [Fx.Tag.SecurityNote(Critical = "Stores the securitycritical callback values, we need to protect these values")] [SecurityCritical] static WindowsIdentity anonymousIdentity; [SecurityCritical] static Action waitOnBeginRequest; [SecurityCritical] static Action waitOnBeginRequestWithFlow; [SecurityCritical] static ContextCallback contextOnBeginRequest; [SecurityCritical] static AsyncCallback processRequestCompleteCallback; [ThreadStatic] static AutoResetEvent waitObject; static Nullable iisSupportsExtendedProtection; [Fx.Tag.SecurityNote(Critical = "Keeps track of impersonated user, caller must use with care")] [SecurityCritical] HostedImpersonationContext impersonationContext; [Fx.Tag.SecurityNote(Critical = "Keeps track of thread static data (HttpContext, CurrentCulture, CurrentUICulture) that is used for AspNetCompatibility mode, caller must use with care")] [SecurityCritical] HostedThreadData hostedThreadData; [Fx.Tag.SecurityNote(Critical = "This field is used to manipulate request/responses using APIs protected by LinkDemand." + "It is critical because we use it to determine whether we believe we're being hosted in ASP.NET or not." + "The field is set in the constructor of this class and we deem it safe because:" + " 1) all paths that lead to the .ctor are SecurityCritical and" + " 2) those paths have called ServiceHostingEnvironment.EnsureInitialized (which is also critical)" + "So if the field is non-null, it's safe to say that we're hosted in ASP.NET, hence all the helper methods in this class that touch this field can be SecurityTreatAsSafe")] [SecurityCritical] HttpApplication context; int state; int streamedReadState; [Fx.Tag.SecurityNote(Critical = "Determines whether to set the HttpContext on the outgoing thread.")] [SecurityCritical] bool flowContext; bool ensureWFService; string configurationBasedServiceVirtualPath; EventTraceActivity eventTraceActivity; readonly bool isWebSocketRequest; [Fx.Tag.SecurityNote(Critical = "Captures HostedImpersonationContext which must be done in the right place, and calls unsafe" + "ScheduleCallbackLowPriNoFlow and ScriptTimeout. Called outside of user security context.")] [SecurityCritical] public HostedHttpRequestAsyncResult(HttpApplication context, bool flowContext, bool ensureWFService, AsyncCallback callback, object state) : this(context, null, flowContext, ensureWFService, callback, state) { } [Fx.Tag.SecurityNote(Critical = "Captures HostedImpersonationContext which must be done in the right place, and calls unsafe" + "ScheduleCallbackLowPriNoFlow and ScriptTimeout. Called outside of user security context.")] [SecurityCritical] public HostedHttpRequestAsyncResult(HttpApplication context, string aspNetRouteServiceVirtualPath, bool flowContext, bool ensureWFService, AsyncCallback callback, object state) : base(callback, state) { if (context == null) { throw FxTrace.Exception.ArgumentNull("context"); } AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet(); HostedAspNetEnvironment.TrySetWebSocketVersion(context); this.context = context; // WebSockets require the integrated pipeline mode and the WebSocket IIS module to be loaded. If these conditions // are not met, the HttpContext.IsWebSocketRequest property throws. Also, if these conditions are not met, // we do not let WebSocket listeners to be started (we fail the service activation), so setting the 'isWebSocketRequest' flag // to false in this case will not create confusion (or make troubleshooting difficult). this.isWebSocketRequest = HttpRuntime.UsingIntegratedPipeline && AspNetEnvironment.Current.IsWebSocketModuleLoaded && this.context.Context.IsWebSocketRequest; this.flowContext = flowContext; if (ensureWFService) { // check for CBA scenario. if true, service should be handled by WCF instead of WF, // set this.ensureWFservice to false if (ServiceHostingEnvironment.IsConfigurationBasedService(context, out this.configurationBasedServiceVirtualPath)) { this.ensureWFService = false; } else { this.ensureWFService = true; } } if (!string.IsNullOrEmpty(aspNetRouteServiceVirtualPath)) { // aspnet routing can hijack CBA request as we append {*pathInfo} to urlpattern and there is no real file for CBA // check for CBA scenario. if the request is hijacked. i.e., // 1) route maps to a virtual directory: // aspNetRouteServiceVirtualPath <> context.Request.AppRelativeCurrentExecutionFilePath == configurationBasedServiceVirtualPath // if RouteExistingFiles <> true, set aspnetRouteServiceVirtualPath to null so that the request will be treated as CBA // if RouteExistingFiles == true, this hijack is by-design, do nothing // 2) route maps to a CBA entry: // aspNetRouteServiceVirtualPath == context.Request.AppRelativeCurrentExecutionFilePath == configurationBasedServiceVirtualPath // we will use RouteExistingFiles to decide which service should be activated. We do it in ServiceHostingEnviroment.HostingManager, // as we cannot pass this info to the latter. if (!RouteTable.Routes.RouteExistingFiles && ServiceHostingEnvironment.IsConfigurationBasedService(context, out this.configurationBasedServiceVirtualPath)) { this.AspNetRouteServiceVirtualPath = null; } else { this.AspNetRouteServiceVirtualPath = aspNetRouteServiceVirtualPath; } } // If this is a DEBUG request, complete right away and let ASP.NET handle it. string method = context.Request.HttpMethod ?? ""; char firstMethodChar = method.Length == 5 ? method[0] : '\0'; if ((firstMethodChar == 'd' || firstMethodChar == 'D') && string.Compare(method, "DEBUG", StringComparison.OrdinalIgnoreCase) == 0) { if (DiagnosticUtility.ShouldTraceVerbose) { TraceUtility.TraceEvent(TraceEventType.Verbose, TraceCode.WebHostDebugRequest, SR.TraceCodeWebHostDebugRequest, this); } this.state = State.Completed; Complete(true, null); return; } this.impersonationContext = new HostedImpersonationContext(); if (flowContext) { if (ServiceHostingEnvironment.AspNetCompatibilityEnabled) { // Capture HttpContext/culture context if necessary. Can be used later by HostedHttpInput to re-apply // the culture during dispatch. Also flowed here. hostedThreadData = new HostedThreadData(); } } // Set this up before calling IncrementRequestCount so if it fails, we don't leak a count. Action iotsCallback = (AspNetPartialTrustHelpers.NeedPartialTrustInvoke || flowContext) ? WaitOnBeginRequestWithFlow : WaitOnBeginRequest; // Tell ASPNET to by-pass all the other events so no other http modules will // be invoked, Indigo basically takes over the request completely. This should // only be called in non-AspNetCompatibilityEnabled mode. if (!ServiceHostingEnvironment.AspNetCompatibilityEnabled && !this.ensureWFService) { context.CompleteRequest(); } // Prevent ASP.NET from generating thread aborts in relation to this request. context.Server.ScriptTimeout = int.MaxValue; ServiceHostingEnvironment.IncrementRequestCount(ref this.eventTraceActivity, context.Request.AppRelativeCurrentExecutionFilePath); IOThreadScheduler.ScheduleCallbackLowPriNoFlow(iotsCallback, this); } public static WindowsIdentity AnonymousIdentity { [Fx.Tag.SecurityNote(Critical = "Access the value of corresponding static field and prevent someone from changing its value")] [SecuritySafeCritical] get { if (anonymousIdentity == null) { anonymousIdentity = WindowsIdentity.GetAnonymous(); } return anonymousIdentity; } } public static Action WaitOnBeginRequest { [Fx.Tag.SecurityNote(Critical = "Access the value of corresponding static field and prevent someone from changing its value")] [SecuritySafeCritical] get { if (waitOnBeginRequest == null) { waitOnBeginRequest = new Action(OnBeginRequest); } return waitOnBeginRequest; } } public static Action WaitOnBeginRequestWithFlow { [Fx.Tag.SecurityNote(Critical = "Access the value of corresponding static field and prevent someone from changing its value")] [SecuritySafeCritical] get { if (waitOnBeginRequestWithFlow == null) { waitOnBeginRequestWithFlow = new Action(OnBeginRequestWithFlow); } return waitOnBeginRequestWithFlow; } } public static ContextCallback ContextOnBeginRequest { [Fx.Tag.SecurityNote(Critical = "Access the value of corresponding static field and prevent someone from changing its value")] [SecuritySafeCritical] get { if (contextOnBeginRequest == null) { contextOnBeginRequest = new ContextCallback(OnBeginRequest); } return contextOnBeginRequest; } } public static AsyncCallback ProcessRequestCompleteCallback { [Fx.Tag.SecurityNote(Critical = "Access the value of corresponding static field and prevent someone from changing its value")] [SecuritySafeCritical] get { if (processRequestCompleteCallback == null) { processRequestCompleteCallback = Fx.ThunkCallback(new AsyncCallback(ProcessRequestComplete)); } return processRequestCompleteCallback; } } public bool IISSupportsExtendedProtection { get { if (HostedHttpRequestAsyncResult.iisSupportsExtendedProtection == null) { HostedHttpRequestAsyncResult.iisSupportsExtendedProtection = this.IISSupportsExtendedProtectionInternal(); } return HostedHttpRequestAsyncResult.iisSupportsExtendedProtection.Value; } } public bool IsWebSocketRequest { get { return this.isWebSocketRequest; } } [Fx.Tag.SecurityNote(Critical = "Touches critical field context.", Safe = "Does not leak control or data, no potential for harm.")] [SecuritySafeCritical] [MethodImpl(MethodImplOptions.NoInlining)] [PermissionSetAttribute(SecurityAction.Assert, Unrestricted = true)] private bool IISSupportsExtendedProtectionInternal() { DiagnosticUtility.DebugAssert(ExtendedProtectionPolicy.OSSupportsExtendedProtection, "OS must support ExtendedProtection"); try { ChannelBinding cbt = this.context.Request.HttpChannelBinding; return true; } catch (PlatformNotSupportedException) { // contract with Asp.Net is that they will always throw a PlatformNotSupportedException if IIS is not patched for CBT yet return false; } catch (COMException) { // If IIS is patched for CBT and an error occurs when trying to retrieve the token a COMException is thrown. Even in this // case we know that IIS is patched for CBT. return true; } } [Fx.Tag.SecurityNote(Critical = "Captures HostedImpersonationContext which must be done in the right place, and calls unsafe" + "ScheduleCallbackLowPriNoFlow and ScriptTimeout. Called outside of user security context." + "Callers of this function must call ServiceHostingEnvironment.EnsureInitialized")] [SecurityCritical] public static void ExecuteSynchronous(HttpApplication context, bool flowContext, bool ensureWFService) { ExecuteSynchronous(context, null, flowContext, ensureWFService); } [Fx.Tag.SecurityNote(Critical = "Captures HostedImpersonationContext which must be done in the right place, and calls unsafe" + "ScheduleCallbackLowPriNoFlow and ScriptTimeout. Called outside of user security context." + "Callers of this function must call ServiceHostingEnvironment.EnsureInitialized")] [SecurityCritical] public static void ExecuteSynchronous(HttpApplication context, string routeServiceVirtualPath, bool flowContext, bool ensureWFService) { AutoResetEvent wait = HostedHttpRequestAsyncResult.waitObject; if (wait == null) { wait = new AutoResetEvent(false); HostedHttpRequestAsyncResult.waitObject = wait; } HostedHttpRequestAsyncResult result; try { result = new HostedHttpRequestAsyncResult(context, routeServiceVirtualPath, flowContext, ensureWFService, ProcessRequestCompleteCallback, wait); if (!result.CompletedSynchronously) { wait.WaitOne(); } wait = null; } finally { if (wait != null) { // Not sure of the state anymore. HostedHttpRequestAsyncResult.waitObject = null; wait.Close(); } } HostedHttpRequestAsyncResult.End(result); } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - Can be called outside of a user context.")] static void ProcessRequestComplete(IAsyncResult result) { if (!result.CompletedSynchronously) { try { ((AutoResetEvent)result.AsyncState).Set(); } catch (ObjectDisposedException exception) { DiagnosticUtility.TraceHandledException(exception, TraceEventType.Warning); } } } [Fx.Tag.SecurityNote(Critical = "Can be called outside of user context, accesses hostedThreadData.", Safe = "Uses hostedThreadData to set HttpContext.Current, cultures to the one attached to this async-result instance.")] [SecuritySafeCritical] static void OnBeginRequestWithFlow(object state) { HostedHttpRequestAsyncResult self = (HostedHttpRequestAsyncResult)state; IDisposable hostedThreadContext = null; try { if (self.flowContext) { // In AspCompat case, these are the three things that need to be flowed. See HostedHttpInput. if (self.hostedThreadData != null) { hostedThreadContext = self.hostedThreadData.CreateContext(); } } // In full-trust, this simply calls the delegate. AspNetPartialTrustHelpers.PartialTrustInvoke(ContextOnBeginRequest, self); } finally { if (hostedThreadContext != null) { hostedThreadContext.Dispose(); } } } static void OnBeginRequest(object state) { HostedHttpRequestAsyncResult self = (HostedHttpRequestAsyncResult)state; Exception completionException = null; try { self.BeginRequest(); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } completionException = e; } if (completionException != null) { self.CompleteOperation(completionException); } } void BeginRequest() { try { HandleRequest(); } catch (EndpointNotFoundException exception) { // HTTP-GET is special cased to avoid that the ServiceActivation-HTTP-response is treated as service response. // For WebSocket requests we treat the ServiceActivation in the same way like for SOAP (HTTP-POST) requests. if (string.Compare(GetHttpMethod(), "GET", StringComparison.OrdinalIgnoreCase) == 0 && !this.isWebSocketRequest) { // Wrap the exception into HttpException throw FxTrace.Exception.AsError(new HttpException((int)HttpStatusCode.NotFound, exception.Message, exception)); } SetStatusCode((int)HttpStatusCode.NotFound); CompleteOperation(null); } catch (ServiceActivationException exception) { // HTTP-GET is special cased to avoid that the ServiceActivation-HTTP-response is treated as service response. // For WebSocket requests we treat the ServiceActivation in the same way like for SOAP (HTTP-POST) requests. if (string.Compare(GetHttpMethod(), "GET", StringComparison.OrdinalIgnoreCase) == 0 && !this.isWebSocketRequest) { if (exception.InnerException is HttpException) { throw exception.InnerException; } else { throw; } } SetStatusCode((int)HttpStatusCode.InternalServerError); SetStatusDescription( HttpChannelUtilities.StatusDescriptionStrings.HttpStatusServiceActivationException); CompleteOperation(null); } finally { ReleaseImpersonation(); } } public WindowsIdentity LogonUserIdentity { get { IPrincipal user = this.Application.User; if (user == null) { return AnonymousIdentity; } WindowsIdentity identity = user.Identity as WindowsIdentity; if (identity == null) { return AnonymousIdentity; } return identity; } } WindowsIdentity HttpChannelListener.IHttpAuthenticationContext.LogonUserIdentity { get { return this.LogonUserIdentity; } } public HostedImpersonationContext ImpersonationContext { [Fx.Tag.SecurityNote(Critical = "Keeps track of impersonated user, caller must use with care.", Safe = "Safe for Get, individual members of HostedImpersonationContext are protected.")] [SecuritySafeCritical] get { return this.impersonationContext; } } public HostedThreadData HostedThreadData { [Fx.Tag.SecurityNote(Critical = "Keeps track of impersonated user, caller must use with care.", Safe = "Safe for Get, individual members of HostedThreadData are protected.")] [SecuritySafeCritical] get { return this.hostedThreadData; } } public EventTraceActivity EventTraceActivity { get { return this.eventTraceActivity; } } public Uri OriginalRequestUri { get; private set; } public Uri RequestUri { get; private set; } public HttpApplication Application { [Fx.Tag.SecurityNote(Critical = "Touches critical field context.", Safe = "Does not leak control or data, no potential for harm.")] [SecuritySafeCritical] get { return this.context; } } public string AspNetRouteServiceVirtualPath { get; private set; } [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects.", Safe = "Does not leak control or data, no potential for harm.")] [SecuritySafeCritical] public Stream GetInputStream() { try { // CSDMain #133228: "Consume GetBufferlessInputStream" // The ReadEntityBodyMode property on the HttpRequest keeps track of whether the request stream has already been accessed, and if so, what API was used to access the request. // - "None" means that the request stream hasn't been accessed. // - "Bufferless" means that GetBufferlessInputStream() was used to access it. // - "Buffered" means GetBufferedInputStream() was used to access it. // - "Classic" means that either the InputStream, Form, Files, or BinaryRead APIs were invoked already. // In general, these values are incompatible with one another, meaning that once the request was accessed in a "Classic" way, only "Classic" APIs can be invoked on the HttpRequest. // If incompatible APIs are invoked, an HttpException is thrown. // In order to prevent HttpExceptions from being thrown for this reason, we will check the ReadEntityBodyMode, and access the request stream with the corresponding API // If the request stream hasn't been accessed yet (eg, by an HttpModule which executed earlier), then we will use GetBufferlessInputStream by default. ReadEntityBodyMode mode = this.context.Request.ReadEntityBodyMode; Fx.Assert(mode == ReadEntityBodyMode.None || mode == ReadEntityBodyMode.Bufferless || mode == ReadEntityBodyMode.Buffered || mode == ReadEntityBodyMode.Classic, "Unknown value for System.Web.ReadEntityBodyMode enum"); if (mode == ReadEntityBodyMode.None && ServiceHostingEnvironment.AspNetCompatibilityEnabled && AppSettings.UseClassicReadEntityMode) { mode = ReadEntityBodyMode.Classic; } switch (mode) { case ReadEntityBodyMode.None: case ReadEntityBodyMode.Bufferless: return this.context.Request.GetBufferlessInputStream(true); // ignores system.web/httpRuntime/maxRequestLength case ReadEntityBodyMode.Buffered: return this.context.Request.GetBufferedInputStream(); default: // ReadEntityBodyMode.Classic: return this.context.Request.InputStream; } } catch (HttpException hostedException) { if (hostedException.WebEventCode == WebEventCodes.RuntimeErrorPostTooLarge) { throw FxTrace.Exception.AsError(HttpInput.CreateHttpProtocolException(SR.Hosting_MaxRequestLengthExceeded, HttpStatusCode.RequestEntityTooLarge, null, hostedException)); } else { throw FxTrace.Exception.AsError(new CommunicationException(hostedException.Message, hostedException)); } } } public void OnReplySent() { CompleteOperation(null); } internal void CompleteOperation(Exception exception) { if (this.state == State.Running && Interlocked.CompareExchange(ref this.state, State.Completed, State.Running) == State.Running) { this.CompleteAsynchronously(exception); } } public void Abort() { if (this.state == State.Running && Interlocked.CompareExchange(ref this.state, State.Aborted, State.Running) == State.Running) { int currentStreamedReadState = Interlocked.Exchange(ref this.streamedReadState, StreamedReadState.AbortStarted); // Closes the socket connection to the client if (HttpRuntime.UsingIntegratedPipeline) { Application.Request.Abort(); } else { Application.Response.Close(); } if (currentStreamedReadState == StreamedReadState.None) { this.CompleteAsynchronously(null); } else { Fx.Assert(currentStreamedReadState == StreamedReadState.ReceiveStarted, string.Format(CultureInfo.InvariantCulture, "currentStramedReadState is not ReceivedStarted: {0}", currentStreamedReadState)); if (Interlocked.CompareExchange(ref this.streamedReadState, StreamedReadState.Aborted, StreamedReadState.AbortStarted) == StreamedReadState.AbortStarted) { return; } Fx.Assert(this.streamedReadState == StreamedReadState.ReceiveFinishedAfterAbortStarted, string.Format(CultureInfo.InvariantCulture, "currentStramedReadState is not ReceiveFinished: {0}", this.streamedReadState)); this.CompleteAsynchronously(null); } } } void CompleteAsynchronously(Exception ex) { Complete(false, ex); ServiceHostingEnvironment.DecrementRequestCount(this.eventTraceActivity); } internal bool TryStartStreamedRead() { return Interlocked.CompareExchange(ref this.streamedReadState, StreamedReadState.ReceiveStarted, StreamedReadState.None) == StreamedReadState.None; } internal void SetStreamedReadFinished() { if (Interlocked.CompareExchange(ref this.streamedReadState, StreamedReadState.None, StreamedReadState.ReceiveStarted) == StreamedReadState.ReceiveStarted) { return; } if (Interlocked.CompareExchange(ref this.streamedReadState, StreamedReadState.ReceiveFinishedAfterAbortStarted, StreamedReadState.AbortStarted) == StreamedReadState.AbortStarted) { return; } Fx.Assert(this.streamedReadState == StreamedReadState.Aborted, string.Format(CultureInfo.InvariantCulture, "currentStramedReadState is not Aborted: {0}", this.streamedReadState)); this.CompleteAsynchronously(null); } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - Can be called outside of a user context.")] public static void End(IAsyncResult result) { try { AsyncResult.End(result); } catch (Exception exception) { if (!Fx.IsFatal(exception)) { // Log the exception. DiagnosticUtility.EventLog.LogEvent(TraceEventType.Error, (ushort)System.Runtime.Diagnostics.EventLogCategory.WebHost, (uint)System.Runtime.Diagnostics.EventLogEventId.WebHostFailedToProcessRequest, TraceUtility.CreateSourceString(result), exception == null ? string.Empty : exception.ToString()); } throw; } } X509Certificate2 HttpChannelListener.IHttpAuthenticationContext.GetClientCertificate(out bool isValidCertificate) { HttpClientCertificate certificateInfo = this.Application.Request.ClientCertificate; isValidCertificate = certificateInfo.IsValid; if (certificateInfo.IsPresent) { return new X509Certificate2(certificateInfo.Certificate); } else { return null; } } TraceRecord HttpChannelListener.IHttpAuthenticationContext.CreateTraceRecord() { return new System.ServiceModel.Diagnostics.HttpRequestTraceRecord(this.Application.Request); } void HandleRequest() { this.OriginalRequestUri = GetUrl(); string relativeVirtualPath; if (!string.IsNullOrEmpty(this.AspNetRouteServiceVirtualPath)) { relativeVirtualPath = this.AspNetRouteServiceVirtualPath; } else if (!string.IsNullOrEmpty(this.configurationBasedServiceVirtualPath)) { relativeVirtualPath = this.configurationBasedServiceVirtualPath; } else { relativeVirtualPath = GetAppRelativeCurrentExecutionFilePath(); } if (ensureWFService) { bool bypass = false; try { if (!ServiceHostingEnvironment.EnsureWorkflowService(relativeVirtualPath)) { CompleteOperation(null); bypass = true; return; } } finally { if (!bypass) { CompleteRequest(); } } } // Support for Cassini. if (ServiceHostingEnvironment.IsSimpleApplicationHost) { HostedTransportConfigurationManager.EnsureInitializedForSimpleApplicationHost(this); } HttpHostedTransportConfiguration transportConfiguration = HostedTransportConfigurationManager.GetConfiguration(this.OriginalRequestUri.Scheme) as HttpHostedTransportConfiguration; HostedHttpTransportManager transportManager = null; // There must be a transport binding that matches the request. if (transportConfiguration != null) { transportManager = transportConfiguration.GetHttpTransportManager(this.OriginalRequestUri); } if (transportManager == null) { InvalidOperationException invalidOpException = new InvalidOperationException(SR.Hosting_TransportBindingNotFound(OriginalRequestUri.ToString())); ServiceActivationException activationException = new ServiceActivationException(invalidOpException.Message, invalidOpException); LogServiceActivationException(activationException); throw FxTrace.Exception.AsError(activationException); } this.RequestUri = new Uri(transportManager.ListenUri, this.OriginalRequestUri.PathAndQuery); Fx.Assert( object.ReferenceEquals(this.RequestUri.Scheme, Uri.UriSchemeHttp) || object.ReferenceEquals(this.RequestUri.Scheme, Uri.UriSchemeHttps), "Scheme must be Http or Https."); ServiceHostingEnvironment.EnsureServiceAvailableFast(relativeVirtualPath, this.eventTraceActivity); transportManager.HttpContextReceived(this); } [Fx.Tag.SecurityNote(Critical = "Calls into an unsafe UnsafeLogEvent method", Safe = "Event identities cannot be spoofed as they are constants determined inside the method")] [SecuritySafeCritical] void LogServiceActivationException(ServiceActivationException activationException) { if (TD2.ServiceExceptionIsEnabled()) { TD2.ServiceException(this.eventTraceActivity, activationException.ToString(), typeof(ServiceActivationException).FullName); } if (TD.ServiceActivationExceptionIsEnabled()) { TD.ServiceActivationException(activationException != null ? activationException.ToString() : string.Empty, activationException); } DiagnosticUtility.UnsafeEventLog.UnsafeLogEvent(TraceEventType.Error, (ushort)System.Runtime.Diagnostics.EventLogCategory.WebHost, (uint)System.Runtime.Diagnostics.EventLogEventId.WebHostFailedToProcessRequest, true, TraceUtility.CreateSourceString(this), activationException.ToString()); } [Fx.Tag.SecurityNote(Critical = "manipulates impersonation object", Safe = "Does not leak control or mutable/harmful data, no potential for harm except memory leak.")] [SecuritySafeCritical] internal void AddRefForImpersonation() { if (this.impersonationContext != null) { this.impersonationContext.AddRef(); } } [Fx.Tag.SecurityNote(Critical = "manipulates impersonation object", Safe = "Releasing the SafeHandle early could only cause a future impersonation attempt to fail. We have to handle impersonation failures well already.")] [SecuritySafeCritical] internal void ReleaseImpersonation() { if (this.impersonationContext != null) { this.impersonationContext.Release(); } } [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects, changes properties of the HTTP response.", Safe = "Does not leak control or mutable/harmful data, no potential for harm.")] [SecuritySafeCritical] internal void SetContentType(string contentType) { this.context.Response.ContentType = contentType; } [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects, changes properties of the HTTP response.", Safe = "Does not leak control or mutable/harmful data, no potential for harm.")] [SecuritySafeCritical] internal void SetContentEncoding(string contentEncoding) { this.context.Response.AddHeader(HttpChannelUtilities.ContentEncodingHeader, contentEncoding); } [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects, completes the request.", Safe = "Does not leak control or mutable/harmful data, no potential for harm.")] [SecuritySafeCritical] internal void CompleteRequest() { this.context.CompleteRequest(); } [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects, changes properties of the HTTP response.", Safe = "Does not leak control or mutable/harmful data, no potential for harm.")] [SecuritySafeCritical] internal void SetTransferModeToStreaming() { this.context.Response.BufferOutput = false; } [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects, changes properties of the HTTP response.", Safe = "Does not leak control or mutable/harmful data, no potential for harm.")] [SecuritySafeCritical] internal void AppendHeader(string name, string value) { this.context.Response.AppendHeader(name, value); } [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects, changes properties of the HTTP response.", Safe = "Does not leak control or mutable/harmful data, no potential for harm.")] [SecuritySafeCritical] internal void SetStatusCode(int statusCode) { this.context.Response.TrySkipIisCustomErrors = true; this.context.Response.StatusCode = statusCode; } [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects, changes properties of the HTTP response.", Safe = "Does not leak control or mutable/harmful data, no potential for harm.")] [SecuritySafeCritical] internal void SetStatusDescription(string statusDescription) { this.context.Response.StatusDescription = statusDescription; } [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects, changes properties of the HTTP response.", Safe = "Does not leak control or mutable/harmful data, no potential for harm.")] [SecuritySafeCritical] internal void SetConnectionClose() { this.context.Response.AppendHeader("Connection", "close"); } [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects.", Safe = "Does not leak control or mutable/harmful data, no potential for harm.")] [SecuritySafeCritical] internal byte[] GetPrereadBuffer(ref int contentLength) { byte[] preReadBuffer = new byte[1]; if (this.GetInputStream().Read(preReadBuffer, 0, 1) > 0) { contentLength = -1; return preReadBuffer; } return null; } [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects.", Safe = "Does not leak control or mutable/harmful data, no potential for harm.")] [SecuritySafeCritical] internal Stream GetOutputStream() { return this.context.Response.OutputStream; } [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects.", Safe = "Does not leak control or mutable/harmful data, no potential for harm.")] [SecuritySafeCritical] internal string GetHttpMethod() { return this.context.Request.HttpMethod; } [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects.", Safe = "Does not leak control or mutable/harmful data, no potential for harm.")] [SecuritySafeCritical] internal string GetContentType() { const string ContentTypeHeaderName = "Content-Type"; return this.context.Request.Headers[ContentTypeHeaderName]; } [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects.", Safe = "Does not leak control or mutable/harmful data, no potential for harm.")] [SecuritySafeCritical] internal string GetAcceptEncoding() { return this.context.Request.Headers[HttpChannelUtilities.AcceptEncodingHeader]; } [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects.", Safe = "Does not leak control or mutable/harmful data, no potential for harm.")] [SecuritySafeCritical] internal string GetContentTypeFast() { return this.context.Request.ContentType; } [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects.", Safe = "Does not leak control or mutable/harmful data, no potential for harm.")] [SecuritySafeCritical] internal int GetContentLength() { return this.context.Request.ContentLength; } [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects.", Safe = "Does not leak control or mutable/harmful data, no potential for harm.")] [SecuritySafeCritical] internal string GetSoapAction() { const string SoapActionHeaderName = "SOAPAction"; return this.context.Request.Headers[SoapActionHeaderName]; } [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects.", Safe = "Does not leak control or mutable/harmful data, no potential for harm.")] [SecuritySafeCritical] internal ChannelBinding GetChannelBinding() { if (!this.IISSupportsExtendedProtection) { return null; } return this.context.Request.HttpChannelBinding; } [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects.", Safe = "Does not leak control or mutable/harmful data, no potential for harm.")] [SecuritySafeCritical] string GetAppRelativeCurrentExecutionFilePath() { return this.context.Request.AppRelativeCurrentExecutionFilePath; } [Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects.", Safe = "Does not leak control or mutable/harmful data, no potential for harm.")] [SecuritySafeCritical] Uri GetUrl() { return this.context.Request.Url; } static class State { internal const int Running = 0; internal const int Completed = 1; internal const int Aborted = 2; } static class StreamedReadState { internal const int None = 0; internal const int ReceiveStarted = 1; internal const int ReceiveFinishedAfterAbortStarted = 2; internal const int AbortStarted = 3; internal const int Aborted = 4; } } }