1 //------------------------------------------------------------------------------ 2 // <copyright file="HttpContext.cs" company="Microsoft"> 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // </copyright> 5 //------------------------------------------------------------------------------ 6 7 /* 8 * HttpContext class 9 * 10 * Copyright (c) 1999 Microsoft Corporation 11 */ 12 13 namespace System.Web { 14 using System; 15 using System.Collections; 16 using System.Collections.Generic; 17 using System.Collections.ObjectModel; 18 using System.ComponentModel; 19 using System.Configuration; 20 using System.Diagnostics.CodeAnalysis; 21 using System.Globalization; 22 using System.Linq; 23 using System.Net; 24 using System.Reflection; 25 using System.Runtime.CompilerServices; 26 using System.Runtime.Remoting.Messaging; 27 using System.Security.Permissions; 28 using System.Security.Principal; 29 using System.Threading; 30 using System.Threading.Tasks; 31 using System.Web.Caching; 32 using System.Web.Compilation; 33 using System.Web.Configuration; 34 using System.Web.Hosting; 35 using System.Web.Instrumentation; 36 using System.Web.Management; 37 using System.Web.Profile; 38 using System.Web.Security; 39 using System.Web.SessionState; 40 using System.Web.UI; 41 using System.Web.Util; 42 using System.Web.WebSockets; 43 44 45 /// <devdoc> 46 /// <para>Encapsulates 47 /// all HTTP-specific 48 /// context used by the HTTP server to process Web requests.</para> 49 /// <para>System.Web.IHttpModules and System.Web.IHttpHandler instances are provided a 50 /// reference to an appropriate HttpContext object. For example 51 /// the Request and Response 52 /// objects.</para> 53 /// </devdoc> 54 [SuppressMessage("Microsoft.Usage", "CA2302:FlagServiceProviders", Justification = "The service provider implementation is only for specific types which are not com interop types.")] 55 public sealed class HttpContext : IServiceProvider, IPrincipalContainer 56 { 57 58 internal static readonly Assembly SystemWebAssembly = typeof(HttpContext).Assembly; 59 private static volatile bool s_eurlSet; 60 private static string s_eurl; 61 62 private IHttpAsyncHandler _asyncAppHandler; // application as handler (not always HttpApplication) 63 private AsyncPreloadModeFlags _asyncPreloadModeFlags; 64 private bool _asyncPreloadModeFlagsSet; 65 private HttpApplication _appInstance; 66 private IHttpHandler _handler; 67 [DoNotReset] 68 private HttpRequest _request; 69 private HttpResponse _response; 70 private HttpServerUtility _server; 71 private Stack _traceContextStack; 72 private TraceContext _topTraceContext; 73 [DoNotReset] 74 private Hashtable _items; 75 private ArrayList _errors; 76 private Exception _tempError; 77 private bool _errorCleared; 78 [DoNotReset] 79 private IPrincipalContainer _principalContainer; 80 [DoNotReset] 81 internal ProfileBase _Profile; 82 [DoNotReset] 83 private DateTime _utcTimestamp; 84 [DoNotReset] 85 private HttpWorkerRequest _wr; 86 private VirtualPath _configurationPath; 87 internal bool _skipAuthorization; 88 [DoNotReset] 89 private CultureInfo _dynamicCulture; 90 [DoNotReset] 91 private CultureInfo _dynamicUICulture; 92 private int _serverExecuteDepth; 93 private Stack _handlerStack; 94 private bool _preventPostback; 95 private bool _runtimeErrorReported; 96 private PageInstrumentationService _pageInstrumentationService = null; 97 private ReadOnlyCollection<string> _webSocketRequestedProtocols; 98 99 // timeout support 100 [DoNotReset] 101 private CancellationTokenHelper _timeoutCancellationTokenHelper; // used for TimedOutToken 102 103 private long _timeoutStartTimeUtcTicks = -1; // should always be accessed atomically; -1 means uninitialized 104 private long _timeoutTicks = -1; // should always be accessed atomically; -1 means uninitialized 105 private int _timeoutState; // 0=non-cancelable, 1=cancelable, -1=canceled 106 private DoubleLink _timeoutLink; // link in the timeout's manager list 107 private bool _threadAbortOnTimeout = true; // whether we should Thread.Abort() this thread when it times out 108 private Thread _thread; 109 110 // cached configuration 111 private CachedPathData _configurationPathData; // Cached data if _configurationPath != null 112 private CachedPathData _filePathData; // Cached data of the file being requested 113 114 // Sql Cache Dependency 115 private string _sqlDependencyCookie; 116 117 // Session State 118 volatile SessionStateModule _sessionStateModule; 119 volatile bool _delayedSessionState; // Delayed session state item 120 121 // non-compiled pages 122 private TemplateControl _templateControl; 123 124 // integrated pipeline state 125 126 // For the virtual Disposing / Disposed events 127 private SubscriptionQueue<Action<HttpContext>> _requestCompletedQueue; 128 [DoNotReset] 129 private SubscriptionQueue<IDisposable> _pipelineCompletedQueue; 130 131 // keep synchronized with mgdhandler.hxx 132 private const int FLAG_NONE = 0x0; 133 private const int FLAG_CHANGE_IN_SERVER_VARIABLES = 0x1; 134 private const int FLAG_CHANGE_IN_REQUEST_HEADERS = 0x2; 135 private const int FLAG_CHANGE_IN_RESPONSE_HEADERS = 0x4; 136 private const int FLAG_CHANGE_IN_USER_OBJECT = 0x8; 137 private const int FLAG_SEND_RESPONSE_HEADERS = 0x10; 138 private const int FLAG_RESPONSE_HEADERS_SENT = 0x20; 139 internal const int FLAG_ETW_PROVIDER_ENABLED = 0x40; 140 private const int FLAG_CHANGE_IN_RESPONSE_STATUS = 0x80; 141 142 private volatile NotificationContext _notificationContext; 143 private bool _isAppInitialized; 144 [DoNotReset] 145 private bool _isIntegratedPipeline; 146 private bool _finishPipelineRequestCalled; 147 [DoNotReset] 148 private bool _impersonationEnabled; 149 150 internal bool HideRequestResponse; 151 internal volatile bool InIndicateCompletion; 152 internal volatile ThreadContext IndicateCompletionContext = null; 153 internal volatile Thread ThreadInsideIndicateCompletion = null; 154 155 156 // This field is a surrogate for the HttpContext object itself. Our HostExecutionContextManager 157 // shouldn't capture a reference to the HttpContext itself since these references could be long-lived, 158 // e.g. if they're captured by a call to ThreadPool.QueueUserWorkItem or a Timer. This would cause the 159 // associated HttpContext object graph to be long-lived, which would negatively affect performance. 160 // Instead we capture a reference to this 'Id' object, which allows the HostExecutionContextManager 161 // to compare the original captured HttpContext with the current HttpContext without actually 162 // holding on to the original HttpContext instance. 163 [DoNotReset] 164 internal readonly object ThreadContextId = new object(); 165 166 // synchronization context (for EAP / TAP models) 167 private AspNetSynchronizationContextBase _syncContext; 168 169 // This field doesn't need to be volatile since it will only ever be written to by a single thread, and when that thread 170 // later reads the field it will be guaranteed non-null. We don't care what other threads see, since it will never be 171 // equal to Thread.CurrentThread for them regardless of whether those threads are seeing the latest value of this field. 172 // This field should not be marked [DoNotReset] since we want it to be cleared when WebSocket processing begins. 173 internal Thread _threadWhichStartedWebSocketTransition; 174 175 // WebSocket state 176 [DoNotReset] 177 private WebSocketTransitionState _webSocketTransitionState; // see comments in WebSocketTransitionState.cs for detailed info on this enum 178 [DoNotReset] 179 private string _webSocketNegotiatedProtocol; 180 181 // see comments on WebSocketInitStatus for what all of these codes mean GetWebSocketInitStatus()182 private WebSocketInitStatus GetWebSocketInitStatus() { 183 IIS7WorkerRequest iis7wr =_wr as IIS7WorkerRequest; 184 if (iis7wr == null) { 185 return WebSocketInitStatus.RequiresIntegratedMode; 186 } 187 188 if (CurrentNotification <= RequestNotification.BeginRequest) { 189 return WebSocketInitStatus.CannotCallFromBeginRequest; 190 } 191 192 if (!iis7wr.IsWebSocketRequest()) { 193 if (iis7wr.IsWebSocketModuleActive()) { 194 return WebSocketInitStatus.NotAWebSocketRequest; 195 } 196 else { 197 return WebSocketInitStatus.NativeModuleNotEnabled; 198 } 199 } 200 201 if (iis7wr.GetIsChildRequest()) { 202 return WebSocketInitStatus.CurrentRequestIsChildRequest; 203 } 204 205 return WebSocketInitStatus.Success; 206 } 207 208 // Returns true if the request contained the initial WebSocket handshake 209 // and IIS's WebSocket module is active. 210 public bool IsWebSocketRequest { 211 get { 212 // If AcceptWebSocketRequest has already been called and run to completion, then this 213 // is obviously a WebSocket request and we can skip further checks (which might throw). 214 if (IsWebSocketRequestUpgrading) { 215 return true; 216 } 217 218 switch (GetWebSocketInitStatus()) { 219 case WebSocketInitStatus.RequiresIntegratedMode: 220 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode)); 221 222 case WebSocketInitStatus.CannotCallFromBeginRequest: 223 throw new InvalidOperationException(SR.GetString(SR.WebSockets_CannotBeCalledDuringBeginRequest)); 224 225 case WebSocketInitStatus.Success: 226 return true; 227 228 default: 229 return false; 230 } 231 } 232 } 233 234 // While unwinding an HTTP request this indicates if the developer 235 // told ASP.NET that they wanted to transition to a websocket request 236 public bool IsWebSocketRequestUpgrading { 237 get { return (WebSocketTransitionState >= WebSocketTransitionState.AcceptWebSocketRequestCalled); } 238 } 239 240 internal bool HasWebSocketRequestTransitionStarted { 241 get { return WebSocketTransitionState >= WebSocketTransitionState.TransitionStarted; } 242 } 243 244 internal bool HasWebSocketRequestTransitionCompleted { 245 get { return WebSocketTransitionState >= WebSocketTransitionState.TransitionCompleted; } 246 } 247 248 internal WebSocketTransitionState WebSocketTransitionState { 249 get { return _webSocketTransitionState; } 250 private set { _webSocketTransitionState = value; } 251 } 252 253 // Returns the ordered list of protocols requested by the client, 254 // or an empty collection if this wasn't a WebSocket request or there was no list present. 255 public IList<string> WebSocketRequestedProtocols { 256 get { 257 if (IsWebSocketRequest) { 258 if (_webSocketRequestedProtocols == null) { 259 string rawHeaderValue = _wr.GetUnknownRequestHeader("Sec-WebSocket-Protocol"); 260 IList<string> requestedProtocols = SubProtocolUtil.ParseHeader(rawHeaderValue); // checks for invalid values 261 _webSocketRequestedProtocols = new ReadOnlyCollection<string>(requestedProtocols ?? new string[0]); 262 } 263 return _webSocketRequestedProtocols; 264 } 265 else { 266 // not a WebSocket request 267 return null; 268 } 269 } 270 } 271 272 // Returns the negotiated protocol (sent from the server to the client) for a 273 // WebSocket request. 274 public string WebSocketNegotiatedProtocol { 275 get { return _webSocketNegotiatedProtocol; } 276 } 277 AcceptWebSocketRequest(Func<AspNetWebSocketContext, Task> userFunc)278 public void AcceptWebSocketRequest(Func<AspNetWebSocketContext, Task> userFunc) { 279 AcceptWebSocketRequest(userFunc, null); 280 } 281 282 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This is a safe critical method.")] AcceptWebSocketRequest(Func<AspNetWebSocketContext, Task> userFunc, AspNetWebSocketOptions options)283 public void AcceptWebSocketRequest(Func<AspNetWebSocketContext, Task> userFunc, AspNetWebSocketOptions options) { 284 // Begin argument & state checking 285 286 // We throw different error codes depending on the check that failed. Things that are 287 // server configuration errors (WebSockets not enabled) or developer errors (called this 288 // method with bad parameters) result in an appropriate exception type. Things that are 289 // remote errors (e.g. bad parameters from the client) result in an HTTP 4xx. 290 291 if (userFunc == null) { 292 throw new ArgumentNullException("userFunc"); 293 } 294 295 if (IsWebSocketRequestUpgrading) { 296 // this method cannot be called multiple times 297 throw new InvalidOperationException(SR.GetString(SR.WebSockets_AcceptWebSocketRequestCanOnlyBeCalledOnce)); 298 } 299 300 // DevDiv #384514: Task<T> doesn't work correctly using the legacy SynchronizationContext setting. Since 301 // WebSockets operation requires correct Task<T> behavior, we should forbid using the feature when legacy 302 // mode is enabled. 303 SynchronizationContextUtil.ValidateModeForWebSockets(); 304 305 switch (GetWebSocketInitStatus()) { 306 case WebSocketInitStatus.RequiresIntegratedMode: 307 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode)); 308 309 case WebSocketInitStatus.CannotCallFromBeginRequest: 310 throw new InvalidOperationException(SR.GetString(SR.WebSockets_CannotBeCalledDuringBeginRequest)); 311 312 case WebSocketInitStatus.NativeModuleNotEnabled: 313 throw new PlatformNotSupportedException(SR.GetString(SR.WebSockets_WebSocketModuleNotEnabled)); 314 315 case WebSocketInitStatus.NotAWebSocketRequest: 316 throw new HttpException((int)HttpStatusCode.BadRequest, SR.GetString(SR.WebSockets_NotAWebSocketRequest)); 317 318 case WebSocketInitStatus.CurrentRequestIsChildRequest: 319 throw new InvalidOperationException(SR.GetString(SR.WebSockets_CannotBeCalledDuringChildExecute)); 320 321 case WebSocketInitStatus.Success: 322 break; 323 324 default: 325 // fallback error message - not a WebSocket request 326 throw new HttpException(SR.GetString(SR.WebSockets_UnknownErrorWhileAccepting)); 327 } 328 329 if (CurrentNotification > RequestNotification.ExecuteRequestHandler) { 330 // it is too late to call this method 331 throw new InvalidOperationException(SR.GetString(SR.WebSockets_CannotBeCalledAfterHandlerExecute)); 332 } 333 // End argument & state checking 334 335 IIS7WorkerRequest wr = (IIS7WorkerRequest)_wr; 336 337 // Begin options checking and parsing 338 if (options != null && options.RequireSameOrigin) { 339 if (!WebSocketUtil.IsSameOriginRequest(wr)) { 340 // use Forbidden (HTTP 403) since it's not an authentication error; it's a usage error 341 throw new HttpException((int)HttpStatusCode.Forbidden, SR.GetString(SR.WebSockets_OriginCheckFailed)); 342 } 343 } 344 345 string subprotocol = null; 346 if (options != null && !String.IsNullOrEmpty(options.SubProtocol)) { 347 // AspNetWebSocketOptions.set_SubProtocol() already checked that the provided value is valid 348 subprotocol = options.SubProtocol; 349 } 350 351 if (subprotocol != null) { 352 IList<string> incomingProtocols = WebSocketRequestedProtocols; 353 if (incomingProtocols == null || !incomingProtocols.Contains(subprotocol, StringComparer.Ordinal)) { 354 // The caller requested a subprotocol that wasn't in the list of accepted protocols coming from the client. 355 // This is disallowed by the WebSockets protocol spec, Sec. 5.2.2 (#2). 356 throw new ArgumentException(SR.GetString(SR.WebSockets_SubProtocolCannotBeNegotiated, subprotocol), "options"); 357 } 358 } 359 // End options checking and parsing 360 361 wr.AcceptWebSocket(); 362 363 // transition: Inactive -> AcceptWebSocketRequestCalled 364 TransitionToWebSocketState(WebSocketTransitionState.AcceptWebSocketRequestCalled); 365 366 Response.StatusCode = (int)HttpStatusCode.SwitchingProtocols; // 101 367 if (subprotocol != null) { 368 Response.AppendHeader("Sec-WebSocket-Protocol", subprotocol); 369 _webSocketNegotiatedProtocol = subprotocol; 370 } 371 RootedObjects.WebSocketPipeline = new WebSocketPipeline(RootedObjects, this, userFunc, subprotocol); 372 } 373 TransitionToWebSocketState(WebSocketTransitionState newState)374 internal void TransitionToWebSocketState(WebSocketTransitionState newState) { 375 // Make sure the state transition is happening in the correct order 376 #if DBG 377 WebSocketTransitionState expectedOldState = checked(newState - 1); 378 Debug.Assert(WebSocketTransitionState == expectedOldState, String.Format(CultureInfo.InvariantCulture, "Expected WebSocketTransitionState to be '{0}', but it was '{1}'.", expectedOldState, WebSocketTransitionState)); 379 #endif 380 381 WebSocketTransitionState = newState; 382 if (newState == Web.WebSocketTransitionState.TransitionStarted) { 383 _threadWhichStartedWebSocketTransition = Thread.CurrentThread; 384 } 385 } 386 387 internal bool DidCurrentThreadStartWebSocketTransition { 388 get { 389 return _threadWhichStartedWebSocketTransition == Thread.CurrentThread; 390 } 391 } 392 393 // helper that throws an exception if we have transitioned the current request to a WebSocket request EnsureHasNotTransitionedToWebSocket()394 internal void EnsureHasNotTransitionedToWebSocket() { 395 if (HasWebSocketRequestTransitionCompleted) { 396 throw new NotSupportedException(SR.GetString(SR.WebSockets_MethodNotAvailableDuringWebSocketProcessing)); 397 } 398 } 399 400 internal bool FirstRequest {get; set;} 401 402 // session state support 403 private bool _requiresSessionStateFromHandler; 404 internal bool RequiresSessionState { 405 get { 406 switch (SessionStateBehavior) { 407 case SessionStateBehavior.Required: 408 case SessionStateBehavior.ReadOnly: 409 return true; 410 case SessionStateBehavior.Disabled: 411 return false; 412 case SessionStateBehavior.Default: 413 default: 414 return _requiresSessionStateFromHandler; 415 } 416 } 417 } 418 419 private bool _readOnlySessionStateFromHandler; 420 internal bool ReadOnlySessionState { 421 get { 422 switch (SessionStateBehavior) { 423 case SessionStateBehavior.ReadOnly: 424 return true; 425 case SessionStateBehavior.Required: 426 case SessionStateBehavior.Disabled: 427 return false; 428 case SessionStateBehavior.Default: 429 default: 430 return _readOnlySessionStateFromHandler; 431 } 432 } 433 } 434 internal bool InAspCompatMode; 435 436 private IHttpHandler _remapHandler = null; 437 438 /// <include file='doc\HttpContext.uex' path='docs/doc[@for="HttpContext.HttpContext"]/*' /> 439 /// <devdoc> 440 /// <para> 441 /// Initializes a new instance of the HttpContext class. 442 /// </para> 443 /// </devdoc> HttpContext(HttpRequest request, HttpResponse response)444 public HttpContext(HttpRequest request, HttpResponse response) { 445 Init(request, response); 446 request.Context = this; 447 response.Context = this; 448 } 449 450 451 /// <devdoc> 452 /// <para> 453 /// Initializes a new instance of the HttpContext class. 454 /// </para> 455 /// </devdoc> HttpContext(HttpWorkerRequest wr)456 public HttpContext(HttpWorkerRequest wr) { 457 _wr = wr; 458 Init(new HttpRequest(wr, this), new HttpResponse(wr, this)); 459 _response.InitResponseWriter(); 460 } 461 462 // ctor used in HttpRuntime HttpContext(HttpWorkerRequest wr, bool initResponseWriter)463 internal HttpContext(HttpWorkerRequest wr, bool initResponseWriter) { 464 _wr = wr; 465 Init(new HttpRequest(wr, this), new HttpResponse(wr, this)); 466 467 if (initResponseWriter) 468 _response.InitResponseWriter(); 469 470 PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_EXECUTING); 471 } 472 Init(HttpRequest request, HttpResponse response)473 private void Init(HttpRequest request, HttpResponse response) { 474 _request = request; 475 _response = response; 476 _utcTimestamp = DateTime.UtcNow; 477 _principalContainer = this; 478 479 if (_wr is IIS7WorkerRequest) { 480 _isIntegratedPipeline = true; 481 } 482 483 if (!(_wr is System.Web.SessionState.StateHttpWorkerRequest)) 484 CookielessHelper.RemoveCookielessValuesFromPath(); // This ensures that the cookieless-helper is initialized and 485 // rewrites the path if the URI contains cookieless form-auth ticket, session-id, etc. 486 487 Profiler p = HttpRuntime.Profile; 488 if (p != null && p.IsEnabled) 489 _topTraceContext = new TraceContext(this); 490 491 // rewrite path in order to remove "/eurl.axd/guid", if it was 492 // added to the URL by aspnet_filter.dll. 493 string eurl = GetEurl(); 494 if (!String.IsNullOrEmpty(eurl)) { 495 string path = request.Path; 496 int idxStartEurl = path.Length - eurl.Length; 497 bool hasTrailingSlash = (path[path.Length - 1] == '/'); 498 if (hasTrailingSlash) { 499 idxStartEurl--; 500 } 501 if (idxStartEurl >= 0 502 && StringUtil.Equals(path, idxStartEurl, eurl, 0, eurl.Length)) { 503 // restore original URL 504 int originalUrlLen = idxStartEurl; 505 if (hasTrailingSlash) { 506 originalUrlLen++; 507 } 508 string originalUrl = path.Substring(0, originalUrlLen); 509 // Dev10 835901: We don't call HttpContext.RewritePath(path) because the 510 // original path may contain '?' encoded as %3F, and RewritePath 511 // would interpret what follows as the query string. So instead, we 512 // clear ConfigurationPath and call InternalRewritePath directly. 513 ConfigurationPath = null; 514 Request.InternalRewritePath(VirtualPath.Create(originalUrl), null, true); 515 } 516 } 517 } 518 519 // We have a feature that directs extensionless URLs 520 // into managed code by appending "/eurl.axd/guid" to the path. On IIS 6.0, 521 // we restore the URL as soon as we get into managed code. Here we get the 522 // actual value of "/eurl.axd/guid" and remember it. GetEurl()523 private string GetEurl() { 524 // only used on IIS 6.0 525 if (!(_wr is ISAPIWorkerRequestInProcForIIS6) 526 || (_wr is ISAPIWorkerRequestInProcForIIS7)) { 527 return null; 528 } 529 530 string eurl = s_eurl; 531 if (eurl == null && !s_eurlSet) { 532 try { 533 IntPtr pBuffer = UnsafeNativeMethods.GetExtensionlessUrlAppendage(); 534 if (pBuffer != IntPtr.Zero) { 535 eurl = StringUtil.StringFromWCharPtr(pBuffer, UnsafeNativeMethods.lstrlenW(pBuffer)); 536 } 537 } 538 catch {} // ignore all exceptions 539 s_eurl = eurl; 540 s_eurlSet = true; 541 } 542 return eurl; 543 } 544 545 // Current HttpContext off the call context 546 #if DBG SetDebugAssertOnAccessToCurrent(bool doAssert)547 internal static void SetDebugAssertOnAccessToCurrent(bool doAssert) { 548 if (doAssert) { 549 CallContext.SetData("__ContextAssert", String.Empty); 550 } 551 else { 552 CallContext.SetData("__ContextAssert", null); 553 } 554 } 555 556 private static bool NeedDebugAssertOnAccessToCurrent { 557 get { 558 return (CallContext.GetData("__ContextAssert") != null); 559 } 560 } 561 #endif 562 563 /// <devdoc> 564 /// <para>Returns the current HttpContext object.</para> 565 /// </devdoc> 566 public static HttpContext Current { 567 get { 568 #if DBG 569 if (NeedDebugAssertOnAccessToCurrent) { 570 Debug.Assert(ContextBase.Current != null); 571 } 572 #endif 573 return ContextBase.Current as HttpContext; 574 } 575 576 set { 577 ContextBase.Current = value; 578 } 579 } 580 581 // 582 // Root / unroot for the duration of async operation 583 // These are only used for the classic pipeline. The integrated pipeline uses a different rooting mechanism. 584 // 585 586 private IntPtr _rootedPtr; 587 588 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This is a safe critical method.")] Root()589 internal void Root() { 590 _rootedPtr = GCUtil.RootObject(this); 591 } 592 Unroot()593 internal void Unroot() { 594 GCUtil.UnrootObject(_rootedPtr); 595 _rootedPtr = IntPtr.Zero; 596 } 597 FinishPipelineRequest()598 internal void FinishPipelineRequest() { 599 if (!_finishPipelineRequestCalled) { 600 _finishPipelineRequestCalled = true; 601 HttpRuntime.FinishPipelineRequest(this); 602 } 603 } 604 605 // This is a virtual event which occurs when the HTTP part of this request is winding down, e.g. after EndRequest 606 // but before the WebSockets pipeline kicks in. The HttpContext is still available for inspection and is provided 607 // as a parameter to the supplied callback. 608 [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate", Justification = @"The normal event pattern doesn't work between HttpContext and HttpContextBase since the signatures differ.")] AddOnRequestCompleted(Action<HttpContext> callback)609 public ISubscriptionToken AddOnRequestCompleted(Action<HttpContext> callback) { 610 if (callback == null) { 611 throw new ArgumentNullException("callback"); 612 } 613 614 return _requestCompletedQueue.Enqueue(callback); 615 } 616 RaiseOnRequestCompleted()617 internal void RaiseOnRequestCompleted() { 618 // The callbacks really shouldn't throw exceptions, but we have a catch block just in case. 619 // Since there's nobody else that can listen for these errors (the request is unwinding and 620 // user code will no longer run), we'll just log the error. 621 try { 622 _requestCompletedQueue.FireAndComplete(action => action(this)); 623 } 624 catch (Exception e) { 625 WebBaseEvent.RaiseRuntimeError(e, this); 626 } 627 finally { 628 // Dispose of TimedOutToken so that nobody tries using it after this point. 629 DisposeTimedOutToken(); 630 } 631 } 632 633 // Allows an object's Dispose() method to be called when the pipeline part of this request is completed, e.g. 634 // after both the HTTP part and the WebSockets loop have completed. The HttpContext is not available for 635 // inspection, and HttpContext.Current will be null. 636 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This is a safe critical method.")] DisposeOnPipelineCompleted(IDisposable target)637 public ISubscriptionToken DisposeOnPipelineCompleted(IDisposable target) { 638 if (target == null) { 639 throw new ArgumentNullException("target"); 640 } 641 642 if (RootedObjects != null) { 643 // integrated pipeline 644 return RootedObjects.DisposeOnPipelineCompleted(target); 645 } 646 else { 647 // classic pipeline 648 return _pipelineCompletedQueue.Enqueue(target); 649 } 650 } 651 RaiseOnPipelineCompleted()652 internal void RaiseOnPipelineCompleted() { 653 // The callbacks really shouldn't throw exceptions, but we have a catch block just in case. 654 // Since there's nobody else that can listen for these errors (the request is unwinding and 655 // user code will no longer run), we'll just log the error. 656 try { 657 _pipelineCompletedQueue.FireAndComplete(disposable => disposable.Dispose()); 658 } 659 catch (Exception e) { 660 WebBaseEvent.RaiseRuntimeError(e, null); 661 } 662 } 663 ValidatePath()664 internal void ValidatePath() { 665 CachedPathData pathData = GetConfigurationPathData(); 666 pathData.ValidatePath(_request.PhysicalPathInternal); 667 } 668 669 670 // IServiceProvider implementation 671 672 /// <internalonly/> IServiceProvider.GetService(Type service)673 Object IServiceProvider.GetService(Type service) { 674 Object obj; 675 676 if (service == typeof(HttpWorkerRequest)) { 677 InternalSecurityPermissions.UnmanagedCode.Demand(); 678 obj = _wr; 679 } 680 else if (service == typeof(HttpRequest)) 681 obj = Request; 682 else if (service == typeof(HttpResponse)) 683 obj = Response; 684 else if (service == typeof(HttpApplication)) 685 obj = ApplicationInstance; 686 else if (service == typeof(HttpApplicationState)) 687 obj = Application; 688 else if (service == typeof(HttpSessionState)) 689 obj = Session; 690 else if (service == typeof(HttpServerUtility)) 691 obj = Server; 692 else 693 obj = null; 694 695 return obj; 696 } 697 698 // 699 // Async app handler is remembered for the duration of execution of the 700 // request when application happens to be IHttpAsyncHandler. It is needed 701 // for HttpRuntime to remember the object on which to call OnEndRequest. 702 // 703 // The assumption is that application is a IHttpAsyncHandler, not always 704 // HttpApplication. 705 // 706 internal IHttpAsyncHandler AsyncAppHandler { 707 get { return _asyncAppHandler; } 708 set { _asyncAppHandler = value; } 709 } 710 711 public AsyncPreloadModeFlags AsyncPreloadMode { 712 get { 713 if (!_asyncPreloadModeFlagsSet) { 714 _asyncPreloadModeFlags = RuntimeConfig.GetConfig(this).HttpRuntime.AsyncPreloadMode; 715 _asyncPreloadModeFlagsSet = true; 716 } 717 return _asyncPreloadModeFlags; 718 } 719 set { 720 _asyncPreloadModeFlags = value; 721 _asyncPreloadModeFlagsSet = true; 722 } 723 } 724 725 // If this flag is not set, the AspNetSynchronizationContext associated with this request will throw 726 // exceptions when it detects the application misusing the async API. This can occur if somebody 727 // tries to call SynchronizationContext.Post / OperationStarted / etc. during a part of the 728 // pipeline where we weren't expecting asynchronous work to take place, if there is still 729 // outstanding asynchronous work when an asynchronous module or handler signals completion, etc. 730 // It is meant as a safety net to let developers know early on when they're writing async code 731 // which doesn't fit our expected patterns and where that code likely has negative side effects. 732 // 733 // This flag is respected only by AspNetSynchronizationContext; it has no effect when the 734 // legacy sync context is in use. 735 [EditorBrowsable(EditorBrowsableState.Advanced)] 736 public bool AllowAsyncDuringSyncStages { 737 get { 738 return SyncContext.AllowAsyncDuringSyncStages; 739 } 740 set { 741 SyncContext.AllowAsyncDuringSyncStages = value; 742 } 743 } 744 745 /// <devdoc> 746 /// <para>Retrieves a reference to the application object for the current Http request.</para> 747 /// </devdoc> 748 public HttpApplication ApplicationInstance { 749 get { 750 return _appInstance; 751 } 752 set { 753 // For integrated pipeline, once this is set to a non-null value, it can only be set to null. 754 // The setter should never have been made public. It probably happened in 1.0, before it was possible 755 // to have getter and setter with different accessibility. 756 if (_isIntegratedPipeline && _appInstance != null && value != null) { 757 throw new InvalidOperationException(SR.GetString(SR.Application_instance_cannot_be_changed)); 758 } 759 else { 760 _appInstance = value; 761 762 // Use HttpApplication instance custom allocator provider 763 if (_isIntegratedPipeline) { 764 // The provider allows null - everyone should fallback to default implementation 765 IAllocatorProvider allocator = _appInstance != null ? _appInstance.AllocatorProvider : null; 766 767 _response.SetAllocatorProvider(allocator); 768 ((IIS7WorkerRequest)_wr).AllocatorProvider = allocator; 769 } 770 } 771 } 772 } 773 774 775 /// <devdoc> 776 /// <para> 777 /// Retrieves a reference to the application object for the current 778 /// Http request. 779 /// </para> 780 /// </devdoc> 781 public HttpApplicationState Application { 782 get { return HttpApplicationFactory.ApplicationState; } 783 } 784 785 786 // flag to suppress use of custom HttpEncoder registered in web.config 787 // for example, yellow error pages should use the default encoder rather than a custom encoder 788 internal bool DisableCustomHttpEncoder { 789 get; 790 set; 791 } 792 793 794 /// <devdoc> 795 /// <para> 796 /// Retrieves or assigns a reference to the <see cref='System.Web.IHttpHandler'/> 797 /// object for the current request. 798 /// </para> 799 /// </devdoc> 800 public IHttpHandler Handler { 801 get { return _handler;} 802 set { 803 _handler = value; 804 _requiresSessionStateFromHandler = false; 805 _readOnlySessionStateFromHandler = false; 806 InAspCompatMode = false; 807 if (_handler != null) { 808 if (_handler is IRequiresSessionState) { 809 _requiresSessionStateFromHandler = true; 810 } 811 if (_handler is IReadOnlySessionState) { 812 _readOnlySessionStateFromHandler = true; 813 } 814 Page page = _handler as Page; 815 if (page != null && page.IsInAspCompatMode) { 816 InAspCompatMode = true; 817 } 818 } 819 } 820 } 821 822 823 /// <devdoc> 824 /// <para> 825 /// Retrieves or assigns a reference to the <see cref='System.Web.IHttpHandler'/> 826 /// object for the previous handler; 827 /// </para> 828 /// </devdoc> 829 830 public IHttpHandler PreviousHandler { 831 get { 832 if (_handlerStack == null || _handlerStack.Count == 0) 833 return null; 834 835 return (IHttpHandler)_handlerStack.Peek(); 836 } 837 } 838 839 840 /// <devdoc> 841 /// <para> 842 /// Retrieves or assigns a reference to the <see cref='System.Web.IHttpHandler'/> 843 /// object for the current executing handler; 844 /// </para> 845 /// </devdoc> 846 private IHttpHandler _currentHandler = null; 847 848 public IHttpHandler CurrentHandler { 849 get { 850 if (_currentHandler == null) 851 _currentHandler = _handler; 852 853 return _currentHandler; 854 } 855 } 856 RestoreCurrentHandler()857 internal void RestoreCurrentHandler() { 858 _currentHandler = (IHttpHandler)_handlerStack.Pop(); 859 } 860 SetCurrentHandler(IHttpHandler newtHandler)861 internal void SetCurrentHandler(IHttpHandler newtHandler) { 862 if (_handlerStack == null) { 863 _handlerStack = new Stack(); 864 } 865 _handlerStack.Push(CurrentHandler); 866 867 _currentHandler = newtHandler; 868 } 869 870 /// <devdoc> 871 /// <para> 872 /// Set custom mapping handler processing the request <see cref='System.Web.IHttpHandler'/> 873 /// </para> 874 /// </devdoc> RemapHandler(IHttpHandler handler)875 public void RemapHandler(IHttpHandler handler) { 876 EnsureHasNotTransitionedToWebSocket(); 877 878 IIS7WorkerRequest wr = _wr as IIS7WorkerRequest; 879 880 if (wr != null) { 881 // Remap handler not allowed after ResolveRequestCache notification 882 if (_notificationContext.CurrentNotification >= RequestNotification.MapRequestHandler) { 883 throw new InvalidOperationException(SR.GetString(SR.Invoke_before_pipeline_event, "HttpContext.RemapHandler", "HttpApplication.MapRequestHandler")); 884 } 885 886 string handlerTypeName = null; 887 string handlerName = null; 888 889 if (handler != null) { 890 Type handlerType = handler.GetType(); 891 892 handlerTypeName = handlerType.AssemblyQualifiedName; 893 handlerName = handlerType.FullName; 894 } 895 896 wr.SetRemapHandler(handlerTypeName, handlerName); 897 } 898 899 _remapHandler = handler; 900 } 901 902 internal IHttpHandler RemapHandlerInstance { 903 get { 904 return _remapHandler; 905 } 906 } 907 908 /// <devdoc> 909 /// <para> 910 /// Retrieves a reference to the target <see cref='System.Web.HttpRequest'/> 911 /// object for the current request. 912 /// </para> 913 /// </devdoc> 914 public HttpRequest Request { 915 get { 916 if (HideRequestResponse) 917 throw new HttpException(SR.GetString(SR.Request_not_available)); 918 return _request; 919 } 920 } 921 922 923 /// <devdoc> 924 /// <para> 925 /// Retrieves a reference to the <see cref='System.Web.HttpResponse'/> 926 /// object for the current response. 927 /// </para> 928 /// </devdoc> 929 public HttpResponse Response { 930 get { 931 if (HideRequestResponse || HasWebSocketRequestTransitionCompleted) 932 throw new HttpException(SR.GetString(SR.Response_not_available)); 933 return _response; 934 } 935 } 936 937 938 internal IHttpHandler TopHandler { 939 get { 940 if (_handlerStack == null) { 941 return _handler; 942 } 943 object[] handlers = _handlerStack.ToArray(); 944 if (handlers == null || handlers.Length == 0) { 945 return _handler; 946 } 947 return (IHttpHandler)handlers[handlers.Length - 1]; 948 } 949 } 950 951 952 /// <devdoc> 953 /// <para>Retrieves a reference to the <see cref='System.Web.TraceContext'/> object for the current 954 /// response.</para> 955 /// </devdoc> 956 public TraceContext Trace { 957 get { 958 if (_topTraceContext == null) 959 _topTraceContext = new TraceContext(this); 960 return _topTraceContext; 961 } 962 } 963 964 internal bool TraceIsEnabled { 965 get { 966 if (_topTraceContext == null) 967 return false; 968 969 return _topTraceContext.IsEnabled; 970 } 971 set { 972 if (value) 973 _topTraceContext = new TraceContext(this); 974 } 975 976 } 977 978 979 980 /// <devdoc> 981 /// <para> 982 /// Retrieves a key-value collection that can be used to 983 /// build up and share data between an <see cref='System.Web.IHttpModule'/> and an <see cref='System.Web.IHttpHandler'/> 984 /// during a 985 /// request. 986 /// </para> 987 /// </devdoc> 988 public IDictionary Items { 989 get { 990 if (_items == null) 991 _items = new Hashtable(); 992 993 return _items; 994 } 995 } 996 997 998 /// <devdoc> 999 /// <para> 1000 /// Gets a reference to the <see cref='System.Web.SessionState'/> instance for the current request. 1001 /// </para> 1002 /// </devdoc> 1003 public HttpSessionState Session { 1004 get { 1005 if (HasWebSocketRequestTransitionCompleted) { 1006 // Session is unavailable at this point 1007 return null; 1008 } 1009 1010 if (_delayedSessionState) { 1011 lock (this) { 1012 if (_delayedSessionState) { 1013 Debug.Assert(_sessionStateModule != null, "_sessionStateModule != null"); 1014 1015 // If it's not null, it means we have a delayed session state item 1016 _sessionStateModule.InitStateStoreItem(true); 1017 _delayedSessionState = false; 1018 } 1019 } 1020 } 1021 1022 return(HttpSessionState)Items[SessionStateUtility.SESSION_KEY]; 1023 } 1024 } 1025 1026 [MethodImpl(MethodImplOptions.NoInlining)] EnsureSessionStateIfNecessary()1027 internal void EnsureSessionStateIfNecessary() { 1028 if (_sessionStateModule == null) 1029 { 1030 // If _sessionStateModule is null, we wouldn't be able to call 1031 // _sessionStateModule.EnsureStateStoreItemLocked(), so we return here. 1032 // _sessionStateModule could be null in the following cases, 1033 // 1. No session state acquired. 1034 // 2. HttpResponse.Flush() happens after session state being released. 1035 // 3. The session state module in use is not System.Web.SessionState.SessionStateModule. 1036 // 1037 // This method is for the in-framework SessionStateModule only. 1038 // OOB SessionStateModule can achieve this by using HttpResponse.AddOnSendingHeaders. 1039 return; 1040 } 1041 1042 HttpSessionState session = (HttpSessionState)Items[SessionStateUtility.SESSION_KEY]; 1043 1044 if (session != null && // The session has been initiated 1045 session.Count > 0 && // The session state is used 1046 !string.IsNullOrEmpty(session.SessionID)) { // Ensure the session Id is valid - it will force to create new if didn't exist 1047 _sessionStateModule.EnsureStateStoreItemLocked(); // Lock the item if in use 1048 } 1049 } 1050 1051 AddHttpSessionStateModule(SessionStateModule module, bool delayed)1052 internal void AddHttpSessionStateModule(SessionStateModule module, bool delayed) { 1053 if (_sessionStateModule != null && _sessionStateModule != module) { 1054 throw new HttpException(SR.GetString(SR.Cant_have_multiple_session_module)); 1055 } 1056 _sessionStateModule = module; 1057 _delayedSessionState = delayed; 1058 } 1059 RemoveHttpSessionStateModule()1060 internal void RemoveHttpSessionStateModule() { 1061 _delayedSessionState = false; 1062 _sessionStateModule = null; 1063 } 1064 1065 1066 /// <devdoc> 1067 /// <para> 1068 /// Gets a reference to the <see cref='System.Web.HttpServerUtility'/> 1069 /// for the current 1070 /// request. 1071 /// </para> 1072 /// </devdoc> 1073 public HttpServerUtility Server { 1074 get { 1075 // create only on demand 1076 if (_server == null) 1077 _server = new HttpServerUtility(this); 1078 return _server; 1079 } 1080 } 1081 1082 // if the context has an error, report it, but only one time ReportRuntimeErrorIfExists(ref RequestNotificationStatus status)1083 internal void ReportRuntimeErrorIfExists(ref RequestNotificationStatus status) { 1084 Exception e = Error; 1085 1086 if (e == null || _runtimeErrorReported) { 1087 return; 1088 } 1089 1090 // WOS 1921799: custom errors don't work in integrated mode if there's an initialization exception 1091 if (_notificationContext != null && CurrentModuleIndex == -1) { 1092 try { 1093 IIS7WorkerRequest wr = _wr as IIS7WorkerRequest; 1094 if (Request.QueryString["aspxerrorpath"] != null 1095 && wr != null 1096 && String.IsNullOrEmpty(wr.GetManagedHandlerType()) 1097 && wr.GetCurrentModuleName() == PipelineRuntime.InitExceptionModuleName) { 1098 status = RequestNotificationStatus.Continue; // allow non-managed handler to execute request 1099 return; 1100 } 1101 } 1102 catch { 1103 } 1104 } 1105 1106 _runtimeErrorReported = true; 1107 1108 if (HttpRuntime.AppOfflineMessage != null) { 1109 try { 1110 // report app offline error 1111 Response.TrySkipIisCustomErrors = true; 1112 HttpRuntime.ReportAppOfflineErrorMessage(Response, HttpRuntime.AppOfflineMessage); 1113 1114 } 1115 catch { 1116 } 1117 } 1118 else { 1119 // report error exception 1120 using (new DisposableHttpContextWrapper(this)) { 1121 1122 // if the custom encoder throws, it might interfere with returning error information 1123 // to the client, so we force use of the default encoder 1124 DisableCustomHttpEncoder = true; 1125 1126 // when application is on UNC share the code below must 1127 // be run while impersonating the token given by IIS 1128 using (new ApplicationImpersonationContext()) { 1129 1130 try { 1131 try { 1132 // try to report error in a way that could possibly throw (a config exception) 1133 Response.ReportRuntimeError(e, true /*canThrow*/, false); 1134 } 1135 catch (Exception eReport) { 1136 // report the config error in a way that would not throw 1137 Response.ReportRuntimeError(eReport, false /*canThrow*/, false); 1138 } 1139 } 1140 catch (Exception) { 1141 } 1142 } 1143 } 1144 } 1145 1146 status = RequestNotificationStatus.FinishRequest; 1147 return; 1148 } 1149 1150 /// <devdoc> 1151 /// <para> 1152 /// Gets the 1153 /// first error (if any) accumulated during request processing. 1154 /// </para> 1155 /// </devdoc> 1156 public Exception Error { 1157 get { 1158 if (_tempError != null) 1159 return _tempError; 1160 if (_errors == null || _errors.Count == 0 || _errorCleared) 1161 return null; 1162 return (Exception)_errors[0]; 1163 } 1164 } 1165 1166 // 1167 // Temp error (yet to be caught on app level) 1168 // to be reported as Server.GetLastError() but could be cleared later 1169 // 1170 internal Exception TempError { 1171 get { return _tempError; } 1172 set { _tempError = value; } 1173 } 1174 1175 1176 /// <devdoc> 1177 /// <para> 1178 /// An array (collection) of errors accumulated while processing a 1179 /// request. 1180 /// </para> 1181 /// </devdoc> 1182 public Exception[] AllErrors { 1183 get { 1184 int n = (_errors != null) ? _errors.Count : 0; 1185 1186 if (n == 0) 1187 return null; 1188 1189 Exception[] errors = new Exception[n]; 1190 _errors.CopyTo(0, errors, 0, n); 1191 return errors; 1192 } 1193 } 1194 1195 1196 /// <devdoc> 1197 /// <para> 1198 /// Registers an error for the current request. 1199 /// </para> 1200 /// </devdoc> AddError(Exception errorInfo)1201 public void AddError(Exception errorInfo) { 1202 if (_errors == null) 1203 _errors = new ArrayList(); 1204 1205 _errors.Add(errorInfo); 1206 1207 if (_isIntegratedPipeline && _notificationContext != null) { 1208 // set the error on the current notification context 1209 _notificationContext.Error = errorInfo; 1210 } 1211 } 1212 1213 1214 /// <devdoc> 1215 /// <para> 1216 /// Clears all errors for the current request. 1217 /// </para> 1218 /// </devdoc> ClearError()1219 public void ClearError() { 1220 if (_tempError != null) 1221 _tempError = null; 1222 else 1223 _errorCleared = true; 1224 1225 if (_isIntegratedPipeline && _notificationContext != null) { 1226 // clear the error on the current notification context 1227 _notificationContext.Error = null; 1228 } 1229 } 1230 1231 1232 /// <devdoc> 1233 /// <para> 1234 /// IPrincipal security information. 1235 /// </para> 1236 /// </devdoc> 1237 public IPrincipal User { 1238 get { return _principalContainer.Principal; } 1239 1240 [SecurityPermission(SecurityAction.Demand, ControlPrincipal=true)] 1241 set { 1242 SetPrincipalNoDemand(value); 1243 } 1244 } 1245 1246 IPrincipal IPrincipalContainer.Principal { 1247 get; 1248 set; 1249 } 1250 1251 // route all internals call to the principal (that don't have luring attacks) 1252 // through this method so we can centralize reporting 1253 // Before this, some auth modules were assigning directly to _user SetPrincipalNoDemand(IPrincipal principal, bool needToSetNativePrincipal)1254 internal void SetPrincipalNoDemand(IPrincipal principal, bool needToSetNativePrincipal) { 1255 _principalContainer.Principal = principal; 1256 1257 // push changes through to native side 1258 if (needToSetNativePrincipal 1259 && _isIntegratedPipeline 1260 && _notificationContext.CurrentNotification == RequestNotification.AuthenticateRequest) { 1261 1262 IntPtr pManagedPrincipal = IntPtr.Zero; 1263 IIS7WorkerRequest wr = (IIS7WorkerRequest)_wr; 1264 wr.SetPrincipal(principal); 1265 } 1266 } 1267 SetPrincipalNoDemand(IPrincipal principal)1268 internal void SetPrincipalNoDemand(IPrincipal principal) { 1269 SetPrincipalNoDemand(principal, true /*needToSetNativePrincipal*/); 1270 } 1271 1272 [DoNotReset] 1273 internal bool _ProfileDelayLoad = false; 1274 1275 public ProfileBase Profile { 1276 get { 1277 if (_Profile == null && _ProfileDelayLoad) 1278 _Profile = ProfileBase.Create(Request.IsAuthenticated ? User.Identity.Name : Request.AnonymousID, Request.IsAuthenticated); 1279 return _Profile; 1280 } 1281 } 1282 1283 internal SessionStateBehavior SessionStateBehavior { get; set; } 1284 1285 [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", 1286 Justification = "An internal property already exists. This method does additional work.")] SetSessionStateBehavior(SessionStateBehavior sessionStateBehavior)1287 public void SetSessionStateBehavior(SessionStateBehavior sessionStateBehavior) { 1288 if (_notificationContext != null && _notificationContext.CurrentNotification >= RequestNotification.AcquireRequestState) { 1289 throw new InvalidOperationException(SR.GetString(SR.Invoke_before_pipeline_event, "HttpContext.SetSessionStateBehavior", "HttpApplication.AcquireRequestState")); 1290 } 1291 1292 SessionStateBehavior = sessionStateBehavior; 1293 } 1294 1295 1296 public bool SkipAuthorization { 1297 get { return _skipAuthorization;} 1298 1299 [SecurityPermission(SecurityAction.Demand, ControlPrincipal=true)] 1300 set { 1301 SetSkipAuthorizationNoDemand(value, false); 1302 } 1303 } 1304 SetSkipAuthorizationNoDemand(bool value, bool managedOnly)1305 internal void SetSkipAuthorizationNoDemand(bool value, bool managedOnly) 1306 { 1307 if (HttpRuntime.UseIntegratedPipeline 1308 && !managedOnly 1309 && value != _skipAuthorization) { 1310 1311 // For integrated mode, persist changes to SkipAuthorization 1312 // in the IS_LOGIN_PAGE server variable. When this server variable exists 1313 // and the value is not "0", IIS skips authorization. 1314 1315 _request.SetSkipAuthorization(value); 1316 } 1317 1318 _skipAuthorization = value; 1319 } 1320 1321 // Pointer to the RootedObjects element, which contains information that needs to be flowed 1322 // between the HttpContext and the WebSocket, such as the current principal. 1323 [DoNotReset] 1324 private RootedObjects _rootedObjects; 1325 1326 internal RootedObjects RootedObjects { 1327 get { 1328 return _rootedObjects; 1329 } 1330 set { 1331 // Sync the Principal between the containers 1332 SwitchPrincipalContainer(value); 1333 _rootedObjects = value; 1334 } 1335 } 1336 SwitchPrincipalContainer(IPrincipalContainer newPrincipalContainer)1337 private void SwitchPrincipalContainer(IPrincipalContainer newPrincipalContainer) { 1338 if (newPrincipalContainer == null) { 1339 newPrincipalContainer = this; 1340 } 1341 1342 // Ensure new container contains the current principal 1343 IPrincipal currentPrincipal = _principalContainer.Principal; 1344 newPrincipalContainer.Principal = currentPrincipal; 1345 _principalContainer = newPrincipalContainer; 1346 } 1347 1348 /// <devdoc> 1349 /// <para> 1350 /// Is this request in debug mode? 1351 /// </para> 1352 /// </devdoc> 1353 public bool IsDebuggingEnabled { 1354 get { 1355 try { 1356 return CompilationUtil.IsDebuggingEnabled(this); 1357 } 1358 catch { 1359 // in case of config errors don't throw 1360 return false; 1361 } 1362 } 1363 } 1364 1365 1366 /// <devdoc> 1367 /// <para> 1368 /// Is this custom error enabled for this request? 1369 /// </para> 1370 /// </devdoc> 1371 public bool IsCustomErrorEnabled { 1372 get { 1373 return CustomErrorsSection.GetSettings(this).CustomErrorsEnabled(_request); 1374 } 1375 } 1376 1377 internal TemplateControl TemplateControl { 1378 get { 1379 return _templateControl; 1380 } 1381 set { 1382 _templateControl = value; 1383 } 1384 } 1385 1386 1387 /// <devdoc> 1388 /// <para>Gets the initial timestamp of the current request.</para> 1389 /// </devdoc> 1390 public DateTime Timestamp { 1391 get { return _utcTimestamp.ToLocalTime();} 1392 } 1393 1394 internal DateTime UtcTimestamp { 1395 get { return _utcTimestamp;} 1396 } 1397 1398 internal HttpWorkerRequest WorkerRequest { 1399 get { return _wr;} 1400 } 1401 1402 1403 /// <devdoc> 1404 /// <para> 1405 /// Gets a reference to the System.Web.Cache.Cache object for the current request. 1406 /// </para> 1407 /// </devdoc> 1408 public Cache Cache { 1409 get { return HttpRuntime.Cache;} 1410 } 1411 1412 /// <summary> 1413 /// Gets a reference to the System.Web.Instrumentation.PageInstrumentationService instance for this request. Guaranteed not to be null (barring private reflection magic). 1414 /// </summary> 1415 public PageInstrumentationService PageInstrumentation { 1416 get { 1417 if(_pageInstrumentationService == null) { 1418 _pageInstrumentationService = new PageInstrumentationService(); 1419 } 1420 return _pageInstrumentationService; 1421 } 1422 } 1423 1424 /* 1425 * The virtual path used to get config settings. This allows the user 1426 * to specify a non default config path, without having to pass it to every 1427 * configuration call. 1428 */ 1429 internal VirtualPath ConfigurationPath { 1430 get { 1431 if (_configurationPath == null) 1432 _configurationPath = _request.FilePathObject; 1433 1434 return _configurationPath; 1435 } 1436 1437 set { 1438 _configurationPath = value; 1439 _configurationPathData = null; 1440 _filePathData = null; 1441 } 1442 } 1443 GetFilePathData()1444 internal CachedPathData GetFilePathData() { 1445 if (_filePathData == null) { 1446 _filePathData = CachedPathData.GetVirtualPathData(_request.FilePathObject, false); 1447 } 1448 1449 return _filePathData; 1450 } 1451 GetConfigurationPathData()1452 internal CachedPathData GetConfigurationPathData() { 1453 if (_configurationPath == null) { 1454 return GetFilePathData(); 1455 } 1456 1457 // 1458 if (_configurationPathData == null) { 1459 _configurationPathData = CachedPathData.GetVirtualPathData(_configurationPath, true); 1460 } 1461 1462 return _configurationPathData; 1463 } 1464 GetPathData(VirtualPath path)1465 internal CachedPathData GetPathData(VirtualPath path) { 1466 if (path != null) { 1467 if (path.Equals(_request.FilePathObject)) { 1468 return GetFilePathData(); 1469 } 1470 1471 if (_configurationPath != null && path.Equals(_configurationPath)) { 1472 return GetConfigurationPathData(); 1473 } 1474 } 1475 1476 return CachedPathData.GetVirtualPathData(path, false); 1477 } 1478 FinishRequestForCachedPathData(int statusCode)1479 internal void FinishRequestForCachedPathData(int statusCode) { 1480 // Remove the cached path data for a file path if the first request for it 1481 // does not succeed due to a bad request. Otherwise we could be vulnerable 1482 // to a DOS attack. 1483 if (_filePathData != null && !_filePathData.CompletedFirstRequest) { 1484 if (400 <= statusCode && statusCode < 500) { 1485 CachedPathData.RemoveBadPathData(_filePathData); 1486 } 1487 else { 1488 CachedPathData.MarkCompleted(_filePathData); 1489 } 1490 } 1491 } 1492 1493 /* 1494 * Uses the Config system to get the specified configuraiton 1495 */ 1496 [Obsolete("The recommended alternative is System.Web.Configuration.WebConfigurationManager.GetWebApplicationSection in System.Web.dll. http://go.microsoft.com/fwlink/?linkid=14202")] GetAppConfig(String name)1497 public static object GetAppConfig(String name) { 1498 return WebConfigurationManager.GetWebApplicationSection(name); 1499 } 1500 1501 [Obsolete("The recommended alternative is System.Web.HttpContext.GetSection in System.Web.dll. http://go.microsoft.com/fwlink/?linkid=14202")] GetConfig(String name)1502 public object GetConfig(String name) { 1503 return GetSection(name); 1504 } 1505 GetSection(String sectionName)1506 public object GetSection(String sectionName) { 1507 if (HttpConfigurationSystem.UseHttpConfigurationSystem) { 1508 return GetConfigurationPathData().ConfigRecord.GetSection(sectionName); 1509 } 1510 else { 1511 return ConfigurationManager.GetSection(sectionName); 1512 } 1513 } 1514 GetRuntimeConfig()1515 internal RuntimeConfig GetRuntimeConfig() { 1516 return GetConfigurationPathData().RuntimeConfig; 1517 } 1518 GetRuntimeConfig(VirtualPath path)1519 internal RuntimeConfig GetRuntimeConfig(VirtualPath path) { 1520 return GetPathData(path).RuntimeConfig; 1521 } 1522 RewritePath(String path)1523 public void RewritePath(String path) { 1524 RewritePath(path, true); 1525 } 1526 1527 /* 1528 * Called by the URL rewrite module to modify the path for downstream modules 1529 */ 1530 1531 /// <devdoc> 1532 /// <para>[To be supplied.]</para> 1533 /// </devdoc> RewritePath(String path, bool rebaseClientPath)1534 public void RewritePath(String path, bool rebaseClientPath) { 1535 if (path == null) 1536 throw new ArgumentNullException("path"); 1537 1538 // extract query string 1539 String qs = null; 1540 int iqs = path.IndexOf('?'); 1541 if (iqs >= 0) { 1542 qs = (iqs < path.Length-1) ? path.Substring(iqs+1) : String.Empty; 1543 path = path.Substring(0, iqs); 1544 } 1545 1546 // resolve relative path 1547 VirtualPath virtualPath = VirtualPath.Create(path); 1548 virtualPath = Request.FilePathObject.Combine(virtualPath); 1549 1550 // disallow paths outside of app 1551 virtualPath.FailIfNotWithinAppRoot(); 1552 1553 // clear things that depend on path 1554 ConfigurationPath = null; 1555 1556 // rewrite path on request 1557 Request.InternalRewritePath(virtualPath, qs, rebaseClientPath); 1558 } 1559 1560 1561 /// <devdoc> 1562 /// <para>[To be supplied.]</para> 1563 /// </devdoc> RewritePath(String filePath, String pathInfo, String queryString)1564 public void RewritePath(String filePath, String pathInfo, String queryString) { 1565 RewritePath(VirtualPath.CreateAllowNull(filePath), VirtualPath.CreateAllowNull(pathInfo), 1566 queryString, false /*setClientFilePath*/); 1567 } RewritePath(string filePath, string pathInfo, String queryString, bool setClientFilePath)1568 public void RewritePath(string filePath, string pathInfo, String queryString, bool setClientFilePath) 1569 { 1570 RewritePath(VirtualPath.CreateAllowNull(filePath), VirtualPath.CreateAllowNull(pathInfo), queryString, setClientFilePath); 1571 } RewritePath(VirtualPath filePath, VirtualPath pathInfo, String queryString, bool setClientFilePath)1572 internal void RewritePath(VirtualPath filePath, VirtualPath pathInfo, String queryString, bool setClientFilePath) { 1573 EnsureHasNotTransitionedToWebSocket(); 1574 1575 if (filePath == null) 1576 throw new ArgumentNullException("filePath"); 1577 1578 // resolve relative path 1579 filePath = Request.FilePathObject.Combine(filePath); 1580 1581 // disallow paths outside of app 1582 filePath.FailIfNotWithinAppRoot(); 1583 1584 // clear things that depend on path 1585 ConfigurationPath = null; 1586 1587 // rewrite path on request 1588 Request.InternalRewritePath(filePath, pathInfo, queryString, setClientFilePath); 1589 } 1590 1591 internal CultureInfo DynamicCulture { 1592 get { return _dynamicCulture; } 1593 set { _dynamicCulture = value; } 1594 } 1595 1596 internal CultureInfo DynamicUICulture { 1597 get { return _dynamicUICulture; } 1598 set { _dynamicUICulture = value; } 1599 } 1600 GetGlobalResourceObject(string classKey, string resourceKey)1601 public static object GetGlobalResourceObject(string classKey, string resourceKey) { 1602 return GetGlobalResourceObject(classKey, resourceKey, null); 1603 } 1604 GetGlobalResourceObject(string classKey, string resourceKey, CultureInfo culture)1605 public static object GetGlobalResourceObject(string classKey, string resourceKey, CultureInfo culture) { 1606 return ResourceExpressionBuilder.GetGlobalResourceObject(classKey, resourceKey, null, null, culture); 1607 } 1608 GetLocalResourceObject(string virtualPath, string resourceKey)1609 public static object GetLocalResourceObject(string virtualPath, string resourceKey) { 1610 return GetLocalResourceObject(virtualPath, resourceKey, null); 1611 } 1612 GetLocalResourceObject(string virtualPath, string resourceKey, CultureInfo culture)1613 public static object GetLocalResourceObject(string virtualPath, string resourceKey, CultureInfo culture) { 1614 IResourceProvider pageProvider = ResourceExpressionBuilder.GetLocalResourceProvider( 1615 VirtualPath.Create(virtualPath)); 1616 return ResourceExpressionBuilder.GetResourceObject(pageProvider, resourceKey, culture); 1617 } 1618 1619 internal int ServerExecuteDepth { 1620 get { return _serverExecuteDepth; } 1621 set { _serverExecuteDepth = value; } 1622 } 1623 1624 internal bool PreventPostback { 1625 get { return _preventPostback; } 1626 set { _preventPostback = value; } 1627 } 1628 1629 // 1630 // Timeout support 1631 // 1632 1633 internal Thread CurrentThread { 1634 get { 1635 return _thread; 1636 } 1637 set { 1638 _thread = value; 1639 } 1640 } 1641 1642 // Property is thread-safe since needs to be accessed by RequestTimeoutManager in addition to 1643 // normal request threads. 1644 internal TimeSpan Timeout { 1645 get { 1646 long ticks = EnsureTimeout(); 1647 return TimeSpan.FromTicks(ticks); 1648 } 1649 1650 set { 1651 Interlocked.Exchange(ref _timeoutTicks, value.Ticks); 1652 } 1653 } 1654 1655 // Access via HttpRequest.TimedOutToken instead. 1656 internal CancellationToken TimedOutToken { 1657 get { 1658 // If we are the first call site to observe the token, then create it in the non-canceled state. 1659 CancellationTokenHelper helper = LazyInitializer.EnsureInitialized(ref _timeoutCancellationTokenHelper, () => new CancellationTokenHelper(canceled: false)); 1660 return helper.Token; 1661 } 1662 } 1663 1664 /// <summary> 1665 /// Determines whether the ASP.NET runtime calls Thread.Abort() on the thread servicing this request when 1666 /// the request times out. Default value is 'true'. 1667 /// </summary> 1668 /// <remarks> 1669 /// Handlers and modules that are using Request.TimedOutToken to implement cooperative cancellation may 1670 /// wish to disable the rude Thread.Abort behavior that ASP.NET has historically performed when a request 1671 /// times out. This can help developers make sure that their g----ful cancellation + cleanup routines 1672 /// will run without interruption by ASP.NET. 1673 /// 1674 /// The rules for determining when a thread is aborted are somewhat complicated, so applications shouldn't 1675 /// try to depend on them. Currently, the behavior is: 1676 /// 1677 /// - The thread will be aborted at some point after Request.TimedOutToken is canceled. The abort might not 1678 /// occur immediately afterward, as the "should Thread.Abort" timer is separate from the "should signal 1679 /// the CancellationToken" timer. 1680 /// 1681 /// - We generally don't abort threads that are processing async modules or handlers. There are some 1682 /// exceptions. E.g., during certain parts of the lifecycle for async WebForms pages, the thread can be 1683 /// a candidate to be aborted when a timeout occurs. 1684 /// 1685 /// If a developer sets this property to 'false', ASP.NET will not automatically display a "Request timed 1686 /// out" YSOD when a timeout occurs. If this happens the application is responsible for setting the response 1687 /// content appropriately. 1688 /// </remarks> 1689 public bool ThreadAbortOnTimeout { 1690 get { return Volatile.Read(ref _threadAbortOnTimeout); } 1691 set { Volatile.Write(ref _threadAbortOnTimeout, value); } 1692 } 1693 DisposeTimedOutToken()1694 private void DisposeTimedOutToken() { 1695 // If we are the first call site to observe the token, then create it in the disposed state. 1696 CancellationTokenHelper helper = LazyInitializer.EnsureInitialized(ref _timeoutCancellationTokenHelper, () => CancellationTokenHelper.StaticDisposed); 1697 helper.Dispose(); 1698 } 1699 EnsureTimeout()1700 internal long EnsureTimeout() { 1701 // Calls to Volatile.* are atomic, even for 64-bit fields. 1702 long ticks = Volatile.Read(ref _timeoutTicks); 1703 if (ticks == -1) { 1704 // Only go to config if the value hasn't yet been initialized. 1705 HttpRuntimeSection cfg = RuntimeConfig.GetConfig(this).HttpRuntime; 1706 ticks = cfg.ExecutionTimeout.Ticks; 1707 1708 // If another thread already came in and initialized _timeoutTicks, 1709 // return that value instead of the value we just read from config. 1710 long originalTicks = Interlocked.CompareExchange(ref _timeoutTicks, ticks, -1); 1711 if (originalTicks != -1) { 1712 ticks = originalTicks; 1713 } 1714 } 1715 1716 return ticks; 1717 } 1718 1719 internal DoubleLink TimeoutLink { 1720 get { return _timeoutLink;} 1721 set { _timeoutLink = value;} 1722 } 1723 1724 /* 1725 1726 Notes on the following 5 functions: 1727 1728 Execution can be cancelled only during certain periods, when inside the catch 1729 block for ThreadAbortException. These periods are marked with the value of 1730 _timeoutState of 1. 1731 1732 There is potential [rare] race condition when the timeout thread would call 1733 thread.abort but the execution logic in the meantime escapes the catch block. 1734 To avoid such race conditions _timeoutState of -1 (cancelled) is introduced. 1735 The timeout thread sets _timeoutState to -1 before thread abort and the 1736 unwinding logic just waits for the exception in this case. The wait cannot 1737 be done in EndCancellablePeriod because the function is call from inside of 1738 a finally block and thus would wait indefinetely. That's why another function 1739 WaitForExceptionIfCancelled had been added. 1740 1741 Originally _timeoutStartTime was set in BeginCancellablePeriod. However, that means 1742 we'll call UtcNow everytime we call ExecuteStep, which is too expensive. So to save 1743 CPU time we created a new method SetStartTime() which is called by the caller of 1744 ExecuteStep. 1745 1746 */ 1747 BeginCancellablePeriod()1748 internal void BeginCancellablePeriod() { 1749 // It could be caused by an exception in OnThreadStart 1750 if (Volatile.Read(ref _timeoutStartTimeUtcTicks) == -1) { 1751 SetStartTime(); 1752 } 1753 1754 Volatile.Write(ref _timeoutState, 1); 1755 } 1756 SetStartTime()1757 internal void SetStartTime() { 1758 Interlocked.Exchange(ref _timeoutStartTimeUtcTicks, DateTime.UtcNow.Ticks); 1759 } 1760 EndCancellablePeriod()1761 internal void EndCancellablePeriod() { 1762 Interlocked.CompareExchange(ref _timeoutState, 0, 1); 1763 } 1764 WaitForExceptionIfCancelled()1765 internal void WaitForExceptionIfCancelled() { 1766 while (Volatile.Read(ref _timeoutState) == -1) 1767 Thread.Sleep(100); 1768 } 1769 1770 internal bool IsInCancellablePeriod { 1771 get { return (Volatile.Read(ref _timeoutState) == 1); } 1772 } 1773 MustTimeout(DateTime utcNow)1774 internal Thread MustTimeout(DateTime utcNow) { 1775 // Note: The TimedOutToken is keyed off of the HttpContext creation time, not the most recent async 1776 // completion time (like the Thread.Abort logic later in this method). 1777 1778 if (_utcTimestamp + Timeout < utcNow) { 1779 // If we are the first call site to observe the token, then create it in the canceled state. 1780 CancellationTokenHelper helper = LazyInitializer.EnsureInitialized(ref _timeoutCancellationTokenHelper, () => new CancellationTokenHelper(canceled: true)); 1781 helper.Cancel(); 1782 } 1783 1784 if (Volatile.Read(ref _timeoutState) == 1 && ThreadAbortOnTimeout) { // fast check 1785 long expirationUtcTicks = Volatile.Read(ref _timeoutStartTimeUtcTicks) + Timeout.Ticks; // don't care about overflow 1786 if (expirationUtcTicks < utcNow.Ticks) { 1787 // don't abort in debug mode 1788 try { 1789 if (CompilationUtil.IsDebuggingEnabled(this) || System.Diagnostics.Debugger.IsAttached) 1790 return null; 1791 } 1792 catch { 1793 // ignore config errors 1794 return null; 1795 } 1796 1797 // abort the thread only if in cancelable state, avoiding race conditions 1798 // the caller MUST timeout if the return is true 1799 if (Interlocked.CompareExchange(ref _timeoutState, -1, 1) == 1) { 1800 if (_wr.IsInReadEntitySync) { 1801 AbortConnection(); 1802 } 1803 return _thread; 1804 } 1805 } 1806 } 1807 1808 return null; 1809 } 1810 1811 internal bool HasTimeoutExpired { 1812 get { 1813 // Check if it is allowed to timeout 1814 if (Volatile.Read(ref _timeoutState) != 1 || !ThreadAbortOnTimeout) { 1815 return false; 1816 } 1817 1818 // Check if the timeout has expired 1819 long expirationUtcTicks = Volatile.Read(ref _timeoutStartTimeUtcTicks) + Timeout.Ticks; // don't care about overflow 1820 if (expirationUtcTicks >= DateTime.UtcNow.Ticks) { 1821 return false; 1822 } 1823 1824 // Dont't timeout when in debug 1825 try { 1826 if (CompilationUtil.IsDebuggingEnabled(this) || System.Diagnostics.Debugger.IsAttached) { 1827 return false; 1828 } 1829 } 1830 catch { 1831 // ignore config errors 1832 return false; 1833 } 1834 1835 return true; 1836 } 1837 } 1838 1839 // call a delegate within cancellable period (possibly throwing timeout exception) InvokeCancellableCallback(WaitCallback callback, Object state)1840 internal void InvokeCancellableCallback(WaitCallback callback, Object state) { 1841 if (IsInCancellablePeriod) { 1842 // call directly 1843 callback(state); 1844 return; 1845 } 1846 1847 try { 1848 BeginCancellablePeriod(); // request can be cancelled from this point 1849 1850 try { 1851 callback(state); 1852 } 1853 finally { 1854 EndCancellablePeriod(); // request can be cancelled until this point 1855 } 1856 1857 WaitForExceptionIfCancelled(); // wait outside of finally 1858 } 1859 catch (ThreadAbortException e) { 1860 if (e.ExceptionState != null && 1861 e.ExceptionState is HttpApplication.CancelModuleException && 1862 ((HttpApplication.CancelModuleException)e.ExceptionState).Timeout) { 1863 1864 Thread.ResetAbort(); 1865 PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_TIMED_OUT); 1866 1867 throw new HttpException(SR.GetString(SR.Request_timed_out), 1868 null, WebEventCodes.RuntimeErrorRequestAbort); 1869 } 1870 } 1871 } 1872 PushTraceContext()1873 internal void PushTraceContext() { 1874 if (_traceContextStack == null) { 1875 _traceContextStack = new Stack(); 1876 } 1877 1878 // push current TraceContext on stack 1879 _traceContextStack.Push(_topTraceContext); 1880 1881 // now make a new one for the top if necessary 1882 if (_topTraceContext != null) { 1883 TraceContext tc = new TraceContext(this); 1884 _topTraceContext.CopySettingsTo(tc); 1885 _topTraceContext = tc; 1886 } 1887 } 1888 PopTraceContext()1889 internal void PopTraceContext() { 1890 Debug.Assert(_traceContextStack != null); 1891 _topTraceContext = (TraceContext) _traceContextStack.Pop(); 1892 } 1893 RequestRequiresAuthorization()1894 internal bool RequestRequiresAuthorization() { 1895 #if !FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features 1896 // if current user is anonymous, then trivially, this page does not require authorization 1897 if (!User.Identity.IsAuthenticated) 1898 return false; 1899 1900 // Ask each of the authorization modules 1901 return 1902 ( FileAuthorizationModule.RequestRequiresAuthorization(this) || 1903 UrlAuthorizationModule.RequestRequiresAuthorization(this) ); 1904 #else // !FEATURE_PAL 1905 return false; // ROTORTODO 1906 #endif // !FEATURE_PAL 1907 } 1908 CallISAPI(UnsafeNativeMethods.CallISAPIFunc iFunction, byte [] bufIn, byte [] bufOut)1909 internal int CallISAPI(UnsafeNativeMethods.CallISAPIFunc iFunction, byte [] bufIn, byte [] bufOut) { 1910 1911 if (_wr == null || !(_wr is System.Web.Hosting.ISAPIWorkerRequest)) 1912 throw new HttpException(SR.GetString(SR.Cannot_call_ISAPI_functions)); 1913 #if !FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features 1914 return ((System.Web.Hosting.ISAPIWorkerRequest) _wr).CallISAPI(iFunction, bufIn, bufOut); 1915 #else // !FEATURE_PAL 1916 throw new NotImplementedException ("ROTORTODO"); 1917 #endif // !FEATURE_PAL 1918 } 1919 SendEmptyResponse()1920 internal void SendEmptyResponse() { 1921 #if !FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features 1922 if (_wr != null && (_wr is System.Web.Hosting.ISAPIWorkerRequest)) 1923 ((System.Web.Hosting.ISAPIWorkerRequest) _wr).SendEmptyResponse(); 1924 #endif // !FEATURE_PAL 1925 } 1926 1927 private CookielessHelperClass _CookielessHelper; 1928 internal CookielessHelperClass CookielessHelper { 1929 get { 1930 if (_CookielessHelper == null) 1931 _CookielessHelper = new CookielessHelperClass(this); 1932 return _CookielessHelper; 1933 } 1934 } 1935 1936 1937 // When a thread enters the pipeline, we may need to set the cookie in the CallContext. ResetSqlDependencyCookie()1938 internal void ResetSqlDependencyCookie() { 1939 if (_sqlDependencyCookie != null) { 1940 System.Runtime.Remoting.Messaging.CallContext.LogicalSetData(SqlCacheDependency.SQL9_OUTPUT_CACHE_DEPENDENCY_COOKIE, _sqlDependencyCookie); 1941 } 1942 } 1943 1944 // When a thread leaves the pipeline, we may need to remove the cookie from the CallContext. RemoveSqlDependencyCookie()1945 internal void RemoveSqlDependencyCookie() { 1946 if (_sqlDependencyCookie != null) { 1947 System.Runtime.Remoting.Messaging.CallContext.LogicalSetData(SqlCacheDependency.SQL9_OUTPUT_CACHE_DEPENDENCY_COOKIE, null); 1948 } 1949 } 1950 1951 internal string SqlDependencyCookie { 1952 get { 1953 return _sqlDependencyCookie; 1954 } 1955 1956 set { 1957 _sqlDependencyCookie = value; 1958 System.Runtime.Remoting.Messaging.CallContext.LogicalSetData(SqlCacheDependency.SQL9_OUTPUT_CACHE_DEPENDENCY_COOKIE, value); 1959 } 1960 } 1961 1962 // 1963 // integrated pipeline related 1964 // 1965 internal NotificationContext NotificationContext { 1966 get { return _notificationContext; } 1967 set { _notificationContext = value; } 1968 } 1969 1970 public RequestNotification CurrentNotification { 1971 get { 1972 EnsureHasNotTransitionedToWebSocket(); 1973 1974 if (!HttpRuntime.UseIntegratedPipeline) { 1975 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode)); 1976 } 1977 1978 return _notificationContext.CurrentNotification; 1979 } 1980 internal set { 1981 if (!HttpRuntime.UseIntegratedPipeline) { 1982 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode)); 1983 } 1984 1985 _notificationContext.CurrentNotification = value; 1986 } 1987 } 1988 1989 internal bool IsChangeInServerVars { 1990 get { return (_notificationContext.CurrentNotificationFlags & FLAG_CHANGE_IN_SERVER_VARIABLES) == FLAG_CHANGE_IN_SERVER_VARIABLES; } 1991 } 1992 1993 internal bool IsChangeInRequestHeaders { 1994 get { return (_notificationContext.CurrentNotificationFlags & FLAG_CHANGE_IN_REQUEST_HEADERS) == FLAG_CHANGE_IN_REQUEST_HEADERS; } 1995 } 1996 1997 internal bool IsChangeInResponseHeaders { 1998 get { return (_notificationContext.CurrentNotificationFlags & FLAG_CHANGE_IN_RESPONSE_HEADERS) == FLAG_CHANGE_IN_RESPONSE_HEADERS; } 1999 } 2000 2001 internal bool IsChangeInResponseStatus { 2002 get { return (_notificationContext.CurrentNotificationFlags & FLAG_CHANGE_IN_RESPONSE_STATUS) == FLAG_CHANGE_IN_RESPONSE_STATUS; } 2003 } 2004 2005 internal bool IsChangeInUserPrincipal { 2006 get { return (_notificationContext.CurrentNotificationFlags & FLAG_CHANGE_IN_USER_OBJECT) == FLAG_CHANGE_IN_USER_OBJECT; } 2007 } 2008 2009 internal bool IsRuntimeErrorReported { 2010 get { return _runtimeErrorReported; } 2011 } 2012 2013 internal bool IsSendResponseHeaders { 2014 get { return (_notificationContext.CurrentNotificationFlags & FLAG_SEND_RESPONSE_HEADERS) == FLAG_SEND_RESPONSE_HEADERS; } 2015 } 2016 SetImpersonationEnabled()2017 internal void SetImpersonationEnabled() { 2018 IdentitySection c = RuntimeConfig.GetConfig(this).Identity; 2019 _impersonationEnabled = (c != null && c.Impersonate); 2020 } 2021 2022 internal bool UsesImpersonation { 2023 get { 2024 // if we're on a UNC share and we have a UNC token, then use impersonation for all notifications 2025 if (HttpRuntime.IsOnUNCShareInternal && HostingEnvironment.ApplicationIdentityToken != IntPtr.Zero) { 2026 return true; 2027 } 2028 // if <identity impersonate=/> is false, then don't use impersonation 2029 if (!_impersonationEnabled) { 2030 return false; 2031 } 2032 // the notification context won't be available after we have completed the transition 2033 if (HasWebSocketRequestTransitionCompleted) { 2034 return true; 2035 } 2036 2037 // if this notification is after AuthenticateRequest and not a SendResponse notification, use impersonation 2038 return (((_notificationContext.CurrentNotification == RequestNotification.AuthenticateRequest && _notificationContext.IsPostNotification) 2039 || _notificationContext.CurrentNotification > RequestNotification.AuthenticateRequest) 2040 && _notificationContext.CurrentNotification != RequestNotification.SendResponse); 2041 } 2042 } 2043 2044 internal bool AreResponseHeadersSent { 2045 get { return (_notificationContext.CurrentNotificationFlags & FLAG_RESPONSE_HEADERS_SENT) == FLAG_RESPONSE_HEADERS_SENT; } 2046 } 2047 NeedToInitializeApp()2048 internal bool NeedToInitializeApp() { 2049 bool needToInit = !_isAppInitialized; 2050 if (needToInit) { 2051 _isAppInitialized = true; 2052 } 2053 return needToInit; 2054 } 2055 2056 // flags passed in on the call to PipelineRuntime::ProcessRequestNotification 2057 internal int CurrentNotificationFlags { 2058 get { 2059 return _notificationContext.CurrentNotificationFlags; 2060 } 2061 set { 2062 _notificationContext.CurrentNotificationFlags = value; 2063 } 2064 } 2065 2066 // index of the current "module" running the request 2067 // into the application module array 2068 internal int CurrentModuleIndex { 2069 get { 2070 return _notificationContext.CurrentModuleIndex; 2071 } 2072 set { 2073 _notificationContext.CurrentModuleIndex = value; 2074 } 2075 } 2076 2077 // Each module has a PipelineModuleStepContainer 2078 // which stores/manages a list of event handlers 2079 // that correspond to each RequestNotification. 2080 // CurrentModuleEventIndex is the index (for the current 2081 // module) of the current event handler. 2082 // This will be greater than one when a single 2083 // module registers multiple delegates for a single event. 2084 // e.g. 2085 // app.BeginRequest += Foo; 2086 // app.BeginRequest += Bar; 2087 internal int CurrentModuleEventIndex { 2088 get { 2089 return _notificationContext.CurrentModuleEventIndex; 2090 } 2091 set { 2092 _notificationContext.CurrentModuleEventIndex = value; 2093 } 2094 } 2095 DisableNotifications(RequestNotification notifications, RequestNotification postNotifications)2096 internal void DisableNotifications(RequestNotification notifications, RequestNotification postNotifications) { 2097 IIS7WorkerRequest wr = _wr as IIS7WorkerRequest; 2098 if (null != wr) { 2099 wr.DisableNotifications(notifications, postNotifications); 2100 } 2101 } 2102 2103 public bool IsPostNotification { 2104 get { 2105 EnsureHasNotTransitionedToWebSocket(); 2106 2107 if (!HttpRuntime.UseIntegratedPipeline) { 2108 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode)); 2109 } 2110 return _notificationContext.IsPostNotification; 2111 } 2112 internal set { 2113 if (!HttpRuntime.UseIntegratedPipeline) { 2114 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode)); 2115 } 2116 _notificationContext.IsPostNotification = value; 2117 } 2118 2119 } 2120 2121 // user token for the request 2122 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This is a safe critical method.")] 2123 internal IntPtr ClientIdentityToken { 2124 get { 2125 if (_wr != null) { 2126 return _wr.GetUserToken(); 2127 } 2128 else { 2129 return IntPtr.Zero; 2130 } 2131 } 2132 } 2133 2134 // is configured to impersonate client? 2135 internal bool IsClientImpersonationConfigured { 2136 get { 2137 try { 2138 IdentitySection c = RuntimeConfig.GetConfig(this).Identity; 2139 return (c != null && c.Impersonate && c.ImpersonateToken == IntPtr.Zero); 2140 } 2141 catch { 2142 // this property should not throw as it is used in the error reporting pass 2143 // config errors will be reported elsewhere 2144 return false; 2145 } 2146 } 2147 } 2148 2149 internal IntPtr ImpersonationToken { 2150 get { 2151 // by default use app identity 2152 IntPtr token = HostingEnvironment.ApplicationIdentityToken; 2153 IdentitySection c = RuntimeConfig.GetConfig(this).Identity; 2154 if (c != null) { 2155 if (c.Impersonate) { 2156 token = (c.ImpersonateToken != IntPtr.Zero) ? c.ImpersonateToken : ClientIdentityToken; 2157 } 2158 else { 2159 // for non-UNC case impersonate="false" means "don't impersonate", 2160 // but there is a special case for UNC shares - even if 2161 // impersonate="false" we still impersonate the UNC identity 2162 // (hosting identity). and this is how v1.x works as well 2163 if (!HttpRuntime.IsOnUNCShareInternal) { 2164 token = IntPtr.Zero; 2165 } 2166 } 2167 } 2168 return token; 2169 } 2170 } 2171 2172 internal AspNetSynchronizationContextBase SyncContext { 2173 get { 2174 if (_syncContext == null) { 2175 _syncContext = CreateNewAspNetSynchronizationContext(); 2176 } 2177 2178 return _syncContext; 2179 } 2180 set { 2181 _syncContext = value; 2182 } 2183 } 2184 InstallNewAspNetSynchronizationContext()2185 internal AspNetSynchronizationContextBase InstallNewAspNetSynchronizationContext() { 2186 AspNetSynchronizationContextBase syncContext = _syncContext; 2187 2188 if (syncContext != null && syncContext == AsyncOperationManager.SynchronizationContext) { 2189 // using current ASP.NET synchronization context - switch it 2190 _syncContext = CreateNewAspNetSynchronizationContext(); 2191 AsyncOperationManager.SynchronizationContext = _syncContext; 2192 return syncContext; 2193 } 2194 2195 return null; 2196 } 2197 CreateNewAspNetSynchronizationContext()2198 private AspNetSynchronizationContextBase CreateNewAspNetSynchronizationContext() { 2199 if (!AppSettings.UseTaskFriendlySynchronizationContext) { 2200 return new LegacyAspNetSynchronizationContext(ApplicationInstance); 2201 } 2202 else { 2203 return new AspNetSynchronizationContext(ApplicationInstance); 2204 } 2205 } 2206 2207 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This is a safe critical method.")] RestoreSavedAspNetSynchronizationContext(AspNetSynchronizationContextBase syncContext)2208 internal void RestoreSavedAspNetSynchronizationContext(AspNetSynchronizationContextBase syncContext) { 2209 AsyncOperationManager.SynchronizationContext = syncContext; 2210 _syncContext = syncContext; 2211 } 2212 UserLanguagesFromContext()2213 internal string[] UserLanguagesFromContext() { 2214 return (Request != null) ? Request.UserLanguages : null; 2215 } 2216 2217 // References should be nulled a.s.a.p. to reduce working set ClearReferences()2218 internal void ClearReferences() { 2219 _appInstance = null; 2220 _handler = null; 2221 _handlerStack = null; 2222 _currentHandler = null; 2223 _remapHandler = null; 2224 if (_isIntegratedPipeline) { 2225 if (!HasWebSocketRequestTransitionStarted) { 2226 // Items is also used by AspNetWebSocketContext and should only be cleared if we're not transitioning to WebSockets 2227 _items = null; 2228 } 2229 _syncContext = null; 2230 } 2231 } 2232 CompleteTransitionToWebSocket()2233 internal void CompleteTransitionToWebSocket() { 2234 ClearReferencesForWebSocketProcessing(); 2235 2236 // transition: TransitionStarted -> TransitionCompleted 2237 TransitionToWebSocketState(WebSocketTransitionState.TransitionCompleted); 2238 } 2239 2240 // This is much stronger than just ClearReferences; it tries to free absolutely as much memory as possible. 2241 // Some necessary items (like _wr, etc.) are preserved. The reason we want to modify this particular instance 2242 // in-place rather than create a new instance is that it is likely that references to this object still exist, 2243 // and we don't want the existence of those references to cause memory leaks. ClearReferencesForWebSocketProcessing()2244 private void ClearReferencesForWebSocketProcessing() { 2245 HttpResponse response = _response; 2246 2247 // everything not marked [DoNotReset] should be eligible for garbage collection 2248 ReflectionUtil.Reset(this); 2249 2250 // Miscellaneous steps: 2251 _request.ClearReferencesForWebSocketProcessing(); // also clean up the HttpRequest instance 2252 if (response != null) { 2253 // HttpResponse is off-limits, but it is possible that the developer accidentally maintained a reference 2254 // to it, e.g. via a closure. We'll release the HttpResponse's references to all its data to prevent 2255 // this from causing memory problems. 2256 ReflectionUtil.Reset(response); 2257 } 2258 } 2259 CultureFromConfig(string configString, bool requireSpecific)2260 internal CultureInfo CultureFromConfig(string configString, bool requireSpecific) { 2261 //auto 2262 if(StringUtil.EqualsIgnoreCase(configString, HttpApplication.AutoCulture)) { 2263 string[] userLanguages = UserLanguagesFromContext(); 2264 if (userLanguages != null) { 2265 try { 2266 return CultureUtil.CreateReadOnlyCulture(userLanguages, requireSpecific); 2267 } 2268 catch { 2269 return null; 2270 } 2271 } 2272 else { 2273 return null; 2274 } 2275 } 2276 else if(StringUtil.StringStartsWithIgnoreCase(configString, "auto:")) { 2277 string[] userLanguages = UserLanguagesFromContext(); 2278 if (userLanguages != null) { 2279 try { 2280 return CultureUtil.CreateReadOnlyCulture(userLanguages, requireSpecific); 2281 } 2282 catch { 2283 return CultureUtil.CreateReadOnlyCulture(configString.Substring(5 /* "auto:".Length */), requireSpecific); 2284 } 2285 } 2286 else { 2287 return CultureUtil.CreateReadOnlyCulture(configString.Substring(5 /* "auto:".Length */), requireSpecific); 2288 } 2289 } 2290 2291 return CultureUtil.CreateReadOnlyCulture(configString, requireSpecific); 2292 } 2293 2294 private enum WebSocketInitStatus { 2295 Success, // iiswsock.dll is active and has told us that the current request is a WebSocket request 2296 RequiresIntegratedMode, // WebSockets requires integrated mode, and the current server is not Integrated mode 2297 CannotCallFromBeginRequest, // We need to wait for BeginRequest to complete before the module has set the server variables 2298 NativeModuleNotEnabled, // iiswsock.dll isn't active in the pipeline 2299 NotAWebSocketRequest, // iiswsock.dll is active, but the current request is not a WebSocket request 2300 CurrentRequestIsChildRequest, // We are currently inside of a child request (IHttpContext::ExecuteRequest) 2301 } 2302 AbortConnection()2303 private void AbortConnection() { 2304 IIS7WorkerRequest wr = _wr as IIS7WorkerRequest; 2305 2306 if (wr != null) { 2307 // Direct API Abort is suported in integrated mode only 2308 wr.AbortConnection(); 2309 } 2310 else { 2311 // Close in classic mode acts as Abort (see HSE_REQ_CLOSE_CONNECTION) 2312 // It closes the underlined connection 2313 _wr.CloseConnection(); 2314 } 2315 } 2316 } 2317 2318 // 2319 // Helper class to add/remove HttpContext to/from CallContext 2320 // 2321 // using (new DisposableHttpContextWrapper(context)) { 2322 // // this code will have HttpContext.Current working 2323 // } 2324 // 2325 2326 internal class DisposableHttpContextWrapper : IDisposable { 2327 private bool _needToUndo; 2328 private HttpContext _savedContext; 2329 SwitchContext(HttpContext context)2330 internal static HttpContext SwitchContext(HttpContext context) { 2331 return ContextBase.SwitchContext(context) as HttpContext; 2332 } 2333 DisposableHttpContextWrapper(HttpContext context)2334 internal DisposableHttpContextWrapper(HttpContext context) { 2335 if (context != null) { 2336 _savedContext = SwitchContext(context); 2337 _needToUndo = (_savedContext != context); 2338 } 2339 } 2340 IDisposable.Dispose()2341 void IDisposable.Dispose() { 2342 if (_needToUndo) { 2343 SwitchContext(_savedContext); 2344 _savedContext = null; 2345 _needToUndo = false; 2346 } 2347 } 2348 } 2349 } 2350