1 //------------------------------------------------------------------------------
2 // <copyright file="HttpApplication.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
9 using System.Collections;
10 using System.Collections.Generic;
11 using System.ComponentModel;
12 using System.ComponentModel.Design;
13 using System.Globalization;
17 using System.Reflection;
18 using System.Runtime.CompilerServices;
19 using System.Runtime.ExceptionServices;
20 using System.Runtime.InteropServices;
21 using System.Runtime.Remoting.Messaging;
22 using System.Runtime.Serialization.Formatters;
23 using System.Security;
24 using System.Security.Permissions;
25 using System.Security.Principal;
26 using System.Threading;
27 using System.Threading.Tasks;
29 using System.Web.Compilation;
30 using System.Web.Configuration;
31 using System.Web.Configuration.Common;
32 using System.Web.Hosting;
33 using System.Web.Management;
34 using System.Web.Security;
35 using System.Web.SessionState;
37 using System.Web.Util;
38 using IIS = System.Web.Hosting.UnsafeIISMethods;
42 // Async EventHandler support
47 /// <para>[To be supplied.]</para>
49 public delegate IAsyncResult BeginEventHandler(object sender, EventArgs e, AsyncCallback cb, object extraData);
52 /// <para>[To be supplied.]</para>
54 public delegate void EndEventHandler(IAsyncResult ar);
56 // Represents an event handler using TAP (Task Asynchronous Pattern).
57 public delegate Task TaskEventHandler(object sender, EventArgs e);
62 /// The HttpApplication class defines the methods, properties and events common to all
63 /// HttpApplication objects within the ASP.NET Framework.
69 public class HttpApplication : IComponent, IHttpAsyncHandler, IRequestCompletedNotifier, ISyncContext {
70 // application state dictionary
71 private HttpApplicationState _state;
73 // context during init for config lookups
74 private HttpContext _initContext;
77 private HttpAsyncResult _ar; // currently pending async result for call into application
80 private static readonly DynamicModuleRegistry _dynamicModuleRegistry = new DynamicModuleRegistry();
81 private HttpModuleCollection _moduleCollection;
84 private static readonly object EventDisposed = new object();
85 private static readonly object EventErrorRecorded = new object();
86 private static readonly object EventRequestCompleted = new object();
87 private static readonly object EventPreSendRequestHeaders = new object();
88 private static readonly object EventPreSendRequestContent = new object();
90 private static readonly object EventBeginRequest = new object();
91 private static readonly object EventAuthenticateRequest = new object();
92 private static readonly object EventDefaultAuthentication = new object();
93 private static readonly object EventPostAuthenticateRequest = new object();
94 private static readonly object EventAuthorizeRequest = new object();
95 private static readonly object EventPostAuthorizeRequest = new object();
96 private static readonly object EventResolveRequestCache = new object();
97 private static readonly object EventPostResolveRequestCache = new object();
98 private static readonly object EventMapRequestHandler = new object();
99 private static readonly object EventPostMapRequestHandler = new object();
100 private static readonly object EventAcquireRequestState = new object();
101 private static readonly object EventPostAcquireRequestState = new object();
102 private static readonly object EventPreRequestHandlerExecute = new object();
103 private static readonly object EventPostRequestHandlerExecute = new object();
104 private static readonly object EventReleaseRequestState = new object();
105 private static readonly object EventPostReleaseRequestState = new object();
106 private static readonly object EventUpdateRequestCache = new object();
107 private static readonly object EventPostUpdateRequestCache = new object();
108 private static readonly object EventLogRequest = new object();
109 private static readonly object EventPostLogRequest = new object();
110 private static readonly object EventEndRequest = new object();
111 internal static readonly string AutoCulture = "auto";
113 private EventHandlerList _events;
114 private AsyncAppEventHandlersTable _asyncEvents;
117 private StepManager _stepManager;
119 // callback for Application ResumeSteps
120 #pragma warning disable 0649
121 private WaitCallback _resumeStepsWaitCallback;
122 #pragma warning restore 0649
124 // event passed to modules
125 private EventArgs _appEvent;
127 // list of handler mappings
128 private Hashtable _handlerFactories = new Hashtable();
130 // list of handler/factory pairs to be recycled
131 private ArrayList _handlerRecycleList;
133 // flag to hide request and response intrinsics
134 private bool _hideRequestResponse;
136 // application execution variables
137 private HttpContext _context;
138 private Exception _lastError; // placeholder for the error when context not avail
139 private bool _timeoutManagerInitialized;
141 // session (supplied by session-on-end outside of context)
142 private HttpSessionState _session;
144 // culture (needs to be set per thread)
145 private CultureInfo _appLevelCulture;
146 private CultureInfo _appLevelUICulture;
147 private CultureInfo _savedAppLevelCulture;
148 private CultureInfo _savedAppLevelUICulture;
149 private bool _appLevelAutoCulture;
150 private bool _appLevelAutoUICulture;
152 // pipeline event mappings
153 private Dictionary<string, RequestNotification> _pipelineEventMasks;
156 // IComponent support
159 // IIS7 specific fields
160 internal const string MANAGED_PRECONDITION = "managedHandler";
161 internal const string IMPLICIT_FILTER_MODULE = "AspNetFilterModule";
162 internal const string IMPLICIT_HANDLER = "ManagedPipelineHandler";
164 // map modules to their index
165 private static Hashtable _moduleIndexMap = new Hashtable();
166 private static bool _initSpecialCompleted;
168 private bool _initInternalCompleted;
169 private RequestNotification _appRequestNotifications;
170 private RequestNotification _appPostNotifications;
172 // Set the current module init key to the global.asax module to enable
173 // the custom global.asax derivation constructor to register event handlers
174 private string _currentModuleCollectionKey = HttpApplicationFactory.applicationFileName;
176 // module config is read once per app domain and used to initialize the per-instance _moduleContainers array
177 private static List<ModuleConfigurationInfo> _moduleConfigInfo;
179 // this is the per instance list that contains the events for each module
180 private PipelineModuleStepContainer[] _moduleContainers;
182 // Byte array to be used by HttpRequest.GetEntireRawContent. Windows OS Bug 1632921
183 private byte[] _entityBuffer;
185 // Counts the number of code paths consuming this HttpApplication instance. When the counter hits zero,
186 // it is safe to release this HttpApplication instance back into the HttpApplication pool.
187 // This counter can be null if we're not using the new Task-friendly code paths.
188 internal CountdownTask ApplicationInstanceConsumersCounter;
190 private IAllocatorProvider _allocator;
193 // Public Application properties
199 /// HTTPRuntime provided context object that provides access to additional
200 /// pipeline-module exposed objects.
205 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
207 public HttpContext Context {
209 return(_context != null) ? _context : _initContext;
213 private bool IsContainerInitalizationAllowed {
215 if (HttpRuntime.UseIntegratedPipeline && _initSpecialCompleted && !_initInternalCompleted) {
217 // i) this is integrated pipeline mode,
218 // ii) InitSpecial has been called at least once in this AppDomain to register events with IIS,
219 // iii) InitInternal has not been invoked yet or is currently executing
226 private void ThrowIfEventBindingDisallowed() {
227 if (HttpRuntime.UseIntegratedPipeline && _initSpecialCompleted && _initInternalCompleted) {
228 // throw if we're using the integrated pipeline and both InitSpecial and InitInternal have completed.
229 throw new InvalidOperationException(SR.GetString(SR.Event_Binding_Disallowed));
233 private PipelineModuleStepContainer[] ModuleContainers {
235 if (_moduleContainers == null) {
237 Debug.Assert(_moduleIndexMap != null && _moduleIndexMap.Count > 0, "_moduleIndexMap != null && _moduleIndexMap.Count > 0");
239 // At this point, all modules have been registered with IIS via RegisterIntegratedEvent.
240 // Now we need to create a container for each module and add execution steps.
241 // The number of containers is the same as the number of modules that have been
242 // registered (_moduleIndexMap.Count).
244 _moduleContainers = new PipelineModuleStepContainer[_moduleIndexMap.Count];
246 for (int i = 0; i < _moduleContainers.Length; i++) {
247 _moduleContainers[i] = new PipelineModuleStepContainer();
252 return _moduleContainers;
257 /// <para>[To be supplied.]</para>
259 public event EventHandler Disposed {
261 Events.AddHandler(EventDisposed, value);
265 Events.RemoveHandler(EventDisposed, value);
271 /// <para>[To be supplied.]</para>
273 protected EventHandlerList Events {
275 if (_events == null) {
276 _events = new EventHandlerList();
282 internal IExecutionStep CreateImplicitAsyncPreloadExecutionStep() {
283 ImplicitAsyncPreloadModule implicitAsyncPreloadModule = new ImplicitAsyncPreloadModule();
284 BeginEventHandler beginHandler = null;
285 EndEventHandler endHandler = null;
286 implicitAsyncPreloadModule.GetEventHandlers(out beginHandler, out endHandler);
287 return new AsyncEventExecutionStep(this, beginHandler, endHandler, null);
290 private AsyncAppEventHandlersTable AsyncEvents {
292 if (_asyncEvents == null)
293 _asyncEvents = new AsyncAppEventHandlersTable();
298 // Last error during the processing of the current request.
299 internal Exception LastError {
301 // only temporaraly public (will be internal and not related context)
302 return (_context != null) ? _context.Error : _lastError;
307 // Used by HttpRequest.GetEntireRawContent. Windows OS Bug 1632921
308 internal byte[] EntityBuffer
312 if (_entityBuffer == null)
314 _entityBuffer = new byte[8 * 1024];
316 return _entityBuffer;
320 // Provides fixed size reusable buffers per request
322 // 1) Eliminates global locks - access to HttpApplication instance is lock free and no concurrent access is expected (by design).
323 // 36+ cores show really bad spin lock characteristics for short locks.
324 // 2) Better lifetime dynamics - Buffers increase/decrease as HttpApplication instances grow/shrink on demand.
325 internal IAllocatorProvider AllocatorProvider {
327 if (_allocator == null) {
328 AllocatorProvider alloc = new AllocatorProvider();
330 alloc.CharBufferAllocator = new SimpleBufferAllocator<char>(BufferingParams.CHAR_BUFFER_SIZE);
331 alloc.IntBufferAllocator = new SimpleBufferAllocator<int>(BufferingParams.INT_BUFFER_SIZE);
332 alloc.IntPtrBufferAllocator = new SimpleBufferAllocator<IntPtr>(BufferingParams.INTPTR_BUFFER_SIZE);
334 Interlocked.CompareExchange(ref _allocator, alloc, null);
341 internal void ClearError() {
346 /// <para>HTTPRuntime provided request intrinsic object that provides access to incoming HTTP
347 /// request data.</para>
351 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
353 public HttpRequest Request {
355 HttpRequest request = null;
357 if (_context != null && !_hideRequestResponse)
358 request = _context.Request;
361 throw new HttpException(SR.GetString(SR.Request_not_available));
369 /// <para>HTTPRuntime provided
370 /// response intrinsic object that allows transmission of HTTP response data to a
375 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
377 public HttpResponse Response {
379 HttpResponse response = null;
381 if (_context != null && !_hideRequestResponse)
382 response = _context.Response;
384 if (response == null)
385 throw new HttpException(SR.GetString(SR.Response_not_available));
394 /// HTTPRuntime provided session intrinsic.
399 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
401 public HttpSessionState Session {
403 HttpSessionState session = null;
405 if (_session != null)
407 else if (_context != null)
408 session = _context.Session;
411 throw new HttpException(SR.GetString(SR.Session_not_available));
421 /// a reference to an HTTPApplication state bag instance.
426 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
428 public HttpApplicationState Application {
430 Debug.Assert(_state != null); // app state always available
437 /// <para>Provides the web server Intrinsic object.</para>
441 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
443 public HttpServerUtility Server {
445 if (_context != null)
446 return _context.Server;
448 return new HttpServerUtility(this); // special Server for application only
454 /// <para>Provides the User Intrinsic object.</para>
458 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
460 public IPrincipal User {
462 if (_context == null)
463 throw new HttpException(SR.GetString(SR.User_not_available));
465 return _context.User;
473 /// of all IHTTPModules configured for the current application.
478 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
480 public HttpModuleCollection Modules {
481 [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.High)]
483 if (_moduleCollection == null)
484 _moduleCollection = new HttpModuleCollection();
485 return _moduleCollection;
489 // event passed to all modules
490 internal EventArgs AppEvent {
492 if (_appEvent == null)
493 _appEvent = EventArgs.Empty;
503 private ISessionStateModule FindISessionStateModule() {
504 if (!HttpRuntime.UseIntegratedPipeline)
507 if (_moduleCollection != null) {
508 for (int i = 0; i < _moduleCollection.Count; i++) {
509 ISessionStateModule module = _moduleCollection.Get(i) as ISessionStateModule;
510 if (module != null) {
519 // DevDiv Bugs 151914: Release session state before executing child request
520 internal void EnsureReleaseState() {
521 ISessionStateModule module = FindISessionStateModule();
522 if (module != null) {
523 module.ReleaseSessionState(Context);
527 internal Task EnsureReleaseStateAsync() {
528 ISessionStateModule module = FindISessionStateModule();
529 if (module != null) {
530 return module.ReleaseSessionStateAsync(Context);
533 return TaskAsyncHelper.CompletedTask;
537 /// <para>[To be supplied.]</para>
539 public void CompleteRequest() {
541 // Request completion (force skipping all steps until RequestEnd
543 _stepManager.CompleteRequest();
546 internal bool IsRequestCompleted {
548 if (null == _stepManager) {
552 return _stepManager.IsCompleted;
556 bool IRequestCompletedNotifier.IsRequestCompleted {
558 return IsRequestCompleted;
562 // Dev10 745301: Asynchronous pipeline steps can start a new thread that triggers
563 // a SendResponse notification. E.g., it might call Flush when a module is registered
564 // for PreSendRequestHeaders/Content. If the async pipeline step returns from ExecuteStep
565 // while the SendResponse notification is executing, the NotificationContext can
566 // be corrupted. To fix this, a lock is now taken to prevent multi-threaded access when
567 // the async pipeline step sets the NotificationContext.PendingAsyncCompletion field.
568 // The SendResponse notification also acquires the lock when it enters managed code and
569 // releases the lock when it leaves.
570 internal void AcquireNotifcationContextLock(ref bool locked) {
571 Debug.Assert(HttpRuntime.UseIntegratedPipeline, "HttpRuntime.UseIntegratedPipeline");
572 Monitor.Enter(_stepManager, ref locked);
575 internal void ReleaseNotifcationContextLock() {
576 Debug.Assert(HttpRuntime.UseIntegratedPipeline, "HttpRuntime.UseIntegratedPipeline");
577 Monitor.Exit(_stepManager);
580 // Some frameworks built on top of the integrated pipeline call Flush() on background thread which will trigger nested
581 // RQ_SEND_RESPONSE notification and replace the old context.NotificationContext with the new context.NotificationContext.
582 // In order to maintain proper synchronization logic at the time when the completion callback is called we need to make sure
583 // we access the original context.NotificationContext (and don't touch the nested one).
584 // It will make sure that we read the correct NotificationContext
585 [MethodImpl(MethodImplOptions.NoInlining)]
586 private void GetNotifcationContextPropertiesUnderLock(ref bool isReentry, ref int eventCount) {
589 AcquireNotifcationContextLock(ref locked);
590 isReentry = Context.NotificationContext.IsReEntry;
591 eventCount = CurrentModuleContainer.GetEventCount(Context.CurrentNotification, Context.IsPostNotification) - 1;
595 ReleaseNotifcationContextLock();
600 [MethodImpl(MethodImplOptions.NoInlining)] // Iniling this causes throughtput regression in ResumeStep
601 private void GetNotifcationContextProperties(ref bool isReentry, ref int eventCount) {
602 // Read optimistically (without lock)
603 var nc = Context.NotificationContext;
604 isReentry = nc.IsReEntry;
605 // We can continue optimistic read only if this is not reentry
607 eventCount = ModuleContainers[nc.CurrentModuleIndex].GetEventCount(nc.CurrentNotification, nc.IsPostNotification) - 1;
608 // Check if the optimistic read was consistent
609 if (object.ReferenceEquals(nc, Context.NotificationContext)) {
613 GetNotifcationContextPropertiesUnderLock(ref isReentry, ref eventCount);
616 private void RaiseOnError() {
617 EventHandler handler = (EventHandler)Events[EventErrorRecorded];
618 if (handler != null) {
620 handler(this, AppEvent);
622 catch (Exception e) {
623 if (_context != null) {
624 _context.AddError(e);
630 private void RaiseOnRequestCompleted() {
631 EventHandler handler = (EventHandler)Events[EventRequestCompleted];
632 if (handler != null) {
634 handler(this, AppEvent);
636 catch (Exception e) {
637 WebBaseEvent.RaiseRuntimeError(e, this);
642 internal void RaiseOnPreSendRequestHeaders() {
643 EventHandler handler = (EventHandler)Events[EventPreSendRequestHeaders];
644 if (handler != null) {
646 handler(this, AppEvent);
648 catch (Exception e) {
654 internal void RaiseOnPreSendRequestContent() {
655 EventHandler handler = (EventHandler)Events[EventPreSendRequestContent];
656 if (handler != null) {
658 handler(this, AppEvent);
660 catch (Exception e) {
666 internal HttpAsyncResult AsyncResult {
668 if (HttpRuntime.UseIntegratedPipeline) {
669 return (_context.NotificationContext != null) ? _context.NotificationContext.AsyncResult : null;
676 if (HttpRuntime.UseIntegratedPipeline) {
677 _context.NotificationContext.AsyncResult = value;
685 internal void AddSyncEventHookup(object key, Delegate handler, RequestNotification notification) {
686 AddSyncEventHookup(key, handler, notification, false);
689 private PipelineModuleStepContainer CurrentModuleContainer { get { return ModuleContainers[_context.CurrentModuleIndex]; } }
691 private PipelineModuleStepContainer GetModuleContainer(string moduleName) {
692 object value = _moduleIndexMap[moduleName];
698 int moduleIndex = (int)value;
701 Debug.Trace("PipelineRuntime", "GetModuleContainer: moduleName=" + moduleName + ", index=" + moduleIndex.ToString(CultureInfo.InvariantCulture) + "\r\n");
702 Debug.Assert(moduleIndex >= 0 && moduleIndex < ModuleContainers.Length, "moduleIndex >= 0 && moduleIndex < ModuleContainers.Length");
705 PipelineModuleStepContainer container = ModuleContainers[moduleIndex];
707 Debug.Assert(container != null, "container != null");
712 private void AddSyncEventHookup(object key, Delegate handler, RequestNotification notification, bool isPostNotification) {
713 ThrowIfEventBindingDisallowed();
715 // add the event to the delegate invocation list
716 // this keeps non-pipeline ASP.NET hosts working
717 Events.AddHandler(key, handler);
719 // For integrated pipeline mode, add events to the IExecutionStep containers only if
720 // InitSpecial has completed and InitInternal has not completed.
721 if (IsContainerInitalizationAllowed) {
722 // lookup the module index and add this notification
723 PipelineModuleStepContainer container = GetModuleContainer(CurrentModuleCollectionKey);
724 //WOS 1985878: HttpModule unsubscribing an event handler causes AV in Integrated Mode
725 if (container != null) {
727 container.DebugModuleName = CurrentModuleCollectionKey;
729 SyncEventExecutionStep step = new SyncEventExecutionStep(this, (EventHandler)handler);
730 container.AddEvent(notification, isPostNotification, step);
735 internal void RemoveSyncEventHookup(object key, Delegate handler, RequestNotification notification) {
736 RemoveSyncEventHookup(key, handler, notification, false);
739 internal void RemoveSyncEventHookup(object key, Delegate handler, RequestNotification notification, bool isPostNotification) {
740 ThrowIfEventBindingDisallowed();
742 Events.RemoveHandler(key, handler);
744 if (IsContainerInitalizationAllowed) {
745 PipelineModuleStepContainer container = GetModuleContainer(CurrentModuleCollectionKey);
746 //WOS 1985878: HttpModule unsubscribing an event handler causes AV in Integrated Mode
747 if (container != null) {
748 container.RemoveEvent(notification, isPostNotification, handler);
753 private void AddSendResponseEventHookup(object key, Delegate handler) {
754 ThrowIfEventBindingDisallowed();
756 // add the event to the delegate invocation list
757 // this keeps non-pipeline ASP.NET hosts working
758 Events.AddHandler(key, handler);
760 // For integrated pipeline mode, add events to the IExecutionStep containers only if
761 // InitSpecial has completed and InitInternal has not completed.
762 if (IsContainerInitalizationAllowed) {
763 // lookup the module index and add this notification
764 PipelineModuleStepContainer container = GetModuleContainer(CurrentModuleCollectionKey);
765 //WOS 1985878: HttpModule unsubscribing an event handler causes AV in Integrated Mode
766 if (container != null) {
768 container.DebugModuleName = CurrentModuleCollectionKey;
770 bool isHeaders = (key == EventPreSendRequestHeaders);
771 SendResponseExecutionStep step = new SendResponseExecutionStep(this, (EventHandler)handler, isHeaders);
772 container.AddEvent(RequestNotification.SendResponse, false /*isPostNotification*/, step);
777 private void RemoveSendResponseEventHookup(object key, Delegate handler) {
778 ThrowIfEventBindingDisallowed();
780 Events.RemoveHandler(key, handler);
782 if (IsContainerInitalizationAllowed) {
783 PipelineModuleStepContainer container = GetModuleContainer(CurrentModuleCollectionKey);
784 //WOS 1985878: HttpModule unsubscribing an event handler causes AV in Integrated Mode
785 if (container != null) {
786 container.RemoveEvent(RequestNotification.SendResponse, false /*isPostNotification*/, handler);
792 // [....] event hookup
796 /// <devdoc><para>[To be supplied.]</para></devdoc>
797 public event EventHandler BeginRequest {
798 add { AddSyncEventHookup(EventBeginRequest, value, RequestNotification.BeginRequest); }
799 remove { RemoveSyncEventHookup(EventBeginRequest, value, RequestNotification.BeginRequest); }
803 /// <devdoc><para>[To be supplied.]</para></devdoc>
804 public event EventHandler AuthenticateRequest {
805 add { AddSyncEventHookup(EventAuthenticateRequest, value, RequestNotification.AuthenticateRequest); }
806 remove { RemoveSyncEventHookup(EventAuthenticateRequest, value, RequestNotification.AuthenticateRequest); }
809 // internal - for back-stop module only
810 internal event EventHandler DefaultAuthentication {
811 add { AddSyncEventHookup(EventDefaultAuthentication, value, RequestNotification.AuthenticateRequest); }
812 remove { RemoveSyncEventHookup(EventDefaultAuthentication, value, RequestNotification.AuthenticateRequest); }
816 /// <devdoc><para>[To be supplied.]</para></devdoc>
817 public event EventHandler PostAuthenticateRequest {
818 add { AddSyncEventHookup(EventPostAuthenticateRequest, value, RequestNotification.AuthenticateRequest, true); }
819 remove { RemoveSyncEventHookup(EventPostAuthenticateRequest, value, RequestNotification.AuthenticateRequest, true); }
823 /// <devdoc><para>[To be supplied.]</para></devdoc>
824 public event EventHandler AuthorizeRequest {
825 add { AddSyncEventHookup(EventAuthorizeRequest, value, RequestNotification.AuthorizeRequest); }
826 remove { RemoveSyncEventHookup(EventAuthorizeRequest, value, RequestNotification.AuthorizeRequest); }
830 /// <devdoc><para>[To be supplied.]</para></devdoc>
831 public event EventHandler PostAuthorizeRequest {
832 add { AddSyncEventHookup(EventPostAuthorizeRequest, value, RequestNotification.AuthorizeRequest, true); }
833 remove { RemoveSyncEventHookup(EventPostAuthorizeRequest, value, RequestNotification.AuthorizeRequest, true); }
837 /// <devdoc><para>[To be supplied.]</para></devdoc>
838 public event EventHandler ResolveRequestCache {
839 add { AddSyncEventHookup(EventResolveRequestCache, value, RequestNotification.ResolveRequestCache); }
840 remove { RemoveSyncEventHookup(EventResolveRequestCache, value, RequestNotification.ResolveRequestCache); }
844 /// <devdoc><para>[To be supplied.]</para></devdoc>
845 public event EventHandler PostResolveRequestCache {
846 add { AddSyncEventHookup(EventPostResolveRequestCache, value, RequestNotification.ResolveRequestCache, true); }
847 remove { RemoveSyncEventHookup(EventPostResolveRequestCache, value, RequestNotification.ResolveRequestCache, true); }
850 public event EventHandler MapRequestHandler {
852 if (!HttpRuntime.UseIntegratedPipeline) {
853 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
855 AddSyncEventHookup(EventMapRequestHandler, value, RequestNotification.MapRequestHandler);
858 if (!HttpRuntime.UseIntegratedPipeline) {
859 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
861 RemoveSyncEventHookup(EventMapRequestHandler, value, RequestNotification.MapRequestHandler);
865 /// <devdoc><para>[To be supplied.]</para></devdoc>
866 public event EventHandler PostMapRequestHandler {
867 add { AddSyncEventHookup(EventPostMapRequestHandler, value, RequestNotification.MapRequestHandler, true); }
868 remove { RemoveSyncEventHookup(EventPostMapRequestHandler, value, RequestNotification.MapRequestHandler); }
872 /// <devdoc><para>[To be supplied.]</para></devdoc>
873 public event EventHandler AcquireRequestState {
874 add { AddSyncEventHookup(EventAcquireRequestState, value, RequestNotification.AcquireRequestState); }
875 remove { RemoveSyncEventHookup(EventAcquireRequestState, value, RequestNotification.AcquireRequestState); }
879 /// <devdoc><para>[To be supplied.]</para></devdoc>
880 public event EventHandler PostAcquireRequestState {
881 add { AddSyncEventHookup(EventPostAcquireRequestState, value, RequestNotification.AcquireRequestState, true); }
882 remove { RemoveSyncEventHookup(EventPostAcquireRequestState, value, RequestNotification.AcquireRequestState, true); }
886 /// <devdoc><para>[To be supplied.]</para></devdoc>
887 public event EventHandler PreRequestHandlerExecute {
888 add { AddSyncEventHookup(EventPreRequestHandlerExecute, value, RequestNotification.PreExecuteRequestHandler); }
889 remove { RemoveSyncEventHookup(EventPreRequestHandlerExecute, value, RequestNotification.PreExecuteRequestHandler); }
892 /// <devdoc><para>[To be supplied.]</para></devdoc>
893 public event EventHandler PostRequestHandlerExecute {
894 add { AddSyncEventHookup(EventPostRequestHandlerExecute, value, RequestNotification.ExecuteRequestHandler, true); }
895 remove { RemoveSyncEventHookup(EventPostRequestHandlerExecute, value, RequestNotification.ExecuteRequestHandler, true); }
899 /// <devdoc><para>[To be supplied.]</para></devdoc>
900 public event EventHandler ReleaseRequestState {
901 add { AddSyncEventHookup(EventReleaseRequestState, value, RequestNotification.ReleaseRequestState ); }
902 remove { RemoveSyncEventHookup(EventReleaseRequestState, value, RequestNotification.ReleaseRequestState); }
906 /// <devdoc><para>[To be supplied.]</para></devdoc>
907 public event EventHandler PostReleaseRequestState {
908 add { AddSyncEventHookup(EventPostReleaseRequestState, value, RequestNotification.ReleaseRequestState, true); }
909 remove { RemoveSyncEventHookup(EventPostReleaseRequestState, value, RequestNotification.ReleaseRequestState, true); }
913 /// <devdoc><para>[To be supplied.]</para></devdoc>
914 public event EventHandler UpdateRequestCache {
915 add { AddSyncEventHookup(EventUpdateRequestCache, value, RequestNotification.UpdateRequestCache); }
916 remove { RemoveSyncEventHookup(EventUpdateRequestCache, value, RequestNotification.UpdateRequestCache); }
920 /// <devdoc><para>[To be supplied.]</para></devdoc>
921 public event EventHandler PostUpdateRequestCache {
922 add { AddSyncEventHookup(EventPostUpdateRequestCache, value, RequestNotification.UpdateRequestCache, true); }
923 remove { RemoveSyncEventHookup(EventPostUpdateRequestCache, value, RequestNotification.UpdateRequestCache, true); }
926 public event EventHandler LogRequest {
928 if (!HttpRuntime.UseIntegratedPipeline) {
929 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
931 AddSyncEventHookup(EventLogRequest, value, RequestNotification.LogRequest);
934 if (!HttpRuntime.UseIntegratedPipeline) {
935 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
937 RemoveSyncEventHookup(EventLogRequest, value, RequestNotification.LogRequest);
941 public event EventHandler PostLogRequest {
943 if (!HttpRuntime.UseIntegratedPipeline) {
944 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
946 AddSyncEventHookup(EventPostLogRequest, value, RequestNotification.LogRequest, true);
949 if (!HttpRuntime.UseIntegratedPipeline) {
950 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
952 RemoveSyncEventHookup(EventPostLogRequest, value, RequestNotification.LogRequest, true);
956 /// <devdoc><para>[To be supplied.]</para></devdoc>
957 public event EventHandler EndRequest {
958 add { AddSyncEventHookup(EventEndRequest, value, RequestNotification.EndRequest); }
959 remove { RemoveSyncEventHookup(EventEndRequest, value, RequestNotification.EndRequest); }
963 /// <devdoc><para>[To be supplied.]</para></devdoc>
964 public event EventHandler Error {
965 add { Events.AddHandler(EventErrorRecorded, value); }
966 remove { Events.RemoveHandler(EventErrorRecorded, value); }
970 // Dev10 902404: a new HttpApplication.RequestCompleted event raised when the managed objects associated with
971 // the request are being released. It allows modules to cleanup resources after all managed modules and handlers
972 // have executed. This may occur before the native processing of the request has completed; for example, before
973 // the final response bytes have been sent to the client. The HttpContext is not available during this event
974 // because it has already been released.
975 public event EventHandler RequestCompleted {
976 add { Events.AddHandler(EventRequestCompleted, value); }
977 remove { Events.RemoveHandler(EventRequestCompleted, value); }
981 /// <devdoc><para>[To be supplied.]</para></devdoc>
982 public event EventHandler PreSendRequestHeaders {
983 add { AddSendResponseEventHookup(EventPreSendRequestHeaders, value); }
984 remove { RemoveSendResponseEventHookup(EventPreSendRequestHeaders, value); }
988 /// <devdoc><para>[To be supplied.]</para></devdoc>
989 public event EventHandler PreSendRequestContent {
990 add { AddSendResponseEventHookup(EventPreSendRequestContent, value); }
991 remove { RemoveSendResponseEventHookup(EventPreSendRequestContent, value); }
995 // Async event hookup
998 public void AddOnBeginRequestAsync(BeginEventHandler bh, EndEventHandler eh) {
999 AddOnBeginRequestAsync(bh, eh, null);
1002 public void AddOnBeginRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1003 AsyncEvents.AddHandler(EventBeginRequest, beginHandler, endHandler, state, RequestNotification.BeginRequest, false, this);
1006 public void AddOnAuthenticateRequestAsync(BeginEventHandler bh, EndEventHandler eh) {
1007 AddOnAuthenticateRequestAsync(bh, eh, null);
1010 public void AddOnAuthenticateRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1011 AsyncEvents.AddHandler(EventAuthenticateRequest, beginHandler, endHandler, state,
1012 RequestNotification.AuthenticateRequest, false, this);
1015 public void AddOnPostAuthenticateRequestAsync(BeginEventHandler bh, EndEventHandler eh) {
1016 AddOnPostAuthenticateRequestAsync(bh, eh, null);
1019 public void AddOnPostAuthenticateRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1020 AsyncEvents.AddHandler(EventPostAuthenticateRequest, beginHandler, endHandler, state,
1021 RequestNotification.AuthenticateRequest, true, this);
1024 public void AddOnAuthorizeRequestAsync(BeginEventHandler bh, EndEventHandler eh) {
1025 AddOnAuthorizeRequestAsync(bh, eh, null);
1028 public void AddOnAuthorizeRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1029 AsyncEvents.AddHandler(EventAuthorizeRequest, beginHandler, endHandler, state,
1030 RequestNotification.AuthorizeRequest, false, this);
1033 public void AddOnPostAuthorizeRequestAsync(BeginEventHandler bh, EndEventHandler eh) {
1034 AddOnPostAuthorizeRequestAsync(bh, eh, null);
1037 public void AddOnPostAuthorizeRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1038 AsyncEvents.AddHandler(EventPostAuthorizeRequest, beginHandler, endHandler, state,
1039 RequestNotification.AuthorizeRequest, true, this);
1042 public void AddOnResolveRequestCacheAsync(BeginEventHandler bh, EndEventHandler eh) {
1043 AddOnResolveRequestCacheAsync(bh, eh, null);
1046 public void AddOnResolveRequestCacheAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1047 AsyncEvents.AddHandler(EventResolveRequestCache, beginHandler, endHandler, state,
1048 RequestNotification.ResolveRequestCache, false, this);
1051 public void AddOnPostResolveRequestCacheAsync(BeginEventHandler bh, EndEventHandler eh) {
1052 AddOnPostResolveRequestCacheAsync(bh, eh, null);
1055 public void AddOnPostResolveRequestCacheAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1056 AsyncEvents.AddHandler(EventPostResolveRequestCache, beginHandler, endHandler, state,
1057 RequestNotification.ResolveRequestCache, true, this);
1060 public void AddOnMapRequestHandlerAsync(BeginEventHandler bh, EndEventHandler eh) {
1061 if (!HttpRuntime.UseIntegratedPipeline) {
1062 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
1064 AddOnMapRequestHandlerAsync(bh, eh, null);
1067 public void AddOnMapRequestHandlerAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1068 if (!HttpRuntime.UseIntegratedPipeline) {
1069 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
1071 AsyncEvents.AddHandler(EventMapRequestHandler, beginHandler, endHandler, state,
1072 RequestNotification.MapRequestHandler, false, this);
1075 public void AddOnPostMapRequestHandlerAsync(BeginEventHandler bh, EndEventHandler eh) {
1076 AddOnPostMapRequestHandlerAsync(bh, eh, null);
1079 public void AddOnPostMapRequestHandlerAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1080 AsyncEvents.AddHandler(EventPostMapRequestHandler, beginHandler, endHandler, state,
1081 RequestNotification.MapRequestHandler, true, this);
1084 public void AddOnAcquireRequestStateAsync(BeginEventHandler bh, EndEventHandler eh) {
1085 AddOnAcquireRequestStateAsync(bh, eh, null);
1088 public void AddOnAcquireRequestStateAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1089 AsyncEvents.AddHandler(EventAcquireRequestState, beginHandler, endHandler, state,
1090 RequestNotification.AcquireRequestState, false, this);
1093 public void AddOnPostAcquireRequestStateAsync(BeginEventHandler bh, EndEventHandler eh) {
1094 AddOnPostAcquireRequestStateAsync(bh, eh, null);
1097 public void AddOnPostAcquireRequestStateAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1098 AsyncEvents.AddHandler(EventPostAcquireRequestState, beginHandler, endHandler, state,
1099 RequestNotification.AcquireRequestState, true, this);
1102 public void AddOnPreRequestHandlerExecuteAsync(BeginEventHandler bh, EndEventHandler eh) {
1103 AddOnPreRequestHandlerExecuteAsync(bh, eh, null);
1106 public void AddOnPreRequestHandlerExecuteAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1107 AsyncEvents.AddHandler(EventPreRequestHandlerExecute, beginHandler, endHandler, state,
1108 RequestNotification.PreExecuteRequestHandler, false, this);
1111 public void AddOnPostRequestHandlerExecuteAsync(BeginEventHandler bh, EndEventHandler eh) {
1112 AddOnPostRequestHandlerExecuteAsync(bh, eh, null);
1115 public void AddOnPostRequestHandlerExecuteAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1116 AsyncEvents.AddHandler(EventPostRequestHandlerExecute, beginHandler, endHandler, state,
1117 RequestNotification.ExecuteRequestHandler, true, this);
1120 public void AddOnReleaseRequestStateAsync(BeginEventHandler bh, EndEventHandler eh) {
1121 AddOnReleaseRequestStateAsync(bh, eh, null);
1124 public void AddOnReleaseRequestStateAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1125 AsyncEvents.AddHandler(EventReleaseRequestState, beginHandler, endHandler, state,
1126 RequestNotification.ReleaseRequestState, false, this);
1129 public void AddOnPostReleaseRequestStateAsync(BeginEventHandler bh, EndEventHandler eh) {
1130 AddOnPostReleaseRequestStateAsync(bh, eh, null);
1133 public void AddOnPostReleaseRequestStateAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1134 AsyncEvents.AddHandler(EventPostReleaseRequestState, beginHandler, endHandler, state,
1135 RequestNotification.ReleaseRequestState, true, this);
1138 public void AddOnUpdateRequestCacheAsync(BeginEventHandler bh, EndEventHandler eh) {
1139 AddOnUpdateRequestCacheAsync(bh, eh, null);
1142 public void AddOnUpdateRequestCacheAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1143 AsyncEvents.AddHandler(EventUpdateRequestCache, beginHandler, endHandler, state,
1144 RequestNotification.UpdateRequestCache , false, this);
1147 public void AddOnPostUpdateRequestCacheAsync(BeginEventHandler bh, EndEventHandler eh) {
1148 AddOnPostUpdateRequestCacheAsync(bh, eh, null);
1151 public void AddOnPostUpdateRequestCacheAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1152 AsyncEvents.AddHandler(EventPostUpdateRequestCache, beginHandler, endHandler, state,
1153 RequestNotification.UpdateRequestCache , true, this);
1156 public void AddOnLogRequestAsync(BeginEventHandler bh, EndEventHandler eh) {
1157 if (!HttpRuntime.UseIntegratedPipeline) {
1158 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
1160 AddOnLogRequestAsync(bh, eh, null);
1163 public void AddOnLogRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1164 if (!HttpRuntime.UseIntegratedPipeline) {
1165 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
1167 AsyncEvents.AddHandler(EventLogRequest, beginHandler, endHandler, state,
1168 RequestNotification.LogRequest, false, this);
1171 public void AddOnPostLogRequestAsync(BeginEventHandler bh, EndEventHandler eh) {
1172 if (!HttpRuntime.UseIntegratedPipeline) {
1173 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
1175 AddOnPostLogRequestAsync(bh, eh, null);
1178 public void AddOnPostLogRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1179 if (!HttpRuntime.UseIntegratedPipeline) {
1180 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
1182 AsyncEvents.AddHandler(EventPostLogRequest, beginHandler, endHandler, state,
1183 RequestNotification.LogRequest, true, this);
1186 public void AddOnEndRequestAsync(BeginEventHandler bh, EndEventHandler eh) {
1187 AddOnEndRequestAsync(bh, eh, null);
1190 public void AddOnEndRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1191 AsyncEvents.AddHandler(EventEndRequest, beginHandler, endHandler, state,
1192 RequestNotification.EndRequest, false, this);
1196 // Public Application virtual methods
1203 /// to initialize a HttpModule?s instance variables, and to wireup event handlers to
1204 /// the hosting HttpApplication.
1207 public virtual void Init() {
1208 // derived class implements this
1215 /// to clean up an HttpModule?s instance variables
1218 public virtual void Dispose() {
1219 // also part of IComponent
1220 // derived class implements this
1222 if (_events != null) {
1224 EventHandler handler = (EventHandler)_events[EventDisposed];
1225 if (handler != null)
1226 handler(this, EventArgs.Empty);
1234 [SecurityPermission(SecurityAction.Assert, ControlPrincipal = true)]
1235 internal static void SetCurrentPrincipalWithAssert(IPrincipal user) {
1236 Thread.CurrentPrincipal = user;
1239 [SecurityPermission(SecurityAction.Assert, ControlPrincipal = true)]
1240 internal static WindowsIdentity GetCurrentWindowsIdentityWithAssert() {
1241 return WindowsIdentity.GetCurrent();
1244 private HttpHandlerAction GetHandlerMapping(HttpContext context, String requestType, VirtualPath path, bool useAppConfig) {
1245 CachedPathData pathData = null;
1246 HandlerMappingMemo memo = null;
1247 HttpHandlerAction mapping = null;
1249 // Check if cached handler could be used
1250 if (!useAppConfig) {
1251 // Grab mapping from cache - verify that the verb matches exactly
1252 pathData = context.GetPathData(path);
1253 memo = pathData.CachedHandler;
1255 // Invalidate cache on missmatch
1256 if (memo != null && !memo.IsMatch(requestType, path)) {
1264 HttpHandlersSection map = useAppConfig ? RuntimeConfig.GetAppConfig().HttpHandlers
1265 : RuntimeConfig.GetConfig(context).HttpHandlers;
1266 mapping = map.FindMapping(requestType, path);
1269 if (!useAppConfig) {
1270 memo = new HandlerMappingMemo(mapping, requestType, path);
1271 pathData.CachedHandler = memo;
1275 // Get mapping from the cache
1276 mapping = memo.Mapping;
1282 internal IHttpHandler MapIntegratedHttpHandler(HttpContext context, String requestType, VirtualPath path, String pathTranslated, bool useAppConfig, bool convertNativeStaticFileModule) {
1283 IHttpHandler handler = null;
1285 using (new ApplicationImpersonationContext()) {
1288 // vpath is a non-relative virtual path
1289 string vpath = path.VirtualPathString;
1291 // If we're using app config, modify vpath by appending the path after the last slash
1292 // to the app's virtual path. This will force IIS IHttpContext::MapHandler to use app configuration.
1294 int index = vpath.LastIndexOf('/');
1296 if (index != 0 && index < vpath.Length) {
1297 vpath = UrlPath.SimpleCombine(HttpRuntime.AppDomainAppVirtualPathString, vpath.Substring(index));
1300 vpath = HttpRuntime.AppDomainAppVirtualPathString;
1305 IIS7WorkerRequest wr = context.WorkerRequest as IIS7WorkerRequest;
1306 type = wr.MapHandlerAndGetHandlerTypeString(method: requestType, path: vpath, convertNativeStaticFileModule: convertNativeStaticFileModule, ignoreWildcardMappings: false);
1308 // If a page developer has removed the default mappings with <handlers><clear>
1309 // without replacing them then we need to give a more descriptive error than
1310 // a null parameter exception.
1312 PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_NOT_FOUND);
1313 PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_FAILED);
1314 throw new HttpException(SR.GetString(SR.Http_handler_not_found_for_request_type, requestType));
1317 // if it's a native type, don't go any further
1318 if(String.IsNullOrEmpty(type)) {
1322 // Get factory from the mapping
1323 IHttpHandlerFactory factory = GetFactory(type);
1326 handler = factory.GetHandler(context, requestType, path.VirtualPathString, pathTranslated);
1328 catch (FileNotFoundException e) {
1329 if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated))
1330 throw new HttpException(404, null, e);
1332 throw new HttpException(404, null);
1334 catch (DirectoryNotFoundException e) {
1335 if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated))
1336 throw new HttpException(404, null, e);
1338 throw new HttpException(404, null);
1340 catch (PathTooLongException e) {
1341 if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated))
1342 throw new HttpException(414, null, e);
1344 throw new HttpException(414, null);
1347 // Remember for recycling
1348 if (_handlerRecycleList == null)
1349 _handlerRecycleList = new ArrayList();
1350 _handlerRecycleList.Add(new HandlerWithFactory(handler, factory));
1356 internal IHttpHandler MapHttpHandler(HttpContext context, String requestType, VirtualPath path, String pathTranslated, bool useAppConfig) {
1357 // Don't use remap handler when HttpServerUtility.Execute called
1358 IHttpHandler handler = (context.ServerExecuteDepth == 0) ? context.RemapHandlerInstance : null;
1360 using (new ApplicationImpersonationContext()) {
1361 // Use remap handler if possible
1362 if (handler != null){
1367 HttpHandlerAction mapping = GetHandlerMapping(context, requestType, path, useAppConfig);
1369 // If a page developer has removed the default mappings with <httpHandlers><clear>
1370 // without replacing them then we need to give a more descriptive error than
1371 // a null parameter exception.
1372 if (mapping == null) {
1373 PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_NOT_FOUND);
1374 PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_FAILED);
1375 throw new HttpException(SR.GetString(SR.Http_handler_not_found_for_request_type, requestType));
1378 // Get factory from the mapping
1379 IHttpHandlerFactory factory = GetFactory(mapping);
1382 // Get factory from the mapping
1384 // Check if it supports the more efficient GetHandler call that can avoid
1385 // a VirtualPath object creation.
1386 IHttpHandlerFactory2 factory2 = factory as IHttpHandlerFactory2;
1388 if (factory2 != null) {
1389 handler = factory2.GetHandler(context, requestType, path, pathTranslated);
1392 handler = factory.GetHandler(context, requestType, path.VirtualPathString, pathTranslated);
1395 catch (FileNotFoundException e) {
1396 if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated))
1397 throw new HttpException(404, null, e);
1399 throw new HttpException(404, null);
1401 catch (DirectoryNotFoundException e) {
1402 if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated))
1403 throw new HttpException(404, null, e);
1405 throw new HttpException(404, null);
1407 catch (PathTooLongException e) {
1408 if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated))
1409 throw new HttpException(414, null, e);
1411 throw new HttpException(414, null);
1414 // Remember for recycling
1415 if (_handlerRecycleList == null)
1416 _handlerRecycleList = new ArrayList();
1417 _handlerRecycleList.Add(new HandlerWithFactory(handler, factory));
1425 /// <para>[To be supplied.]</para>
1427 public virtual string GetVaryByCustomString(HttpContext context, string custom) {
1429 if (StringUtil.EqualsIgnoreCase(custom, "browser")) {
1430 return context.Request.Browser.Type;
1436 public virtual string GetOutputCacheProviderName(HttpContext context) {
1437 // default implementation
1438 return System.Web.Caching.OutputCache.DefaultProviderName;
1442 // IComponent implementation
1447 /// <para>[To be supplied.]</para>
1451 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
1454 get { return _site;}
1455 set { _site = value;}
1459 // IHttpAsyncHandler implementation
1464 IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) {
1465 HttpAsyncResult result;
1467 // Setup the asynchronous stuff and application variables
1469 _context.ApplicationInstance = this;
1471 _stepManager.InitRequest();
1473 // Make sure the context stays rooted (including all async operations)
1476 // Create the async result
1477 result = new HttpAsyncResult(cb, extraData);
1479 // Remember the async result for use in async completions
1480 AsyncResult = result;
1482 if (_context.TraceIsEnabled)
1483 HttpRuntime.Profile.StartRequest(_context);
1485 // Start the application
1488 // Return the async result
1494 void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) {
1495 // throw error caught during execution
1496 HttpAsyncResult ar = (HttpAsyncResult)result;
1497 if (ar.Error != null)
1502 // IHttpHandler implementation
1507 void IHttpHandler.ProcessRequest(HttpContext context) {
1508 throw new HttpException(SR.GetString(SR.Sync_not_supported));
1513 bool IHttpHandler.IsReusable {
1514 get { return true; }
1518 // Support for external calls into the application like app_onStart
1521 [ReflectionPermission(SecurityAction.Assert, Flags=ReflectionPermissionFlag.RestrictedMemberAccess)]
1522 private void InvokeMethodWithAssert(MethodInfo method, int paramCount, object eventSource, EventArgs eventArgs) {
1523 if (paramCount == 0) {
1524 method.Invoke(this, new Object[0]);
1527 Debug.Assert(paramCount == 2);
1529 method.Invoke(this, new Object[2] { eventSource, eventArgs });
1533 internal void ProcessSpecialRequest(HttpContext context,
1537 EventArgs eventArgs,
1538 HttpSessionState session) {
1540 if (HttpRuntime.UseIntegratedPipeline && _context != null) {
1541 _context.HideRequestResponse = true;
1543 _hideRequestResponse = true;
1547 using (new DisposableHttpContextWrapper(context)) {
1548 using (new ApplicationImpersonationContext()) {
1550 // set culture on the current thread
1551 SetAppLevelCulture();
1552 InvokeMethodWithAssert(method, paramCount, eventSource, eventArgs);
1554 catch (Exception e) {
1555 // dereference reflection invocation exceptions
1557 if (e is TargetInvocationException)
1558 eActual = e.InnerException;
1562 RecordError(eActual);
1564 if (context == null) {
1566 WebBaseEvent.RaiseRuntimeError(eActual, this);
1575 // this thread should not be locking app state
1577 _state.EnsureUnLock();
1580 RestoreAppLevelCulture();
1582 if (HttpRuntime.UseIntegratedPipeline && _context != null) {
1583 _context.HideRequestResponse = false;
1585 _hideRequestResponse = false;
1596 // Report context-less error
1599 internal void RaiseErrorWithoutContext(Exception error) {
1602 SetAppLevelCulture();
1608 // this thread should not be locking app state
1610 _state.EnsureUnLock();
1612 RestoreAppLevelCulture();
1617 catch { // Protect against exception filters
1626 internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers) {
1627 Debug.Assert(context != null, "context != null");
1632 PerfCounters.IncrementCounter(AppPerfCounter.PIPELINES);
1636 // Remember context for config lookups
1637 _initContext = context;
1638 _initContext.ApplicationInstance = this;
1640 // Set config path to be application path for the application initialization
1641 context.ConfigurationPath = context.Request.ApplicationPathObject;
1643 // keep HttpContext.Current working while running user code
1644 using (new DisposableHttpContextWrapper(context)) {
1646 // Build module list from config
1647 if (HttpRuntime.UseIntegratedPipeline) {
1649 Debug.Assert(_moduleConfigInfo != null, "_moduleConfigInfo != null");
1650 Debug.Assert(_moduleConfigInfo.Count >= 0, "_moduleConfigInfo.Count >= 0");
1653 context.HideRequestResponse = true;
1654 _hideRequestResponse = true;
1655 InitIntegratedModules();
1658 context.HideRequestResponse = false;
1659 _hideRequestResponse = false;
1665 // this is used exclusively for integrated mode
1666 Debug.Assert(null == _moduleContainers, "null == _moduleContainers");
1669 // Hookup event handlers via reflection
1670 if (handlers != null)
1671 HookupEventHandlersForApplicationAndModules(handlers);
1673 // Initialization of the derived class
1675 if (HttpRuntime.UseIntegratedPipeline && _context != null) {
1676 _context.HideRequestResponse = true;
1678 _hideRequestResponse = true;
1683 catch (Exception e) {
1688 if (HttpRuntime.UseIntegratedPipeline && _context != null) {
1689 _context.HideRequestResponse = false;
1691 _hideRequestResponse = false;
1693 _resumeStepsWaitCallback= new WaitCallback(this.ResumeStepsWaitCallback);
1695 // Construct the execution steps array
1696 if (HttpRuntime.UseIntegratedPipeline) {
1697 _stepManager = new PipelineStepManager(this);
1700 _stepManager = new ApplicationStepManager(this);
1703 _stepManager.BuildSteps(_resumeStepsWaitCallback);
1706 _initInternalCompleted = true;
1708 // Reset config path
1709 context.ConfigurationPath = null;
1711 // don't hold on to the context
1712 _initContext.ApplicationInstance = null;
1713 _initContext = null;
1716 catch { // Protect against exception filters
1721 // helper to expand an event handler into application steps
1722 private void CreateEventExecutionSteps(Object eventIndex, ArrayList steps) {
1724 AsyncAppEventHandler asyncHandler = AsyncEvents[eventIndex];
1726 if (asyncHandler != null) {
1727 asyncHandler.CreateExecutionSteps(this, steps);
1731 EventHandler handler = (EventHandler)Events[eventIndex];
1733 if (handler != null) {
1734 Delegate[] handlers = handler.GetInvocationList();
1736 for (int i = 0; i < handlers.Length; i++) {
1737 steps.Add(new SyncEventExecutionStep(this, (EventHandler)handlers[i]));
1742 internal void InitSpecial(HttpApplicationState state, MethodInfo[] handlers, IntPtr appContext, HttpContext context) {
1747 // Remember the context for the initialization
1748 if (context != null) {
1749 _initContext = context;
1750 _initContext.ApplicationInstance = this;
1753 // if we're doing integrated pipeline wireup, then appContext is non-null and we need to init modules and register event subscriptions with IIS
1754 if (appContext != IntPtr.Zero) {
1755 // 1694356: app_offline.htm and <httpRuntime enabled=/> require that we make this check here for integrated mode
1756 using (new ApplicationImpersonationContext()) {
1757 HttpRuntime.CheckApplicationEnabled();
1760 // retrieve app level culture
1761 InitAppLevelCulture();
1763 Debug.Trace("PipelineRuntime", "InitSpecial for " + appContext.ToString() + "\n");
1764 RegisterEventSubscriptionsWithIIS(appContext, context, handlers);
1767 // retrieve app level culture
1768 InitAppLevelCulture();
1770 // Hookup event handlers via reflection
1771 if (handlers != null) {
1772 HookupEventHandlersForApplicationAndModules(handlers);
1776 // if we're doing integrated pipeline wireup, then appContext is non-null and we need to register the application (global.asax) event handlers
1777 if (appContext != IntPtr.Zero) {
1778 if (_appPostNotifications != 0 || _appRequestNotifications != 0) {
1779 RegisterIntegratedEvent(appContext,
1780 HttpApplicationFactory.applicationFileName,
1781 _appRequestNotifications,
1782 _appPostNotifications,
1783 this.GetType().FullName,
1784 MANAGED_PRECONDITION,
1790 _initSpecialCompleted = true;
1792 // Do not hold on to the context
1793 if (_initContext != null) {
1794 _initContext.ApplicationInstance = null;
1795 _initContext = null;
1800 internal void DisposeInternal() {
1801 PerfCounters.DecrementCounter(AppPerfCounter.PIPELINES);
1803 // call derived class
1808 catch (Exception e) {
1814 if (_moduleCollection != null) {
1815 int numModules = _moduleCollection.Count;
1817 for (int i = 0; i < numModules; i++) {
1819 // set the init key during Dispose for modules
1820 // that try to unregister events
1821 if (HttpRuntime.UseIntegratedPipeline) {
1822 _currentModuleCollectionKey = _moduleCollection.GetKey(i);
1824 _moduleCollection[i].Dispose();
1830 _moduleCollection = null;
1834 if (_allocator != null) {
1835 _allocator.TrimMemory();
1839 private void BuildEventMaskDictionary(Dictionary<string, RequestNotification> eventMask) {
1840 eventMask["BeginRequest"] = RequestNotification.BeginRequest;
1841 eventMask["AuthenticateRequest"] = RequestNotification.AuthenticateRequest;
1842 eventMask["PostAuthenticateRequest"] = RequestNotification.AuthenticateRequest;
1843 eventMask["AuthorizeRequest"] = RequestNotification.AuthorizeRequest;
1844 eventMask["PostAuthorizeRequest"] = RequestNotification.AuthorizeRequest;
1845 eventMask["ResolveRequestCache"] = RequestNotification.ResolveRequestCache;
1846 eventMask["PostResolveRequestCache"] = RequestNotification.ResolveRequestCache;
1847 eventMask["MapRequestHandler"] = RequestNotification.MapRequestHandler;
1848 eventMask["PostMapRequestHandler"] = RequestNotification.MapRequestHandler;
1849 eventMask["AcquireRequestState"] = RequestNotification.AcquireRequestState;
1850 eventMask["PostAcquireRequestState"] = RequestNotification.AcquireRequestState;
1851 eventMask["PreRequestHandlerExecute"] = RequestNotification.PreExecuteRequestHandler;
1852 eventMask["PostRequestHandlerExecute"] = RequestNotification.ExecuteRequestHandler;
1853 eventMask["ReleaseRequestState"] = RequestNotification.ReleaseRequestState;
1854 eventMask["PostReleaseRequestState"] = RequestNotification.ReleaseRequestState;
1855 eventMask["UpdateRequestCache"] = RequestNotification.UpdateRequestCache;
1856 eventMask["PostUpdateRequestCache"] = RequestNotification.UpdateRequestCache;
1857 eventMask["LogRequest"] = RequestNotification.LogRequest;
1858 eventMask["PostLogRequest"] = RequestNotification.LogRequest;
1859 eventMask["EndRequest"] = RequestNotification.EndRequest;
1860 eventMask["PreSendRequestHeaders"] = RequestNotification.SendResponse;
1861 eventMask["PreSendRequestContent"] = RequestNotification.SendResponse;
1864 private void HookupEventHandlersForApplicationAndModules(MethodInfo[] handlers) {
1865 _currentModuleCollectionKey = HttpApplicationFactory.applicationFileName;
1867 if(null == _pipelineEventMasks) {
1868 Dictionary<string, RequestNotification> dict = new Dictionary<string, RequestNotification>();
1869 BuildEventMaskDictionary(dict);
1870 if(null == _pipelineEventMasks) {
1871 _pipelineEventMasks = dict;
1876 for (int i = 0; i < handlers.Length; i++) {
1877 MethodInfo appMethod = handlers[i];
1878 String appMethodName = appMethod.Name;
1879 int namePosIndex = appMethodName.IndexOf('_');
1880 String targetName = appMethodName.Substring(0, namePosIndex);
1882 // Find target for method
1883 Object target = null;
1885 if (StringUtil.EqualsIgnoreCase(targetName, "Application"))
1887 else if (_moduleCollection != null)
1888 target = _moduleCollection[targetName];
1893 // Find event on the module type
1894 Type targetType = target.GetType();
1895 EventDescriptorCollection events = TypeDescriptor.GetEvents(targetType);
1896 string eventName = appMethodName.Substring(namePosIndex+1);
1898 EventDescriptor foundEvent = events.Find(eventName, true);
1899 if (foundEvent == null
1900 && StringUtil.EqualsIgnoreCase(eventName.Substring(0, 2), "on")) {
1902 eventName = eventName.Substring(2);
1903 foundEvent = events.Find(eventName, true);
1906 MethodInfo addMethod = null;
1907 if (foundEvent != null) {
1908 EventInfo reflectionEvent = targetType.GetEvent(foundEvent.Name);
1909 Debug.Assert(reflectionEvent != null);
1910 if (reflectionEvent != null) {
1911 addMethod = reflectionEvent.GetAddMethod();
1915 if (addMethod == null)
1918 ParameterInfo[] addMethodParams = addMethod.GetParameters();
1920 if (addMethodParams.Length != 1)
1923 // Create the delegate from app method to pass to AddXXX(handler) method
1925 Delegate handlerDelegate = null;
1927 ParameterInfo[] appMethodParams = appMethod.GetParameters();
1929 if (appMethodParams.Length == 0) {
1930 // If the app method doesn't have arguments --
1931 // -- hookup via intermidiate handler
1933 // only can do it for EventHandler, not strongly typed
1934 if (addMethodParams[0].ParameterType != typeof(System.EventHandler))
1937 ArglessEventHandlerProxy proxy = new ArglessEventHandlerProxy(this, appMethod);
1938 handlerDelegate = proxy.Handler;
1941 // Hookup directly to the app methods hoping all types match
1944 handlerDelegate = Delegate.CreateDelegate(addMethodParams[0].ParameterType, this, appMethodName);
1947 // some type mismatch
1952 // Call the AddXXX() to hook up the delegate
1955 addMethod.Invoke(target, new Object[1]{handlerDelegate});
1958 if (HttpRuntime.UseIntegratedPipeline) {
1963 if (eventName != null) {
1964 if (_pipelineEventMasks.ContainsKey(eventName)) {
1965 if (!StringUtil.StringStartsWith(eventName, "Post")) {
1966 _appRequestNotifications |= _pipelineEventMasks[eventName];
1969 _appPostNotifications |= _pipelineEventMasks[eventName];
1976 private void RegisterIntegratedEvent(IntPtr appContext,
1978 RequestNotification requestNotifications,
1979 RequestNotification postRequestNotifications,
1981 string modulePrecondition,
1982 bool useHighPriority) {
1984 // lookup the modules event index, if it already exists
1985 // use it, otherwise, bump the global count
1986 // the module is used for event dispatch
1989 if (_moduleIndexMap.ContainsKey(moduleName)) {
1990 moduleIndex = (int) _moduleIndexMap[moduleName];
1993 moduleIndex = _moduleIndexMap.Count;
1994 _moduleIndexMap[moduleName] = moduleIndex;
1998 Debug.Assert(moduleIndex >= 0, "moduleIndex >= 0");
1999 Debug.Trace("PipelineRuntime", "RegisterIntegratedEvent:"
2000 + " module=" + moduleName
2001 + ", index=" + moduleIndex.ToString(CultureInfo.InvariantCulture)
2002 + ", rq_notify=" + requestNotifications
2003 + ", post_rq_notify=" + postRequestNotifications
2004 + ", preconditon=" + modulePrecondition + "\r\n");
2007 int result = UnsafeIISMethods.MgdRegisterEventSubscription(appContext,
2009 requestNotifications,
2010 postRequestNotifications,
2013 new IntPtr(moduleIndex),
2017 throw new HttpException(SR.GetString(SR.Failed_Pipeline_Subscription, moduleName));
2022 private void SetAppLevelCulture() {
2023 CultureInfo culture = null;
2024 CultureInfo uiculture = null;
2025 CultureInfo browserCulture = null;
2026 //get the language from the browser
2027 //DevDivBugs 2001091: Request object is not available in integrated mode during Application_Start,
2028 //so don't try to access it if it is hidden
2029 if((_appLevelAutoCulture || _appLevelAutoUICulture) && _context != null && _context.HideRequestResponse == false) {
2030 string[] userLanguages = _context.UserLanguagesFromContext();
2031 if (userLanguages != null) {
2032 try { browserCulture = CultureUtil.CreateReadOnlyCulture(userLanguages, requireSpecific: true); }
2037 culture = _appLevelCulture;
2038 uiculture = _appLevelUICulture;
2039 if(browserCulture != null) {
2040 if(_appLevelAutoCulture) {
2041 culture = browserCulture;
2043 if(_appLevelAutoUICulture) {
2044 uiculture = browserCulture;
2048 _savedAppLevelCulture = Thread.CurrentThread.CurrentCulture;
2049 _savedAppLevelUICulture = Thread.CurrentThread.CurrentUICulture;
2051 if (culture != null && culture != Thread.CurrentThread.CurrentCulture) {
2052 HttpRuntime.SetCurrentThreadCultureWithAssert(culture);
2055 if (uiculture != null && uiculture != Thread.CurrentThread.CurrentUICulture) {
2056 Thread.CurrentThread.CurrentUICulture = uiculture;
2060 private void RestoreAppLevelCulture() {
2061 CultureInfo currentCulture = Thread.CurrentThread.CurrentCulture;
2062 CultureInfo currentUICulture = Thread.CurrentThread.CurrentUICulture;
2064 if (_savedAppLevelCulture != null) {
2065 // Avoid the cost of the Demand when setting the culture by comparing the cultures first
2066 if (currentCulture != _savedAppLevelCulture) {
2067 HttpRuntime.SetCurrentThreadCultureWithAssert(_savedAppLevelCulture);
2070 _savedAppLevelCulture = null;
2073 if (_savedAppLevelUICulture != null) {
2074 // Avoid the cost of the Demand when setting the culture by comparing the cultures first
2075 if (currentUICulture != _savedAppLevelUICulture) {
2076 Thread.CurrentThread.CurrentUICulture = _savedAppLevelUICulture;
2079 _savedAppLevelUICulture = null;
2083 // Initializes the thread on entry to the managed pipeline. A ThreadContext is returned, on
2084 // which the caller must call Leave. The IIS7 integrated pipeline uses setImpersonationContext
2085 // to prevent it from being set until after the authentication notification.
2087 // OnThreadEnterPrivate returns ThreadContext.
2088 // ThreadContext.Enter sets variables that are stored on the thread,
2089 // and saves anything currently on the thread so it can be restored
2090 // during the call to ThreadContext.Leave. All variables that are
2091 // modified on the thread should be stored in ThreadContext so they
2092 // can be restored later. ThreadContext.Enter should only be called
2093 // when holding a lock on the HttpApplication instance.
2094 // ThreadContext.Leave is also normally called under the lock, but
2095 // the Integrated Pipeline may delay this call until after the call to
2096 // IndicateCompletion returns. When IndicateCompletion is called,
2097 // IIS7 will execute the remaining notifications for the request on
2098 // the current thread. As a performance improvement, we do not call
2099 // Leave before calling IndicateCompletion, and we do not call Enter/Leave
2100 // for the notifications executed while we are in the call to
2101 // IndicateCompletion. But when IndicateCompletion returns, we do not
2102 // have a lock on the HttpApplication instance and therefore cannot
2103 // modify request state, such as the HttpContext or HttpApplication.
2104 // The only thing we can do is restore the state of the thread.
2105 // There's one problem, the Culture/UICulture may be changed by
2106 // user code that directly updates the values on the current thread, so
2107 // before leaving the pipeline we call ThreadContext.Synchronize to
2108 // synchronize the values that are stored on the HttpContext with what
2109 // is on the thread. Because of this, the next notification will end up using
2110 // the Culture/UICulture set by user-code, just as it did on IIS6.
2111 private ThreadContext OnThreadEnterPrivate(bool setImpersonationContext) {
2112 ThreadContext threadContext = new ThreadContext(_context);
2113 threadContext.AssociateWithCurrentThread(setImpersonationContext);
2115 // An entry is added to the request timeout manager once per request
2116 // and removed in ReleaseAppInstance.
2117 if (!_timeoutManagerInitialized) {
2118 // ensure Timeout is set (see ASURT 148698)
2119 // to avoid ---- getting config later (ASURT 127388)
2120 _context.EnsureTimeout();
2122 HttpRuntime.RequestTimeoutManager.Add(_context);
2123 _timeoutManagerInitialized = true;
2126 return threadContext;
2129 // consumed by AppVerifier when it is enabled
2130 HttpContext ISyncContext.HttpContext {
2136 // consumed by AspNetSynchronizationContext
2137 ISyncContextLock ISyncContext.Enter() {
2138 return OnThreadEnter();
2141 internal ThreadContext OnThreadEnter() {
2142 return OnThreadEnterPrivate(true /* setImpersonationContext */);
2145 internal ThreadContext OnThreadEnter(bool setImpersonationContext) {
2146 return OnThreadEnterPrivate(setImpersonationContext);
2150 * Execute single step catching exceptions in a fancy way (see below)
2152 internal Exception ExecuteStep(IExecutionStep step, ref bool completedSynchronously) {
2153 Exception error = null;
2157 if (step.IsCancellable) {
2158 _context.BeginCancellablePeriod(); // request can be cancelled from this point
2164 _context.EndCancellablePeriod(); // request can be cancelled until this point
2167 _context.WaitForExceptionIfCancelled(); // wait outside of finally
2173 if (!step.CompletedSynchronously) {
2174 completedSynchronously = false;
2178 catch (Exception e) {
2181 // Since we will leave the context later, we need to remember if we are impersonating
2182 // before we lose that info - VSWhidbey 494476
2183 if (ImpersonationContext.CurrentThreadTokenExists) {
2184 e.Data[System.Web.Management.WebThreadInformation.IsImpersonatingKey] = String.Empty;
2186 // This might force ThreadAbortException to be thrown
2187 // automatically, because we consumed an exception that was
2188 // hiding ThreadAbortException behind it
2190 if (e is ThreadAbortException &&
2191 ((Thread.CurrentThread.ThreadState & ThreadState.AbortRequested) == 0)) {
2192 // Response.End from a COM+ component that re-throws ThreadAbortException
2193 // It is not a real ThreadAbort
2196 _stepManager.CompleteRequest();
2199 #pragma warning disable 1058
2201 // ignore non-Exception objects that could be thrown
2203 #pragma warning restore 1058
2205 catch (ThreadAbortException e) {
2206 // ThreadAbortException could be masked as another one
2207 // the try-catch above consumes all exceptions, only
2208 // ThreadAbortException can filter up here because it gets
2209 // auto rethrown if no other exception is thrown on catch
2211 if (e.ExceptionState != null && e.ExceptionState is CancelModuleException) {
2212 // one of ours (Response.End or timeout) -- cancel abort
2214 CancelModuleException cancelException = (CancelModuleException)e.ExceptionState;
2216 if (cancelException.Timeout) {
2218 error = new HttpException(SR.GetString(SR.Request_timed_out),
2219 null, WebEventCodes.RuntimeErrorRequestAbort);
2220 PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_TIMED_OUT);
2225 _stepManager.CompleteRequest();
2228 Thread.ResetAbort();
2232 completedSynchronously = true;
2237 * Resume execution of the app steps
2240 private void ResumeStepsFromThreadPoolThread(Exception error) {
2241 if (Thread.CurrentThread.IsThreadPoolThread) {
2242 // if on thread pool thread, use the current thread
2246 // if on a non-threadpool thread, requeue
2247 ThreadPool.QueueUserWorkItem(_resumeStepsWaitCallback, error);
2251 private void ResumeStepsWaitCallback(Object error) {
2252 ResumeSteps(error as Exception);
2255 private void ResumeSteps(Exception error) {
2256 _stepManager.ResumeSteps(error);
2261 * Add error to the context fire OnError on first error
2263 private void RecordError(Exception error) {
2264 bool firstError = true;
2266 if (_context != null) {
2267 if (_context.Error != null)
2270 _context.AddError(error);
2273 if (_lastError != null)
2288 private void InitModulesCommon() {
2289 int n = _moduleCollection.Count;
2291 for (int i = 0; i < n; i++) {
2292 // remember the module being inited for event subscriptions
2293 // we'll later use this for routing
2294 _currentModuleCollectionKey = _moduleCollection.GetKey(i);
2295 _moduleCollection[i].Init(this);
2298 _currentModuleCollectionKey = null;
2299 InitAppLevelCulture();
2302 private void InitIntegratedModules() {
2303 Debug.Assert(null != _moduleConfigInfo, "null != _moduleConfigInfo");
2304 _moduleCollection = BuildIntegratedModuleCollection(_moduleConfigInfo);
2305 InitModulesCommon();
2308 private void InitModules() {
2309 HttpModulesSection pconfig = RuntimeConfig.GetAppConfig().HttpModules;
2311 // get the static list, then add the dynamic members
2312 HttpModuleCollection moduleCollection = pconfig.CreateModules();
2313 HttpModuleCollection dynamicModules = CreateDynamicModules();
2315 moduleCollection.AppendCollection(dynamicModules);
2316 _moduleCollection = moduleCollection; // don't assign until all ops have succeeded
2318 InitModulesCommon();
2321 // instantiates modules that have been added to the dynamic registry (classic pipeline)
2322 private HttpModuleCollection CreateDynamicModules() {
2323 HttpModuleCollection moduleCollection = new HttpModuleCollection();
2325 foreach (DynamicModuleRegistryEntry entry in _dynamicModuleRegistry.LockAndFetchList()) {
2326 HttpModuleAction modAction = new HttpModuleAction(entry.Name, entry.Type);
2327 moduleCollection.AddModule(modAction.Entry.ModuleName, modAction.Entry.Create());
2330 return moduleCollection;
2333 internal string CurrentModuleCollectionKey {
2335 return (null == _currentModuleCollectionKey) ? "UnknownModule" : _currentModuleCollectionKey;
2339 internal static void RegisterModuleInternal(Type moduleType) {
2340 _dynamicModuleRegistry.Add(moduleType);
2343 public static void RegisterModule(Type moduleType) {
2344 RuntimeConfig config = RuntimeConfig.GetAppConfig();
2345 HttpRuntimeSection runtimeSection = config.HttpRuntime;
2346 if (runtimeSection.AllowDynamicModuleRegistration) {
2347 RegisterModuleInternal(moduleType);
2350 throw new InvalidOperationException(SR.GetString(SR.DynamicModuleRegistrationOff));
2354 private void RegisterEventSubscriptionsWithIIS(IntPtr appContext, HttpContext context, MethodInfo[] handlers) {
2355 RequestNotification requestNotifications;
2356 RequestNotification postRequestNotifications;
2358 // register an implicit filter module
2359 RegisterIntegratedEvent(appContext,
2360 IMPLICIT_FILTER_MODULE,
2361 RequestNotification.UpdateRequestCache| RequestNotification.LogRequest /*requestNotifications*/,
2362 0 /*postRequestNotifications*/,
2363 String.Empty /*type*/,
2364 String.Empty /*precondition*/,
2365 true /*useHighPriority*/);
2367 // integrated pipeline will always use serverModules instead of <httpModules>
2368 _moduleCollection = GetModuleCollection(appContext);
2370 if (handlers != null) {
2371 HookupEventHandlersForApplicationAndModules(handlers);
2374 // 1643363: Breaking Change: ASP.Net v2.0: Application_OnStart is called after Module.Init (Integarted mode)
2375 HttpApplicationFactory.EnsureAppStartCalledForIntegratedMode(context, this);
2377 // Call Init on HttpApplication derived class ("global.asax")
2378 // and process event subscriptions before processing other modules.
2379 // Doing this now prevents clearing any events that may
2380 // have been added to event handlers during instantiation of this instance.
2381 // NOTE: If "global.asax" has a constructor which hooks up event handlers,
2382 // then they were added to the event handler lists but have not been registered with IIS yet,
2383 // so we MUST call ProcessEventSubscriptions on it first, before the other modules.
2384 _currentModuleCollectionKey = HttpApplicationFactory.applicationFileName;
2387 _hideRequestResponse = true;
2388 context.HideRequestResponse = true;
2392 catch (Exception e) {
2394 Exception error = context.Error;
2395 if (error != null) {
2401 context.HideRequestResponse = false;
2402 _hideRequestResponse = false;
2405 ProcessEventSubscriptions(out requestNotifications, out postRequestNotifications);
2407 // Save the notification subscriptions so we can register them with IIS later, after
2408 // we call HookupEventHandlersForApplicationAndModules and process global.asax event handlers.
2409 _appRequestNotifications |= requestNotifications;
2410 _appPostNotifications |= postRequestNotifications;
2412 for (int i = 0; i < _moduleCollection.Count; i++) {
2413 _currentModuleCollectionKey = _moduleCollection.GetKey(i);
2414 IHttpModule httpModule = _moduleCollection.Get(i);
2415 ModuleConfigurationInfo moduleInfo = _moduleConfigInfo[i];
2418 Debug.Trace("PipelineRuntime", "RegisterEventSubscriptionsWithIIS: name=" + CurrentModuleCollectionKey
2419 + ", type=" + httpModule.GetType().FullName + "\n");
2421 // make sure collections are in [....]
2422 Debug.Assert(moduleInfo.Name == _currentModuleCollectionKey, "moduleInfo.Name == _currentModuleCollectionKey");
2425 httpModule.Init(this);
2427 ProcessEventSubscriptions(out requestNotifications, out postRequestNotifications);
2429 // are any events wired up?
2430 if (requestNotifications != 0 || postRequestNotifications != 0) {
2432 RegisterIntegratedEvent(appContext,
2434 requestNotifications,
2435 postRequestNotifications,
2437 moduleInfo.Precondition,
2438 false /*useHighPriority*/);
2442 // WOS 1728067: RewritePath does not remap the handler when rewriting from a non-ASP.NET request
2443 // register a default implicit handler
2444 RegisterIntegratedEvent(appContext,
2446 RequestNotification.ExecuteRequestHandler | RequestNotification.MapRequestHandler /*requestNotifications*/,
2447 RequestNotification.EndRequest /*postRequestNotifications*/,
2448 String.Empty /*type*/,
2449 String.Empty /*precondition*/,
2450 false /*useHighPriority*/);
2453 private void ProcessEventSubscriptions(out RequestNotification requestNotifications,
2454 out RequestNotification postRequestNotifications) {
2455 requestNotifications = 0;
2456 postRequestNotifications = 0;
2459 if(HasEventSubscription(EventBeginRequest)) {
2460 requestNotifications |= RequestNotification.BeginRequest;
2464 if(HasEventSubscription(EventAuthenticateRequest)) {
2465 requestNotifications |= RequestNotification.AuthenticateRequest;
2468 if(HasEventSubscription(EventPostAuthenticateRequest)) {
2469 postRequestNotifications |= RequestNotification.AuthenticateRequest;
2473 if(HasEventSubscription(EventAuthorizeRequest)) {
2474 requestNotifications |= RequestNotification.AuthorizeRequest;
2476 if(HasEventSubscription(EventPostAuthorizeRequest)) {
2477 postRequestNotifications |= RequestNotification.AuthorizeRequest;
2480 // ResolveRequestCache
2481 if(HasEventSubscription(EventResolveRequestCache)) {
2482 requestNotifications |= RequestNotification.ResolveRequestCache;
2484 if(HasEventSubscription(EventPostResolveRequestCache)) {
2485 postRequestNotifications |= RequestNotification.ResolveRequestCache;
2488 // MapRequestHandler
2489 if(HasEventSubscription(EventMapRequestHandler)) {
2490 requestNotifications |= RequestNotification.MapRequestHandler;
2492 if(HasEventSubscription(EventPostMapRequestHandler)) {
2493 postRequestNotifications |= RequestNotification.MapRequestHandler;
2496 // AcquireRequestState
2497 if(HasEventSubscription(EventAcquireRequestState)) {
2498 requestNotifications |= RequestNotification.AcquireRequestState;
2500 if(HasEventSubscription(EventPostAcquireRequestState)) {
2501 postRequestNotifications |= RequestNotification.AcquireRequestState;
2504 // PreExecuteRequestHandler
2505 if(HasEventSubscription(EventPreRequestHandlerExecute)) {
2506 requestNotifications |= RequestNotification.PreExecuteRequestHandler;
2509 // PostRequestHandlerExecute
2510 if (HasEventSubscription(EventPostRequestHandlerExecute)) {
2511 postRequestNotifications |= RequestNotification.ExecuteRequestHandler;
2514 // ReleaseRequestState
2515 if(HasEventSubscription(EventReleaseRequestState)) {
2516 requestNotifications |= RequestNotification.ReleaseRequestState;
2518 if(HasEventSubscription(EventPostReleaseRequestState)) {
2519 postRequestNotifications |= RequestNotification.ReleaseRequestState;
2522 // UpdateRequestCache
2523 if(HasEventSubscription(EventUpdateRequestCache)) {
2524 requestNotifications |= RequestNotification.UpdateRequestCache;
2526 if(HasEventSubscription(EventPostUpdateRequestCache)) {
2527 postRequestNotifications |= RequestNotification.UpdateRequestCache;
2531 if(HasEventSubscription(EventLogRequest)) {
2532 requestNotifications |= RequestNotification.LogRequest;
2534 if(HasEventSubscription(EventPostLogRequest)) {
2535 postRequestNotifications |= RequestNotification.LogRequest;
2539 if(HasEventSubscription(EventEndRequest)) {
2540 requestNotifications |= RequestNotification.EndRequest;
2543 // PreSendRequestHeaders
2544 if(HasEventSubscription(EventPreSendRequestHeaders)) {
2545 requestNotifications |= RequestNotification.SendResponse;
2548 // PreSendRequestContent
2549 if(HasEventSubscription(EventPreSendRequestContent)) {
2550 requestNotifications |= RequestNotification.SendResponse;
2554 // check if an event has subscribers
2555 // and *reset* them if so
2556 // this is used only for special app instances
2557 // and not for processing requests
2558 private bool HasEventSubscription(Object eventIndex) {
2559 bool hasEvents = false;
2562 AsyncAppEventHandler asyncHandler = AsyncEvents[eventIndex];
2564 if (asyncHandler != null && asyncHandler.Count > 0) {
2565 asyncHandler.Reset();
2570 EventHandler handler = (EventHandler)Events[eventIndex];
2572 if (handler != null) {
2573 Delegate[] handlers = handler.GetInvocationList();
2574 if( handlers.Length > 0 ) {
2578 foreach(Delegate d in handlers) {
2579 Events.RemoveHandler(eventIndex, d);
2588 // Get app-level culture info (needed to context-less 'global' methods)
2591 private void InitAppLevelCulture() {
2592 GlobalizationSection globConfig = RuntimeConfig.GetAppConfig().Globalization;
2593 string culture = globConfig.Culture;
2594 string uiCulture = globConfig.UICulture;
2595 if (!String.IsNullOrEmpty(culture)) {
2596 if (StringUtil.StringStartsWithIgnoreCase(culture, AutoCulture)) {
2597 _appLevelAutoCulture = true;
2598 string appLevelCulture = GetFallbackCulture(culture);
2599 if(appLevelCulture != null) {
2600 _appLevelCulture = HttpServerUtility.CreateReadOnlyCultureInfo(culture.Substring(5));
2604 _appLevelAutoCulture = false;
2605 _appLevelCulture = HttpServerUtility.CreateReadOnlyCultureInfo(globConfig.Culture);
2608 if (!String.IsNullOrEmpty(uiCulture)) {
2609 if (StringUtil.StringStartsWithIgnoreCase(uiCulture, AutoCulture))
2611 _appLevelAutoUICulture = true;
2612 string appLevelUICulture = GetFallbackCulture(uiCulture);
2613 if(appLevelUICulture != null) {
2614 _appLevelUICulture = HttpServerUtility.CreateReadOnlyCultureInfo(uiCulture.Substring(5));
2618 _appLevelAutoUICulture = false;
2619 _appLevelUICulture = HttpServerUtility.CreateReadOnlyCultureInfo(globConfig.UICulture);
2624 internal static string GetFallbackCulture(string culture) {
2625 if((culture.Length > 5) && (culture.IndexOf(':') == 4)) {
2626 return culture.Substring(5);
2632 // Request mappings management functions
2635 private IHttpHandlerFactory GetFactory(HttpHandlerAction mapping) {
2636 HandlerFactoryCache entry = (HandlerFactoryCache)_handlerFactories[mapping.Type];
2637 if (entry == null) {
2638 entry = new HandlerFactoryCache(mapping);
2639 _handlerFactories[mapping.Type] = entry;
2642 return entry.Factory;
2645 private IHttpHandlerFactory GetFactory(string type) {
2646 HandlerFactoryCache entry = (HandlerFactoryCache)_handlerFactories[type];
2647 if (entry == null) {
2648 entry = new HandlerFactoryCache(type);
2649 _handlerFactories[type] = entry;
2652 return entry.Factory;
2657 * Recycle all handlers mapped during the request processing
2659 private void RecycleHandlers() {
2660 if (_handlerRecycleList != null) {
2661 int numHandlers = _handlerRecycleList.Count;
2663 for (int i = 0; i < numHandlers; i++)
2664 ((HandlerWithFactory)_handlerRecycleList[i]).Recycle();
2666 _handlerRecycleList = null;
2671 * Special exception to cancel module execution (not really an exception)
2672 * used in Response.End and when cancelling requests
2674 internal class CancelModuleException {
2675 private bool _timeout;
2677 internal CancelModuleException(bool timeout) {
2681 internal bool Timeout { get { return _timeout;}}
2684 // Setup the asynchronous stuff and application variables
2685 // context for the entire deal is already rooted for native handler
2686 internal void AssignContext(HttpContext context) {
2687 Debug.Assert(HttpRuntime.UseIntegratedPipeline, "HttpRuntime.UseIntegratedPipeline");
2689 if (null == _context) {
2690 _stepManager.InitRequest();
2693 _context.ApplicationInstance = this;
2695 if (_context.TraceIsEnabled)
2696 HttpRuntime.Profile.StartRequest(_context);
2698 // this will throw if config is invalid, so we do it after HttpContext.ApplicationInstance is set
2699 _context.SetImpersonationEnabled();
2703 internal IAsyncResult BeginProcessRequestNotification(HttpContext context, AsyncCallback cb) {
2704 Debug.Trace("PipelineRuntime", "BeginProcessRequestNotification");
2706 HttpAsyncResult result;
2708 if (_context == null) {
2710 AssignContext(context);
2714 // everytime initialization
2717 context.CurrentModuleEventIndex = -1;
2719 // Create the async result
2720 result = new HttpAsyncResult(cb, context);
2721 context.NotificationContext.AsyncResult = result;
2723 // enter notification execution loop
2730 internal RequestNotificationStatus EndProcessRequestNotification(IAsyncResult result) {
2731 HttpAsyncResult ar = (HttpAsyncResult)result;
2732 if (ar.Error != null)
2738 internal void ReleaseAppInstance() {
2739 if (_context != null)
2741 if (_context.TraceIsEnabled) {
2742 HttpRuntime.Profile.EndRequest(_context);
2744 _context.ClearReferences();
2745 if (_timeoutManagerInitialized) {
2746 HttpRuntime.RequestTimeoutManager.Remove(_context);
2747 _timeoutManagerInitialized = false;
2750 if(HttpRuntime.EnablePrefetchOptimization &&
2751 HttpRuntime.InitializationException == null &&
2752 _context.FirstRequest &&
2753 _context.Error == null) {
2754 UnsafeNativeMethods.EndPrefetchActivity((uint)StringUtil.GetNonRandomizedHashCode(HttpRuntime.AppDomainAppId));
2758 if (AsyncResult != null) {
2762 RaiseOnRequestCompleted();
2765 if (ApplicationInstanceConsumersCounter != null) {
2766 ApplicationInstanceConsumersCounter.MarkOperationCompleted(); // ReleaseAppInstance call complete
2769 HttpApplicationFactory.RecycleApplicationInstance(this);
2773 private void AddEventMapping(string moduleName,
2774 RequestNotification requestNotification,
2775 bool isPostNotification,
2776 IExecutionStep step) {
2778 ThrowIfEventBindingDisallowed();
2780 // Add events to the IExecutionStep containers only if
2781 // InitSpecial has completed and InitInternal has not completed.
2782 if (!IsContainerInitalizationAllowed) {
2786 Debug.Assert(!String.IsNullOrEmpty(moduleName), "!String.IsNullOrEmpty(moduleName)");
2787 Debug.Trace("PipelineRuntime", "AddEventMapping: for " + moduleName +
2788 " for " + requestNotification + "\r\n" );
2791 PipelineModuleStepContainer container = GetModuleContainer(moduleName);
2792 //WOS 1985878: HttpModule unsubscribing an event handler causes AV in Integrated Mode
2793 if (container != null) {
2795 container.DebugModuleName = moduleName;
2797 container.AddEvent(requestNotification, isPostNotification, step);
2801 static internal List<ModuleConfigurationInfo> IntegratedModuleList {
2803 return _moduleConfigInfo;
2807 private HttpModuleCollection GetModuleCollection(IntPtr appContext) {
2808 if (_moduleConfigInfo != null) {
2809 return BuildIntegratedModuleCollection(_moduleConfigInfo);
2812 List<ModuleConfigurationInfo> moduleList = null;
2814 IntPtr pModuleCollection = IntPtr.Zero;
2815 IntPtr pBstrModuleName = IntPtr.Zero;
2816 int cBstrModuleName = 0;
2817 IntPtr pBstrModuleType = IntPtr.Zero;
2818 int cBstrModuleType = 0;
2819 IntPtr pBstrModulePrecondition = IntPtr.Zero;
2820 int cBstrModulePrecondition = 0;
2823 int result = UnsafeIISMethods.MgdGetModuleCollection(IntPtr.Zero, appContext, out pModuleCollection, out count);
2825 throw new HttpException(SR.GetString(SR.Cant_Read_Native_Modules, result.ToString("X8", CultureInfo.InvariantCulture)));
2827 moduleList = new List<ModuleConfigurationInfo>(count);
2829 for (uint index = 0; index < count; index++) {
2830 result = UnsafeIISMethods.MgdGetNextModule(pModuleCollection, ref index,
2831 out pBstrModuleName, out cBstrModuleName,
2832 out pBstrModuleType, out cBstrModuleType,
2833 out pBstrModulePrecondition, out cBstrModulePrecondition);
2835 throw new HttpException(SR.GetString(SR.Cant_Read_Native_Modules, result.ToString("X8", CultureInfo.InvariantCulture)));
2837 string moduleName = (cBstrModuleName > 0) ? StringUtil.StringFromWCharPtr(pBstrModuleName, cBstrModuleName) : null;
2838 string moduleType = (cBstrModuleType > 0) ? StringUtil.StringFromWCharPtr(pBstrModuleType, cBstrModuleType) : null;
2839 string modulePrecondition = (cBstrModulePrecondition > 0) ? StringUtil.StringFromWCharPtr(pBstrModulePrecondition, cBstrModulePrecondition) : String.Empty;
2840 Marshal.FreeBSTR(pBstrModuleName);
2841 pBstrModuleName = IntPtr.Zero;
2842 cBstrModuleName = 0;
2843 Marshal.FreeBSTR(pBstrModuleType);
2844 pBstrModuleType = IntPtr.Zero;
2845 cBstrModuleType = 0;
2846 Marshal.FreeBSTR(pBstrModulePrecondition);
2847 pBstrModulePrecondition = IntPtr.Zero;
2848 cBstrModulePrecondition = 0;
2850 if (!String.IsNullOrEmpty(moduleName) && !String.IsNullOrEmpty(moduleType)) {
2851 moduleList.Add(new ModuleConfigurationInfo(moduleName, moduleType, modulePrecondition));
2856 if (pModuleCollection != IntPtr.Zero) {
2857 Marshal.Release(pModuleCollection);
2858 pModuleCollection = IntPtr.Zero;
2860 if (pBstrModuleName != IntPtr.Zero) {
2861 Marshal.FreeBSTR(pBstrModuleName);
2862 pBstrModuleName = IntPtr.Zero;
2864 if (pBstrModuleType != IntPtr.Zero) {
2865 Marshal.FreeBSTR(pBstrModuleType);
2866 pBstrModuleType = IntPtr.Zero;
2868 if (pBstrModulePrecondition != IntPtr.Zero) {
2869 Marshal.FreeBSTR(pBstrModulePrecondition);
2870 pBstrModulePrecondition = IntPtr.Zero;
2874 // now that the static list has been processed, add in the dynamic module list
2875 moduleList.AddRange(GetConfigInfoForDynamicModules());
2876 _moduleConfigInfo = moduleList;
2878 return BuildIntegratedModuleCollection(_moduleConfigInfo);
2881 // gets configuration for modules that have been added to the dynamic registry (integrated pipeline)
2882 private IEnumerable<ModuleConfigurationInfo> GetConfigInfoForDynamicModules() {
2883 return from entry in _dynamicModuleRegistry.LockAndFetchList()
2884 select new ModuleConfigurationInfo(entry.Name, entry.Type, "managedHandler" /* condition */);
2887 HttpModuleCollection BuildIntegratedModuleCollection(List<ModuleConfigurationInfo> moduleList) {
2888 HttpModuleCollection modules = new HttpModuleCollection();
2890 foreach(ModuleConfigurationInfo mod in moduleList) {
2892 Debug.Trace("NativeConfig", "Runtime module: " + mod.Name + " of type " + mod.Type + "\n");
2894 ModulesEntry currentModule = new ModulesEntry(mod.Name, mod.Type, "type", null);
2896 modules.AddModule(currentModule.ModuleName, currentModule.Create());
2903 // Internal classes to support [asynchronous] app execution logic
2906 internal class AsyncAppEventHandler {
2908 ArrayList _beginHandlers;
2909 ArrayList _endHandlers;
2910 ArrayList _stateObjects;
2912 internal AsyncAppEventHandler() {
2914 _beginHandlers = new ArrayList();
2915 _endHandlers = new ArrayList();
2916 _stateObjects = new ArrayList();
2919 internal void Reset() {
2921 _beginHandlers.Clear();
2922 _endHandlers.Clear();
2923 _stateObjects.Clear();
2926 internal int Count {
2932 internal void Add(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
2933 _beginHandlers.Add(beginHandler);
2934 _endHandlers.Add(endHandler);
2935 _stateObjects.Add(state);
2939 internal void CreateExecutionSteps(HttpApplication app, ArrayList steps) {
2940 for (int i = 0; i < _count; i++) {
2941 steps.Add(new AsyncEventExecutionStep(
2943 (BeginEventHandler)_beginHandlers[i],
2944 (EndEventHandler)_endHandlers[i],
2950 internal class AsyncAppEventHandlersTable {
2951 private Hashtable _table;
2953 internal void AddHandler(Object eventId, BeginEventHandler beginHandler,
2954 EndEventHandler endHandler, Object state,
2955 RequestNotification requestNotification,
2956 bool isPost, HttpApplication app) {
2958 _table = new Hashtable();
2960 AsyncAppEventHandler asyncHandler = (AsyncAppEventHandler)_table[eventId];
2962 if (asyncHandler == null) {
2963 asyncHandler = new AsyncAppEventHandler();
2964 _table[eventId] = asyncHandler;
2967 asyncHandler.Add(beginHandler, endHandler, state);
2969 if (HttpRuntime.UseIntegratedPipeline) {
2970 AsyncEventExecutionStep step =
2971 new AsyncEventExecutionStep(app,
2976 app.AddEventMapping(app.CurrentModuleCollectionKey, requestNotification, isPost, step);
2980 internal AsyncAppEventHandler this[Object eventId] {
2984 return (AsyncAppEventHandler)_table[eventId];
2989 // interface to represent one execution step
2990 internal interface IExecutionStep {
2992 bool CompletedSynchronously { get;}
2993 bool IsCancellable { get; }
2996 // execution step -- stub
2997 internal class NoopExecutionStep : IExecutionStep {
2998 internal NoopExecutionStep() {
3001 void IExecutionStep.Execute() {
3004 bool IExecutionStep.CompletedSynchronously {
3008 bool IExecutionStep.IsCancellable {
3009 get { return false; }
3013 // execution step -- call synchronous event
3014 internal class SyncEventExecutionStep : IExecutionStep {
3015 private HttpApplication _application;
3016 private EventHandler _handler;
3018 internal SyncEventExecutionStep(HttpApplication app, EventHandler handler) {
3023 internal EventHandler Handler {
3029 void IExecutionStep.Execute() {
3030 string targetTypeStr = null;
3032 if (_handler != null) {
3033 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Module)) {
3034 targetTypeStr = _handler.Method.ReflectedType.ToString();
3036 EtwTrace.Trace(EtwTraceType.ETW_TYPE_PIPELINE_ENTER, _application.Context.WorkerRequest, targetTypeStr);
3038 _handler(_application, _application.AppEvent);
3039 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Module)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_PIPELINE_LEAVE, _application.Context.WorkerRequest, targetTypeStr);
3043 bool IExecutionStep.CompletedSynchronously {
3047 bool IExecutionStep.IsCancellable {
3048 get { return true; }
3052 // execution step -- call asynchronous event
3053 internal class AsyncEventExecutionStep : IExecutionStep {
3054 private HttpApplication _application;
3055 private BeginEventHandler _beginHandler;
3056 private EndEventHandler _endHandler;
3057 private Object _state;
3058 private AsyncCallback _completionCallback;
3059 private AsyncStepCompletionInfo _asyncStepCompletionInfo; // per call
3060 private bool _sync; // per call
3061 private string _targetTypeStr;
3063 internal AsyncEventExecutionStep(HttpApplication app, BeginEventHandler beginHandler, EndEventHandler endHandler, Object state)
3064 :this(app, beginHandler, endHandler, state, HttpRuntime.UseIntegratedPipeline)
3068 internal AsyncEventExecutionStep(HttpApplication app, BeginEventHandler beginHandler, EndEventHandler endHandler, Object state, bool useIntegratedPipeline) {
3071 // Instrument the beginHandler method if AppVerifier is enabled.
3072 // If AppVerifier not enabled, we just get back the original delegate to beginHandler uninstrumented.
3073 _beginHandler = AppVerifier.WrapBeginMethod(_application, beginHandler);
3074 _endHandler = endHandler;
3076 _completionCallback = new AsyncCallback(this.OnAsyncEventCompletion);
3079 private void OnAsyncEventCompletion(IAsyncResult ar) {
3080 if (ar.CompletedSynchronously) {
3081 // Synchronous completions will be handled by IExecutionStep.Execute.
3085 // This IAsyncResult may actually have completed synchronously (we might be on the same thread
3086 // which called IExecutionStep.Execute) even if CompletedSynchronously = false. Regardless,
3087 // we should invoke the End* method on the same thread that invoked this callback, as some
3088 // applications use TLS instead of the IAsyncResult object itself to convey state information.
3090 Debug.Trace("PipelineRuntime", "AsyncStep.OnAsyncEventCompletion");
3091 HttpContext context = _application.Context;
3092 Exception error = null;
3094 // The asynchronous step has completed, so we should disallow further
3095 // async operations until the next step.
3096 context.SyncContext.ProhibitVoidAsyncOperations();
3101 catch (Exception e) {
3105 bool shouldCallResumeSteps = _asyncStepCompletionInfo.RegisterAsyncCompletion(error);
3106 if (!shouldCallResumeSteps) {
3110 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Module)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_PIPELINE_LEAVE, context.WorkerRequest, _targetTypeStr);
3112 // re-set start time after an async completion (see VSWhidbey 231010)
3113 context.SetStartTime();
3115 // Assert to disregard the user code up the stack
3116 if (HttpRuntime.IsLegacyCas) {
3117 ResumeStepsWithAssert(error);
3124 [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
3125 void ResumeStepsWithAssert(Exception error) {
3129 void ResumeSteps(Exception error) {
3130 _application.ResumeStepsFromThreadPoolThread(error);
3133 void IExecutionStep.Execute() {
3136 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Module)) {
3137 _targetTypeStr = _beginHandler.Method.ReflectedType.ToString();
3138 EtwTrace.Trace(EtwTraceType.ETW_TYPE_PIPELINE_ENTER, _application.Context.WorkerRequest, _targetTypeStr);
3141 HttpContext context = _application.Context;
3143 _asyncStepCompletionInfo.Reset();
3144 context.SyncContext.AllowVoidAsyncOperations();
3147 ar = _beginHandler(_application, _application.AppEvent, _completionCallback, _state);
3150 // The asynchronous step has completed, so we should disallow further
3151 // async operations until the next step.
3152 context.SyncContext.ProhibitVoidAsyncOperations();
3156 bool operationCompleted;
3157 bool mustCallEndHandler;
3158 _asyncStepCompletionInfo.RegisterBeginUnwound(ar, out operationCompleted, out mustCallEndHandler);
3160 if (operationCompleted) {
3163 if (mustCallEndHandler) {
3164 // The asynchronous step has completed, so we should disallow further
3165 // async operations until the next step.
3166 context.SyncContext.ProhibitVoidAsyncOperations();
3170 _asyncStepCompletionInfo.ReportError();
3172 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Module)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_PIPELINE_LEAVE, _application.Context.WorkerRequest, _targetTypeStr);
3176 bool IExecutionStep.CompletedSynchronously {
3177 get { return _sync;}
3180 bool IExecutionStep.IsCancellable {
3181 get { return false; }
3185 // execution step -- validate the path for canonicalization issues
3186 internal class ValidatePathExecutionStep : IExecutionStep {
3187 private HttpApplication _application;
3189 internal ValidatePathExecutionStep(HttpApplication app) {
3193 void IExecutionStep.Execute() {
3194 _application.Context.ValidatePath();
3197 bool IExecutionStep.CompletedSynchronously {
3198 get { return true; }
3201 bool IExecutionStep.IsCancellable {
3202 get { return false; }
3206 // execution step -- validate request (virtual path, query string, entity body, etc)
3207 internal class ValidateRequestExecutionStep : IExecutionStep {
3208 private HttpApplication _application;
3210 internal ValidateRequestExecutionStep(HttpApplication app) {
3214 void IExecutionStep.Execute() {
3215 _application.Context.Request.ValidateInputIfRequiredByConfig();
3218 bool IExecutionStep.CompletedSynchronously {
3219 get { return true; }
3222 bool IExecutionStep.IsCancellable {
3223 get { return false; }
3227 // materialize handler for integrated pipeline
3228 // this does not map handler, rather that's done by the core
3229 // this does instantiate the managed type so that things that need to
3231 internal class MaterializeHandlerExecutionStep : IExecutionStep {
3232 private HttpApplication _application;
3234 internal MaterializeHandlerExecutionStep(HttpApplication app) {
3238 void IExecutionStep.Execute() {
3239 HttpContext context = _application.Context;
3240 HttpRequest request = context.Request;
3241 IHttpHandler handler = null;
3242 string configType = null;
3244 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_MAPHANDLER_ENTER, context.WorkerRequest);
3246 IIS7WorkerRequest wr = context.WorkerRequest as IIS7WorkerRequest;
3249 if (context.RemapHandlerInstance != null){
3250 //RemapHandler overrides all
3251 wr.SetScriptMapForRemapHandler();
3252 context.Handler = context.RemapHandlerInstance;
3254 else if (request.RewrittenUrl != null) {
3255 // RewritePath, we need to re-map the handler
3257 configType = wr.ReMapHandlerAndGetHandlerTypeString(context, request.Path, out handlerExists);
3258 if (!handlerExists) {
3259 // WOS 1973590: When RewritePath is used with missing handler in Integrated Mode,an empty response 200 is returned instead of 404
3260 throw new HttpException(404, SR.GetString(SR.Http_handler_not_found_for_request_type, request.RequestType));
3264 configType = wr.GetManagedHandlerType();
3267 if (!String.IsNullOrEmpty(configType)) {
3268 IHttpHandlerFactory factory = _application.GetFactory(configType);
3269 string pathTranslated = request.PhysicalPathInternal;
3272 handler = factory.GetHandler(context, request.RequestType, request.FilePath, pathTranslated);
3274 catch (FileNotFoundException e) {
3275 if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated))
3276 throw new HttpException(404, null, e);
3278 throw new HttpException(404, null);
3280 catch (DirectoryNotFoundException e) {
3281 if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated))
3282 throw new HttpException(404, null, e);
3284 throw new HttpException(404, null);
3286 catch (PathTooLongException e) {
3287 if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated))
3288 throw new HttpException(414, null, e);
3290 throw new HttpException(414, null);
3293 context.Handler = handler;
3295 // Remember for recycling
3296 if (_application._handlerRecycleList == null)
3297 _application._handlerRecycleList = new ArrayList();
3298 _application._handlerRecycleList.Add(new HandlerWithFactory(handler, factory));
3301 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_MAPHANDLER_LEAVE, context.WorkerRequest);
3304 bool IExecutionStep.CompletedSynchronously {
3308 bool IExecutionStep.IsCancellable {
3309 get { return false; }
3314 // execution step -- map HTTP handler (used to be a separate module)
3315 internal class MapHandlerExecutionStep : IExecutionStep {
3316 private HttpApplication _application;
3318 internal MapHandlerExecutionStep(HttpApplication app) {
3322 void IExecutionStep.Execute() {
3323 HttpContext context = _application.Context;
3324 HttpRequest request = context.Request;
3326 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_MAPHANDLER_ENTER, context.WorkerRequest);
3328 context.Handler = _application.MapHttpHandler(
3330 request.RequestType,
3331 request.FilePathObject,
3332 request.PhysicalPathInternal,
3333 false /*useAppConfig*/);
3334 Debug.Assert(context.ConfigurationPath == context.Request.FilePathObject, "context.ConfigurationPath (" +
3335 context.ConfigurationPath + ") != context.Request.FilePath (" + context.Request.FilePath + ")");
3337 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_MAPHANDLER_LEAVE, context.WorkerRequest);
3340 bool IExecutionStep.CompletedSynchronously {
3344 bool IExecutionStep.IsCancellable {
3345 get { return false; }
3349 // execution step -- call HTTP handler (used to be a separate module)
3350 internal class CallHandlerExecutionStep : IExecutionStep {
3351 private HttpApplication _application;
3352 private AsyncCallback _completionCallback;
3353 private IHttpAsyncHandler _handler; // per call
3354 private AsyncStepCompletionInfo _asyncStepCompletionInfo; // per call
3355 private bool _sync; // per call
3357 internal CallHandlerExecutionStep(HttpApplication app) {
3359 _completionCallback = new AsyncCallback(this.OnAsyncHandlerCompletion);
3362 private void OnAsyncHandlerCompletion(IAsyncResult ar) {
3363 if (ar.CompletedSynchronously) {
3364 // Synchronous completions will be handled by IExecutionStep.Execute.
3368 // This IAsyncResult may actually have completed synchronously (we might be on the same thread
3369 // which called IExecutionStep.Execute) even if CompletedSynchronously = false. Regardless,
3370 // we should invoke the End* method on the same thread that invoked this callback, as some
3371 // applications use TLS instead of the IAsyncResult object itself to convey state information.
3373 HttpContext context = _application.Context;
3374 Exception error = null;
3376 // The asynchronous step has completed, so we should disallow further
3377 // async operations until the next step.
3378 context.SyncContext.ProhibitVoidAsyncOperations();
3382 _handler.EndProcessRequest(ar);
3385 SuppressPostEndRequestIfNecessary(context);
3387 // In Integrated mode, generate the necessary response headers
3388 // after the ASP.NET handler runs. If EndProcessRequest throws,
3389 // the headers will be generated by ReportRuntimeError
3390 context.Response.GenerateResponseHeadersForHandler();
3393 catch (Exception e) {
3394 if (e is ThreadAbortException || e.InnerException != null && e.InnerException is ThreadAbortException) {
3395 // Response.End happened during async operation
3396 _application.CompleteRequest();
3403 bool shouldCallResumeSteps = _asyncStepCompletionInfo.RegisterAsyncCompletion(error);
3404 if (!shouldCallResumeSteps) {
3408 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Information, EtwTraceFlags.Page)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_HTTPHANDLER_LEAVE, context.WorkerRequest);
3410 _handler = null; // not to remember
3412 // re-set start time after an async completion (see VSWhidbey 231010)
3413 context.SetStartTime();
3415 // Assert to disregard the user code up the stack
3416 if (HttpRuntime.IsLegacyCas) {
3417 ResumeStepsWithAssert(error);
3424 [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
3425 void ResumeStepsWithAssert(Exception error) {
3429 void ResumeSteps(Exception error) {
3430 _application.ResumeStepsFromThreadPoolThread(error);
3433 private static void SuppressPostEndRequestIfNecessary(HttpContext context) {
3434 // DevDiv #245124 - ASP.NET now hooks PostEndRequest in order to kick off the WebSocket pipeline.
3435 // If this is not a WebSocket request or the handshake was not completed, then we can suppress
3436 // this pipeline event. This allows us to send the appropriate cache headers to the client,
3437 // and it also gives a small perf boost.
3439 if (!context.IsWebSocketRequestUpgrading) {
3440 IIS7WorkerRequest wr = context.WorkerRequest as IIS7WorkerRequest;
3442 wr.DisableNotifications(notifications: 0, postNotifications: RequestNotification.EndRequest);
3447 void IExecutionStep.Execute() {
3448 HttpContext context = _application.Context;
3449 IHttpHandler handler = context.Handler;
3451 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Information, EtwTraceFlags.Page)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_HTTPHANDLER_ENTER, context.WorkerRequest);
3453 if (handler != null && HttpRuntime.UseIntegratedPipeline) {
3454 IIS7WorkerRequest wr = context.WorkerRequest as IIS7WorkerRequest;
3455 if (wr != null && wr.IsHandlerExecutionDenied()) {
3457 HttpException error = new HttpException(403, SR.GetString(SR.Handler_access_denied));
3458 error.SetFormatter(new PageForbiddenErrorFormatter(context.Request.Path, SR.GetString(SR.Handler_access_denied)));
3463 if (handler == null) {
3466 else if (handler is IHttpAsyncHandler) {
3467 // asynchronous handler
3468 IHttpAsyncHandler asyncHandler = (IHttpAsyncHandler)handler;
3471 _handler = asyncHandler;
3473 // Instrument the BeginProcessRequest method if AppVerifier is enabled.
3474 // If AppVerifier not enabled, we just get back the original delegate to BeginProcessRequest uninstrumented.
3475 var beginProcessRequestDelegate = AppVerifier.WrapBeginMethod<HttpContext>(_application, asyncHandler.BeginProcessRequest);
3477 _asyncStepCompletionInfo.Reset();
3478 context.SyncContext.AllowVoidAsyncOperations();
3481 ar = beginProcessRequestDelegate(context, _completionCallback, null);
3484 // The asynchronous step has completed, so we should disallow further
3485 // async operations until the next step.
3486 context.SyncContext.ProhibitVoidAsyncOperations();
3490 bool operationCompleted;
3491 bool mustCallEndHandler;
3492 _asyncStepCompletionInfo.RegisterBeginUnwound(ar, out operationCompleted, out mustCallEndHandler);
3494 if (operationCompleted) {
3496 _handler = null; // not to remember
3498 // The asynchronous step has completed, so we should disallow further
3499 // async operations until the next step.
3500 context.SyncContext.ProhibitVoidAsyncOperations();
3503 if (mustCallEndHandler) {
3504 asyncHandler.EndProcessRequest(ar);
3507 _asyncStepCompletionInfo.ReportError();
3510 SuppressPostEndRequestIfNecessary(context);
3512 // In Integrated mode, generate the necessary response headers
3513 // after the ASP.NET handler runs
3514 context.Response.GenerateResponseHeadersForHandler();
3517 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Information, EtwTraceFlags.Page)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_HTTPHANDLER_LEAVE, context.WorkerRequest);
3521 // synchronous handler
3524 // disable async operations
3525 //_application.SyncContext.Disable();
3527 // VSWhidbey 268772 - If a synchronous handler internally kicks off an asynchronous operation and waits (blocking) for that
3528 // operation to complete, the handler will deadlock since the asynchronous operation can't come back to the appropriate
3529 // thread to perform the completion. The solution below was only meant to be temporary but was accidentally left in the product
3530 // for v2.0 RTM, so it's now legacy behavior and cannot be changed.
3531 context.SyncContext.SetSyncCaller();
3534 handler.ProcessRequest(context);
3537 context.SyncContext.ResetSyncCaller();
3538 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Information, EtwTraceFlags.Page)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_HTTPHANDLER_LEAVE, context.WorkerRequest);
3540 SuppressPostEndRequestIfNecessary(context);
3542 // In Integrated mode, generate the necessary response headers
3543 // after the ASP.NET handler runs
3544 context.Response.GenerateResponseHeadersForHandler();
3549 bool IExecutionStep.CompletedSynchronously {
3550 get { return _sync;}
3553 bool IExecutionStep.IsCancellable {
3554 // launching of async handler should not be cancellable
3555 get { return (_application.Context.Handler is IHttpAsyncHandler) ? false : true; }
3559 // execution step -- initiate the transition to a WebSocket request
3560 internal class TransitionToWebSocketsExecutionStep : IExecutionStep {
3561 private readonly HttpApplication _application;
3563 internal TransitionToWebSocketsExecutionStep(HttpApplication app) {
3567 void IExecutionStep.Execute() {
3568 HttpContext context = _application.Context;
3570 if (context.RootedObjects == null
3571 || context.RootedObjects.WebSocketPipeline == null
3572 || context.Response.StatusCode != (int)HttpStatusCode.SwitchingProtocols) {
3574 // If this isn't a WebSocket request or something has caused the status code
3575 // not to be HTTP 101 (such as an error, redirect, or something else), no-op.
3576 CompletedSynchronously = true;
3579 // DevDiv #273639: Let the HttpRequest instance maintain a reference to the response
3580 // cookie collection, as the HttpResponse instance won't be available after the transition.
3581 context.Request.StoreReferenceToResponseCookies(context.Response.GetCookiesNoCreate());
3583 // If this is a WebSocket request, mark as transitioned so that asynchronous events (like SendRequest)
3584 // don't execute. We also need to mark ourselves as not having completed synchronously so that the
3585 // pipeline unwinds back to ProcessRequestNotification. That method special-cases WebSocket handlers
3586 // and cleans up the HttpContext / HttpApplication eagerly.
3588 // transition: AcceptWebSocketRequestCalled -> TransitionStarted
3589 context.TransitionToWebSocketState(WebSocketTransitionState.TransitionStarted);
3590 CompletedSynchronously = false;
3594 public bool CompletedSynchronously {
3599 public bool IsCancellable {
3600 // launching of async operation should not be cancellable
3601 get { return false; }
3605 // execution step -- call response filter
3606 internal class CallFilterExecutionStep : IExecutionStep {
3607 private HttpApplication _application;
3609 internal CallFilterExecutionStep(HttpApplication app) {
3613 void IExecutionStep.Execute() {
3615 _application.Context.Response.FilterOutput();
3618 // if this is the UpdateCache notification, then disable the LogRequest notification (which handles the error case)
3619 if (HttpRuntime.UseIntegratedPipeline && (_application.Context.CurrentNotification == RequestNotification.UpdateRequestCache)) {
3620 _application.Context.DisableNotifications(RequestNotification.LogRequest, 0 /*postNotifications*/);
3625 bool IExecutionStep.CompletedSynchronously {
3629 bool IExecutionStep.IsCancellable {
3630 get { return true; }
3634 // integrated pipeline execution step for RaiseOnPreSendRequestHeaders and RaiseOnPreSendRequestContent
3635 internal class SendResponseExecutionStep : IExecutionStep {
3636 private HttpApplication _application;
3637 private EventHandler _handler;
3638 private bool _isHeaders;
3640 internal SendResponseExecutionStep(HttpApplication app, EventHandler handler, bool isHeaders) {
3643 _isHeaders = isHeaders;
3646 void IExecutionStep.Execute() {
3648 // IIS only has a SendResponse notification, so we check the flags
3649 // to determine whether this notification is for headers or content.
3650 // The step uses _isHeaders to keep track of whether this is for headers or content.
3651 if (_application.Context.IsSendResponseHeaders && _isHeaders
3654 string targetTypeStr = null;
3656 if (_handler != null) {
3657 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Module)) {
3658 targetTypeStr = _handler.Method.ReflectedType.ToString();
3660 EtwTrace.Trace(EtwTraceType.ETW_TYPE_PIPELINE_ENTER, _application.Context.WorkerRequest, targetTypeStr);
3662 _handler(_application, _application.AppEvent);
3663 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Module)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_PIPELINE_LEAVE, _application.Context.WorkerRequest, targetTypeStr);
3668 bool IExecutionStep.CompletedSynchronously {
3672 bool IExecutionStep.IsCancellable {
3673 get { return true; }
3677 internal class UrlMappingsExecutionStep : IExecutionStep {
3678 private HttpApplication _application;
3681 internal UrlMappingsExecutionStep(HttpApplication app) {
3685 void IExecutionStep.Execute() {
3686 HttpContext context = _application.Context;
3687 UrlMappingsModule.UrlMappingRewritePath(context);
3690 bool IExecutionStep.CompletedSynchronously {
3694 bool IExecutionStep.IsCancellable {
3695 get { return false; }
3699 internal abstract class StepManager {
3700 protected HttpApplication _application;
3701 protected bool _requestCompleted;
3703 internal StepManager(HttpApplication application) {
3704 _application = application;
3707 internal bool IsCompleted { get { return _requestCompleted; } }
3709 internal abstract void BuildSteps(WaitCallback stepCallback);
3711 internal void CompleteRequest() {
3712 _requestCompleted = true;
3713 if (HttpRuntime.UseIntegratedPipeline) {
3714 HttpContext context = _application.Context;
3715 if (context != null && context.NotificationContext != null) {
3716 context.NotificationContext.RequestCompleted = true;
3721 internal abstract void InitRequest();
3723 internal abstract void ResumeSteps(Exception error);
3726 internal class ApplicationStepManager : StepManager {
3727 private IExecutionStep[] _execSteps;
3728 private WaitCallback _resumeStepsWaitCallback;
3729 private int _currentStepIndex;
3730 private int _numStepCalls;
3731 private int _numSyncStepCalls;
3732 private int _endRequestStepIndex;
3734 internal ApplicationStepManager(HttpApplication app): base(app) {
3737 internal override void BuildSteps(WaitCallback stepCallback ) {
3738 ArrayList steps = new ArrayList();
3739 HttpApplication app = _application;
3741 bool urlMappingsEnabled = false;
3742 UrlMappingsSection urlMappings = RuntimeConfig.GetConfig().UrlMappings;
3743 urlMappingsEnabled = urlMappings.IsEnabled && ( urlMappings.UrlMappings.Count > 0 );
3745 steps.Add(new ValidateRequestExecutionStep(app));
3746 steps.Add(new ValidatePathExecutionStep(app));
3748 if (urlMappingsEnabled)
3749 steps.Add(new UrlMappingsExecutionStep(app)); // url mappings
3751 app.CreateEventExecutionSteps(HttpApplication.EventBeginRequest, steps);
3752 app.CreateEventExecutionSteps(HttpApplication.EventAuthenticateRequest, steps);
3753 app.CreateEventExecutionSteps(HttpApplication.EventDefaultAuthentication, steps);
3754 app.CreateEventExecutionSteps(HttpApplication.EventPostAuthenticateRequest, steps);
3755 app.CreateEventExecutionSteps(HttpApplication.EventAuthorizeRequest, steps);
3756 app.CreateEventExecutionSteps(HttpApplication.EventPostAuthorizeRequest, steps);
3757 app.CreateEventExecutionSteps(HttpApplication.EventResolveRequestCache, steps);
3758 app.CreateEventExecutionSteps(HttpApplication.EventPostResolveRequestCache, steps);
3759 steps.Add(new MapHandlerExecutionStep(app)); // map handler
3760 app.CreateEventExecutionSteps(HttpApplication.EventPostMapRequestHandler, steps);
3761 app.CreateEventExecutionSteps(HttpApplication.EventAcquireRequestState, steps);
3762 app.CreateEventExecutionSteps(HttpApplication.EventPostAcquireRequestState, steps);
3763 app.CreateEventExecutionSteps(HttpApplication.EventPreRequestHandlerExecute, steps);
3764 steps.Add(app.CreateImplicitAsyncPreloadExecutionStep()); // implict async preload step
3765 steps.Add(new CallHandlerExecutionStep(app)); // execute handler
3766 app.CreateEventExecutionSteps(HttpApplication.EventPostRequestHandlerExecute, steps);
3767 app.CreateEventExecutionSteps(HttpApplication.EventReleaseRequestState, steps);
3768 app.CreateEventExecutionSteps(HttpApplication.EventPostReleaseRequestState, steps);
3769 steps.Add(new CallFilterExecutionStep(app)); // filtering
3770 app.CreateEventExecutionSteps(HttpApplication.EventUpdateRequestCache, steps);
3771 app.CreateEventExecutionSteps(HttpApplication.EventPostUpdateRequestCache, steps);
3772 _endRequestStepIndex = steps.Count;
3773 app.CreateEventExecutionSteps(HttpApplication.EventEndRequest, steps);
3774 steps.Add(new NoopExecutionStep()); // the last is always there
3776 _execSteps = new IExecutionStep[steps.Count];
3777 steps.CopyTo(_execSteps);
3779 // callback for async completion when reposting to threadpool thread
3780 _resumeStepsWaitCallback = stepCallback;
3783 internal override void InitRequest() {
3784 _currentStepIndex = -1;
3786 _numSyncStepCalls = 0;
3787 _requestCompleted = false;
3790 // This attribute prevents undesirable 'just-my-code' debugging behavior (VSWhidbey 404406/VSWhidbey 609188)
3791 [System.Diagnostics.DebuggerStepperBoundaryAttribute]
3792 internal override void ResumeSteps(Exception error) {
3793 bool appCompleted = false;
3794 bool stepCompletedSynchronously = true;
3795 HttpApplication app = _application;
3796 CountdownTask appInstanceConsumersCounter = app.ApplicationInstanceConsumersCounter;
3797 HttpContext context = app.Context;
3798 ThreadContext threadContext = null;
3799 AspNetSynchronizationContextBase syncContext = context.SyncContext;
3801 Debug.Trace("Async", "HttpApplication.ResumeSteps");
3804 if (appInstanceConsumersCounter != null) {
3805 appInstanceConsumersCounter.MarkOperationPending(); // ResumeSteps call started
3808 using (syncContext.AcquireThreadLock()) {
3809 // avoid ---- between the app code and fast async completion from a module
3813 threadContext = app.OnThreadEnter();
3815 catch (Exception e) {
3825 if (syncContext.Error != null) {
3826 error = syncContext.Error;
3827 syncContext.ClearError();
3830 if (error != null) {
3831 app.RecordError(error);
3835 // check for any outstanding async operations
3837 if (syncContext.PendingCompletion(_resumeStepsWaitCallback)) {
3838 // wait until all pending async operations complete
3842 // advance to next step
3844 if (_currentStepIndex < _endRequestStepIndex && (context.Error != null || _requestCompleted)) {
3846 context.Response.FilterOutput();
3847 _currentStepIndex = _endRequestStepIndex;
3850 _currentStepIndex++;
3853 if (_currentStepIndex >= _execSteps.Length) {
3854 appCompleted = true;
3858 // execute the current step
3860 _numStepCalls++; // count all calls
3862 // enable launching async operations before each new step
3863 syncContext.Enable();
3865 // call to execute current step catching thread abort exception
3866 error = app.ExecuteStep(_execSteps[_currentStepIndex], ref stepCompletedSynchronously);
3868 // unwind the stack in the async case
3869 if (!stepCompletedSynchronously)
3872 _numSyncStepCalls++; // count synchronous calls
3877 // need to raise OnRequestCompleted while within the ThreadContext so that things like User, CurrentCulture, etc. are available
3878 context.RaiseOnRequestCompleted();
3881 if (threadContext != null) {
3883 threadContext.DisassociateFromCurrentThread();
3890 catch { // Protect against exception filters
3897 // need to raise OnPipelineCompleted outside of the ThreadContext so that HttpContext.Current, User, etc. are unavailable
3898 context.RaiseOnPipelineCompleted();
3900 // unroot context (async app operations ended)
3904 app.AsyncResult.Complete((_numStepCalls == _numSyncStepCalls), null, null);
3905 app.ReleaseAppInstance();
3909 if (appInstanceConsumersCounter != null) {
3910 appInstanceConsumersCounter.MarkOperationCompleted(); // ResumeSteps call complete
3916 internal class PipelineStepManager : StepManager {
3918 WaitCallback _resumeStepsWaitCallback;
3919 bool _validatePathCalled;
3920 bool _validateInputCalled;
3922 internal PipelineStepManager(HttpApplication app): base(app) {
3925 internal override void BuildSteps(WaitCallback stepCallback) {
3926 Debug.Trace("PipelineRuntime", "BuildSteps");
3927 //ArrayList steps = new ArrayList();
3928 HttpApplication app = _application;
3930 // add special steps that don't currently
3931 // correspond to a configured handler
3933 IExecutionStep materializeStep = new MaterializeHandlerExecutionStep(app);
3935 // implicit map step
3936 app.AddEventMapping(
3937 HttpApplication.IMPLICIT_HANDLER,
3938 RequestNotification.MapRequestHandler,
3939 false, materializeStep);
3941 // implicit async preload step
3942 app.AddEventMapping(
3943 HttpApplication.IMPLICIT_HANDLER,
3944 RequestNotification.ExecuteRequestHandler,
3945 false, app.CreateImplicitAsyncPreloadExecutionStep());
3947 // implicit handler routing step
3948 IExecutionStep handlerStep = new CallHandlerExecutionStep(app);
3950 app.AddEventMapping(
3951 HttpApplication.IMPLICIT_HANDLER,
3952 RequestNotification.ExecuteRequestHandler,
3953 false, handlerStep);
3955 // implicit handler WebSockets step
3956 IExecutionStep webSocketsStep = new TransitionToWebSocketsExecutionStep(app);
3958 app.AddEventMapping(
3959 HttpApplication.IMPLICIT_HANDLER,
3960 RequestNotification.EndRequest,
3961 true /* isPostNotification */, webSocketsStep);
3963 // add implicit request filtering step
3964 IExecutionStep filterStep = new CallFilterExecutionStep(app);
3966 // normally, this executes during UpdateRequestCache as a high priority module
3967 app.AddEventMapping(
3968 HttpApplication.IMPLICIT_FILTER_MODULE,
3969 RequestNotification.UpdateRequestCache,
3972 // for error conditions, this executes during LogRequest as a high priority module
3973 app.AddEventMapping(
3974 HttpApplication.IMPLICIT_FILTER_MODULE,
3975 RequestNotification.LogRequest,
3978 _resumeStepsWaitCallback = stepCallback;
3981 internal override void InitRequest() {
3982 _requestCompleted = false;
3983 _validatePathCalled = false;
3984 _validateInputCalled = false;
3987 // PipelineStepManager::ResumeSteps
3988 // called from IIS7 (on IIS thread) via BeginProcessRequestNotification
3989 // or from an async completion (on CLR thread) via HttpApplication::ResumeStepsFromThreadPoolThread
3990 // This attribute prevents undesirable 'just-my-code' debugging behavior (VSWhidbey 404406/VSWhidbey 609188)
3991 [System.Diagnostics.DebuggerStepperBoundaryAttribute]
3992 internal override void ResumeSteps(Exception error) {
3993 HttpContext context = _application.Context;
3994 IIS7WorkerRequest wr = context.WorkerRequest as IIS7WorkerRequest;
3995 AspNetSynchronizationContextBase syncContext = context.SyncContext;
3997 RequestNotificationStatus status = RequestNotificationStatus.Continue;
3998 ThreadContext threadContext = null;
3999 bool needToDisassociateThreadContext = false;
4000 bool isSynchronousCompletion = false;
4001 bool needToComplete = false;
4002 bool stepCompletedSynchronously = false;
4003 bool isReEntry = false;
4004 int currentModuleLastEventIndex = -1;
4005 _application.GetNotifcationContextProperties(ref isReEntry, ref currentModuleLastEventIndex);
4007 CountdownTask appInstanceConsumersCounter = _application.ApplicationInstanceConsumersCounter;
4009 using (context.RootedObjects.WithinTraceBlock()) {
4010 // DevDiv Bugs 187441: IIS7 Integrated Mode: Problem flushing Response from background threads in IIS7 integrated mode
4011 if (!isReEntry) // currently we only re-enter for SendResponse
4013 syncContext.AssociateWithCurrentThread();
4016 if (appInstanceConsumersCounter != null) {
4017 appInstanceConsumersCounter.MarkOperationPending(); // ResumeSteps call started
4020 bool locked = false;
4022 // As a performance optimization, ASP.NET uses the IIS IHttpContext::IndicateCompletion function to continue executing notifications
4023 // on a thread that is associated with the AppDomain. This is done by calling IndicateCompletion from within the AppDomain, instead
4024 // of returning to native code. This technique can only be used for notifications that complete synchronously.
4026 // There are two cases where notifications happen on a thread that has an initialized ThreadContext, and therefore does not need
4027 // to call ThreadContext.OnThreadEnter. These include SendResponse notifications and notifications that occur within a call to
4028 // IndicateCompletion. Note that SendResponse notifications occur on-demand, i.e., they happen when another notification triggers
4029 // a SendResponse, at which point it blocks until the SendResponse notification completes.
4031 if (!isReEntry) { // currently we only re-enter for SendResponse
4032 // DevDiv 482614 (Sharepoint Bug 3137123)
4033 // Async completion or SendResponse can happen on a background thread while the thread that called IndicateCompletion has not unwound yet
4034 // Therefore (InIndicateCompletion == true) is not a sufficient evidence that we can use the ThreadContext stored in IndicateCompletionContext
4035 // To avoid using other thread's ThreadContext we use IndicateCompletionContext only if ThreadInsideIndicateCompletion is indeed our thread
4036 if (context.InIndicateCompletion && context.ThreadInsideIndicateCompletion == Thread.CurrentThread) {
4037 // we already have a ThreadContext
4038 threadContext = context.IndicateCompletionContext;
4039 if (context.UsesImpersonation) {
4040 // UsesImpersonation is set to true after RQ_AUTHENTICATE_REQUEST
4041 threadContext.SetImpersonationContext();
4045 // we need to create a new ThreadContext
4046 threadContext = _application.OnThreadEnter(context.UsesImpersonation);
4047 // keep track if we need to disassociate it later
4048 needToDisassociateThreadContext = true;
4054 Debug.Trace("PipelineRuntime", "ResumeSteps: CurrentModuleEventIndex=" + context.CurrentModuleEventIndex);
4057 // check and record errors into the HttpContext
4058 if (syncContext.Error != null) {
4059 error = syncContext.Error;
4060 syncContext.ClearError();
4062 if (error != null) {
4063 // the error can be cleared by the user
4064 _application.RecordError(error);
4068 if (!_validateInputCalled || !_validatePathCalled) {
4069 error = ValidateHelper(context);
4070 if (error != null) {
4075 // check for any outstanding async operations
4076 // DevDiv 1020085: User code may leave pending async completions on the synchronization context
4077 // while processing nested (isReEntry == true) and not nested (isReEntry == false) notifications.
4078 // In both cases only the non nested notification which has proper synchronization should handle it.
4079 if (!isReEntry && syncContext.PendingCompletion(_resumeStepsWaitCallback)) {
4080 // Background flushes may trigger RQ_SEND_RESPONSE notifications which will set new context.NotificationContext
4081 // Synchronize access to context.NotificationContext to make sure we update the correct NotificationContext instance
4082 _application.AcquireNotifcationContextLock(ref locked);
4084 // Since the step completed asynchronously, this thread must return RequestNotificationStatus.Pending to IIS,
4085 // and the async completion of this step must call IIS7WorkerRequest::PostCompletion. The async completion of
4086 // this step will call ResumeSteps again.
4087 context.NotificationContext.PendingAsyncCompletion = true;
4091 // LogRequest and EndRequest never report errors, and never return a status of FinishRequest.
4092 bool needToFinishRequest = (context.NotificationContext.Error != null || context.NotificationContext.RequestCompleted)
4093 && context.CurrentNotification != RequestNotification.LogRequest
4094 && context.CurrentNotification != RequestNotification.EndRequest;
4096 if (needToFinishRequest || context.CurrentModuleEventIndex == currentModuleLastEventIndex) {
4098 // if an error occured or someone completed the request, set the status to FinishRequest
4099 status = needToFinishRequest ? RequestNotificationStatus.FinishRequest : RequestNotificationStatus.Continue;
4102 if (context.NotificationContext.PendingAsyncCompletion) {
4103 context.Response.SyncStatusIntegrated();
4104 context.NotificationContext.PendingAsyncCompletion = false;
4105 isSynchronousCompletion = false;
4106 needToComplete = true;
4110 // [....] case (we might be able to stay in managed code and execute another notification)
4111 if (needToFinishRequest || UnsafeIISMethods.MgdGetNextNotification(wr.RequestContext, RequestNotificationStatus.Continue) != 1) {
4112 isSynchronousCompletion = true;
4113 needToComplete = true;
4117 int currentModuleIndex = 0;
4118 bool isPostNotification = false;
4119 int currentNotification = 0;
4121 UnsafeIISMethods.MgdGetCurrentNotificationInfo(wr.RequestContext, out currentModuleIndex, out isPostNotification, out currentNotification);
4123 // setup the HttpContext for this event/module combo
4124 context.CurrentModuleIndex = currentModuleIndex;
4125 context.IsPostNotification = isPostNotification;
4126 context.CurrentNotification = (RequestNotification)currentNotification;
4127 context.CurrentModuleEventIndex = -1;
4128 currentModuleLastEventIndex = _application.CurrentModuleContainer.GetEventCount(context.CurrentNotification, context.IsPostNotification) - 1;
4131 context.CurrentModuleEventIndex++;
4133 IExecutionStep step = _application.CurrentModuleContainer.GetNextEvent(context.CurrentNotification, context.IsPostNotification,
4134 context.CurrentModuleEventIndex);
4136 // enable launching async operations before each new step
4137 context.SyncContext.Enable();
4139 stepCompletedSynchronously = false;
4140 error = _application.ExecuteStep(step, ref stepCompletedSynchronously);
4143 Debug.Trace("PipelineRuntime", "ResumeSteps: notification=" + context.CurrentNotification.ToString()
4144 + ", isPost=" + context.IsPostNotification
4145 + ", step=" + step.GetType().FullName
4146 + ", completedSync=" + stepCompletedSynchronously
4147 + ", moduleName=" + _application.CurrentModuleContainer.DebugModuleName
4148 + ", moduleIndex=" + context.CurrentModuleIndex
4149 + ", eventIndex=" + context.CurrentModuleEventIndex);
4153 if (!stepCompletedSynchronously) {
4154 // Since the step completed asynchronously, this thread must return RequestNotificationStatus.Pending to IIS,
4155 // and the async completion of this step must call IIS7WorkerRequest::PostCompletion. The async completion of
4156 // this step will call ResumeSteps again.
4157 //context.AcquireNotifcationContextLockBeforeUnwind();
4158 _application.AcquireNotifcationContextLock(ref locked);
4159 context.NotificationContext.PendingAsyncCompletion = true;
4163 context.Response.SyncStatusIntegrated();
4169 _application.ReleaseNotifcationContextLock();
4171 if (threadContext != null) {
4172 if (context.InIndicateCompletion) {
4173 if (isSynchronousCompletion) {
4174 // this is a [....] completion on an IIS thread
4175 threadContext.Synchronize();
4176 // Note for DevDiv 482614 fix:
4177 // If this threadContext is from IndicateCompletionContext (e.g. this thread called IndicateCompletion)
4178 // then we continue reusing this thread and only undo impersonation before unwinding back to IIS.
4180 // If this threadContext was created while another thread was and still is in IndicateCompletion call
4181 // (e.g. [....] or async flush on a background thread from native code, not managed since isReEnty==false)
4182 // then we can not reuse this thread and this threadContext will be cleaned before we leave ResumeSteps
4183 // (because needToDisassociateThreadContext was set to true when we created this threadContext)
4185 //always undo impersonation so that the token is removed before returning to IIS (DDB 156421)
4186 threadContext.UndoImpersonationContext();
4189 // We're returning pending on an IIS thread in a call to IndicateCompletion.
4190 // Leave the thread context now while we're still under the lock so that the
4191 // async completion does not corrupt the state of HttpContext or IndicateCompletionContext.
4192 if (!threadContext.HasBeenDisassociatedFromThread) {
4193 lock (threadContext) {
4194 if (!threadContext.HasBeenDisassociatedFromThread) {
4195 threadContext.DisassociateFromCurrentThread();
4196 // remember to not disassociate again
4197 needToDisassociateThreadContext = false;
4199 // Async steps or completions may happen while another thread is inside IndicateCompletion
4200 // We do not clear IndicateCompletionContext if it belongs to another thread
4201 // (otherwise future notifications on the thread that called IndicateCompletion won't have
4202 // context.IndicateCompletionContext pointing to their not yet disassociated ThreadContext)
4203 if (context.ThreadInsideIndicateCompletion == Thread.CurrentThread) {
4204 context.IndicateCompletionContext = null;
4211 else if (isSynchronousCompletion) {
4212 Debug.Assert(needToDisassociateThreadContext == true, "needToDisassociateThreadContext MUST BE true");
4213 // this is a [....] completion on an IIS thread
4214 threadContext.Synchronize();
4215 // get ready to call IndicateCompletion
4216 context.IndicateCompletionContext = threadContext;
4217 // Note for DevDiv 482614 fix:
4218 // This thread created a new ThreadContext if it did not call IndicateCompletion yet or if there was
4219 // another thread already in IndicateCompletion (a background flush from native code or a completion
4220 // on another thread). In either case if currently there is no thread in IndicateCompletion
4221 // then we can reuse this thread and its threadContext and call IndicateCompletion on the current thread.
4222 // In this case we will not disassociate this threadContext now
4223 needToDisassociateThreadContext = false;
4224 //always undo impersonation so that the token is removed before returning to IIS (DDB 156421)
4225 threadContext.UndoImpersonationContext();
4228 Debug.Assert(needToDisassociateThreadContext == true, "needToDisassociateThreadContext MUST BE true");
4229 // We're not in a call to IndicateCompletion. We're either returning pending or
4230 // we're in an async completion, and therefore we must clean-up the thread state. Impersonation is reverted
4231 threadContext.DisassociateFromCurrentThread();
4232 // remember to not disassociate again
4233 needToDisassociateThreadContext = false;
4236 // Cleanup the thread state unless we prepared to call IndicateCompletion or already cleaned up
4237 if (needToDisassociateThreadContext) {
4238 threadContext.DisassociateFromCurrentThread();
4243 // WOS #1703315: we cannot complete until after OnThreadLeave is called.
4244 if (needToComplete) {
4245 // call HttpRuntime::OnRequestNotificationCompletion
4246 _application.AsyncResult.Complete(isSynchronousCompletion, null /*result*/, null /*error*/, status);
4248 } // end of try statement that begins after AssociateWithCurrentThread
4251 syncContext.DisassociateFromCurrentThread();
4253 if (appInstanceConsumersCounter != null) {
4254 appInstanceConsumersCounter.MarkOperationCompleted(); // ResumeSteps call completed
4260 private Exception ValidateHelper(HttpContext context) {
4261 if (!_validateInputCalled) {
4262 _validateInputCalled = true;
4264 context.Request.ValidateInputIfRequiredByConfig();
4266 catch(Exception e) {
4270 if (!_validatePathCalled) {
4271 _validatePathCalled = true;
4273 context.ValidatePath();
4275 catch(Exception e) {
4283 // WARNING: Mutable struct for performance reasons; exercise caution when using this type.
4284 private struct AsyncStepCompletionInfo {
4285 #pragma warning disable 420 // volatile passed by reference; our uses are safe
4286 // state for async execution steps
4287 private const int ASYNC_STATE_NONE = 0;
4288 private const int ASYNC_STATE_BEGIN_UNWOUND = 1;
4289 private const int ASYNC_STATE_CALLBACK_COMPLETED = 2;
4291 private volatile int _asyncState;
4292 private ExceptionDispatchInfo _error;
4294 // Invoked from the callback to signal that the End* method has run to completion.
4295 // Returns 'true' if the current thread should call ResumeSteps, 'false' if not.
4296 public bool RegisterAsyncCompletion(Exception error) {
4297 // Before the call to Exchange below, the _asyncCompletionInfo field will have the value
4298 // ASYNC_STATE_NONE or ASYNC_STATE_BEGIN_UNWOUND. If it's the former, then the Begin* method
4299 // hasn't yet returned control to IExecutionStep.Execute. From this step's point of view,
4300 // this can be treated as a synchronous completion, which will allow us to call ResumeSteps
4301 // on the original thread and save the cost of destroying the existing ThreadContext and
4302 // creating a new one. If the original value is instead ASYNC_STATE_BEGIN_UNWOUND, then
4303 // the Begin* method already returned control to IExecutionStep.Execute and this step was
4304 // marked as having an asynchronous completion. The original thread will tear down the
4305 // ThreadContext, so the current thread should call back into ResumeSteps to resurrect it.
4307 // If there was an error, we'll use the _error field to store it so that IExecutionStep.Execute
4308 // can rethrow it as it's unwinding.
4310 // Interlocked performs a volatile write; all processors will see the write to _error as being
4311 // no later than the write to _asyncState.
4312 _error = (error != null) ? ExceptionDispatchInfo.Capture(error) : null;
4313 int originalState = Interlocked.Exchange(ref _asyncState, ASYNC_STATE_CALLBACK_COMPLETED);
4314 if (originalState == ASYNC_STATE_NONE) {
4315 return false; // IExecutionStep.Execute should call ResumeSteps
4318 Debug.Assert(originalState == ASYNC_STATE_BEGIN_UNWOUND, "Unexpected state.");
4319 _error = null; // to prevent long-lived exception object; write doesn't need to be volatile since nobody reads this field anyway in this case
4320 return true; // this thread should call ResumeSteps
4323 public void RegisterBeginUnwound(IAsyncResult asyncResult, out bool operationCompleted, out bool mustCallEndHandler) {
4324 operationCompleted = false;
4325 mustCallEndHandler = false;
4327 int originalState = Interlocked.Exchange(ref _asyncState, ASYNC_STATE_BEGIN_UNWOUND);
4328 if (originalState == ASYNC_STATE_NONE) {
4329 if (asyncResult.CompletedSynchronously) {
4330 // Synchronous completion; the callback either wasn't called or was a no-op.
4331 // In either case, we should call the End* method from this thread.
4332 operationCompleted = true;
4333 mustCallEndHandler = true;
4336 // Otherwise, this is an asynchronous completion, and the callback hasn't yet been invoked or hasn't fully completed.
4337 // We'll let the thread that invokes the callback call the End* method.
4340 Debug.Assert(originalState == ASYNC_STATE_CALLBACK_COMPLETED, "Unexpected state.");
4342 // The operation completed, and the callback already invoked the End* method.
4343 // The only thing we need to do is to report to our caller that the operation completed synchronously
4344 // (so that ResumeSteps runs on this thread) and to observe any exceptions that occurred.
4345 operationCompleted = true;
4348 // Interlocked performs a volatile read; if RethrowExceptionIfNecessary() is called after RegisterBeginUnwound(),
4349 // the thread will see the correct value for the _error field.
4352 public void ReportError() {
4353 // Using ExceptionDispatchInfo preserves the Exception's stack trace when rethrowing.
4354 ExceptionDispatchInfo error = _error;
4355 if (error != null) {
4356 _error = null; // prevent long-lived Exception objects on the heap
4361 public void Reset() {
4362 // All processors see the _error field write as being no later than the _asyncState field write.
4364 _asyncState = ASYNC_STATE_NONE;
4366 #pragma warning restore 420 // volatile passed by reference