2016-08-03 10:59:49 +00:00
//------------------------------------------------------------------------------
// <copyright file="HttpContext.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
/ *
* HttpContext class
*
* Copyright ( c ) 1999 Microsoft Corporation
* /
namespace System.Web {
using System ;
using System.Collections ;
using System.Collections.Generic ;
using System.Collections.ObjectModel ;
using System.ComponentModel ;
using System.Configuration ;
using System.Diagnostics.CodeAnalysis ;
using System.Globalization ;
using System.Linq ;
using System.Net ;
using System.Reflection ;
2016-11-10 13:04:39 +00:00
using System.Runtime.CompilerServices ;
2016-08-03 10:59:49 +00:00
using System.Runtime.Remoting.Messaging ;
using System.Security.Permissions ;
using System.Security.Principal ;
using System.Threading ;
using System.Threading.Tasks ;
using System.Web.Caching ;
using System.Web.Compilation ;
using System.Web.Configuration ;
using System.Web.Hosting ;
using System.Web.Instrumentation ;
using System.Web.Management ;
using System.Web.Profile ;
using System.Web.Security ;
using System.Web.SessionState ;
using System.Web.UI ;
using System.Web.Util ;
using System.Web.WebSockets ;
/// <devdoc>
/// <para>Encapsulates
/// all HTTP-specific
/// context used by the HTTP server to process Web requests.</para>
/// <para>System.Web.IHttpModules and System.Web.IHttpHandler instances are provided a
/// reference to an appropriate HttpContext object. For example
/// the Request and Response
/// objects.</para>
/// </devdoc>
[SuppressMessage("Microsoft.Usage", "CA2302:FlagServiceProviders", Justification = "The service provider implementation is only for specific types which are not com interop types.")]
public sealed class HttpContext : IServiceProvider , IPrincipalContainer
{
internal static readonly Assembly SystemWebAssembly = typeof ( HttpContext ) . Assembly ;
private static volatile bool s_eurlSet ;
private static string s_eurl ;
private IHttpAsyncHandler _asyncAppHandler ; // application as handler (not always HttpApplication)
private AsyncPreloadModeFlags _asyncPreloadModeFlags ;
private bool _asyncPreloadModeFlagsSet ;
private HttpApplication _appInstance ;
private IHttpHandler _handler ;
[DoNotReset]
private HttpRequest _request ;
private HttpResponse _response ;
private HttpServerUtility _server ;
private Stack _traceContextStack ;
private TraceContext _topTraceContext ;
[DoNotReset]
private Hashtable _items ;
private ArrayList _errors ;
private Exception _tempError ;
private bool _errorCleared ;
[DoNotReset]
private IPrincipalContainer _principalContainer ;
[DoNotReset]
internal ProfileBase _Profile ;
[DoNotReset]
private DateTime _utcTimestamp ;
[DoNotReset]
private HttpWorkerRequest _wr ;
private VirtualPath _configurationPath ;
internal bool _skipAuthorization ;
[DoNotReset]
private CultureInfo _dynamicCulture ;
[DoNotReset]
private CultureInfo _dynamicUICulture ;
private int _serverExecuteDepth ;
private Stack _handlerStack ;
private bool _preventPostback ;
private bool _runtimeErrorReported ;
private PageInstrumentationService _pageInstrumentationService = null ;
private ReadOnlyCollection < string > _webSocketRequestedProtocols ;
// timeout support
[DoNotReset]
private CancellationTokenHelper _timeoutCancellationTokenHelper ; // used for TimedOutToken
private long _timeoutStartTimeUtcTicks = - 1 ; // should always be accessed atomically; -1 means uninitialized
private long _timeoutTicks = - 1 ; // should always be accessed atomically; -1 means uninitialized
private int _timeoutState ; // 0=non-cancelable, 1=cancelable, -1=canceled
private DoubleLink _timeoutLink ; // link in the timeout's manager list
private bool _threadAbortOnTimeout = true ; // whether we should Thread.Abort() this thread when it times out
private Thread _thread ;
// cached configuration
private CachedPathData _configurationPathData ; // Cached data if _configurationPath != null
private CachedPathData _filePathData ; // Cached data of the file being requested
// Sql Cache Dependency
private string _sqlDependencyCookie ;
// Session State
volatile SessionStateModule _sessionStateModule ;
volatile bool _delayedSessionState ; // Delayed session state item
// non-compiled pages
private TemplateControl _templateControl ;
// integrated pipeline state
// For the virtual Disposing / Disposed events
private SubscriptionQueue < Action < HttpContext > > _requestCompletedQueue ;
[DoNotReset]
private SubscriptionQueue < IDisposable > _pipelineCompletedQueue ;
// keep synchronized with mgdhandler.hxx
private const int FLAG_NONE = 0x0 ;
private const int FLAG_CHANGE_IN_SERVER_VARIABLES = 0x1 ;
private const int FLAG_CHANGE_IN_REQUEST_HEADERS = 0x2 ;
private const int FLAG_CHANGE_IN_RESPONSE_HEADERS = 0x4 ;
private const int FLAG_CHANGE_IN_USER_OBJECT = 0x8 ;
private const int FLAG_SEND_RESPONSE_HEADERS = 0x10 ;
private const int FLAG_RESPONSE_HEADERS_SENT = 0x20 ;
internal const int FLAG_ETW_PROVIDER_ENABLED = 0x40 ;
private const int FLAG_CHANGE_IN_RESPONSE_STATUS = 0x80 ;
private volatile NotificationContext _notificationContext ;
private bool _isAppInitialized ;
[DoNotReset]
private bool _isIntegratedPipeline ;
private bool _finishPipelineRequestCalled ;
[DoNotReset]
private bool _impersonationEnabled ;
internal bool HideRequestResponse ;
internal volatile bool InIndicateCompletion ;
internal volatile ThreadContext IndicateCompletionContext = null ;
internal volatile Thread ThreadInsideIndicateCompletion = null ;
// This field is a surrogate for the HttpContext object itself. Our HostExecutionContextManager
// shouldn't capture a reference to the HttpContext itself since these references could be long-lived,
// e.g. if they're captured by a call to ThreadPool.QueueUserWorkItem or a Timer. This would cause the
// associated HttpContext object graph to be long-lived, which would negatively affect performance.
// Instead we capture a reference to this 'Id' object, which allows the HostExecutionContextManager
// to compare the original captured HttpContext with the current HttpContext without actually
// holding on to the original HttpContext instance.
[DoNotReset]
internal readonly object ThreadContextId = new object ( ) ;
// synchronization context (for EAP / TAP models)
private AspNetSynchronizationContextBase _syncContext ;
// This field doesn't need to be volatile since it will only ever be written to by a single thread, and when that thread
// later reads the field it will be guaranteed non-null. We don't care what other threads see, since it will never be
// equal to Thread.CurrentThread for them regardless of whether those threads are seeing the latest value of this field.
// This field should not be marked [DoNotReset] since we want it to be cleared when WebSocket processing begins.
internal Thread _threadWhichStartedWebSocketTransition ;
// WebSocket state
[DoNotReset]
private WebSocketTransitionState _webSocketTransitionState ; // see comments in WebSocketTransitionState.cs for detailed info on this enum
[DoNotReset]
private string _webSocketNegotiatedProtocol ;
// see comments on WebSocketInitStatus for what all of these codes mean
private WebSocketInitStatus GetWebSocketInitStatus ( ) {
IIS7WorkerRequest iis7wr = _wr as IIS7WorkerRequest ;
if ( iis7wr = = null ) {
return WebSocketInitStatus . RequiresIntegratedMode ;
}
if ( CurrentNotification < = RequestNotification . BeginRequest ) {
return WebSocketInitStatus . CannotCallFromBeginRequest ;
}
if ( ! iis7wr . IsWebSocketRequest ( ) ) {
if ( iis7wr . IsWebSocketModuleActive ( ) ) {
return WebSocketInitStatus . NotAWebSocketRequest ;
}
else {
return WebSocketInitStatus . NativeModuleNotEnabled ;
}
}
if ( iis7wr . GetIsChildRequest ( ) ) {
return WebSocketInitStatus . CurrentRequestIsChildRequest ;
}
return WebSocketInitStatus . Success ;
}
// Returns true if the request contained the initial WebSocket handshake
// and IIS's WebSocket module is active.
public bool IsWebSocketRequest {
get {
// If AcceptWebSocketRequest has already been called and run to completion, then this
// is obviously a WebSocket request and we can skip further checks (which might throw).
if ( IsWebSocketRequestUpgrading ) {
return true ;
}
switch ( GetWebSocketInitStatus ( ) ) {
case WebSocketInitStatus . RequiresIntegratedMode :
throw new PlatformNotSupportedException ( SR . GetString ( SR . Requires_Iis_Integrated_Mode ) ) ;
case WebSocketInitStatus . CannotCallFromBeginRequest :
throw new InvalidOperationException ( SR . GetString ( SR . WebSockets_CannotBeCalledDuringBeginRequest ) ) ;
case WebSocketInitStatus . Success :
return true ;
default :
return false ;
}
}
}
// While unwinding an HTTP request this indicates if the developer
// told ASP.NET that they wanted to transition to a websocket request
public bool IsWebSocketRequestUpgrading {
get { return ( WebSocketTransitionState > = WebSocketTransitionState . AcceptWebSocketRequestCalled ) ; }
}
internal bool HasWebSocketRequestTransitionStarted {
get { return WebSocketTransitionState > = WebSocketTransitionState . TransitionStarted ; }
}
internal bool HasWebSocketRequestTransitionCompleted {
get { return WebSocketTransitionState > = WebSocketTransitionState . TransitionCompleted ; }
}
internal WebSocketTransitionState WebSocketTransitionState {
get { return _webSocketTransitionState ; }
private set { _webSocketTransitionState = value ; }
}
// Returns the ordered list of protocols requested by the client,
// or an empty collection if this wasn't a WebSocket request or there was no list present.
public IList < string > WebSocketRequestedProtocols {
get {
if ( IsWebSocketRequest ) {
if ( _webSocketRequestedProtocols = = null ) {
string rawHeaderValue = _wr . GetUnknownRequestHeader ( "Sec-WebSocket-Protocol" ) ;
IList < string > requestedProtocols = SubProtocolUtil . ParseHeader ( rawHeaderValue ) ; // checks for invalid values
_webSocketRequestedProtocols = new ReadOnlyCollection < string > ( requestedProtocols ? ? new string [ 0 ] ) ;
}
return _webSocketRequestedProtocols ;
}
else {
// not a WebSocket request
return null ;
}
}
}
// Returns the negotiated protocol (sent from the server to the client) for a
// WebSocket request.
public string WebSocketNegotiatedProtocol {
get { return _webSocketNegotiatedProtocol ; }
}
public void AcceptWebSocketRequest ( Func < AspNetWebSocketContext , Task > userFunc ) {
AcceptWebSocketRequest ( userFunc , null ) ;
}
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This is a safe critical method.")]
public void AcceptWebSocketRequest ( Func < AspNetWebSocketContext , Task > userFunc , AspNetWebSocketOptions options ) {
// Begin argument & state checking
// We throw different error codes depending on the check that failed. Things that are
// server configuration errors (WebSockets not enabled) or developer errors (called this
// method with bad parameters) result in an appropriate exception type. Things that are
// remote errors (e.g. bad parameters from the client) result in an HTTP 4xx.
if ( userFunc = = null ) {
throw new ArgumentNullException ( "userFunc" ) ;
}
if ( IsWebSocketRequestUpgrading ) {
// this method cannot be called multiple times
throw new InvalidOperationException ( SR . GetString ( SR . WebSockets_AcceptWebSocketRequestCanOnlyBeCalledOnce ) ) ;
}
// DevDiv #384514: Task<T> doesn't work correctly using the legacy SynchronizationContext setting. Since
// WebSockets operation requires correct Task<T> behavior, we should forbid using the feature when legacy
// mode is enabled.
SynchronizationContextUtil . ValidateModeForWebSockets ( ) ;
switch ( GetWebSocketInitStatus ( ) ) {
case WebSocketInitStatus . RequiresIntegratedMode :
throw new PlatformNotSupportedException ( SR . GetString ( SR . Requires_Iis_Integrated_Mode ) ) ;
case WebSocketInitStatus . CannotCallFromBeginRequest :
throw new InvalidOperationException ( SR . GetString ( SR . WebSockets_CannotBeCalledDuringBeginRequest ) ) ;
case WebSocketInitStatus . NativeModuleNotEnabled :
throw new PlatformNotSupportedException ( SR . GetString ( SR . WebSockets_WebSocketModuleNotEnabled ) ) ;
case WebSocketInitStatus . NotAWebSocketRequest :
throw new HttpException ( ( int ) HttpStatusCode . BadRequest , SR . GetString ( SR . WebSockets_NotAWebSocketRequest ) ) ;
case WebSocketInitStatus . CurrentRequestIsChildRequest :
throw new InvalidOperationException ( SR . GetString ( SR . WebSockets_CannotBeCalledDuringChildExecute ) ) ;
case WebSocketInitStatus . Success :
break ;
default :
// fallback error message - not a WebSocket request
throw new HttpException ( SR . GetString ( SR . WebSockets_UnknownErrorWhileAccepting ) ) ;
}
if ( CurrentNotification > RequestNotification . ExecuteRequestHandler ) {
// it is too late to call this method
throw new InvalidOperationException ( SR . GetString ( SR . WebSockets_CannotBeCalledAfterHandlerExecute ) ) ;
}
// End argument & state checking
IIS7WorkerRequest wr = ( IIS7WorkerRequest ) _wr ;
// Begin options checking and parsing
if ( options ! = null & & options . RequireSameOrigin ) {
if ( ! WebSocketUtil . IsSameOriginRequest ( wr ) ) {
// use Forbidden (HTTP 403) since it's not an authentication error; it's a usage error
throw new HttpException ( ( int ) HttpStatusCode . Forbidden , SR . GetString ( SR . WebSockets_OriginCheckFailed ) ) ;
}
}
string subprotocol = null ;
if ( options ! = null & & ! String . IsNullOrEmpty ( options . SubProtocol ) ) {
// AspNetWebSocketOptions.set_SubProtocol() already checked that the provided value is valid
subprotocol = options . SubProtocol ;
}
if ( subprotocol ! = null ) {
IList < string > incomingProtocols = WebSocketRequestedProtocols ;
if ( incomingProtocols = = null | | ! incomingProtocols . Contains ( subprotocol , StringComparer . Ordinal ) ) {
// The caller requested a subprotocol that wasn't in the list of accepted protocols coming from the client.
// This is disallowed by the WebSockets protocol spec, Sec. 5.2.2 (#2).
throw new ArgumentException ( SR . GetString ( SR . WebSockets_SubProtocolCannotBeNegotiated , subprotocol ) , "options" ) ;
}
}
// End options checking and parsing
wr . AcceptWebSocket ( ) ;
// transition: Inactive -> AcceptWebSocketRequestCalled
TransitionToWebSocketState ( WebSocketTransitionState . AcceptWebSocketRequestCalled ) ;
Response . StatusCode = ( int ) HttpStatusCode . SwitchingProtocols ; // 101
if ( subprotocol ! = null ) {
Response . AppendHeader ( "Sec-WebSocket-Protocol" , subprotocol ) ;
_webSocketNegotiatedProtocol = subprotocol ;
}
RootedObjects . WebSocketPipeline = new WebSocketPipeline ( RootedObjects , this , userFunc , subprotocol ) ;
}
internal void TransitionToWebSocketState ( WebSocketTransitionState newState ) {
// Make sure the state transition is happening in the correct order
#if DBG
WebSocketTransitionState expectedOldState = checked ( newState - 1 ) ;
Debug . Assert ( WebSocketTransitionState = = expectedOldState , String . Format ( CultureInfo . InvariantCulture , "Expected WebSocketTransitionState to be '{0}', but it was '{1}'." , expectedOldState , WebSocketTransitionState ) ) ;
#endif
WebSocketTransitionState = newState ;
if ( newState = = Web . WebSocketTransitionState . TransitionStarted ) {
_threadWhichStartedWebSocketTransition = Thread . CurrentThread ;
}
}
internal bool DidCurrentThreadStartWebSocketTransition {
get {
return _threadWhichStartedWebSocketTransition = = Thread . CurrentThread ;
}
}
// helper that throws an exception if we have transitioned the current request to a WebSocket request
internal void EnsureHasNotTransitionedToWebSocket ( ) {
if ( HasWebSocketRequestTransitionCompleted ) {
throw new NotSupportedException ( SR . GetString ( SR . WebSockets_MethodNotAvailableDuringWebSocketProcessing ) ) ;
}
}
internal bool FirstRequest { get ; set ; }
// session state support
private bool _requiresSessionStateFromHandler ;
internal bool RequiresSessionState {
get {
switch ( SessionStateBehavior ) {
case SessionStateBehavior . Required :
case SessionStateBehavior . ReadOnly :
return true ;
case SessionStateBehavior . Disabled :
return false ;
case SessionStateBehavior . Default :
default :
return _requiresSessionStateFromHandler ;
}
}
}
private bool _readOnlySessionStateFromHandler ;
internal bool ReadOnlySessionState {
get {
switch ( SessionStateBehavior ) {
case SessionStateBehavior . ReadOnly :
return true ;
case SessionStateBehavior . Required :
case SessionStateBehavior . Disabled :
return false ;
case SessionStateBehavior . Default :
default :
return _readOnlySessionStateFromHandler ;
}
}
}
internal bool InAspCompatMode ;
private IHttpHandler _remapHandler = null ;
/// <include file='doc\HttpContext.uex' path='docs/doc[@for="HttpContext.HttpContext"]/*' />
/// <devdoc>
/// <para>
/// Initializes a new instance of the HttpContext class.
/// </para>
/// </devdoc>
public HttpContext ( HttpRequest request , HttpResponse response ) {
Init ( request , response ) ;
request . Context = this ;
response . Context = this ;
}
/// <devdoc>
/// <para>
/// Initializes a new instance of the HttpContext class.
/// </para>
/// </devdoc>
public HttpContext ( HttpWorkerRequest wr ) {
_wr = wr ;
Init ( new HttpRequest ( wr , this ) , new HttpResponse ( wr , this ) ) ;
_response . InitResponseWriter ( ) ;
}
// ctor used in HttpRuntime
internal HttpContext ( HttpWorkerRequest wr , bool initResponseWriter ) {
_wr = wr ;
Init ( new HttpRequest ( wr , this ) , new HttpResponse ( wr , this ) ) ;
if ( initResponseWriter )
_response . InitResponseWriter ( ) ;
PerfCounters . IncrementCounter ( AppPerfCounter . REQUESTS_EXECUTING ) ;
}
private void Init ( HttpRequest request , HttpResponse response ) {
_request = request ;
_response = response ;
_utcTimestamp = DateTime . UtcNow ;
_principalContainer = this ;
if ( _wr is IIS7WorkerRequest ) {
_isIntegratedPipeline = true ;
}
if ( ! ( _wr is System . Web . SessionState . StateHttpWorkerRequest ) )
CookielessHelper . RemoveCookielessValuesFromPath ( ) ; // This ensures that the cookieless-helper is initialized and
// rewrites the path if the URI contains cookieless form-auth ticket, session-id, etc.
Profiler p = HttpRuntime . Profile ;
if ( p ! = null & & p . IsEnabled )
_topTraceContext = new TraceContext ( this ) ;
// rewrite path in order to remove "/eurl.axd/guid", if it was
// added to the URL by aspnet_filter.dll.
string eurl = GetEurl ( ) ;
if ( ! String . IsNullOrEmpty ( eurl ) ) {
string path = request . Path ;
int idxStartEurl = path . Length - eurl . Length ;
bool hasTrailingSlash = ( path [ path . Length - 1 ] = = '/' ) ;
if ( hasTrailingSlash ) {
idxStartEurl - - ;
}
if ( idxStartEurl > = 0
& & StringUtil . Equals ( path , idxStartEurl , eurl , 0 , eurl . Length ) ) {
// restore original URL
int originalUrlLen = idxStartEurl ;
if ( hasTrailingSlash ) {
originalUrlLen + + ;
}
string originalUrl = path . Substring ( 0 , originalUrlLen ) ;
// Dev10 835901: We don't call HttpContext.RewritePath(path) because the
// original path may contain '?' encoded as %3F, and RewritePath
// would interpret what follows as the query string. So instead, we
// clear ConfigurationPath and call InternalRewritePath directly.
ConfigurationPath = null ;
Request . InternalRewritePath ( VirtualPath . Create ( originalUrl ) , null , true ) ;
}
}
}
// We have a feature that directs extensionless URLs
// into managed code by appending "/eurl.axd/guid" to the path. On IIS 6.0,
// we restore the URL as soon as we get into managed code. Here we get the
// actual value of "/eurl.axd/guid" and remember it.
private string GetEurl ( ) {
// only used on IIS 6.0
if ( ! ( _wr is ISAPIWorkerRequestInProcForIIS6 )
| | ( _wr is ISAPIWorkerRequestInProcForIIS7 ) ) {
return null ;
}
string eurl = s_eurl ;
if ( eurl = = null & & ! s_eurlSet ) {
try {
IntPtr pBuffer = UnsafeNativeMethods . GetExtensionlessUrlAppendage ( ) ;
if ( pBuffer ! = IntPtr . Zero ) {
eurl = StringUtil . StringFromWCharPtr ( pBuffer , UnsafeNativeMethods . lstrlenW ( pBuffer ) ) ;
}
}
catch { } // ignore all exceptions
s_eurl = eurl ;
s_eurlSet = true ;
}
return eurl ;
}
// Current HttpContext off the call context
#if DBG
internal static void SetDebugAssertOnAccessToCurrent ( bool doAssert ) {
if ( doAssert ) {
CallContext . SetData ( "__ContextAssert" , String . Empty ) ;
}
else {
CallContext . SetData ( "__ContextAssert" , null ) ;
}
}
private static bool NeedDebugAssertOnAccessToCurrent {
get {
return ( CallContext . GetData ( "__ContextAssert" ) ! = null ) ;
}
}
#endif
/// <devdoc>
/// <para>Returns the current HttpContext object.</para>
/// </devdoc>
public static HttpContext Current {
get {
#if DBG
if ( NeedDebugAssertOnAccessToCurrent ) {
Debug . Assert ( ContextBase . Current ! = null ) ;
}
#endif
return ContextBase . Current as HttpContext ;
}
set {
ContextBase . Current = value ;
}
}
//
// Root / unroot for the duration of async operation
// These are only used for the classic pipeline. The integrated pipeline uses a different rooting mechanism.
//
private IntPtr _rootedPtr ;
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This is a safe critical method.")]
internal void Root ( ) {
_rootedPtr = GCUtil . RootObject ( this ) ;
}
internal void Unroot ( ) {
GCUtil . UnrootObject ( _rootedPtr ) ;
_rootedPtr = IntPtr . Zero ;
}
internal void FinishPipelineRequest ( ) {
if ( ! _finishPipelineRequestCalled ) {
_finishPipelineRequestCalled = true ;
HttpRuntime . FinishPipelineRequest ( this ) ;
}
}
// This is a virtual event which occurs when the HTTP part of this request is winding down, e.g. after EndRequest
// but before the WebSockets pipeline kicks in. The HttpContext is still available for inspection and is provided
// as a parameter to the supplied callback.
[SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate", Justification = @"The normal event pattern doesn't work between HttpContext and HttpContextBase since the signatures differ.")]
public ISubscriptionToken AddOnRequestCompleted ( Action < HttpContext > callback ) {
if ( callback = = null ) {
throw new ArgumentNullException ( "callback" ) ;
}
return _requestCompletedQueue . Enqueue ( callback ) ;
}
internal void RaiseOnRequestCompleted ( ) {
// The callbacks really shouldn't throw exceptions, but we have a catch block just in case.
// Since there's nobody else that can listen for these errors (the request is unwinding and
// user code will no longer run), we'll just log the error.
try {
_requestCompletedQueue . FireAndComplete ( action = > action ( this ) ) ;
}
catch ( Exception e ) {
WebBaseEvent . RaiseRuntimeError ( e , this ) ;
}
finally {
// Dispose of TimedOutToken so that nobody tries using it after this point.
DisposeTimedOutToken ( ) ;
}
}
// Allows an object's Dispose() method to be called when the pipeline part of this request is completed, e.g.
// after both the HTTP part and the WebSockets loop have completed. The HttpContext is not available for
// inspection, and HttpContext.Current will be null.
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This is a safe critical method.")]
public ISubscriptionToken DisposeOnPipelineCompleted ( IDisposable target ) {
if ( target = = null ) {
throw new ArgumentNullException ( "target" ) ;
}
if ( RootedObjects ! = null ) {
// integrated pipeline
return RootedObjects . DisposeOnPipelineCompleted ( target ) ;
}
else {
// classic pipeline
return _pipelineCompletedQueue . Enqueue ( target ) ;
}
}
internal void RaiseOnPipelineCompleted ( ) {
// The callbacks really shouldn't throw exceptions, but we have a catch block just in case.
// Since there's nobody else that can listen for these errors (the request is unwinding and
// user code will no longer run), we'll just log the error.
try {
_pipelineCompletedQueue . FireAndComplete ( disposable = > disposable . Dispose ( ) ) ;
}
catch ( Exception e ) {
WebBaseEvent . RaiseRuntimeError ( e , null ) ;
}
}
internal void ValidatePath ( ) {
CachedPathData pathData = GetConfigurationPathData ( ) ;
pathData . ValidatePath ( _request . PhysicalPathInternal ) ;
}
// IServiceProvider implementation
/// <internalonly/>
Object IServiceProvider . GetService ( Type service ) {
Object obj ;
if ( service = = typeof ( HttpWorkerRequest ) ) {
InternalSecurityPermissions . UnmanagedCode . Demand ( ) ;
obj = _wr ;
}
else if ( service = = typeof ( HttpRequest ) )
obj = Request ;
else if ( service = = typeof ( HttpResponse ) )
obj = Response ;
else if ( service = = typeof ( HttpApplication ) )
obj = ApplicationInstance ;
else if ( service = = typeof ( HttpApplicationState ) )
obj = Application ;
else if ( service = = typeof ( HttpSessionState ) )
obj = Session ;
else if ( service = = typeof ( HttpServerUtility ) )
obj = Server ;
else
obj = null ;
return obj ;
}
//
// Async app handler is remembered for the duration of execution of the
// request when application happens to be IHttpAsyncHandler. It is needed
// for HttpRuntime to remember the object on which to call OnEndRequest.
//
// The assumption is that application is a IHttpAsyncHandler, not always
// HttpApplication.
//
internal IHttpAsyncHandler AsyncAppHandler {
get { return _asyncAppHandler ; }
set { _asyncAppHandler = value ; }
}
public AsyncPreloadModeFlags AsyncPreloadMode {
get {
if ( ! _asyncPreloadModeFlagsSet ) {
_asyncPreloadModeFlags = RuntimeConfig . GetConfig ( this ) . HttpRuntime . AsyncPreloadMode ;
_asyncPreloadModeFlagsSet = true ;
}
return _asyncPreloadModeFlags ;
}
set {
_asyncPreloadModeFlags = value ;
_asyncPreloadModeFlagsSet = true ;
}
}
// If this flag is not set, the AspNetSynchronizationContext associated with this request will throw
// exceptions when it detects the application misusing the async API. This can occur if somebody
// tries to call SynchronizationContext.Post / OperationStarted / etc. during a part of the
// pipeline where we weren't expecting asynchronous work to take place, if there is still
// outstanding asynchronous work when an asynchronous module or handler signals completion, etc.
// It is meant as a safety net to let developers know early on when they're writing async code
// which doesn't fit our expected patterns and where that code likely has negative side effects.
//
// This flag is respected only by AspNetSynchronizationContext; it has no effect when the
// legacy [....] context is in use.
[EditorBrowsable(EditorBrowsableState.Advanced)]
public bool AllowAsyncDuringSyncStages {
get {
return SyncContext . AllowAsyncDuringSyncStages ;
}
set {
SyncContext . AllowAsyncDuringSyncStages = value ;
}
}
/// <devdoc>
/// <para>Retrieves a reference to the application object for the current Http request.</para>
/// </devdoc>
public HttpApplication ApplicationInstance {
get {
return _appInstance ;
}
set {
// For integrated pipeline, once this is set to a non-null value, it can only be set to null.
// The setter should never have been made public. It probably happened in 1.0, before it was possible
// to have getter and setter with different accessibility.
if ( _isIntegratedPipeline & & _appInstance ! = null & & value ! = null ) {
throw new InvalidOperationException ( SR . GetString ( SR . Application_instance_cannot_be_changed ) ) ;
}
else {
_appInstance = value ;
// Use HttpApplication instance custom allocator provider
if ( _isIntegratedPipeline ) {
// The provider allows null - everyone should fallback to default implementation
IAllocatorProvider allocator = _appInstance ! = null ? _appInstance . AllocatorProvider : null ;
_response . SetAllocatorProvider ( allocator ) ;
( ( IIS7WorkerRequest ) _wr ) . AllocatorProvider = allocator ;
}
}
}
}
/// <devdoc>
/// <para>
/// Retrieves a reference to the application object for the current
/// Http request.
/// </para>
/// </devdoc>
public HttpApplicationState Application {
get { return HttpApplicationFactory . ApplicationState ; }
}
// flag to suppress use of custom HttpEncoder registered in web.config
// for example, yellow error pages should use the default encoder rather than a custom encoder
internal bool DisableCustomHttpEncoder {
get ;
set ;
}
/// <devdoc>
/// <para>
/// Retrieves or assigns a reference to the <see cref='System.Web.IHttpHandler'/>
/// object for the current request.
/// </para>
/// </devdoc>
public IHttpHandler Handler {
get { return _handler ; }
set {
_handler = value ;
_requiresSessionStateFromHandler = false ;
_readOnlySessionStateFromHandler = false ;
InAspCompatMode = false ;
if ( _handler ! = null ) {
if ( _handler is IRequiresSessionState ) {
_requiresSessionStateFromHandler = true ;
}
if ( _handler is IReadOnlySessionState ) {
_readOnlySessionStateFromHandler = true ;
}
Page page = _handler as Page ;
if ( page ! = null & & page . IsInAspCompatMode ) {
InAspCompatMode = true ;
}
}
}
}
/// <devdoc>
/// <para>
/// Retrieves or assigns a reference to the <see cref='System.Web.IHttpHandler'/>
/// object for the previous handler;
/// </para>
/// </devdoc>
public IHttpHandler PreviousHandler {
get {
if ( _handlerStack = = null | | _handlerStack . Count = = 0 )
return null ;
return ( IHttpHandler ) _handlerStack . Peek ( ) ;
}
}
/// <devdoc>
/// <para>
/// Retrieves or assigns a reference to the <see cref='System.Web.IHttpHandler'/>
/// object for the current executing handler;
/// </para>
/// </devdoc>
private IHttpHandler _currentHandler = null ;
public IHttpHandler CurrentHandler {
get {
if ( _currentHandler = = null )
_currentHandler = _handler ;
return _currentHandler ;
}
}
internal void RestoreCurrentHandler ( ) {
_currentHandler = ( IHttpHandler ) _handlerStack . Pop ( ) ;
}
internal void SetCurrentHandler ( IHttpHandler newtHandler ) {
if ( _handlerStack = = null ) {
_handlerStack = new Stack ( ) ;
}
_handlerStack . Push ( CurrentHandler ) ;
_currentHandler = newtHandler ;
}
/// <devdoc>
/// <para>
/// Set custom mapping handler processing the request <see cref='System.Web.IHttpHandler'/>
/// </para>
/// </devdoc>
public void RemapHandler ( IHttpHandler handler ) {
EnsureHasNotTransitionedToWebSocket ( ) ;
IIS7WorkerRequest wr = _wr as IIS7WorkerRequest ;
if ( wr ! = null ) {
// Remap handler not allowed after ResolveRequestCache notification
if ( _notificationContext . CurrentNotification > = RequestNotification . MapRequestHandler ) {
throw new InvalidOperationException ( SR . GetString ( SR . Invoke_before_pipeline_event , "HttpContext.RemapHandler" , "HttpApplication.MapRequestHandler" ) ) ;
}
string handlerTypeName = null ;
string handlerName = null ;
if ( handler ! = null ) {
Type handlerType = handler . GetType ( ) ;
handlerTypeName = handlerType . AssemblyQualifiedName ;
handlerName = handlerType . FullName ;
}
wr . SetRemapHandler ( handlerTypeName , handlerName ) ;
}
_remapHandler = handler ;
}
internal IHttpHandler RemapHandlerInstance {
get {
return _remapHandler ;
}
}
/// <devdoc>
/// <para>
/// Retrieves a reference to the target <see cref='System.Web.HttpRequest'/>
/// object for the current request.
/// </para>
/// </devdoc>
public HttpRequest Request {
get {
if ( HideRequestResponse )
throw new HttpException ( SR . GetString ( SR . Request_not_available ) ) ;
return _request ;
}
}
/// <devdoc>
/// <para>
/// Retrieves a reference to the <see cref='System.Web.HttpResponse'/>
/// object for the current response.
/// </para>
/// </devdoc>
public HttpResponse Response {
get {
if ( HideRequestResponse | | HasWebSocketRequestTransitionCompleted )
throw new HttpException ( SR . GetString ( SR . Response_not_available ) ) ;
return _response ;
}
}
internal IHttpHandler TopHandler {
get {
if ( _handlerStack = = null ) {
return _handler ;
}
object [ ] handlers = _handlerStack . ToArray ( ) ;
if ( handlers = = null | | handlers . Length = = 0 ) {
return _handler ;
}
return ( IHttpHandler ) handlers [ handlers . Length - 1 ] ;
}
}
/// <devdoc>
/// <para>Retrieves a reference to the <see cref='System.Web.TraceContext'/> object for the current
/// response.</para>
/// </devdoc>
public TraceContext Trace {
get {
if ( _topTraceContext = = null )
_topTraceContext = new TraceContext ( this ) ;
return _topTraceContext ;
}
}
internal bool TraceIsEnabled {
get {
if ( _topTraceContext = = null )
return false ;
return _topTraceContext . IsEnabled ;
}
set {
if ( value )
_topTraceContext = new TraceContext ( this ) ;
}
}
/// <devdoc>
/// <para>
/// Retrieves a key-value collection that can be used to
/// build up and share data between an <see cref='System.Web.IHttpModule'/> and an <see cref='System.Web.IHttpHandler'/>
/// during a
/// request.
/// </para>
/// </devdoc>
public IDictionary Items {
get {
if ( _items = = null )
_items = new Hashtable ( ) ;
return _items ;
}
}
/// <devdoc>
/// <para>
/// Gets a reference to the <see cref='System.Web.SessionState'/> instance for the current request.
/// </para>
/// </devdoc>
public HttpSessionState Session {
get {
if ( HasWebSocketRequestTransitionCompleted ) {
// Session is unavailable at this point
return null ;
}
if ( _delayedSessionState ) {
lock ( this ) {
if ( _delayedSessionState ) {
2016-11-10 13:04:39 +00:00
Debug . Assert ( _sessionStateModule ! = null , "_sessionStateModule != null" ) ;
2016-08-03 10:59:49 +00:00
// If it's not null, it means we have a delayed session state item
_sessionStateModule . InitStateStoreItem ( true ) ;
_delayedSessionState = false ;
}
}
}
return ( HttpSessionState ) Items [ SessionStateUtility . SESSION_KEY ] ;
}
}
2016-11-10 13:04:39 +00:00
[MethodImpl(MethodImplOptions.NoInlining)]
2016-08-03 10:59:49 +00:00
internal void EnsureSessionStateIfNecessary ( ) {
2016-11-10 13:04:39 +00:00
if ( _sessionStateModule = = null )
{
// If _sessionStateModule is null, we wouldn't be able to call
// _sessionStateModule.EnsureStateStoreItemLocked(), so we return here.
// _sessionStateModule could be null in the following cases,
// 1. No session state acquired.
// 2. HttpResponse.Flush() happens after session state being released.
// 3. The session state module in use is not System.Web.SessionState.SessionStateModule.
//
// This method is for the in-framework SessionStateModule only.
// OOB SessionStateModule can achieve this by using HttpResponse.AddOnSendingHeaders.
return ;
}
2016-08-03 10:59:49 +00:00
HttpSessionState session = ( HttpSessionState ) Items [ SessionStateUtility . SESSION_KEY ] ;
if ( session ! = null & & // The session has been initiated
session . Count > 0 & & // The session state is used
! string . IsNullOrEmpty ( session . SessionID ) ) { // Ensure the session Id is valid - it will force to create new if didn't exist
_sessionStateModule . EnsureStateStoreItemLocked ( ) ; // Lock the item if in use
}
}
internal void AddHttpSessionStateModule ( SessionStateModule module , bool delayed ) {
if ( _sessionStateModule ! = null & & _sessionStateModule ! = module ) {
throw new HttpException ( SR . GetString ( SR . Cant_have_multiple_session_module ) ) ;
}
_sessionStateModule = module ;
_delayedSessionState = delayed ;
}
internal void RemoveHttpSessionStateModule ( ) {
_delayedSessionState = false ;
_sessionStateModule = null ;
}
/// <devdoc>
/// <para>
/// Gets a reference to the <see cref='System.Web.HttpServerUtility'/>
/// for the current
/// request.
/// </para>
/// </devdoc>
public HttpServerUtility Server {
get {
// create only on demand
if ( _server = = null )
_server = new HttpServerUtility ( this ) ;
return _server ;
}
}
// if the context has an error, report it, but only one time
internal void ReportRuntimeErrorIfExists ( ref RequestNotificationStatus status ) {
Exception e = Error ;
if ( e = = null | | _runtimeErrorReported ) {
return ;
}
// WOS 1921799: custom errors don't work in integrated mode if there's an initialization exception
if ( _notificationContext ! = null & & CurrentModuleIndex = = - 1 ) {
try {
IIS7WorkerRequest wr = _wr as IIS7WorkerRequest ;
if ( Request . QueryString [ "aspxerrorpath" ] ! = null
& & wr ! = null
& & String . IsNullOrEmpty ( wr . GetManagedHandlerType ( ) )
& & wr . GetCurrentModuleName ( ) = = PipelineRuntime . InitExceptionModuleName ) {
status = RequestNotificationStatus . Continue ; // allow non-managed handler to execute request
return ;
}
}
catch {
}
}
_runtimeErrorReported = true ;
if ( HttpRuntime . AppOfflineMessage ! = null ) {
try {
// report app offline error
Response . TrySkipIisCustomErrors = true ;
HttpRuntime . ReportAppOfflineErrorMessage ( Response , HttpRuntime . AppOfflineMessage ) ;
}
catch {
}
}
else {
// report error exception
using ( new DisposableHttpContextWrapper ( this ) ) {
// if the custom encoder throws, it might interfere with returning error information
// to the client, so we force use of the default encoder
DisableCustomHttpEncoder = true ;
// when application is on UNC share the code below must
// be run while impersonating the token given by IIS
using ( new ApplicationImpersonationContext ( ) ) {
try {
try {
// try to report error in a way that could possibly throw (a config exception)
Response . ReportRuntimeError ( e , true /*canThrow*/ , false ) ;
}
catch ( Exception eReport ) {
// report the config error in a way that would not throw
Response . ReportRuntimeError ( eReport , false /*canThrow*/ , false ) ;
}
}
catch ( Exception ) {
}
}
}
}
status = RequestNotificationStatus . FinishRequest ;
return ;
}
/// <devdoc>
/// <para>
/// Gets the
/// first error (if any) accumulated during request processing.
/// </para>
/// </devdoc>
public Exception Error {
get {
if ( _tempError ! = null )
return _tempError ;
if ( _errors = = null | | _errors . Count = = 0 | | _errorCleared )
return null ;
return ( Exception ) _errors [ 0 ] ;
}
}
//
// Temp error (yet to be caught on app level)
// to be reported as Server.GetLastError() but could be cleared later
//
internal Exception TempError {
get { return _tempError ; }
set { _tempError = value ; }
}
/// <devdoc>
/// <para>
/// An array (collection) of errors accumulated while processing a
/// request.
/// </para>
/// </devdoc>
public Exception [ ] AllErrors {
get {
int n = ( _errors ! = null ) ? _errors . Count : 0 ;
if ( n = = 0 )
return null ;
Exception [ ] errors = new Exception [ n ] ;
_errors . CopyTo ( 0 , errors , 0 , n ) ;
return errors ;
}
}
/// <devdoc>
/// <para>
/// Registers an error for the current request.
/// </para>
/// </devdoc>
public void AddError ( Exception errorInfo ) {
if ( _errors = = null )
_errors = new ArrayList ( ) ;
_errors . Add ( errorInfo ) ;
if ( _isIntegratedPipeline & & _notificationContext ! = null ) {
// set the error on the current notification context
_notificationContext . Error = errorInfo ;
}
}
/// <devdoc>
/// <para>
/// Clears all errors for the current request.
/// </para>
/// </devdoc>
public void ClearError ( ) {
if ( _tempError ! = null )
_tempError = null ;
else
_errorCleared = true ;
if ( _isIntegratedPipeline & & _notificationContext ! = null ) {
// clear the error on the current notification context
_notificationContext . Error = null ;
}
}
/// <devdoc>
/// <para>
/// IPrincipal security information.
/// </para>
/// </devdoc>
public IPrincipal User {
get { return _principalContainer . Principal ; }
[SecurityPermission(SecurityAction.Demand, ControlPrincipal=true)]
set {
SetPrincipalNoDemand ( value ) ;
}
}
IPrincipal IPrincipalContainer . Principal {
get ;
set ;
}
// route all internals call to the principal (that don't have luring attacks)
// through this method so we can centralize reporting
// Before this, some auth modules were assigning directly to _user
internal void SetPrincipalNoDemand ( IPrincipal principal , bool needToSetNativePrincipal ) {
_principalContainer . Principal = principal ;
// push changes through to native side
if ( needToSetNativePrincipal
& & _isIntegratedPipeline
& & _notificationContext . CurrentNotification = = RequestNotification . AuthenticateRequest ) {
IntPtr pManagedPrincipal = IntPtr . Zero ;
IIS7WorkerRequest wr = ( IIS7WorkerRequest ) _wr ;
wr . SetPrincipal ( principal ) ;
}
}
internal void SetPrincipalNoDemand ( IPrincipal principal ) {
SetPrincipalNoDemand ( principal , true /*needToSetNativePrincipal*/ ) ;
}
[DoNotReset]
internal bool _ProfileDelayLoad = false ;
public ProfileBase Profile {
get {
if ( _Profile = = null & & _ProfileDelayLoad )
_Profile = ProfileBase . Create ( Request . IsAuthenticated ? User . Identity . Name : Request . AnonymousID , Request . IsAuthenticated ) ;
return _Profile ;
}
}
internal SessionStateBehavior SessionStateBehavior { get ; set ; }
[ SuppressMessage ( "Microsoft.Design" , "CA1024:UsePropertiesWhereAppropriate" ,
Justification = "An internal property already exists. This method does additional work." ) ]
public void SetSessionStateBehavior ( SessionStateBehavior sessionStateBehavior ) {
if ( _notificationContext ! = null & & _notificationContext . CurrentNotification > = RequestNotification . AcquireRequestState ) {
throw new InvalidOperationException ( SR . GetString ( SR . Invoke_before_pipeline_event , "HttpContext.SetSessionStateBehavior" , "HttpApplication.AcquireRequestState" ) ) ;
}
SessionStateBehavior = sessionStateBehavior ;
}
public bool SkipAuthorization {
get { return _skipAuthorization ; }
[SecurityPermission(SecurityAction.Demand, ControlPrincipal=true)]
set {
SetSkipAuthorizationNoDemand ( value , false ) ;
}
}
internal void SetSkipAuthorizationNoDemand ( bool value , bool managedOnly )
{
if ( HttpRuntime . UseIntegratedPipeline
& & ! managedOnly
& & value ! = _skipAuthorization ) {
// For integrated mode, persist changes to SkipAuthorization
// in the IS_LOGIN_PAGE server variable. When this server variable exists
// and the value is not "0", IIS skips authorization.
_request . SetSkipAuthorization ( value ) ;
}
_skipAuthorization = value ;
}
// Pointer to the RootedObjects element, which contains information that needs to be flowed
// between the HttpContext and the WebSocket, such as the current principal.
[DoNotReset]
private RootedObjects _rootedObjects ;
internal RootedObjects RootedObjects {
get {
return _rootedObjects ;
}
set {
// [....] the Principal between the containers
SwitchPrincipalContainer ( value ) ;
_rootedObjects = value ;
}
}
private void SwitchPrincipalContainer ( IPrincipalContainer newPrincipalContainer ) {
if ( newPrincipalContainer = = null ) {
newPrincipalContainer = this ;
}
// Ensure new container contains the current principal
IPrincipal currentPrincipal = _principalContainer . Principal ;
newPrincipalContainer . Principal = currentPrincipal ;
_principalContainer = newPrincipalContainer ;
}
/// <devdoc>
/// <para>
/// Is this request in debug mode?
/// </para>
/// </devdoc>
public bool IsDebuggingEnabled {
get {
try {
return CompilationUtil . IsDebuggingEnabled ( this ) ;
}
catch {
// in case of config errors don't throw
return false ;
}
}
}
/// <devdoc>
/// <para>
/// Is this custom error enabled for this request?
/// </para>
/// </devdoc>
public bool IsCustomErrorEnabled {
get {
return CustomErrorsSection . GetSettings ( this ) . CustomErrorsEnabled ( _request ) ;
}
}
internal TemplateControl TemplateControl {
get {
return _templateControl ;
}
set {
_templateControl = value ;
}
}
/// <devdoc>
/// <para>Gets the initial timestamp of the current request.</para>
/// </devdoc>
public DateTime Timestamp {
get { return _utcTimestamp . ToLocalTime ( ) ; }
}
internal DateTime UtcTimestamp {
get { return _utcTimestamp ; }
}
internal HttpWorkerRequest WorkerRequest {
get { return _wr ; }
}
/// <devdoc>
/// <para>
/// Gets a reference to the System.Web.Cache.Cache object for the current request.
/// </para>
/// </devdoc>
public Cache Cache {
get { return HttpRuntime . Cache ; }
}
/// <summary>
/// Gets a reference to the System.Web.Instrumentation.PageInstrumentationService instance for this request. Guaranteed not to be null (barring private reflection magic).
/// </summary>
public PageInstrumentationService PageInstrumentation {
get {
if ( _pageInstrumentationService = = null ) {
_pageInstrumentationService = new PageInstrumentationService ( ) ;
}
return _pageInstrumentationService ;
}
}
/ *
* The virtual path used to get config settings . This allows the user
* to specify a non default config path , without having to pass it to every
* configuration call .
* /
internal VirtualPath ConfigurationPath {
get {
if ( _configurationPath = = null )
_configurationPath = _request . FilePathObject ;
return _configurationPath ;
}
set {
_configurationPath = value ;
_configurationPathData = null ;
_filePathData = null ;
}
}
internal CachedPathData GetFilePathData ( ) {
if ( _filePathData = = null ) {
_filePathData = CachedPathData . GetVirtualPathData ( _request . FilePathObject , false ) ;
}
return _filePathData ;
}
internal CachedPathData GetConfigurationPathData ( ) {
if ( _configurationPath = = null ) {
return GetFilePathData ( ) ;
}
//
if ( _configurationPathData = = null ) {
_configurationPathData = CachedPathData . GetVirtualPathData ( _configurationPath , true ) ;
}
return _configurationPathData ;
}
internal CachedPathData GetPathData ( VirtualPath path ) {
if ( path ! = null ) {
if ( path . Equals ( _request . FilePathObject ) ) {
return GetFilePathData ( ) ;
}
if ( _configurationPath ! = null & & path . Equals ( _configurationPath ) ) {
return GetConfigurationPathData ( ) ;
}
}
return CachedPathData . GetVirtualPathData ( path , false ) ;
}
internal void FinishRequestForCachedPathData ( int statusCode ) {
// Remove the cached path data for a file path if the first request for it
// does not succeed due to a bad request. Otherwise we could be vulnerable
// to a DOS attack.
if ( _filePathData ! = null & & ! _filePathData . CompletedFirstRequest ) {
if ( 400 < = statusCode & & statusCode < 500 ) {
CachedPathData . RemoveBadPathData ( _filePathData ) ;
}
else {
CachedPathData . MarkCompleted ( _filePathData ) ;
}
}
}
/ *
* Uses the Config system to get the specified configuraiton
* /
[Obsolete("The recommended alternative is System.Web.Configuration.WebConfigurationManager.GetWebApplicationSection in System.Web.dll. http://go.microsoft.com/fwlink/?linkid=14202")]
public static object GetAppConfig ( String name ) {
return WebConfigurationManager . GetWebApplicationSection ( name ) ;
}
[Obsolete("The recommended alternative is System.Web.HttpContext.GetSection in System.Web.dll. http://go.microsoft.com/fwlink/?linkid=14202")]
public object GetConfig ( String name ) {
return GetSection ( name ) ;
}
public object GetSection ( String sectionName ) {
if ( HttpConfigurationSystem . UseHttpConfigurationSystem ) {
return GetConfigurationPathData ( ) . ConfigRecord . GetSection ( sectionName ) ;
}
else {
return ConfigurationManager . GetSection ( sectionName ) ;
}
}
internal RuntimeConfig GetRuntimeConfig ( ) {
return GetConfigurationPathData ( ) . RuntimeConfig ;
}
internal RuntimeConfig GetRuntimeConfig ( VirtualPath path ) {
return GetPathData ( path ) . RuntimeConfig ;
}
public void RewritePath ( String path ) {
RewritePath ( path , true ) ;
}
/ *
* Called by the URL rewrite module to modify the path for downstream modules
* /
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void RewritePath ( String path , bool rebaseClientPath ) {
if ( path = = null )
throw new ArgumentNullException ( "path" ) ;
// extract query string
String qs = null ;
int iqs = path . IndexOf ( '?' ) ;
if ( iqs > = 0 ) {
qs = ( iqs < path . Length - 1 ) ? path . Substring ( iqs + 1 ) : String . Empty ;
path = path . Substring ( 0 , iqs ) ;
}
// resolve relative path
VirtualPath virtualPath = VirtualPath . Create ( path ) ;
virtualPath = Request . FilePathObject . Combine ( virtualPath ) ;
// disallow paths outside of app
virtualPath . FailIfNotWithinAppRoot ( ) ;
// clear things that depend on path
ConfigurationPath = null ;
// rewrite path on request
Request . InternalRewritePath ( virtualPath , qs , rebaseClientPath ) ;
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void RewritePath ( String filePath , String pathInfo , String queryString ) {
RewritePath ( VirtualPath . CreateAllowNull ( filePath ) , VirtualPath . CreateAllowNull ( pathInfo ) ,
queryString , false /*setClientFilePath*/ ) ;
}
public void RewritePath ( string filePath , string pathInfo , String queryString , bool setClientFilePath )
{
RewritePath ( VirtualPath . CreateAllowNull ( filePath ) , VirtualPath . CreateAllowNull ( pathInfo ) , queryString , setClientFilePath ) ;
}
internal void RewritePath ( VirtualPath filePath , VirtualPath pathInfo , String queryString , bool setClientFilePath ) {
EnsureHasNotTransitionedToWebSocket ( ) ;
if ( filePath = = null )
throw new ArgumentNullException ( "filePath" ) ;
// resolve relative path
filePath = Request . FilePathObject . Combine ( filePath ) ;
// disallow paths outside of app
filePath . FailIfNotWithinAppRoot ( ) ;
// clear things that depend on path
ConfigurationPath = null ;
// rewrite path on request
Request . InternalRewritePath ( filePath , pathInfo , queryString , setClientFilePath ) ;
}
internal CultureInfo DynamicCulture {
get { return _dynamicCulture ; }
set { _dynamicCulture = value ; }
}
internal CultureInfo DynamicUICulture {
get { return _dynamicUICulture ; }
set { _dynamicUICulture = value ; }
}
public static object GetGlobalResourceObject ( string classKey , string resourceKey ) {
return GetGlobalResourceObject ( classKey , resourceKey , null ) ;
}
public static object GetGlobalResourceObject ( string classKey , string resourceKey , CultureInfo culture ) {
return ResourceExpressionBuilder . GetGlobalResourceObject ( classKey , resourceKey , null , null , culture ) ;
}
public static object GetLocalResourceObject ( string virtualPath , string resourceKey ) {
return GetLocalResourceObject ( virtualPath , resourceKey , null ) ;
}
public static object GetLocalResourceObject ( string virtualPath , string resourceKey , CultureInfo culture ) {
IResourceProvider pageProvider = ResourceExpressionBuilder . GetLocalResourceProvider (
VirtualPath . Create ( virtualPath ) ) ;
return ResourceExpressionBuilder . GetResourceObject ( pageProvider , resourceKey , culture ) ;
}
internal int ServerExecuteDepth {
get { return _serverExecuteDepth ; }
set { _serverExecuteDepth = value ; }
}
internal bool PreventPostback {
get { return _preventPostback ; }
set { _preventPostback = value ; }
}
//
// Timeout support
//
internal Thread CurrentThread {
get {
return _thread ;
}
set {
_thread = value ;
}
}
// Property is thread-safe since needs to be accessed by RequestTimeoutManager in addition to
// normal request threads.
internal TimeSpan Timeout {
get {
long ticks = EnsureTimeout ( ) ;
return TimeSpan . FromTicks ( ticks ) ;
}
set {
Interlocked . Exchange ( ref _timeoutTicks , value . Ticks ) ;
}
}
// Access via HttpRequest.TimedOutToken instead.
internal CancellationToken TimedOutToken {
get {
// If we are the first call site to observe the token, then create it in the non-canceled state.
CancellationTokenHelper helper = LazyInitializer . EnsureInitialized ( ref _timeoutCancellationTokenHelper , ( ) = > new CancellationTokenHelper ( canceled : false ) ) ;
return helper . Token ;
}
}
/// <summary>
/// Determines whether the ASP.NET runtime calls Thread.Abort() on the thread servicing this request when
/// the request times out. Default value is 'true'.
/// </summary>
/// <remarks>
/// Handlers and modules that are using Request.TimedOutToken to implement cooperative cancellation may
/// wish to disable the rude Thread.Abort behavior that ASP.NET has historically performed when a request
/// times out. This can help developers make sure that their g----ful cancellation + cleanup routines
/// will run without interruption by ASP.NET.
///
/// The rules for determining when a thread is aborted are somewhat complicated, so applications shouldn't
/// try to depend on them. Currently, the behavior is:
///
/// - The thread will be aborted at some point after Request.TimedOutToken is canceled. The abort might not
/// occur immediately afterward, as the "should Thread.Abort" timer is separate from the "should signal
/// the CancellationToken" timer.
///
/// - We generally don't abort threads that are processing async modules or handlers. There are some
/// exceptions. E.g., during certain parts of the lifecycle for async WebForms pages, the thread can be
/// a candidate to be aborted when a timeout occurs.
///
/// If a developer sets this property to 'false', ASP.NET will not automatically display a "Request timed
/// out" YSOD when a timeout occurs. If this happens the application is responsible for setting the response
/// content appropriately.
/// </remarks>
public bool ThreadAbortOnTimeout {
get { return Volatile . Read ( ref _threadAbortOnTimeout ) ; }
set { Volatile . Write ( ref _threadAbortOnTimeout , value ) ; }
}
private void DisposeTimedOutToken ( ) {
// If we are the first call site to observe the token, then create it in the disposed state.
CancellationTokenHelper helper = LazyInitializer . EnsureInitialized ( ref _timeoutCancellationTokenHelper , ( ) = > CancellationTokenHelper . StaticDisposed ) ;
helper . Dispose ( ) ;
}
internal long EnsureTimeout ( ) {
// Calls to Volatile.* are atomic, even for 64-bit fields.
long ticks = Volatile . Read ( ref _timeoutTicks ) ;
if ( ticks = = - 1 ) {
// Only go to config if the value hasn't yet been initialized.
HttpRuntimeSection cfg = RuntimeConfig . GetConfig ( this ) . HttpRuntime ;
ticks = cfg . ExecutionTimeout . Ticks ;
// If another thread already came in and initialized _timeoutTicks,
// return that value instead of the value we just read from config.
long originalTicks = Interlocked . CompareExchange ( ref _timeoutTicks , ticks , - 1 ) ;
if ( originalTicks ! = - 1 ) {
ticks = originalTicks ;
}
}
return ticks ;
}
internal DoubleLink TimeoutLink {
get { return _timeoutLink ; }
set { _timeoutLink = value ; }
}
/ *
Notes on the following 5 functions :
Execution can be cancelled only during certain periods , when inside the catch
block for ThreadAbortException . These periods are marked with the value of
_timeoutState of 1.
There is potential [ rare ] race condition when the timeout thread would call
thread . abort but the execution logic in the meantime escapes the catch block .
To avoid such race conditions _timeoutState of - 1 ( cancelled ) is introduced .
The timeout thread sets _timeoutState to - 1 before thread abort and the
unwinding logic just waits for the exception in this case . The wait cannot
be done in EndCancellablePeriod because the function is call from inside of
a finally block and thus would wait indefinetely . That ' s why another function
WaitForExceptionIfCancelled had been added .
Originally _timeoutStartTime was set in BeginCancellablePeriod . However , that means
we ' ll call UtcNow everytime we call ExecuteStep , which is too expensive . So to save
CPU time we created a new method SetStartTime ( ) which is called by the caller of
ExecuteStep .
* /
internal void BeginCancellablePeriod ( ) {
// It could be caused by an exception in OnThreadStart
if ( Volatile . Read ( ref _timeoutStartTimeUtcTicks ) = = - 1 ) {
SetStartTime ( ) ;
}
Volatile . Write ( ref _timeoutState , 1 ) ;
}
internal void SetStartTime ( ) {
Interlocked . Exchange ( ref _timeoutStartTimeUtcTicks , DateTime . UtcNow . Ticks ) ;
}
internal void EndCancellablePeriod ( ) {
Interlocked . CompareExchange ( ref _timeoutState , 0 , 1 ) ;
}
internal void WaitForExceptionIfCancelled ( ) {
while ( Volatile . Read ( ref _timeoutState ) = = - 1 )
Thread . Sleep ( 100 ) ;
}
internal bool IsInCancellablePeriod {
get { return ( Volatile . Read ( ref _timeoutState ) = = 1 ) ; }
}
internal Thread MustTimeout ( DateTime utcNow ) {
// Note: The TimedOutToken is keyed off of the HttpContext creation time, not the most recent async
// completion time (like the Thread.Abort logic later in this method).
if ( _utcTimestamp + Timeout < utcNow ) {
// If we are the first call site to observe the token, then create it in the canceled state.
CancellationTokenHelper helper = LazyInitializer . EnsureInitialized ( ref _timeoutCancellationTokenHelper , ( ) = > new CancellationTokenHelper ( canceled : true ) ) ;
helper . Cancel ( ) ;
}
if ( Volatile . Read ( ref _timeoutState ) = = 1 & & ThreadAbortOnTimeout ) { // fast check
long expirationUtcTicks = Volatile . Read ( ref _timeoutStartTimeUtcTicks ) + Timeout . Ticks ; // don't care about overflow
if ( expirationUtcTicks < utcNow . Ticks ) {
// don't abort in debug mode
try {
if ( CompilationUtil . IsDebuggingEnabled ( this ) | | System . Diagnostics . Debugger . IsAttached )
return null ;
}
catch {
// ignore config errors
return null ;
}
// abort the thread only if in cancelable state, avoiding race conditions
// the caller MUST timeout if the return is true
if ( Interlocked . CompareExchange ( ref _timeoutState , - 1 , 1 ) = = 1 ) {
if ( _wr . IsInReadEntitySync ) {
AbortConnection ( ) ;
}
return _thread ;
}
}
}
return null ;
}
internal bool HasTimeoutExpired {
get {
// Check if it is allowed to timeout
if ( Volatile . Read ( ref _timeoutState ) ! = 1 | | ! ThreadAbortOnTimeout ) {
return false ;
}
// Check if the timeout has expired
long expirationUtcTicks = Volatile . Read ( ref _timeoutStartTimeUtcTicks ) + Timeout . Ticks ; // don't care about overflow
if ( expirationUtcTicks > = DateTime . UtcNow . Ticks ) {
return false ;
}
// Dont't timeout when in debug
try {
if ( CompilationUtil . IsDebuggingEnabled ( this ) | | System . Diagnostics . Debugger . IsAttached ) {
return false ;
}
}
catch {
// ignore config errors
return false ;
}
return true ;
}
}
// call a delegate within cancellable period (possibly throwing timeout exception)
internal void InvokeCancellableCallback ( WaitCallback callback , Object state ) {
if ( IsInCancellablePeriod ) {
// call directly
callback ( state ) ;
return ;
}
try {
BeginCancellablePeriod ( ) ; // request can be cancelled from this point
try {
callback ( state ) ;
}
finally {
EndCancellablePeriod ( ) ; // request can be cancelled until this point
}
WaitForExceptionIfCancelled ( ) ; // wait outside of finally
}
catch ( ThreadAbortException e ) {
if ( e . ExceptionState ! = null & &
e . ExceptionState is HttpApplication . CancelModuleException & &
( ( HttpApplication . CancelModuleException ) e . ExceptionState ) . Timeout ) {
Thread . ResetAbort ( ) ;
PerfCounters . IncrementCounter ( AppPerfCounter . REQUESTS_TIMED_OUT ) ;
throw new HttpException ( SR . GetString ( SR . Request_timed_out ) ,
null , WebEventCodes . RuntimeErrorRequestAbort ) ;
}
}
}
internal void PushTraceContext ( ) {
if ( _traceContextStack = = null ) {
_traceContextStack = new Stack ( ) ;
}
// push current TraceContext on stack
_traceContextStack . Push ( _topTraceContext ) ;
// now make a new one for the top if necessary
if ( _topTraceContext ! = null ) {
TraceContext tc = new TraceContext ( this ) ;
_topTraceContext . CopySettingsTo ( tc ) ;
_topTraceContext = tc ;
}
}
internal void PopTraceContext ( ) {
Debug . Assert ( _traceContextStack ! = null ) ;
_topTraceContext = ( TraceContext ) _traceContextStack . Pop ( ) ;
}
internal bool RequestRequiresAuthorization ( ) {
#if ! FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features
// if current user is anonymous, then trivially, this page does not require authorization
if ( ! User . Identity . IsAuthenticated )
return false ;
// Ask each of the authorization modules
return
( FileAuthorizationModule . RequestRequiresAuthorization ( this ) | |
UrlAuthorizationModule . RequestRequiresAuthorization ( this ) ) ;
#else // !FEATURE_PAL
return false ; // ROTORTODO
#endif // !FEATURE_PAL
}
internal int CallISAPI ( UnsafeNativeMethods . CallISAPIFunc iFunction , byte [ ] bufIn , byte [ ] bufOut ) {
if ( _wr = = null | | ! ( _wr is System . Web . Hosting . ISAPIWorkerRequest ) )
throw new HttpException ( SR . GetString ( SR . Cannot_call_ISAPI_functions ) ) ;
#if ! FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features
return ( ( System . Web . Hosting . ISAPIWorkerRequest ) _wr ) . CallISAPI ( iFunction , bufIn , bufOut ) ;
#else // !FEATURE_PAL
throw new NotImplementedException ( "ROTORTODO" ) ;
#endif // !FEATURE_PAL
}
internal void SendEmptyResponse ( ) {
#if ! FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features
if ( _wr ! = null & & ( _wr is System . Web . Hosting . ISAPIWorkerRequest ) )
( ( System . Web . Hosting . ISAPIWorkerRequest ) _wr ) . SendEmptyResponse ( ) ;
#endif // !FEATURE_PAL
}
private CookielessHelperClass _CookielessHelper ;
internal CookielessHelperClass CookielessHelper {
get {
if ( _CookielessHelper = = null )
_CookielessHelper = new CookielessHelperClass ( this ) ;
return _CookielessHelper ;
}
}
// When a thread enters the pipeline, we may need to set the cookie in the CallContext.
internal void ResetSqlDependencyCookie ( ) {
if ( _sqlDependencyCookie ! = null ) {
System . Runtime . Remoting . Messaging . CallContext . LogicalSetData ( SqlCacheDependency . SQL9_OUTPUT_CACHE_DEPENDENCY_COOKIE , _sqlDependencyCookie ) ;
}
}
// When a thread leaves the pipeline, we may need to remove the cookie from the CallContext.
internal void RemoveSqlDependencyCookie ( ) {
if ( _sqlDependencyCookie ! = null ) {
System . Runtime . Remoting . Messaging . CallContext . LogicalSetData ( SqlCacheDependency . SQL9_OUTPUT_CACHE_DEPENDENCY_COOKIE , null ) ;
}
}
internal string SqlDependencyCookie {
get {
return _sqlDependencyCookie ;
}
set {
_sqlDependencyCookie = value ;
System . Runtime . Remoting . Messaging . CallContext . LogicalSetData ( SqlCacheDependency . SQL9_OUTPUT_CACHE_DEPENDENCY_COOKIE , value ) ;
}
}
//
// integrated pipeline related
//
internal NotificationContext NotificationContext {
get { return _notificationContext ; }
set { _notificationContext = value ; }
}
public RequestNotification CurrentNotification {
get {
EnsureHasNotTransitionedToWebSocket ( ) ;
if ( ! HttpRuntime . UseIntegratedPipeline ) {
throw new PlatformNotSupportedException ( SR . GetString ( SR . Requires_Iis_Integrated_Mode ) ) ;
}
return _notificationContext . CurrentNotification ;
}
internal set {
if ( ! HttpRuntime . UseIntegratedPipeline ) {
throw new PlatformNotSupportedException ( SR . GetString ( SR . Requires_Iis_Integrated_Mode ) ) ;
}
_notificationContext . CurrentNotification = value ;
}
}
internal bool IsChangeInServerVars {
get { return ( _notificationContext . CurrentNotificationFlags & FLAG_CHANGE_IN_SERVER_VARIABLES ) = = FLAG_CHANGE_IN_SERVER_VARIABLES ; }
}
internal bool IsChangeInRequestHeaders {
get { return ( _notificationContext . CurrentNotificationFlags & FLAG_CHANGE_IN_REQUEST_HEADERS ) = = FLAG_CHANGE_IN_REQUEST_HEADERS ; }
}
internal bool IsChangeInResponseHeaders {
get { return ( _notificationContext . CurrentNotificationFlags & FLAG_CHANGE_IN_RESPONSE_HEADERS ) = = FLAG_CHANGE_IN_RESPONSE_HEADERS ; }
}
internal bool IsChangeInResponseStatus {
get { return ( _notificationContext . CurrentNotificationFlags & FLAG_CHANGE_IN_RESPONSE_STATUS ) = = FLAG_CHANGE_IN_RESPONSE_STATUS ; }
}
internal bool IsChangeInUserPrincipal {
get { return ( _notificationContext . CurrentNotificationFlags & FLAG_CHANGE_IN_USER_OBJECT ) = = FLAG_CHANGE_IN_USER_OBJECT ; }
}
internal bool IsSendResponseHeaders {
get { return ( _notificationContext . CurrentNotificationFlags & FLAG_SEND_RESPONSE_HEADERS ) = = FLAG_SEND_RESPONSE_HEADERS ; }
}
internal void SetImpersonationEnabled ( ) {
IdentitySection c = RuntimeConfig . GetConfig ( this ) . Identity ;
_impersonationEnabled = ( c ! = null & & c . Impersonate ) ;
}
internal bool UsesImpersonation {
get {
// if we're on a UNC share and we have a UNC token, then use impersonation for all notifications
if ( HttpRuntime . IsOnUNCShareInternal & & HostingEnvironment . ApplicationIdentityToken ! = IntPtr . Zero ) {
return true ;
}
// if <identity impersonate=/> is false, then don't use impersonation
if ( ! _impersonationEnabled ) {
return false ;
}
// the notification context won't be available after we have completed the transition
if ( HasWebSocketRequestTransitionCompleted ) {
return true ;
}
// if this notification is after AuthenticateRequest and not a SendResponse notification, use impersonation
return ( ( ( _notificationContext . CurrentNotification = = RequestNotification . AuthenticateRequest & & _notificationContext . IsPostNotification )
| | _notificationContext . CurrentNotification > RequestNotification . AuthenticateRequest )
& & _notificationContext . CurrentNotification ! = RequestNotification . SendResponse ) ;
}
}
internal bool AreResponseHeadersSent {
get { return ( _notificationContext . CurrentNotificationFlags & FLAG_RESPONSE_HEADERS_SENT ) = = FLAG_RESPONSE_HEADERS_SENT ; }
}
internal bool NeedToInitializeApp ( ) {
bool needToInit = ! _isAppInitialized ;
if ( needToInit ) {
_isAppInitialized = true ;
}
return needToInit ;
}
// flags passed in on the call to PipelineRuntime::ProcessRequestNotification
internal int CurrentNotificationFlags {
get {
return _notificationContext . CurrentNotificationFlags ;
}
set {
_notificationContext . CurrentNotificationFlags = value ;
}
}
// index of the current "module" running the request
// into the application module array
internal int CurrentModuleIndex {
get {
return _notificationContext . CurrentModuleIndex ;
}
set {
_notificationContext . CurrentModuleIndex = value ;
}
}
// Each module has a PipelineModuleStepContainer
// which stores/manages a list of event handlers
// that correspond to each RequestNotification.
// CurrentModuleEventIndex is the index (for the current
// module) of the current event handler.
// This will be greater than one when a single
// module registers multiple delegates for a single event.
// e.g.
// app.BeginRequest += Foo;
// app.BeginRequest += Bar;
internal int CurrentModuleEventIndex {
get {
return _notificationContext . CurrentModuleEventIndex ;
}
set {
_notificationContext . CurrentModuleEventIndex = value ;
}
}
internal void DisableNotifications ( RequestNotification notifications , RequestNotification postNotifications ) {
IIS7WorkerRequest wr = _wr as IIS7WorkerRequest ;
if ( null ! = wr ) {
wr . DisableNotifications ( notifications , postNotifications ) ;
}
}
public bool IsPostNotification {
get {
EnsureHasNotTransitionedToWebSocket ( ) ;
if ( ! HttpRuntime . UseIntegratedPipeline ) {
throw new PlatformNotSupportedException ( SR . GetString ( SR . Requires_Iis_Integrated_Mode ) ) ;
}
return _notificationContext . IsPostNotification ;
}
internal set {
if ( ! HttpRuntime . UseIntegratedPipeline ) {
throw new PlatformNotSupportedException ( SR . GetString ( SR . Requires_Iis_Integrated_Mode ) ) ;
}
_notificationContext . IsPostNotification = value ;
}
}
// user token for the request
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This is a safe critical method.")]
internal IntPtr ClientIdentityToken {
get {
if ( _wr ! = null ) {
return _wr . GetUserToken ( ) ;
}
else {
return IntPtr . Zero ;
}
}
}
// is configured to impersonate client?
internal bool IsClientImpersonationConfigured {
get {
try {
IdentitySection c = RuntimeConfig . GetConfig ( this ) . Identity ;
return ( c ! = null & & c . Impersonate & & c . ImpersonateToken = = IntPtr . Zero ) ;
}
catch {
// this property should not throw as it is used in the error reporting pass
// config errors will be reported elsewhere
return false ;
}
}
}
internal IntPtr ImpersonationToken {
get {
// by default use app identity
IntPtr token = HostingEnvironment . ApplicationIdentityToken ;
IdentitySection c = RuntimeConfig . GetConfig ( this ) . Identity ;
if ( c ! = null ) {
if ( c . Impersonate ) {
token = ( c . ImpersonateToken ! = IntPtr . Zero ) ? c . ImpersonateToken : ClientIdentityToken ;
}
else {
// for non-UNC case impersonate="false" means "don't impersonate",
// but there is a special case for UNC shares - even if
// impersonate="false" we still impersonate the UNC identity
// (hosting identity). and this is how v1.x works as well
if ( ! HttpRuntime . IsOnUNCShareInternal ) {
token = IntPtr . Zero ;
}
}
}
return token ;
}
}
internal AspNetSynchronizationContextBase SyncContext {
get {
if ( _syncContext = = null ) {
_syncContext = CreateNewAspNetSynchronizationContext ( ) ;
}
return _syncContext ;
}
set {
_syncContext = value ;
}
}
internal AspNetSynchronizationContextBase InstallNewAspNetSynchronizationContext ( ) {
AspNetSynchronizationContextBase syncContext = _syncContext ;
if ( syncContext ! = null & & syncContext = = AsyncOperationManager . SynchronizationContext ) {
// using current ASP.NET synchronization context - switch it
_syncContext = CreateNewAspNetSynchronizationContext ( ) ;
AsyncOperationManager . SynchronizationContext = _syncContext ;
return syncContext ;
}
return null ;
}
private AspNetSynchronizationContextBase CreateNewAspNetSynchronizationContext ( ) {
if ( ! AppSettings . UseTaskFriendlySynchronizationContext ) {
return new LegacyAspNetSynchronizationContext ( ApplicationInstance ) ;
}
else {
return new AspNetSynchronizationContext ( ApplicationInstance ) ;
}
}
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This is a safe critical method.")]
internal void RestoreSavedAspNetSynchronizationContext ( AspNetSynchronizationContextBase syncContext ) {
AsyncOperationManager . SynchronizationContext = syncContext ;
_syncContext = syncContext ;
}
internal string [ ] UserLanguagesFromContext ( ) {
return ( Request ! = null ) ? Request . UserLanguages : null ;
}
// References should be nulled a.s.a.p. to reduce working set
internal void ClearReferences ( ) {
_appInstance = null ;
_handler = null ;
_handlerStack = null ;
_currentHandler = null ;
_remapHandler = null ;
if ( _isIntegratedPipeline ) {
if ( ! HasWebSocketRequestTransitionStarted ) {
// Items is also used by AspNetWebSocketContext and should only be cleared if we're not transitioning to WebSockets
_items = null ;
}
_syncContext = null ;
}
}
internal void CompleteTransitionToWebSocket ( ) {
ClearReferencesForWebSocketProcessing ( ) ;
// transition: TransitionStarted -> TransitionCompleted
TransitionToWebSocketState ( WebSocketTransitionState . TransitionCompleted ) ;
}
// This is much stronger than just ClearReferences; it tries to free absolutely as much memory as possible.
// Some necessary items (like _wr, etc.) are preserved. The reason we want to modify this particular instance
// in-place rather than create a new instance is that it is likely that references to this object still exist,
// and we don't want the existence of those references to cause memory leaks.
private void ClearReferencesForWebSocketProcessing ( ) {
HttpResponse response = _response ;
// everything not marked [DoNotReset] should be eligible for garbage collection
ReflectionUtil . Reset ( this ) ;
// Miscellaneous steps:
_request . ClearReferencesForWebSocketProcessing ( ) ; // also clean up the HttpRequest instance
if ( response ! = null ) {
// HttpResponse is off-limits, but it is possible that the developer accidentally maintained a reference
// to it, e.g. via a closure. We'll release the HttpResponse's references to all its data to prevent
// this from causing memory problems.
ReflectionUtil . Reset ( response ) ;
}
}
internal CultureInfo CultureFromConfig ( string configString , bool requireSpecific ) {
//auto
if ( StringUtil . EqualsIgnoreCase ( configString , HttpApplication . AutoCulture ) ) {
string [ ] userLanguages = UserLanguagesFromContext ( ) ;
if ( userLanguages ! = null ) {
try {
return CultureUtil . CreateReadOnlyCulture ( userLanguages , requireSpecific ) ;
}
catch {
return null ;
}
}
else {
return null ;
}
}
else if ( StringUtil . StringStartsWithIgnoreCase ( configString , "auto:" ) ) {
string [ ] userLanguages = UserLanguagesFromContext ( ) ;
if ( userLanguages ! = null ) {
try {
return CultureUtil . CreateReadOnlyCulture ( userLanguages , requireSpecific ) ;
}
catch {
return CultureUtil . CreateReadOnlyCulture ( configString . Substring ( 5 /* "auto:".Length */ ) , requireSpecific ) ;
}
}
else {
return CultureUtil . CreateReadOnlyCulture ( configString . Substring ( 5 /* "auto:".Length */ ) , requireSpecific ) ;
}
}
return CultureUtil . CreateReadOnlyCulture ( configString , requireSpecific ) ;
}
private enum WebSocketInitStatus {
Success , // iiswsock.dll is active and has told us that the current request is a WebSocket request
RequiresIntegratedMode , // WebSockets requires integrated mode, and the current server is not Integrated mode
CannotCallFromBeginRequest , // We need to wait for BeginRequest to complete before the module has set the server variables
NativeModuleNotEnabled , // iiswsock.dll isn't active in the pipeline
NotAWebSocketRequest , // iiswsock.dll is active, but the current request is not a WebSocket request
CurrentRequestIsChildRequest , // We are currently inside of a child request (IHttpContext::ExecuteRequest)
}
private void AbortConnection ( ) {
IIS7WorkerRequest wr = _wr as IIS7WorkerRequest ;
if ( wr ! = null ) {
// Direct API Abort is suported in integrated mode only
wr . AbortConnection ( ) ;
}
else {
// Close in classic mode acts as Abort (see HSE_REQ_CLOSE_CONNECTION)
// It closes the underlined connection
_wr . CloseConnection ( ) ;
}
}
}
//
// Helper class to add/remove HttpContext to/from CallContext
//
// using (new DisposableHttpContextWrapper(context)) {
// // this code will have HttpContext.Current working
// }
//
internal class DisposableHttpContextWrapper : IDisposable {
private bool _needToUndo ;
private HttpContext _savedContext ;
internal static HttpContext SwitchContext ( HttpContext context ) {
return ContextBase . SwitchContext ( context ) as HttpContext ;
}
internal DisposableHttpContextWrapper ( HttpContext context ) {
if ( context ! = null ) {
_savedContext = SwitchContext ( context ) ;
_needToUndo = ( _savedContext ! = context ) ;
}
}
void IDisposable . Dispose ( ) {
if ( _needToUndo ) {
SwitchContext ( _savedContext ) ;
_savedContext = null ;
_needToUndo = false ;
}
}
}
}