Merge pull request #3389 from lambdageek/bug-43099
[mono.git] / mcs / class / referencesource / System.Web / HttpApplication.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="HttpApplication.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 namespace System.Web {
8     using System;
9     using System.Collections;
10     using System.Collections.Generic;
11     using System.ComponentModel;
12     using System.ComponentModel.Design;
13     using System.Globalization;
14     using System.IO;
15     using System.Linq;
16     using System.Net;
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;
28     using System.Web;
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;
36     using System.Web.UI;
37     using System.Web.Util;
38     using IIS = System.Web.Hosting.UnsafeIISMethods;
39
40
41     //
42     // Async EventHandler support
43     //
44
45
46     /// <devdoc>
47     ///    <para>[To be supplied.]</para>
48     /// </devdoc>
49     public delegate IAsyncResult BeginEventHandler(object sender, EventArgs e, AsyncCallback cb, object extraData);
50
51     /// <devdoc>
52     ///    <para>[To be supplied.]</para>
53     /// </devdoc>
54     public delegate void EndEventHandler(IAsyncResult ar);
55
56     // Represents an event handler using TAP (Task Asynchronous Pattern).
57     public delegate Task TaskEventHandler(object sender, EventArgs e);
58
59
60     /// <devdoc>
61     ///    <para>
62     ///       The  HttpApplication class defines the methods, properties and events common to all
63     ///       HttpApplication objects within the ASP.NET Framework.
64     ///    </para>
65     /// </devdoc>
66     [
67     ToolboxItem(false)
68     ]
69     public class HttpApplication : IComponent, IHttpAsyncHandler, IRequestCompletedNotifier, ISyncContext {
70         // application state dictionary
71         private HttpApplicationState _state;
72
73         // context during init for config lookups
74         private HttpContext _initContext;
75
76         // async support
77         private HttpAsyncResult _ar; // currently pending async result for call into application
78
79         // list of modules
80         private static readonly DynamicModuleRegistry _dynamicModuleRegistry = new DynamicModuleRegistry();
81         private HttpModuleCollection  _moduleCollection;
82
83         // event handlers
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();
89
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";
112
113         private EventHandlerList _events;
114         private AsyncAppEventHandlersTable _asyncEvents;
115
116         // execution steps
117         private StepManager _stepManager;
118
119         // callback for Application ResumeSteps
120         #pragma warning disable 0649
121         private WaitCallback _resumeStepsWaitCallback;
122         #pragma warning restore 0649
123
124         // event passed to modules
125         private EventArgs _appEvent;
126
127         // list of handler mappings
128         private Hashtable _handlerFactories = new Hashtable();
129
130         // list of handler/factory pairs to be recycled
131         private ArrayList _handlerRecycleList;
132
133         // flag to hide request and response intrinsics
134         private bool _hideRequestResponse;
135
136         // application execution variables
137         private HttpContext _context;
138         private Exception _lastError;  // placeholder for the error when context not avail
139         private bool _timeoutManagerInitialized;
140
141         // session (supplied by session-on-end outside of context)
142         private HttpSessionState _session;
143
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;
151
152         // pipeline event mappings
153         private Dictionary<string, RequestNotification> _pipelineEventMasks;
154
155
156         // IComponent support
157         private ISite _site;
158
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";
163
164         // map modules to their index
165         private static Hashtable _moduleIndexMap = new Hashtable();
166         private static bool _initSpecialCompleted;
167
168         private bool _initInternalCompleted;
169         private RequestNotification _appRequestNotifications;
170         private RequestNotification _appPostNotifications;
171
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;
175
176         // module config is read once per app domain and used to initialize the per-instance _moduleContainers array
177         private static List<ModuleConfigurationInfo> _moduleConfigInfo;
178
179         // this is the per instance list that contains the events for each module
180         private PipelineModuleStepContainer[] _moduleContainers;
181
182         // Byte array to be used by HttpRequest.GetEntireRawContent. Windows OS Bug 1632921
183         private byte[] _entityBuffer;
184
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;
189
190         private IAllocatorProvider _allocator;
191
192         //
193         // Public Application properties
194         //
195
196
197         /// <devdoc>
198         ///    <para>
199         ///          HTTPRuntime provided context object that provides access to additional
200         ///          pipeline-module exposed objects.
201         ///       </para>
202         ///    </devdoc>
203         [
204         Browsable(false),
205         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
206         ]
207         public HttpContext Context {
208             get {
209                 return(_context != null) ? _context : _initContext;
210             }
211         }
212
213         private bool IsContainerInitalizationAllowed {
214             get {
215                 if (HttpRuntime.UseIntegratedPipeline && _initSpecialCompleted && !_initInternalCompleted) {
216                     // return true if
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
220                     return true;
221                 }
222                 return false;
223             }
224         }
225
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));
230             }
231         }
232
233         private PipelineModuleStepContainer[] ModuleContainers {
234             get {
235                 if (_moduleContainers == null) {
236
237                     Debug.Assert(_moduleIndexMap != null && _moduleIndexMap.Count > 0, "_moduleIndexMap != null && _moduleIndexMap.Count > 0");
238
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).
243
244                     _moduleContainers = new PipelineModuleStepContainer[_moduleIndexMap.Count];
245
246                     for (int i = 0; i < _moduleContainers.Length; i++) {
247                         _moduleContainers[i] = new PipelineModuleStepContainer();
248                     }
249
250                 }
251
252                 return _moduleContainers;
253             }
254         }
255
256         /// <devdoc>
257         ///    <para>[To be supplied.]</para>
258         /// </devdoc>
259         public event EventHandler Disposed {
260             add {
261                 Events.AddHandler(EventDisposed, value);
262             }
263
264             remove {
265                 Events.RemoveHandler(EventDisposed, value);
266             }
267         }
268
269
270         /// <devdoc>
271         ///    <para>[To be supplied.]</para>
272         /// </devdoc>
273         protected EventHandlerList Events {
274             get {
275                 if (_events == null) {
276                     _events = new EventHandlerList();
277                 }
278                 return _events;
279             }
280         }
281
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);            
288         }
289
290         private AsyncAppEventHandlersTable AsyncEvents {
291             get {
292                 if (_asyncEvents == null)
293                     _asyncEvents = new AsyncAppEventHandlersTable();
294                 return _asyncEvents;
295             }
296         }
297
298         // Last error during the processing of the current request.
299         internal Exception LastError {
300             get {
301                 // only temporaraly public (will be internal and not related context)
302                 return (_context != null) ? _context.Error : _lastError;
303             }
304
305         }
306
307         // Used by HttpRequest.GetEntireRawContent. Windows OS Bug 1632921
308         internal byte[] EntityBuffer
309         {
310             get
311             {
312                 if (_entityBuffer == null)
313                 {
314                     _entityBuffer = new byte[8 * 1024];
315                 }
316                 return _entityBuffer;
317             }
318         }
319
320         // Provides fixed size reusable buffers per request
321         // Benefit:
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 {
326             get {
327                 if (_allocator == null) {
328                     AllocatorProvider alloc = new AllocatorProvider();
329
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);
333
334                     Interlocked.CompareExchange(ref _allocator, alloc, null);
335                 }
336
337                 return _allocator;
338             }
339         }
340
341         internal void ClearError() {
342             _lastError = null;
343         }
344
345         /// <devdoc>
346         ///    <para>HTTPRuntime provided request intrinsic object that provides access to incoming HTTP
347         ///       request data.</para>
348         /// </devdoc>
349         [
350         Browsable(false),
351         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
352         ]
353         public HttpRequest Request {
354             get {
355                 HttpRequest request = null;
356
357                 if (_context != null && !_hideRequestResponse)
358                     request = _context.Request;
359
360                 if (request == null)
361                     throw new HttpException(SR.GetString(SR.Request_not_available));
362
363                 return request;
364             }
365         }
366
367
368         /// <devdoc>
369         ///    <para>HTTPRuntime provided
370         ///       response intrinsic object that allows transmission of HTTP response data to a
371         ///       client.</para>
372         /// </devdoc>
373         [
374         Browsable(false),
375         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
376         ]
377         public HttpResponse Response {
378             get {
379                 HttpResponse response = null;
380
381                 if (_context != null && !_hideRequestResponse)
382                     response = _context.Response;
383
384                 if (response == null)
385                     throw new HttpException(SR.GetString(SR.Response_not_available));
386
387                 return response;
388             }
389         }
390
391
392         /// <devdoc>
393         ///    <para>
394         ///    HTTPRuntime provided session intrinsic.
395         ///    </para>
396         /// </devdoc>
397         [
398         Browsable(false),
399         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
400         ]
401         public HttpSessionState Session {
402             get {
403                 HttpSessionState session = null;
404
405                 if (_session != null)
406                     session = _session;
407                 else if (_context != null)
408                     session = _context.Session;
409
410                 if (session == null)
411                     throw new HttpException(SR.GetString(SR.Session_not_available));
412
413                 return session;
414             }
415         }
416
417
418         /// <devdoc>
419         ///    <para>
420         ///       Returns
421         ///          a reference to an HTTPApplication state bag instance.
422         ///       </para>
423         ///    </devdoc>
424         [
425         Browsable(false),
426         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
427         ]
428         public HttpApplicationState Application {
429             get {
430                 Debug.Assert(_state != null);  // app state always available
431                 return _state;
432             }
433         }
434
435
436         /// <devdoc>
437         ///    <para>Provides the web server Intrinsic object.</para>
438         /// </devdoc>
439         [
440         Browsable(false),
441         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
442         ]
443         public HttpServerUtility Server {
444             get {
445                 if (_context != null)
446                     return _context.Server;
447                 else
448                     return new HttpServerUtility(this); // special Server for application only
449             }
450         }
451
452
453         /// <devdoc>
454         ///    <para>Provides the User Intrinsic object.</para>
455         /// </devdoc>
456         [
457         Browsable(false),
458         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
459         ]
460         public IPrincipal User {
461             get {
462                 if (_context == null)
463                     throw new HttpException(SR.GetString(SR.User_not_available));
464
465                 return _context.User;
466             }
467         }
468
469
470         /// <devdoc>
471         ///    <para>
472         ///       Collection
473         ///          of all IHTTPModules configured for the current application.
474         ///       </para>
475         ///    </devdoc>
476         [
477         Browsable(false),
478         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
479         ]
480         public HttpModuleCollection Modules {
481             [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.High)]
482             get {
483                 if (_moduleCollection == null)
484                     _moduleCollection = new HttpModuleCollection();
485                 return _moduleCollection;
486             }
487         }
488
489         // event passed to all modules
490         internal EventArgs AppEvent {
491             get {
492                 if (_appEvent == null)
493                     _appEvent = EventArgs.Empty;
494
495                 return _appEvent;
496             }
497
498             set {
499                 _appEvent = null;
500             }
501         }
502
503         private ISessionStateModule FindISessionStateModule() {
504             if (!HttpRuntime.UseIntegratedPipeline)
505                 return null;
506
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) {
511                         return module;
512                     }
513                 }
514             }
515
516             return null;
517         }
518
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);
524             }
525         }
526
527         internal Task EnsureReleaseStateAsync() {
528             ISessionStateModule module = FindISessionStateModule();
529             if (module != null) {
530                 return module.ReleaseSessionStateAsync(Context);
531             }
532
533             return TaskAsyncHelper.CompletedTask;
534         }
535
536         /// <devdoc>
537         ///    <para>[To be supplied.]</para>
538         /// </devdoc>
539         public void CompleteRequest() {
540             //
541             // Request completion (force skipping all steps until RequestEnd
542             //
543             _stepManager.CompleteRequest();
544         }
545
546         internal bool IsRequestCompleted {
547             get {
548                 if (null == _stepManager) {
549                     return false;
550                 }
551
552                 return _stepManager.IsCompleted;
553             }
554         }
555
556         bool IRequestCompletedNotifier.IsRequestCompleted {
557             get {
558                 return IsRequestCompleted;
559             }
560         }
561
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);
573         }
574
575         internal void ReleaseNotifcationContextLock() {
576             Debug.Assert(HttpRuntime.UseIntegratedPipeline, "HttpRuntime.UseIntegratedPipeline");
577             Monitor.Exit(_stepManager);
578         }
579
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) {
587             bool locked = false;
588             try {
589                 AcquireNotifcationContextLock(ref locked);
590                 isReentry = Context.NotificationContext.IsReEntry;
591                 eventCount = CurrentModuleContainer.GetEventCount(Context.CurrentNotification, Context.IsPostNotification) - 1;
592             }
593             finally {
594                 if (locked) {
595                     ReleaseNotifcationContextLock();
596                 }
597             }
598         }
599         
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
606             if (!isReentry) {
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)) {
610                     return;
611                 }
612             }
613             GetNotifcationContextPropertiesUnderLock(ref isReentry, ref eventCount);
614         }
615
616         private void RaiseOnError() {
617             EventHandler handler = (EventHandler)Events[EventErrorRecorded];
618             if (handler != null) {
619                 try {
620                     handler(this, AppEvent);
621                 }
622                 catch (Exception e) {
623                     if (_context != null) {
624                         _context.AddError(e);
625                     }
626                 }
627             }
628         }
629
630         private void RaiseOnRequestCompleted() {
631             EventHandler handler = (EventHandler)Events[EventRequestCompleted];
632             if (handler != null) {
633                 try {
634                     handler(this, AppEvent);
635                 }
636                 catch (Exception e) {
637                     WebBaseEvent.RaiseRuntimeError(e, this);
638                 }
639             }
640         }
641
642         internal void RaiseOnPreSendRequestHeaders() {
643             EventHandler handler = (EventHandler)Events[EventPreSendRequestHeaders];
644             if (handler != null) {
645                 try {
646                     handler(this, AppEvent);
647                 }
648                 catch (Exception e) {
649                     RecordError(e);
650                 }
651             }
652         }
653
654         internal void RaiseOnPreSendRequestContent() {
655             EventHandler handler = (EventHandler)Events[EventPreSendRequestContent];
656             if (handler != null) {
657                 try {
658                     handler(this, AppEvent);
659                 }
660                 catch (Exception e) {
661                     RecordError(e);
662                 }
663             }
664         }
665
666         internal HttpAsyncResult AsyncResult {
667             get {
668                 if (HttpRuntime.UseIntegratedPipeline) {
669                     return (_context.NotificationContext != null) ? _context.NotificationContext.AsyncResult : null;
670                 }
671                 else {
672                     return _ar;
673                 }
674             }
675             set {
676                 if (HttpRuntime.UseIntegratedPipeline) {
677                     _context.NotificationContext.AsyncResult = value;
678                 }
679                 else {
680                     _ar = value;
681                 }
682             }
683         }
684
685         internal void AddSyncEventHookup(object key, Delegate handler, RequestNotification notification) {
686             AddSyncEventHookup(key, handler, notification, false);
687         }
688
689         private PipelineModuleStepContainer CurrentModuleContainer { get { return ModuleContainers[_context.CurrentModuleIndex]; } }
690
691         private PipelineModuleStepContainer GetModuleContainer(string moduleName) {
692             object value = _moduleIndexMap[moduleName];
693
694             if (value == null) {
695                 return null;
696             }
697
698             int moduleIndex = (int)value;
699
700 #if DBG
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");
703 #endif
704
705             PipelineModuleStepContainer container = ModuleContainers[moduleIndex];
706
707             Debug.Assert(container != null, "container != null");
708
709             return container;
710         }
711
712         private void AddSyncEventHookup(object key, Delegate handler, RequestNotification notification, bool isPostNotification) {
713             ThrowIfEventBindingDisallowed();
714
715             // add the event to the delegate invocation list
716             // this keeps non-pipeline ASP.NET hosts working
717             Events.AddHandler(key, handler);
718
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) {
726 #if DBG
727                     container.DebugModuleName = CurrentModuleCollectionKey;
728 #endif
729                     SyncEventExecutionStep step = new SyncEventExecutionStep(this, (EventHandler)handler);
730                     container.AddEvent(notification, isPostNotification, step);
731                 }
732             }
733         }
734
735         internal void RemoveSyncEventHookup(object key, Delegate handler, RequestNotification notification) {
736             RemoveSyncEventHookup(key, handler, notification, false);
737         }
738
739         internal void RemoveSyncEventHookup(object key, Delegate handler, RequestNotification notification, bool isPostNotification) {
740             ThrowIfEventBindingDisallowed();
741
742             Events.RemoveHandler(key, handler);
743
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);
749                 }
750             }
751         }
752
753         private void AddSendResponseEventHookup(object key, Delegate handler) {
754             ThrowIfEventBindingDisallowed();
755
756             // add the event to the delegate invocation list
757             // this keeps non-pipeline ASP.NET hosts working
758             Events.AddHandler(key, handler);
759
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) {
767 #if DBG
768                     container.DebugModuleName = CurrentModuleCollectionKey;
769 #endif
770                     bool isHeaders = (key == EventPreSendRequestHeaders);
771                     SendResponseExecutionStep step = new SendResponseExecutionStep(this, (EventHandler)handler, isHeaders);
772                     container.AddEvent(RequestNotification.SendResponse, false /*isPostNotification*/, step);
773                 }
774             }
775         }
776
777         private void RemoveSendResponseEventHookup(object key, Delegate handler) {
778             ThrowIfEventBindingDisallowed();
779
780             Events.RemoveHandler(key, handler);
781
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);
787                 }
788             }
789         }
790
791         //
792         // [....] event hookup
793         //
794
795
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); }
800         }
801
802
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); }
807         }
808
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); }
813         }
814
815
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); }
820         }
821
822
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); }
827         }
828
829
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); }
834         }
835
836
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); }
841         }
842
843
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); }
848         }
849
850         public event EventHandler MapRequestHandler {
851             add {
852                 if (!HttpRuntime.UseIntegratedPipeline) {
853                     throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
854                 }
855                 AddSyncEventHookup(EventMapRequestHandler, value, RequestNotification.MapRequestHandler);
856             }
857             remove {
858                 if (!HttpRuntime.UseIntegratedPipeline) {
859                     throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
860                 }
861                 RemoveSyncEventHookup(EventMapRequestHandler, value, RequestNotification.MapRequestHandler);
862             }
863         }
864
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); }
869         }
870
871
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); }
876         }
877
878
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); }
883         }
884
885
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); }
890         }
891
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); }
896         }
897
898
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); }
903         }
904
905
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); }
910         }
911
912
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); }
917         }
918
919
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); }
924         }
925
926         public event EventHandler LogRequest {
927             add {
928                 if (!HttpRuntime.UseIntegratedPipeline) {
929                     throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
930                 }
931                 AddSyncEventHookup(EventLogRequest, value, RequestNotification.LogRequest);
932             }
933             remove {
934                 if (!HttpRuntime.UseIntegratedPipeline) {
935                     throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
936                 }
937                 RemoveSyncEventHookup(EventLogRequest, value, RequestNotification.LogRequest);
938             }
939         }
940
941         public event EventHandler PostLogRequest {
942             add {
943                 if (!HttpRuntime.UseIntegratedPipeline) {
944                     throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
945                 }
946                 AddSyncEventHookup(EventPostLogRequest, value, RequestNotification.LogRequest, true);
947             }
948             remove {
949                 if (!HttpRuntime.UseIntegratedPipeline) {
950                     throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
951                 }
952                 RemoveSyncEventHookup(EventPostLogRequest, value, RequestNotification.LogRequest, true);
953             }
954         }
955
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); }
960         }
961
962
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); }
967         }
968
969
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); }
978         }
979
980
981         /// <devdoc><para>[To be supplied.]</para></devdoc>
982         public event EventHandler PreSendRequestHeaders {
983             add { AddSendResponseEventHookup(EventPreSendRequestHeaders, value); }
984             remove { RemoveSendResponseEventHookup(EventPreSendRequestHeaders, value); }
985         }
986
987
988         /// <devdoc><para>[To be supplied.]</para></devdoc>
989         public event EventHandler PreSendRequestContent {
990             add { AddSendResponseEventHookup(EventPreSendRequestContent, value); }
991             remove { RemoveSendResponseEventHookup(EventPreSendRequestContent, value); }
992         }
993
994         //
995         // Async event hookup
996         //
997
998         public void AddOnBeginRequestAsync(BeginEventHandler bh, EndEventHandler eh) {
999             AddOnBeginRequestAsync(bh, eh, null);
1000         }
1001
1002         public void AddOnBeginRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1003             AsyncEvents.AddHandler(EventBeginRequest, beginHandler, endHandler, state, RequestNotification.BeginRequest, false, this);
1004         }
1005
1006         public void AddOnAuthenticateRequestAsync(BeginEventHandler bh, EndEventHandler eh) {
1007             AddOnAuthenticateRequestAsync(bh, eh, null);
1008         }
1009
1010         public void AddOnAuthenticateRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1011             AsyncEvents.AddHandler(EventAuthenticateRequest, beginHandler, endHandler, state,
1012                                    RequestNotification.AuthenticateRequest, false, this);
1013         }
1014
1015         public void AddOnPostAuthenticateRequestAsync(BeginEventHandler bh, EndEventHandler eh) {
1016             AddOnPostAuthenticateRequestAsync(bh, eh, null);
1017         }
1018
1019         public void AddOnPostAuthenticateRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1020             AsyncEvents.AddHandler(EventPostAuthenticateRequest, beginHandler, endHandler, state,
1021                                    RequestNotification.AuthenticateRequest, true, this);
1022         }
1023
1024         public void AddOnAuthorizeRequestAsync(BeginEventHandler bh, EndEventHandler eh) {
1025             AddOnAuthorizeRequestAsync(bh, eh, null);
1026         }
1027
1028         public void AddOnAuthorizeRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1029             AsyncEvents.AddHandler(EventAuthorizeRequest, beginHandler, endHandler, state,
1030                                    RequestNotification.AuthorizeRequest, false, this);
1031         }
1032
1033         public void AddOnPostAuthorizeRequestAsync(BeginEventHandler bh, EndEventHandler eh) {
1034             AddOnPostAuthorizeRequestAsync(bh, eh, null);
1035         }
1036
1037         public void AddOnPostAuthorizeRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1038             AsyncEvents.AddHandler(EventPostAuthorizeRequest, beginHandler, endHandler, state,
1039                                    RequestNotification.AuthorizeRequest, true, this);
1040         }
1041
1042         public void AddOnResolveRequestCacheAsync(BeginEventHandler bh, EndEventHandler eh) {
1043             AddOnResolveRequestCacheAsync(bh, eh, null);
1044         }
1045
1046         public void AddOnResolveRequestCacheAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1047             AsyncEvents.AddHandler(EventResolveRequestCache, beginHandler, endHandler, state,
1048                                    RequestNotification.ResolveRequestCache, false, this);
1049         }
1050
1051         public void AddOnPostResolveRequestCacheAsync(BeginEventHandler bh, EndEventHandler eh) {
1052             AddOnPostResolveRequestCacheAsync(bh, eh, null);
1053         }
1054
1055         public void AddOnPostResolveRequestCacheAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1056             AsyncEvents.AddHandler(EventPostResolveRequestCache, beginHandler, endHandler, state,
1057                                    RequestNotification.ResolveRequestCache, true, this);
1058         }
1059
1060         public void AddOnMapRequestHandlerAsync(BeginEventHandler bh, EndEventHandler eh) {
1061             if (!HttpRuntime.UseIntegratedPipeline) {
1062                 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
1063             }
1064             AddOnMapRequestHandlerAsync(bh, eh, null);
1065         }
1066
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));
1070             }
1071             AsyncEvents.AddHandler(EventMapRequestHandler, beginHandler, endHandler, state,
1072                                    RequestNotification.MapRequestHandler, false, this);
1073         }
1074
1075         public void AddOnPostMapRequestHandlerAsync(BeginEventHandler bh, EndEventHandler eh) {
1076             AddOnPostMapRequestHandlerAsync(bh, eh, null);
1077         }
1078
1079         public void AddOnPostMapRequestHandlerAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1080             AsyncEvents.AddHandler(EventPostMapRequestHandler, beginHandler, endHandler, state,
1081                                    RequestNotification.MapRequestHandler, true, this);
1082         }
1083
1084         public void AddOnAcquireRequestStateAsync(BeginEventHandler bh, EndEventHandler eh) {
1085             AddOnAcquireRequestStateAsync(bh, eh, null);
1086         }
1087
1088         public void AddOnAcquireRequestStateAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1089             AsyncEvents.AddHandler(EventAcquireRequestState, beginHandler, endHandler, state,
1090                                    RequestNotification.AcquireRequestState, false, this);
1091         }
1092
1093         public void AddOnPostAcquireRequestStateAsync(BeginEventHandler bh, EndEventHandler eh) {
1094             AddOnPostAcquireRequestStateAsync(bh, eh, null);
1095         }
1096
1097         public void AddOnPostAcquireRequestStateAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1098             AsyncEvents.AddHandler(EventPostAcquireRequestState, beginHandler, endHandler, state,
1099                                    RequestNotification.AcquireRequestState, true, this);
1100         }
1101
1102         public void AddOnPreRequestHandlerExecuteAsync(BeginEventHandler bh, EndEventHandler eh) {
1103             AddOnPreRequestHandlerExecuteAsync(bh, eh, null);
1104         }
1105
1106         public void AddOnPreRequestHandlerExecuteAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1107             AsyncEvents.AddHandler(EventPreRequestHandlerExecute, beginHandler, endHandler, state,
1108                                    RequestNotification.PreExecuteRequestHandler, false, this);
1109         }
1110
1111         public void AddOnPostRequestHandlerExecuteAsync(BeginEventHandler bh, EndEventHandler eh) {
1112             AddOnPostRequestHandlerExecuteAsync(bh, eh, null);
1113         }
1114
1115         public void AddOnPostRequestHandlerExecuteAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1116             AsyncEvents.AddHandler(EventPostRequestHandlerExecute, beginHandler, endHandler, state,
1117                                    RequestNotification.ExecuteRequestHandler, true, this);
1118         }
1119
1120         public void AddOnReleaseRequestStateAsync(BeginEventHandler bh, EndEventHandler eh) {
1121             AddOnReleaseRequestStateAsync(bh, eh, null);
1122         }
1123
1124         public void AddOnReleaseRequestStateAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1125             AsyncEvents.AddHandler(EventReleaseRequestState, beginHandler, endHandler, state,
1126                                    RequestNotification.ReleaseRequestState, false, this);
1127         }
1128
1129         public void AddOnPostReleaseRequestStateAsync(BeginEventHandler bh, EndEventHandler eh) {
1130             AddOnPostReleaseRequestStateAsync(bh, eh, null);
1131         }
1132
1133         public void AddOnPostReleaseRequestStateAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1134             AsyncEvents.AddHandler(EventPostReleaseRequestState, beginHandler, endHandler, state,
1135                                    RequestNotification.ReleaseRequestState, true, this);
1136         }
1137
1138         public void AddOnUpdateRequestCacheAsync(BeginEventHandler bh, EndEventHandler eh) {
1139             AddOnUpdateRequestCacheAsync(bh, eh, null);
1140         }
1141
1142         public void AddOnUpdateRequestCacheAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1143             AsyncEvents.AddHandler(EventUpdateRequestCache, beginHandler, endHandler, state,
1144                                    RequestNotification.UpdateRequestCache , false, this);
1145         }
1146
1147         public void AddOnPostUpdateRequestCacheAsync(BeginEventHandler bh, EndEventHandler eh) {
1148             AddOnPostUpdateRequestCacheAsync(bh, eh, null);
1149         }
1150
1151         public void AddOnPostUpdateRequestCacheAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1152             AsyncEvents.AddHandler(EventPostUpdateRequestCache, beginHandler, endHandler, state,
1153                                    RequestNotification.UpdateRequestCache , true, this);
1154         }
1155
1156         public void AddOnLogRequestAsync(BeginEventHandler bh, EndEventHandler eh) {
1157             if (!HttpRuntime.UseIntegratedPipeline) {
1158                 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
1159             }
1160             AddOnLogRequestAsync(bh, eh, null);
1161         }
1162
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));
1166             }
1167             AsyncEvents.AddHandler(EventLogRequest, beginHandler, endHandler, state,
1168                                    RequestNotification.LogRequest, false, this);
1169         }
1170
1171         public void AddOnPostLogRequestAsync(BeginEventHandler bh, EndEventHandler eh) {
1172             if (!HttpRuntime.UseIntegratedPipeline) {
1173                 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
1174             }
1175             AddOnPostLogRequestAsync(bh, eh, null);
1176         }
1177
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));
1181             }
1182             AsyncEvents.AddHandler(EventPostLogRequest, beginHandler, endHandler, state,
1183                                    RequestNotification.LogRequest, true, this);
1184         }
1185
1186         public void AddOnEndRequestAsync(BeginEventHandler bh, EndEventHandler eh) {
1187             AddOnEndRequestAsync(bh, eh, null);
1188         }
1189
1190         public void AddOnEndRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
1191             AsyncEvents.AddHandler(EventEndRequest, beginHandler, endHandler, state,
1192                                    RequestNotification.EndRequest, false, this);
1193         }
1194
1195         //
1196         // Public Application virtual methods
1197         //
1198
1199
1200         /// <devdoc>
1201         ///    <para>
1202         ///       Used
1203         ///          to initialize a HttpModule?s instance variables, and to wireup event handlers to
1204         ///          the hosting HttpApplication.
1205         ///       </para>
1206         ///    </devdoc>
1207         public virtual void Init() {
1208             // derived class implements this
1209         }
1210
1211
1212         /// <devdoc>
1213         ///    <para>
1214         ///       Used
1215         ///          to clean up an HttpModule?s instance variables
1216         ///       </para>
1217         ///    </devdoc>
1218         public virtual void Dispose() {
1219             // also part of IComponent
1220             // derived class implements this
1221             _site = null;
1222             if (_events != null) {
1223                 try {
1224                     EventHandler handler = (EventHandler)_events[EventDisposed];
1225                     if (handler != null)
1226                         handler(this, EventArgs.Empty);
1227                 }
1228                 finally {
1229                     _events.Dispose();
1230                 }
1231             }
1232         }
1233
1234         [SecurityPermission(SecurityAction.Assert, ControlPrincipal = true)]
1235         internal static void SetCurrentPrincipalWithAssert(IPrincipal user) {
1236             Thread.CurrentPrincipal = user;
1237         }
1238
1239         [SecurityPermission(SecurityAction.Assert, ControlPrincipal = true)]
1240         internal static WindowsIdentity GetCurrentWindowsIdentityWithAssert() {
1241             return WindowsIdentity.GetCurrent();
1242         }
1243
1244         private HttpHandlerAction GetHandlerMapping(HttpContext context, String requestType, VirtualPath path, bool useAppConfig) {
1245             CachedPathData pathData = null;
1246             HandlerMappingMemo memo = null;
1247             HttpHandlerAction mapping = null;
1248
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;
1254
1255                 // Invalidate cache on missmatch
1256                 if (memo != null && !memo.IsMatch(requestType, path)) {
1257                     memo = null;
1258                 }
1259             }
1260
1261             // Get new mapping
1262             if (memo == null) {
1263                 // Load from config
1264                 HttpHandlersSection map = useAppConfig ? RuntimeConfig.GetAppConfig().HttpHandlers
1265                                                        : RuntimeConfig.GetConfig(context).HttpHandlers;
1266                 mapping = map.FindMapping(requestType, path);
1267
1268                 // Add cache entry
1269                 if (!useAppConfig) {
1270                     memo = new HandlerMappingMemo(mapping, requestType, path);
1271                     pathData.CachedHandler = memo;
1272                 }
1273             }
1274             else {
1275                 // Get mapping from the cache
1276                 mapping = memo.Mapping;
1277             }
1278
1279             return mapping;
1280         }
1281
1282         internal IHttpHandler MapIntegratedHttpHandler(HttpContext context, String requestType, VirtualPath path, String pathTranslated, bool useAppConfig, bool convertNativeStaticFileModule) {
1283             IHttpHandler handler = null;
1284
1285             using (new ApplicationImpersonationContext()) {
1286                 string type;
1287
1288                 // vpath is a non-relative virtual path
1289                 string vpath = path.VirtualPathString;
1290
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.
1293                 if (useAppConfig) {
1294                     int index = vpath.LastIndexOf('/');
1295                     index++;
1296                     if (index != 0 && index < vpath.Length) {
1297                         vpath = UrlPath.SimpleCombine(HttpRuntime.AppDomainAppVirtualPathString, vpath.Substring(index));
1298                     }
1299                     else {
1300                         vpath = HttpRuntime.AppDomainAppVirtualPathString;
1301                     }
1302                 }
1303
1304
1305                 IIS7WorkerRequest wr = context.WorkerRequest as IIS7WorkerRequest;
1306                 type = wr.MapHandlerAndGetHandlerTypeString(method: requestType, path: vpath, convertNativeStaticFileModule: convertNativeStaticFileModule, ignoreWildcardMappings: false);
1307
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.
1311                 if (type == null) {
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));
1315                 }
1316
1317                 // if it's a native type, don't go any further
1318                 if(String.IsNullOrEmpty(type)) {
1319                     return handler;
1320                 }
1321
1322                 // Get factory from the mapping
1323                 IHttpHandlerFactory factory = GetFactory(type);
1324
1325                 try {
1326                     handler = factory.GetHandler(context, requestType, path.VirtualPathString, pathTranslated);
1327                 }
1328                 catch (FileNotFoundException e) {
1329                     if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated))
1330                         throw new HttpException(404, null, e);
1331                     else
1332                         throw new HttpException(404, null);
1333                 }
1334                 catch (DirectoryNotFoundException e) {
1335                     if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated))
1336                         throw new HttpException(404, null, e);
1337                     else
1338                         throw new HttpException(404, null);
1339                 }
1340                 catch (PathTooLongException e) {
1341                     if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated))
1342                         throw new HttpException(414, null, e);
1343                     else
1344                         throw new HttpException(414, null);
1345                 }
1346
1347                 // Remember for recycling
1348                 if (_handlerRecycleList == null)
1349                     _handlerRecycleList = new ArrayList();
1350                 _handlerRecycleList.Add(new HandlerWithFactory(handler, factory));
1351             }
1352
1353             return handler;
1354         }
1355
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;
1359
1360             using (new ApplicationImpersonationContext()) {
1361                 // Use remap handler if possible
1362                 if (handler != null){
1363                     return handler;
1364                 }
1365
1366                 // Map new handler
1367                 HttpHandlerAction mapping = GetHandlerMapping(context, requestType, path, useAppConfig);
1368
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));
1376                 }
1377
1378                 // Get factory from the mapping
1379                 IHttpHandlerFactory factory = GetFactory(mapping);
1380
1381
1382                 // Get factory from the mapping
1383                 try {
1384                     // Check if it supports the more efficient GetHandler call that can avoid
1385                     // a VirtualPath object creation.
1386                     IHttpHandlerFactory2 factory2 = factory as IHttpHandlerFactory2;
1387
1388                     if (factory2 != null) {
1389                         handler = factory2.GetHandler(context, requestType, path, pathTranslated);
1390                     }
1391                     else {
1392                         handler = factory.GetHandler(context, requestType, path.VirtualPathString, pathTranslated);
1393                     }
1394                 }
1395                 catch (FileNotFoundException e) {
1396                     if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated))
1397                         throw new HttpException(404, null, e);
1398                     else
1399                         throw new HttpException(404, null);
1400                 }
1401                 catch (DirectoryNotFoundException e) {
1402                     if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated))
1403                         throw new HttpException(404, null, e);
1404                     else
1405                         throw new HttpException(404, null);
1406                 }
1407                 catch (PathTooLongException e) {
1408                     if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated))
1409                         throw new HttpException(414, null, e);
1410                     else
1411                         throw new HttpException(414, null);
1412                 }
1413
1414                 // Remember for recycling
1415                 if (_handlerRecycleList == null)
1416                     _handlerRecycleList = new ArrayList();
1417                 _handlerRecycleList.Add(new HandlerWithFactory(handler, factory));
1418             }
1419
1420             return handler;
1421         }
1422
1423
1424         /// <devdoc>
1425         ///    <para>[To be supplied.]</para>
1426         /// </devdoc>
1427         public virtual string GetVaryByCustomString(HttpContext context, string custom) {
1428
1429             if (StringUtil.EqualsIgnoreCase(custom, "browser")) {
1430                 return context.Request.Browser.Type;
1431             }
1432
1433             return null;
1434         }
1435
1436         public virtual string GetOutputCacheProviderName(HttpContext context) {
1437             // default implementation
1438             return System.Web.Caching.OutputCache.DefaultProviderName;
1439         }
1440
1441         //
1442         // IComponent implementation
1443         //
1444
1445
1446         /// <devdoc>
1447         ///    <para>[To be supplied.]</para>
1448         /// </devdoc>
1449         [
1450         Browsable(false),
1451         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
1452         ]
1453         public ISite Site {
1454             get { return _site;}
1455             set { _site = value;}
1456         }
1457
1458         //
1459         // IHttpAsyncHandler implementation
1460         //
1461
1462
1463         /// <internalonly/>
1464         IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) {
1465             HttpAsyncResult result;
1466
1467             // Setup the asynchronous stuff and application variables
1468             _context = context;
1469             _context.ApplicationInstance = this;
1470
1471             _stepManager.InitRequest();
1472
1473             // Make sure the context stays rooted (including all async operations)
1474             _context.Root();
1475
1476             // Create the async result
1477             result = new HttpAsyncResult(cb, extraData);
1478
1479             // Remember the async result for use in async completions
1480             AsyncResult = result;
1481
1482             if (_context.TraceIsEnabled)
1483                 HttpRuntime.Profile.StartRequest(_context);
1484
1485             // Start the application
1486             ResumeSteps(null);
1487
1488             // Return the async result
1489             return result;
1490         }
1491
1492
1493         /// <internalonly/>
1494         void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) {
1495             // throw error caught during execution
1496             HttpAsyncResult ar = (HttpAsyncResult)result;
1497             if (ar.Error != null)
1498                 throw ar.Error;
1499         }
1500
1501         //
1502         // IHttpHandler implementation
1503         //
1504
1505
1506         /// <internalonly/>
1507         void IHttpHandler.ProcessRequest(HttpContext context) {
1508             throw new HttpException(SR.GetString(SR.Sync_not_supported));
1509         }
1510
1511
1512         /// <internalonly/>
1513         bool IHttpHandler.IsReusable {
1514             get { return true; }
1515         }
1516
1517         //
1518         // Support for external calls into the application like app_onStart
1519         //
1520
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]);
1525             }
1526             else {
1527                 Debug.Assert(paramCount == 2);
1528
1529                 method.Invoke(this, new Object[2] { eventSource, eventArgs });
1530             }
1531         }
1532
1533         internal void ProcessSpecialRequest(HttpContext context,
1534                                             MethodInfo method,
1535                                             int paramCount,
1536                                             Object eventSource,
1537                                             EventArgs eventArgs,
1538                                             HttpSessionState session) {
1539             _context = context;
1540             if (HttpRuntime.UseIntegratedPipeline && _context != null) {
1541                 _context.HideRequestResponse = true;
1542             }
1543             _hideRequestResponse = true;
1544             _session = session;
1545             _lastError = null;
1546
1547             using (new DisposableHttpContextWrapper(context)) {
1548                 using (new ApplicationImpersonationContext()) {
1549                     try {
1550                         // set culture on the current thread
1551                         SetAppLevelCulture();
1552                         InvokeMethodWithAssert(method, paramCount, eventSource, eventArgs);
1553                     }
1554                     catch (Exception e) {
1555                         // dereference reflection invocation exceptions
1556                         Exception eActual;
1557                         if (e is TargetInvocationException)
1558                             eActual = e.InnerException;
1559                         else
1560                             eActual = e;
1561
1562                         RecordError(eActual);
1563
1564                         if (context == null) {
1565                             try {
1566                                 WebBaseEvent.RaiseRuntimeError(eActual, this);
1567                             }
1568                             catch {
1569                             }
1570                         }
1571
1572                     }
1573                     finally {
1574
1575                         // this thread should not be locking app state
1576                         if (_state != null)
1577                             _state.EnsureUnLock();
1578
1579                         // restore culture
1580                         RestoreAppLevelCulture();
1581
1582                         if (HttpRuntime.UseIntegratedPipeline && _context != null) {
1583                             _context.HideRequestResponse = false;
1584                         }
1585                         _hideRequestResponse = false;
1586                         _context = null;
1587                         _session = null;
1588                         _lastError = null;
1589                         _appEvent = null;
1590                     }
1591                 }
1592             }
1593         }
1594
1595         //
1596         // Report context-less error
1597         //
1598
1599         internal void RaiseErrorWithoutContext(Exception error) {
1600             try {
1601                 try {
1602                     SetAppLevelCulture();
1603                     _lastError = error;
1604
1605                     RaiseOnError();
1606                 }
1607                 finally {
1608                     // this thread should not be locking app state
1609                     if (_state != null)
1610                         _state.EnsureUnLock();
1611
1612                     RestoreAppLevelCulture();
1613                     _lastError = null;
1614                     _appEvent = null;
1615                 }
1616             }
1617             catch { // Protect against exception filters
1618                 throw;
1619             }
1620         }
1621
1622         //
1623         //
1624         //
1625
1626         internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers) {
1627             Debug.Assert(context != null, "context != null");
1628
1629             // Remember state
1630             _state = state;
1631
1632             PerfCounters.IncrementCounter(AppPerfCounter.PIPELINES);
1633
1634             try {
1635                 try {
1636                     // Remember context for config lookups
1637                     _initContext = context;
1638                     _initContext.ApplicationInstance = this;
1639
1640                     // Set config path to be application path for the application initialization
1641                     context.ConfigurationPath = context.Request.ApplicationPathObject;
1642
1643                     // keep HttpContext.Current working while running user code
1644                     using (new DisposableHttpContextWrapper(context)) {
1645
1646                         // Build module list from config
1647                         if (HttpRuntime.UseIntegratedPipeline) {
1648
1649                             Debug.Assert(_moduleConfigInfo != null, "_moduleConfigInfo != null");
1650                             Debug.Assert(_moduleConfigInfo.Count >= 0, "_moduleConfigInfo.Count >= 0");
1651
1652                             try {
1653                                 context.HideRequestResponse = true;
1654                                 _hideRequestResponse = true;
1655                                 InitIntegratedModules();
1656                             }
1657                             finally {
1658                                 context.HideRequestResponse = false;
1659                                 _hideRequestResponse = false;
1660                             }
1661                         }
1662                         else {
1663                             InitModules();
1664
1665                             // this is used exclusively for integrated mode
1666                             Debug.Assert(null == _moduleContainers, "null == _moduleContainers");
1667                         }
1668
1669                         // Hookup event handlers via reflection
1670                         if (handlers != null)
1671                             HookupEventHandlersForApplicationAndModules(handlers);
1672
1673                         // Initialization of the derived class
1674                         _context = context;
1675                         if (HttpRuntime.UseIntegratedPipeline && _context != null) {
1676                             _context.HideRequestResponse = true;
1677                         }
1678                         _hideRequestResponse = true;
1679
1680                         try {
1681                             Init();
1682                         }
1683                         catch (Exception e) {
1684                             RecordError(e);
1685                         }
1686                     }
1687
1688                     if (HttpRuntime.UseIntegratedPipeline && _context != null) {
1689                         _context.HideRequestResponse = false;
1690                     }
1691                     _hideRequestResponse = false;
1692                     _context = null;
1693                     _resumeStepsWaitCallback= new WaitCallback(this.ResumeStepsWaitCallback);
1694
1695                     // Construct the execution steps array
1696                     if (HttpRuntime.UseIntegratedPipeline) {
1697                         _stepManager = new PipelineStepManager(this);
1698                     }
1699                     else {
1700                         _stepManager = new ApplicationStepManager(this);
1701                     }
1702
1703                     _stepManager.BuildSteps(_resumeStepsWaitCallback);
1704                 }
1705                 finally {
1706                     _initInternalCompleted = true;
1707
1708                     // Reset config path
1709                     context.ConfigurationPath = null;
1710
1711                     // don't hold on to the context
1712                     _initContext.ApplicationInstance = null;
1713                     _initContext = null;
1714                 }
1715             }
1716             catch { // Protect against exception filters
1717                 throw;
1718             }
1719         }
1720
1721         // helper to expand an event handler into application steps
1722         private void CreateEventExecutionSteps(Object eventIndex, ArrayList steps) {
1723             // async
1724             AsyncAppEventHandler asyncHandler = AsyncEvents[eventIndex];
1725
1726             if (asyncHandler != null) {
1727                 asyncHandler.CreateExecutionSteps(this, steps);
1728             }
1729
1730             // [....]
1731             EventHandler handler = (EventHandler)Events[eventIndex];
1732
1733             if (handler != null) {
1734                 Delegate[] handlers = handler.GetInvocationList();
1735
1736                 for (int i = 0; i < handlers.Length; i++)  {
1737                     steps.Add(new SyncEventExecutionStep(this, (EventHandler)handlers[i]));
1738                 }
1739             }
1740         }
1741
1742         internal void InitSpecial(HttpApplicationState state, MethodInfo[] handlers, IntPtr appContext, HttpContext context) {
1743             // Remember state
1744             _state = state;
1745
1746             try {
1747                 //  Remember the context for the initialization
1748                 if (context != null) {
1749                     _initContext = context;
1750                     _initContext.ApplicationInstance = this;
1751                 }
1752
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();
1758                     }
1759
1760                     // retrieve app level culture
1761                     InitAppLevelCulture();
1762
1763                     Debug.Trace("PipelineRuntime", "InitSpecial for " + appContext.ToString() + "\n");
1764                     RegisterEventSubscriptionsWithIIS(appContext, context, handlers);
1765                 }
1766                 else {
1767                     // retrieve app level culture
1768                     InitAppLevelCulture();
1769
1770                     // Hookup event handlers via reflection
1771                     if (handlers != null) {
1772                         HookupEventHandlersForApplicationAndModules(handlers);
1773                     }
1774                 }
1775
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,
1785                                                 false);
1786                     }
1787                 }
1788             }
1789             finally  {
1790                 _initSpecialCompleted = true;
1791
1792                 //  Do not hold on to the context
1793                 if (_initContext != null) {
1794                     _initContext.ApplicationInstance = null;
1795                     _initContext = null;
1796                 }
1797             }
1798         }
1799
1800         internal void DisposeInternal() {
1801             PerfCounters.DecrementCounter(AppPerfCounter.PIPELINES);
1802
1803             // call derived class
1804
1805             try {
1806                 Dispose();
1807             }
1808             catch (Exception e) {
1809                 RecordError(e);
1810             }
1811
1812             // dispose modules
1813
1814             if (_moduleCollection != null) {
1815                 int numModules = _moduleCollection.Count;
1816
1817                 for (int i = 0; i < numModules; i++) {
1818                     try {
1819                         // set the init key during Dispose for modules
1820                         // that try to unregister events
1821                         if (HttpRuntime.UseIntegratedPipeline) {
1822                             _currentModuleCollectionKey = _moduleCollection.GetKey(i);
1823                         }
1824                         _moduleCollection[i].Dispose();
1825                     }
1826                     catch {
1827                     }
1828                 }
1829
1830                 _moduleCollection = null;
1831             }
1832
1833             // Release buffers
1834             if (_allocator != null) {
1835                 _allocator.TrimMemory();
1836             }
1837         }
1838
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;
1862         }
1863
1864         private void HookupEventHandlersForApplicationAndModules(MethodInfo[] handlers) {
1865             _currentModuleCollectionKey = HttpApplicationFactory.applicationFileName;
1866
1867             if(null == _pipelineEventMasks) {
1868                 Dictionary<string, RequestNotification> dict = new Dictionary<string, RequestNotification>();
1869                 BuildEventMaskDictionary(dict);
1870                 if(null == _pipelineEventMasks) {
1871                     _pipelineEventMasks = dict;
1872                 }
1873             }
1874
1875
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);
1881
1882                 // Find target for method
1883                 Object target = null;
1884
1885                 if (StringUtil.EqualsIgnoreCase(targetName, "Application"))
1886                     target = this;
1887                 else if (_moduleCollection != null)
1888                     target = _moduleCollection[targetName];
1889
1890                 if (target == null)
1891                     continue;
1892
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);
1897
1898                 EventDescriptor foundEvent = events.Find(eventName, true);
1899                 if (foundEvent == null
1900                     && StringUtil.EqualsIgnoreCase(eventName.Substring(0, 2), "on")) {
1901
1902                     eventName = eventName.Substring(2);
1903                     foundEvent = events.Find(eventName, true);
1904                 }
1905
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();
1912                     }
1913                 }
1914
1915                 if (addMethod == null)
1916                     continue;
1917
1918                 ParameterInfo[] addMethodParams = addMethod.GetParameters();
1919
1920                 if (addMethodParams.Length != 1)
1921                     continue;
1922
1923                 // Create the delegate from app method to pass to AddXXX(handler) method
1924
1925                 Delegate handlerDelegate = null;
1926
1927                 ParameterInfo[] appMethodParams = appMethod.GetParameters();
1928
1929                 if (appMethodParams.Length == 0) {
1930                     // If the app method doesn't have arguments --
1931                     // -- hookup via intermidiate handler
1932
1933                     // only can do it for EventHandler, not strongly typed
1934                     if (addMethodParams[0].ParameterType != typeof(System.EventHandler))
1935                         continue;
1936
1937                     ArglessEventHandlerProxy proxy = new ArglessEventHandlerProxy(this, appMethod);
1938                     handlerDelegate = proxy.Handler;
1939                 }
1940                 else {
1941                     // Hookup directly to the app methods hoping all types match
1942
1943                     try {
1944                         handlerDelegate = Delegate.CreateDelegate(addMethodParams[0].ParameterType, this, appMethodName);
1945                     }
1946                     catch {
1947                         // some type mismatch
1948                         continue;
1949                     }
1950                 }
1951
1952                 // Call the AddXXX() to hook up the delegate
1953
1954                 try {
1955                     addMethod.Invoke(target, new Object[1]{handlerDelegate});
1956                 }
1957                 catch {
1958                     if (HttpRuntime.UseIntegratedPipeline) {
1959                         throw;
1960                     }
1961                 }
1962
1963                 if (eventName != null) {
1964                     if (_pipelineEventMasks.ContainsKey(eventName)) {
1965                         if (!StringUtil.StringStartsWith(eventName, "Post")) {
1966                             _appRequestNotifications |= _pipelineEventMasks[eventName];
1967                         }
1968                         else {
1969                             _appPostNotifications |= _pipelineEventMasks[eventName];
1970                         }
1971                     }
1972                 }
1973             }
1974         }
1975
1976         private void RegisterIntegratedEvent(IntPtr appContext,
1977                                              string moduleName,
1978                                              RequestNotification requestNotifications,
1979                                              RequestNotification postRequestNotifications,
1980                                              string moduleType,
1981                                              string modulePrecondition,
1982                                              bool useHighPriority) {
1983
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
1987
1988             int moduleIndex;
1989             if (_moduleIndexMap.ContainsKey(moduleName)) {
1990                 moduleIndex = (int) _moduleIndexMap[moduleName];
1991             }
1992             else {
1993                 moduleIndex = _moduleIndexMap.Count;
1994                 _moduleIndexMap[moduleName] = moduleIndex;
1995             }
1996
1997 #if DBG
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");
2005 #endif
2006
2007             int result = UnsafeIISMethods.MgdRegisterEventSubscription(appContext,
2008                                                                        moduleName,
2009                                                                        requestNotifications,
2010                                                                        postRequestNotifications,
2011                                                                        moduleType,
2012                                                                        modulePrecondition,
2013                                                                        new IntPtr(moduleIndex),
2014                                                                        useHighPriority);
2015
2016             if(result < 0) {
2017                 throw new HttpException(SR.GetString(SR.Failed_Pipeline_Subscription, moduleName));
2018             }
2019         }
2020
2021
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); }
2033                     catch { }
2034                 }
2035             }
2036
2037             culture = _appLevelCulture;
2038             uiculture = _appLevelUICulture;
2039             if(browserCulture != null) {
2040                 if(_appLevelAutoCulture) {
2041                     culture = browserCulture;
2042                 }
2043                 if(_appLevelAutoUICulture) {
2044                     uiculture = browserCulture;
2045                 }
2046             }
2047
2048             _savedAppLevelCulture = Thread.CurrentThread.CurrentCulture;
2049             _savedAppLevelUICulture = Thread.CurrentThread.CurrentUICulture;
2050
2051             if (culture != null && culture != Thread.CurrentThread.CurrentCulture) {
2052                 HttpRuntime.SetCurrentThreadCultureWithAssert(culture);
2053             }
2054
2055             if (uiculture != null && uiculture != Thread.CurrentThread.CurrentUICulture) {
2056                 Thread.CurrentThread.CurrentUICulture = uiculture;
2057             }
2058         }
2059
2060         private void RestoreAppLevelCulture() {
2061             CultureInfo currentCulture = Thread.CurrentThread.CurrentCulture;
2062             CultureInfo currentUICulture = Thread.CurrentThread.CurrentUICulture;
2063
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);
2068                 }
2069
2070                 _savedAppLevelCulture = null;
2071             }
2072
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;
2077                 }
2078
2079                 _savedAppLevelUICulture = null;
2080             }
2081         }
2082
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.
2086
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);
2114
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();
2121
2122                 HttpRuntime.RequestTimeoutManager.Add(_context);
2123                 _timeoutManagerInitialized = true;
2124             }
2125
2126             return threadContext;
2127         }
2128
2129         // consumed by AppVerifier when it is enabled
2130         HttpContext ISyncContext.HttpContext {
2131             get {
2132                 return _context;
2133             }
2134         }
2135
2136         // consumed by AspNetSynchronizationContext
2137         ISyncContextLock ISyncContext.Enter() {
2138             return OnThreadEnter();
2139         }
2140
2141         internal ThreadContext OnThreadEnter() {
2142             return OnThreadEnterPrivate(true /* setImpersonationContext */);
2143         }
2144
2145         internal ThreadContext OnThreadEnter(bool setImpersonationContext) {
2146             return OnThreadEnterPrivate(setImpersonationContext);
2147         }
2148
2149         /*
2150          * Execute single step catching exceptions in a fancy way (see below)
2151          */
2152         internal Exception ExecuteStep(IExecutionStep step, ref bool completedSynchronously) {
2153             Exception error = null;
2154
2155             try {
2156                 try {
2157                     if (step.IsCancellable) {
2158                         _context.BeginCancellablePeriod();  // request can be cancelled from this point
2159
2160                         try {
2161                             step.Execute();
2162                         }
2163                         finally {
2164                             _context.EndCancellablePeriod();  // request can be cancelled until this point
2165                         }
2166
2167                         _context.WaitForExceptionIfCancelled();  // wait outside of finally
2168                     }
2169                     else {
2170                         step.Execute();
2171                     }
2172
2173                     if (!step.CompletedSynchronously) {
2174                         completedSynchronously = false;
2175                         return null;
2176                     }
2177                 }
2178                 catch (Exception e) {
2179                     error = e;
2180
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;
2185                     }
2186                     // This might force ThreadAbortException to be thrown
2187                     // automatically, because we consumed an exception that was
2188                     // hiding ThreadAbortException behind it
2189
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
2194                         // VSWhidbey 178556
2195                         error = null;
2196                         _stepManager.CompleteRequest();
2197                     }
2198                 }
2199 #pragma warning disable 1058
2200                 catch {
2201                     // ignore non-Exception objects that could be thrown
2202                 }
2203 #pragma warning restore 1058
2204             }
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
2210
2211                 if (e.ExceptionState != null && e.ExceptionState is CancelModuleException) {
2212                     // one of ours (Response.End or timeout) -- cancel abort
2213
2214                     CancelModuleException cancelException = (CancelModuleException)e.ExceptionState;
2215
2216                     if (cancelException.Timeout) {
2217                         // Timed out
2218                         error = new HttpException(SR.GetString(SR.Request_timed_out),
2219                                             null, WebEventCodes.RuntimeErrorRequestAbort);
2220                         PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_TIMED_OUT);
2221                     }
2222                     else {
2223                         // Response.End
2224                         error = null;
2225                         _stepManager.CompleteRequest();
2226                     }
2227
2228                     Thread.ResetAbort();
2229                 }
2230             }
2231
2232             completedSynchronously = true;
2233             return error;
2234         }
2235
2236         /*
2237          * Resume execution of the app steps
2238          */
2239
2240         private void ResumeStepsFromThreadPoolThread(Exception error) {
2241             if (Thread.CurrentThread.IsThreadPoolThread) {
2242                 // if on thread pool thread, use the current thread
2243                 ResumeSteps(error);
2244             }
2245             else {
2246                 // if on a non-threadpool thread, requeue
2247                 ThreadPool.QueueUserWorkItem(_resumeStepsWaitCallback, error);
2248             }
2249         }
2250
2251         private void ResumeStepsWaitCallback(Object error) {
2252             ResumeSteps(error as Exception);
2253         }
2254
2255         private void ResumeSteps(Exception error) {
2256             _stepManager.ResumeSteps(error);
2257         }
2258
2259
2260         /*
2261          * Add error to the context fire OnError on first error
2262          */
2263         private void RecordError(Exception error) {
2264             bool firstError = true;
2265
2266             if (_context != null) {
2267                 if (_context.Error != null)
2268                     firstError = false;
2269
2270                 _context.AddError(error);
2271             }
2272             else {
2273                 if (_lastError != null)
2274                     firstError = false;
2275
2276                 _lastError = error;
2277             }
2278
2279             if (firstError)
2280                 RaiseOnError();
2281         }
2282
2283
2284         //
2285         // Init module list
2286         //
2287
2288         private void InitModulesCommon() {
2289             int n = _moduleCollection.Count;
2290
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);
2296             }
2297
2298             _currentModuleCollectionKey = null;
2299             InitAppLevelCulture();
2300         }
2301
2302         private void InitIntegratedModules() {
2303             Debug.Assert(null != _moduleConfigInfo, "null != _moduleConfigInfo");
2304             _moduleCollection = BuildIntegratedModuleCollection(_moduleConfigInfo);
2305             InitModulesCommon();
2306         }
2307
2308         private void InitModules() {
2309             HttpModulesSection pconfig = RuntimeConfig.GetAppConfig().HttpModules;
2310
2311             // get the static list, then add the dynamic members
2312             HttpModuleCollection moduleCollection = pconfig.CreateModules();
2313             HttpModuleCollection dynamicModules = CreateDynamicModules();
2314
2315             moduleCollection.AppendCollection(dynamicModules);
2316             _moduleCollection = moduleCollection; // don't assign until all ops have succeeded
2317
2318             InitModulesCommon();
2319         }
2320
2321         // instantiates modules that have been added to the dynamic registry (classic pipeline)
2322         private HttpModuleCollection CreateDynamicModules() {
2323             HttpModuleCollection moduleCollection = new HttpModuleCollection();
2324
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());
2328             }
2329
2330             return moduleCollection;
2331         }
2332
2333         internal string CurrentModuleCollectionKey {
2334             get {
2335                 return (null == _currentModuleCollectionKey) ? "UnknownModule" : _currentModuleCollectionKey;
2336             }
2337         }
2338
2339         internal static void RegisterModuleInternal(Type moduleType) {
2340             _dynamicModuleRegistry.Add(moduleType);
2341         }
2342
2343         public static void RegisterModule(Type moduleType) {
2344             RuntimeConfig config = RuntimeConfig.GetAppConfig();
2345             HttpRuntimeSection runtimeSection = config.HttpRuntime;
2346             if (runtimeSection.AllowDynamicModuleRegistration) {
2347                 RegisterModuleInternal(moduleType);
2348             }
2349             else {
2350                 throw new InvalidOperationException(SR.GetString(SR.DynamicModuleRegistrationOff));
2351             }
2352         }
2353
2354         private void RegisterEventSubscriptionsWithIIS(IntPtr appContext, HttpContext context, MethodInfo[] handlers) {
2355             RequestNotification requestNotifications;
2356             RequestNotification postRequestNotifications;
2357
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*/);
2366
2367             // integrated pipeline will always use serverModules instead of <httpModules>
2368             _moduleCollection = GetModuleCollection(appContext);
2369
2370             if (handlers != null) {
2371                 HookupEventHandlersForApplicationAndModules(handlers);
2372             }
2373
2374             // 1643363: Breaking Change: ASP.Net v2.0: Application_OnStart is called after Module.Init (Integarted mode)
2375             HttpApplicationFactory.EnsureAppStartCalledForIntegratedMode(context, this);
2376
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;
2385
2386             try {
2387                 _hideRequestResponse = true;
2388                 context.HideRequestResponse = true;
2389                 _context = context;
2390                 Init();
2391             }
2392             catch (Exception e) {
2393                 RecordError(e);
2394                 Exception error = context.Error;
2395                 if (error != null) {
2396                     throw error;
2397                 }
2398             }
2399             finally {
2400                 _context = null;
2401                 context.HideRequestResponse = false;
2402                 _hideRequestResponse = false;
2403             }
2404
2405             ProcessEventSubscriptions(out requestNotifications, out postRequestNotifications);
2406
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;
2411
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];
2416
2417 #if DBG
2418                 Debug.Trace("PipelineRuntime", "RegisterEventSubscriptionsWithIIS: name=" + CurrentModuleCollectionKey
2419                             + ", type=" + httpModule.GetType().FullName + "\n");
2420
2421                 // make sure collections are in [....]
2422                 Debug.Assert(moduleInfo.Name == _currentModuleCollectionKey, "moduleInfo.Name == _currentModuleCollectionKey");
2423 #endif
2424
2425                 httpModule.Init(this);
2426
2427                 ProcessEventSubscriptions(out requestNotifications, out postRequestNotifications);
2428
2429                 // are any events wired up?
2430                 if (requestNotifications != 0 || postRequestNotifications != 0) {
2431
2432                     RegisterIntegratedEvent(appContext,
2433                                             moduleInfo.Name,
2434                                             requestNotifications,
2435                                             postRequestNotifications,
2436                                             moduleInfo.Type,
2437                                             moduleInfo.Precondition,
2438                                             false /*useHighPriority*/);
2439                 }
2440             }
2441
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,
2445                                     IMPLICIT_HANDLER,
2446                                     RequestNotification.ExecuteRequestHandler | RequestNotification.MapRequestHandler /*requestNotifications*/,
2447                                     RequestNotification.EndRequest /*postRequestNotifications*/,
2448                                     String.Empty /*type*/,
2449                                     String.Empty /*precondition*/,
2450                                     false /*useHighPriority*/);
2451         }
2452
2453         private void ProcessEventSubscriptions(out RequestNotification requestNotifications,
2454                                                out RequestNotification postRequestNotifications) {
2455             requestNotifications = 0;
2456             postRequestNotifications = 0;
2457
2458             // Begin
2459             if(HasEventSubscription(EventBeginRequest)) {
2460                 requestNotifications |= RequestNotification.BeginRequest;
2461             }
2462
2463             // Authenticate
2464             if(HasEventSubscription(EventAuthenticateRequest)) {
2465                 requestNotifications |= RequestNotification.AuthenticateRequest;
2466             }
2467
2468             if(HasEventSubscription(EventPostAuthenticateRequest)) {
2469                 postRequestNotifications |= RequestNotification.AuthenticateRequest;
2470             }
2471
2472             // Authorize
2473             if(HasEventSubscription(EventAuthorizeRequest)) {
2474                 requestNotifications |= RequestNotification.AuthorizeRequest;
2475             }
2476             if(HasEventSubscription(EventPostAuthorizeRequest)) {
2477                 postRequestNotifications |= RequestNotification.AuthorizeRequest;
2478             }
2479
2480             // ResolveRequestCache
2481             if(HasEventSubscription(EventResolveRequestCache)) {
2482                 requestNotifications |= RequestNotification.ResolveRequestCache;
2483             }
2484             if(HasEventSubscription(EventPostResolveRequestCache)) {
2485                 postRequestNotifications |= RequestNotification.ResolveRequestCache;
2486             }
2487
2488             // MapRequestHandler
2489             if(HasEventSubscription(EventMapRequestHandler)) {
2490                 requestNotifications |= RequestNotification.MapRequestHandler;
2491             }
2492             if(HasEventSubscription(EventPostMapRequestHandler)) {
2493                 postRequestNotifications |= RequestNotification.MapRequestHandler;
2494             }
2495
2496             // AcquireRequestState
2497             if(HasEventSubscription(EventAcquireRequestState)) {
2498                 requestNotifications |= RequestNotification.AcquireRequestState;
2499             }
2500             if(HasEventSubscription(EventPostAcquireRequestState)) {
2501                 postRequestNotifications |= RequestNotification.AcquireRequestState;
2502             }
2503
2504             // PreExecuteRequestHandler
2505             if(HasEventSubscription(EventPreRequestHandlerExecute)) {
2506                 requestNotifications |= RequestNotification.PreExecuteRequestHandler;
2507             }
2508
2509             // PostRequestHandlerExecute
2510             if (HasEventSubscription(EventPostRequestHandlerExecute)) {
2511                 postRequestNotifications |= RequestNotification.ExecuteRequestHandler;
2512             }
2513
2514             // ReleaseRequestState
2515             if(HasEventSubscription(EventReleaseRequestState)) {
2516                 requestNotifications |= RequestNotification.ReleaseRequestState;
2517             }
2518             if(HasEventSubscription(EventPostReleaseRequestState)) {
2519                 postRequestNotifications |= RequestNotification.ReleaseRequestState;
2520             }
2521
2522             // UpdateRequestCache
2523             if(HasEventSubscription(EventUpdateRequestCache)) {
2524                 requestNotifications |= RequestNotification.UpdateRequestCache;
2525             }
2526             if(HasEventSubscription(EventPostUpdateRequestCache)) {
2527                 postRequestNotifications |= RequestNotification.UpdateRequestCache;
2528             }
2529
2530             // LogRequest
2531             if(HasEventSubscription(EventLogRequest)) {
2532                 requestNotifications |= RequestNotification.LogRequest;
2533             }
2534             if(HasEventSubscription(EventPostLogRequest)) {
2535                 postRequestNotifications |= RequestNotification.LogRequest;
2536             }
2537
2538             // EndRequest
2539             if(HasEventSubscription(EventEndRequest)) {
2540                 requestNotifications |= RequestNotification.EndRequest;
2541             }
2542
2543             // PreSendRequestHeaders
2544             if(HasEventSubscription(EventPreSendRequestHeaders)) {
2545                 requestNotifications |= RequestNotification.SendResponse;
2546             }
2547
2548             // PreSendRequestContent
2549             if(HasEventSubscription(EventPreSendRequestContent)) {
2550                 requestNotifications |= RequestNotification.SendResponse;
2551             }
2552         }
2553
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;
2560
2561             // async
2562             AsyncAppEventHandler asyncHandler = AsyncEvents[eventIndex];
2563
2564             if (asyncHandler != null && asyncHandler.Count > 0) {
2565                 asyncHandler.Reset();
2566                 hasEvents = true;
2567             }
2568
2569             // [....]
2570             EventHandler handler = (EventHandler)Events[eventIndex];
2571
2572             if (handler != null) {
2573                 Delegate[] handlers = handler.GetInvocationList();
2574                 if( handlers.Length > 0 ) {
2575                     hasEvents = true;
2576                 }
2577
2578                 foreach(Delegate d in handlers) {
2579                     Events.RemoveHandler(eventIndex, d);
2580                 }
2581             }
2582
2583             return hasEvents;
2584         }
2585
2586
2587         //
2588         // Get app-level culture info (needed to context-less 'global' methods)
2589         //
2590
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));
2601                     }
2602                 }
2603                 else {
2604                     _appLevelAutoCulture = false;
2605                     _appLevelCulture = HttpServerUtility.CreateReadOnlyCultureInfo(globConfig.Culture);
2606                 }
2607             }
2608             if (!String.IsNullOrEmpty(uiCulture)) {
2609                 if (StringUtil.StringStartsWithIgnoreCase(uiCulture, AutoCulture))
2610                 {
2611                     _appLevelAutoUICulture = true;
2612                     string appLevelUICulture = GetFallbackCulture(uiCulture);
2613                     if(appLevelUICulture != null) {
2614                         _appLevelUICulture = HttpServerUtility.CreateReadOnlyCultureInfo(uiCulture.Substring(5));
2615                     }
2616                 }
2617                 else {
2618                     _appLevelAutoUICulture = false;
2619                     _appLevelUICulture = HttpServerUtility.CreateReadOnlyCultureInfo(globConfig.UICulture);
2620                 }
2621             }
2622         }
2623
2624         internal static string GetFallbackCulture(string culture) {
2625             if((culture.Length > 5) && (culture.IndexOf(':') == 4)) {
2626                 return culture.Substring(5);
2627             }
2628             return null;
2629         }
2630
2631         //
2632         // Request mappings management functions
2633         //
2634
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;
2640             }
2641
2642             return entry.Factory;
2643         }
2644
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;
2650             }
2651
2652             return entry.Factory;
2653         }
2654
2655
2656         /*
2657          * Recycle all handlers mapped during the request processing
2658          */
2659         private void RecycleHandlers() {
2660             if (_handlerRecycleList != null) {
2661                 int numHandlers = _handlerRecycleList.Count;
2662
2663                 for (int i = 0; i < numHandlers; i++)
2664                     ((HandlerWithFactory)_handlerRecycleList[i]).Recycle();
2665
2666                 _handlerRecycleList = null;
2667             }
2668         }
2669
2670         /*
2671          * Special exception to cancel module execution (not really an exception)
2672          * used in Response.End and when cancelling requests
2673          */
2674         internal class CancelModuleException {
2675             private bool _timeout;
2676
2677             internal CancelModuleException(bool timeout) {
2678                 _timeout = timeout;
2679             }
2680
2681             internal bool Timeout { get { return _timeout;}}
2682         }
2683
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");
2688
2689             if (null == _context) {
2690                 _stepManager.InitRequest();
2691
2692                 _context = context;
2693                 _context.ApplicationInstance = this;
2694
2695                 if (_context.TraceIsEnabled)
2696                     HttpRuntime.Profile.StartRequest(_context);
2697
2698                 // this will throw if config is invalid, so we do it after HttpContext.ApplicationInstance is set
2699                 _context.SetImpersonationEnabled();
2700             }
2701         }
2702
2703         internal IAsyncResult BeginProcessRequestNotification(HttpContext context, AsyncCallback cb) {
2704             Debug.Trace("PipelineRuntime", "BeginProcessRequestNotification");
2705
2706             HttpAsyncResult result;
2707
2708             if (_context == null) {
2709                 // 
2710                 AssignContext(context);
2711             }
2712
2713             //
2714             // everytime initialization
2715             //
2716
2717             context.CurrentModuleEventIndex = -1;
2718
2719             // Create the async result
2720             result = new HttpAsyncResult(cb, context);
2721             context.NotificationContext.AsyncResult = result;
2722
2723             // enter notification execution loop
2724
2725             ResumeSteps(null);
2726
2727             return result;
2728         }
2729
2730         internal RequestNotificationStatus EndProcessRequestNotification(IAsyncResult result) {
2731             HttpAsyncResult ar = (HttpAsyncResult)result;
2732             if (ar.Error != null)
2733                 throw ar.Error;
2734
2735             return ar.Status;
2736         }
2737
2738         internal void ReleaseAppInstance() {
2739             if (_context != null)
2740             {
2741                 if (_context.TraceIsEnabled) {
2742                     HttpRuntime.Profile.EndRequest(_context);
2743                 }
2744                 _context.ClearReferences();
2745                 if (_timeoutManagerInitialized) {
2746                     HttpRuntime.RequestTimeoutManager.Remove(_context);
2747                     _timeoutManagerInitialized = false;
2748                 }
2749
2750                 if(HttpRuntime.EnablePrefetchOptimization && 
2751                    HttpRuntime.InitializationException == null && 
2752                    _context.FirstRequest && 
2753                    _context.Error == null) {
2754                        UnsafeNativeMethods.EndPrefetchActivity((uint)StringUtil.GetNonRandomizedHashCode(HttpRuntime.AppDomainAppId));
2755                 }
2756             }
2757             RecycleHandlers();
2758             if (AsyncResult != null) {
2759                 AsyncResult = null;
2760             }
2761             _context = null;
2762             RaiseOnRequestCompleted();
2763             AppEvent = null;
2764
2765             if (ApplicationInstanceConsumersCounter != null) {
2766                 ApplicationInstanceConsumersCounter.MarkOperationCompleted(); // ReleaseAppInstance call complete
2767             }
2768             else {
2769                 HttpApplicationFactory.RecycleApplicationInstance(this);
2770             }
2771         }
2772
2773         private void AddEventMapping(string moduleName,
2774                                       RequestNotification requestNotification,
2775                                       bool isPostNotification,
2776                                       IExecutionStep step) {
2777
2778             ThrowIfEventBindingDisallowed();
2779
2780             // Add events to the IExecutionStep containers only if
2781             // InitSpecial has completed and InitInternal has not completed.
2782             if (!IsContainerInitalizationAllowed) {
2783                 return;
2784             }
2785
2786             Debug.Assert(!String.IsNullOrEmpty(moduleName), "!String.IsNullOrEmpty(moduleName)");
2787             Debug.Trace("PipelineRuntime", "AddEventMapping: for " + moduleName +
2788                         " for " + requestNotification + "\r\n" );
2789
2790
2791             PipelineModuleStepContainer container = GetModuleContainer(moduleName);
2792             //WOS 1985878: HttpModule unsubscribing an event handler causes AV in Integrated Mode
2793             if (container != null) {
2794 #if DBG
2795                 container.DebugModuleName = moduleName;
2796 #endif
2797                 container.AddEvent(requestNotification, isPostNotification, step);
2798             }
2799         }
2800
2801         static internal List<ModuleConfigurationInfo> IntegratedModuleList {
2802             get {
2803                 return _moduleConfigInfo;
2804             }
2805         }
2806
2807         private HttpModuleCollection GetModuleCollection(IntPtr appContext) {
2808             if (_moduleConfigInfo != null) {
2809                 return BuildIntegratedModuleCollection(_moduleConfigInfo);
2810             }
2811
2812             List<ModuleConfigurationInfo> moduleList = null;
2813
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;
2821             try {
2822                 int count = 0;
2823                 int result = UnsafeIISMethods.MgdGetModuleCollection(IntPtr.Zero, appContext, out pModuleCollection, out count);
2824                 if (result < 0) {
2825                     throw new HttpException(SR.GetString(SR.Cant_Read_Native_Modules, result.ToString("X8", CultureInfo.InvariantCulture)));
2826                 }
2827                 moduleList = new List<ModuleConfigurationInfo>(count);
2828
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);
2834                     if (result < 0) {
2835                         throw new HttpException(SR.GetString(SR.Cant_Read_Native_Modules, result.ToString("X8", CultureInfo.InvariantCulture)));
2836                     }
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;
2849
2850                     if (!String.IsNullOrEmpty(moduleName) && !String.IsNullOrEmpty(moduleType)) {
2851                         moduleList.Add(new ModuleConfigurationInfo(moduleName, moduleType, modulePrecondition));
2852                     }
2853                 }
2854             }
2855             finally {
2856                 if (pModuleCollection != IntPtr.Zero) {
2857                     Marshal.Release(pModuleCollection);
2858                     pModuleCollection = IntPtr.Zero;
2859                 }
2860                 if (pBstrModuleName != IntPtr.Zero) {
2861                     Marshal.FreeBSTR(pBstrModuleName);
2862                     pBstrModuleName = IntPtr.Zero;
2863                 }
2864                 if (pBstrModuleType != IntPtr.Zero) {
2865                     Marshal.FreeBSTR(pBstrModuleType);
2866                     pBstrModuleType = IntPtr.Zero;
2867                 }
2868                 if (pBstrModulePrecondition != IntPtr.Zero) {
2869                     Marshal.FreeBSTR(pBstrModulePrecondition);
2870                     pBstrModulePrecondition = IntPtr.Zero;
2871                 }
2872             }
2873
2874             // now that the static list has been processed, add in the dynamic module list
2875             moduleList.AddRange(GetConfigInfoForDynamicModules());
2876             _moduleConfigInfo = moduleList;
2877
2878             return BuildIntegratedModuleCollection(_moduleConfigInfo);
2879         }
2880
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 */);
2885         }
2886
2887         HttpModuleCollection BuildIntegratedModuleCollection(List<ModuleConfigurationInfo> moduleList) {
2888             HttpModuleCollection modules = new HttpModuleCollection();
2889
2890             foreach(ModuleConfigurationInfo mod in moduleList) {
2891 #if DBG
2892                 Debug.Trace("NativeConfig", "Runtime module: " + mod.Name + " of type " + mod.Type + "\n");
2893 #endif
2894                 ModulesEntry currentModule = new ModulesEntry(mod.Name, mod.Type, "type", null);
2895
2896                 modules.AddModule(currentModule.ModuleName, currentModule.Create());
2897             }
2898
2899             return modules;
2900         }
2901
2902         //
2903         // Internal classes to support [asynchronous] app execution logic
2904         //
2905
2906         internal class AsyncAppEventHandler {
2907             int _count;
2908             ArrayList _beginHandlers;
2909             ArrayList _endHandlers;
2910             ArrayList _stateObjects;
2911
2912             internal AsyncAppEventHandler() {
2913                 _count = 0;
2914                 _beginHandlers = new ArrayList();
2915                 _endHandlers   = new ArrayList();
2916                 _stateObjects  = new ArrayList();
2917             }
2918
2919             internal void Reset() {
2920                 _count = 0;
2921                 _beginHandlers.Clear();
2922                 _endHandlers.Clear();
2923                 _stateObjects.Clear();
2924             }
2925
2926             internal int Count {
2927                 get {
2928                     return _count;
2929                 }
2930             }
2931
2932             internal void Add(BeginEventHandler beginHandler, EndEventHandler endHandler, Object state) {
2933                 _beginHandlers.Add(beginHandler);
2934                 _endHandlers.Add(endHandler);
2935                 _stateObjects.Add(state);
2936                 _count++;
2937             }
2938
2939             internal void CreateExecutionSteps(HttpApplication app, ArrayList steps) {
2940                 for (int i = 0; i < _count; i++) {
2941                     steps.Add(new AsyncEventExecutionStep(
2942                         app,
2943                         (BeginEventHandler)_beginHandlers[i],
2944                         (EndEventHandler)_endHandlers[i],
2945                         _stateObjects[i]));
2946                 }
2947             }
2948         }
2949
2950         internal class AsyncAppEventHandlersTable {
2951             private Hashtable _table;
2952
2953             internal void AddHandler(Object eventId, BeginEventHandler beginHandler,
2954                                      EndEventHandler endHandler, Object state,
2955                                      RequestNotification requestNotification,
2956                                      bool isPost, HttpApplication app) {
2957                 if (_table == null)
2958                     _table = new Hashtable();
2959
2960                 AsyncAppEventHandler asyncHandler = (AsyncAppEventHandler)_table[eventId];
2961
2962                 if (asyncHandler == null) {
2963                     asyncHandler = new AsyncAppEventHandler();
2964                     _table[eventId] = asyncHandler;
2965                 }
2966
2967                 asyncHandler.Add(beginHandler, endHandler, state);
2968
2969                 if (HttpRuntime.UseIntegratedPipeline) {
2970                     AsyncEventExecutionStep step =
2971                         new AsyncEventExecutionStep(app,
2972                                                     beginHandler,
2973                                                     endHandler,
2974                                                     state);
2975
2976                     app.AddEventMapping(app.CurrentModuleCollectionKey, requestNotification, isPost, step);
2977                 }
2978             }
2979
2980             internal AsyncAppEventHandler this[Object eventId] {
2981                 get {
2982                     if (_table == null)
2983                         return null;
2984                     return (AsyncAppEventHandler)_table[eventId];
2985                 }
2986             }
2987         }
2988
2989         // interface to represent one execution step
2990         internal interface IExecutionStep {
2991             void Execute();
2992             bool CompletedSynchronously { get;}
2993             bool IsCancellable { get; }
2994         }
2995
2996         // execution step -- stub
2997         internal class NoopExecutionStep : IExecutionStep {
2998             internal NoopExecutionStep() {
2999             }
3000
3001             void IExecutionStep.Execute() {
3002             }
3003
3004             bool IExecutionStep.CompletedSynchronously {
3005                 get { return true;}
3006             }
3007
3008             bool IExecutionStep.IsCancellable {
3009                 get { return false; }
3010             }
3011         }
3012
3013         // execution step -- call synchronous event
3014         internal class SyncEventExecutionStep : IExecutionStep {
3015             private HttpApplication _application;
3016             private EventHandler    _handler;
3017
3018             internal SyncEventExecutionStep(HttpApplication app, EventHandler handler) {
3019                 _application = app;
3020                 _handler = handler;
3021             }
3022
3023             internal EventHandler Handler {
3024                 get {
3025                     return _handler;
3026                 }
3027             }
3028
3029             void IExecutionStep.Execute() {
3030                 string targetTypeStr = null;
3031
3032                 if (_handler != null) {
3033                     if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Module)) {
3034                         targetTypeStr = _handler.Method.ReflectedType.ToString();
3035
3036                         EtwTrace.Trace(EtwTraceType.ETW_TYPE_PIPELINE_ENTER, _application.Context.WorkerRequest, targetTypeStr);
3037                     }
3038                     _handler(_application, _application.AppEvent);
3039                     if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Module)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_PIPELINE_LEAVE, _application.Context.WorkerRequest, targetTypeStr);
3040                 }
3041             }
3042
3043             bool IExecutionStep.CompletedSynchronously {
3044                 get { return true;}
3045             }
3046
3047             bool IExecutionStep.IsCancellable {
3048                 get { return true; }
3049             }
3050         }
3051
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;
3062
3063             internal AsyncEventExecutionStep(HttpApplication app, BeginEventHandler beginHandler, EndEventHandler endHandler, Object state)
3064                 :this(app, beginHandler, endHandler, state, HttpRuntime.UseIntegratedPipeline)
3065                 {
3066                 }
3067
3068             internal AsyncEventExecutionStep(HttpApplication app, BeginEventHandler beginHandler, EndEventHandler endHandler, Object state, bool useIntegratedPipeline) {
3069
3070                 _application = app;
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;
3075                 _state = state;
3076                 _completionCallback = new AsyncCallback(this.OnAsyncEventCompletion);
3077             }
3078
3079             private void OnAsyncEventCompletion(IAsyncResult ar) {
3080                 if (ar.CompletedSynchronously) {
3081                     // Synchronous completions will be handled by IExecutionStep.Execute.
3082                     return;
3083                 }
3084
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.
3089
3090                 Debug.Trace("PipelineRuntime", "AsyncStep.OnAsyncEventCompletion");
3091                 HttpContext context = _application.Context;
3092                 Exception error = null;
3093
3094                 // The asynchronous step has completed, so we should disallow further
3095                 // async operations until the next step.
3096                 context.SyncContext.ProhibitVoidAsyncOperations();
3097
3098                 try {
3099                     _endHandler(ar);
3100                 }
3101                 catch (Exception e) {
3102                     error = e;
3103                 }
3104
3105                 bool shouldCallResumeSteps = _asyncStepCompletionInfo.RegisterAsyncCompletion(error);
3106                 if (!shouldCallResumeSteps) {
3107                     return;
3108                 }
3109
3110                 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Module)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_PIPELINE_LEAVE, context.WorkerRequest, _targetTypeStr);
3111
3112                 // re-set start time after an async completion (see VSWhidbey 231010)
3113                 context.SetStartTime();
3114
3115                 // Assert to disregard the user code up the stack
3116                 if (HttpRuntime.IsLegacyCas) {
3117                     ResumeStepsWithAssert(error);
3118                 }
3119                 else {
3120                     ResumeSteps(error);
3121                 }
3122             }
3123
3124             [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
3125             void ResumeStepsWithAssert(Exception error) {
3126                 ResumeSteps(error);
3127             }
3128
3129             void ResumeSteps(Exception error) {
3130                 _application.ResumeStepsFromThreadPoolThread(error);
3131             }
3132
3133             void IExecutionStep.Execute() {
3134                 _sync = false;
3135
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);
3139                 }
3140
3141                 HttpContext context = _application.Context;
3142
3143                 _asyncStepCompletionInfo.Reset();
3144                 context.SyncContext.AllowVoidAsyncOperations();
3145                 IAsyncResult ar;
3146                 try {
3147                     ar = _beginHandler(_application, _application.AppEvent, _completionCallback, _state);
3148                 }
3149                 catch {
3150                     // The asynchronous step has completed, so we should disallow further
3151                     // async operations until the next step.
3152                     context.SyncContext.ProhibitVoidAsyncOperations();
3153                     throw;
3154                 }
3155
3156                 bool operationCompleted;
3157                 bool mustCallEndHandler;
3158                 _asyncStepCompletionInfo.RegisterBeginUnwound(ar, out operationCompleted, out mustCallEndHandler);
3159
3160                 if (operationCompleted) {
3161                     _sync = true;
3162
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();
3167                         _endHandler(ar);
3168                     }
3169
3170                     _asyncStepCompletionInfo.ReportError();
3171
3172                     if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Module)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_PIPELINE_LEAVE, _application.Context.WorkerRequest, _targetTypeStr);
3173                 }
3174             }
3175
3176             bool IExecutionStep.CompletedSynchronously {
3177                 get { return _sync;}
3178             }
3179
3180             bool IExecutionStep.IsCancellable {
3181                 get { return false; }
3182             }
3183         }
3184
3185         // execution step -- validate the path for canonicalization issues
3186         internal class ValidatePathExecutionStep : IExecutionStep {
3187             private HttpApplication _application;
3188
3189             internal ValidatePathExecutionStep(HttpApplication app) {
3190                 _application = app;
3191             }
3192
3193             void IExecutionStep.Execute() {
3194                 _application.Context.ValidatePath();
3195             }
3196
3197             bool IExecutionStep.CompletedSynchronously {
3198                 get { return true; }
3199             }
3200
3201             bool IExecutionStep.IsCancellable {
3202                 get { return false; }
3203             }
3204         }
3205
3206         // execution step -- validate request (virtual path, query string, entity body, etc)
3207         internal class ValidateRequestExecutionStep : IExecutionStep {
3208             private HttpApplication _application;
3209
3210             internal ValidateRequestExecutionStep(HttpApplication app) {
3211                 _application = app;
3212             }
3213
3214             void IExecutionStep.Execute() {
3215                 _application.Context.Request.ValidateInputIfRequiredByConfig();
3216             }
3217
3218             bool IExecutionStep.CompletedSynchronously {
3219                 get { return true; }
3220             }
3221
3222             bool IExecutionStep.IsCancellable {
3223                 get { return false; }
3224             }
3225         }
3226
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
3230         // look at it can
3231         internal class MaterializeHandlerExecutionStep : IExecutionStep {
3232             private HttpApplication _application;
3233
3234             internal MaterializeHandlerExecutionStep(HttpApplication app) {
3235                 _application = app;
3236             }
3237
3238             void IExecutionStep.Execute() {
3239                 HttpContext context = _application.Context;
3240                 HttpRequest request = context.Request;
3241                 IHttpHandler handler = null;
3242                 string configType = null;
3243
3244                 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_MAPHANDLER_ENTER, context.WorkerRequest);
3245
3246                 IIS7WorkerRequest wr = context.WorkerRequest as IIS7WorkerRequest;
3247
3248                 // Get handler
3249                 if (context.RemapHandlerInstance != null){
3250                     //RemapHandler overrides all
3251                     wr.SetScriptMapForRemapHandler();
3252                     context.Handler = context.RemapHandlerInstance;
3253                 }
3254                 else if (request.RewrittenUrl != null) {
3255                     // RewritePath, we need to re-map the handler
3256                     bool handlerExists;
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));
3261                     }
3262                 }
3263                 else {
3264                     configType = wr.GetManagedHandlerType();
3265                 }
3266
3267                 if (!String.IsNullOrEmpty(configType)) {
3268                     IHttpHandlerFactory factory = _application.GetFactory(configType);
3269                     string pathTranslated = request.PhysicalPathInternal;
3270
3271                     try {
3272                         handler = factory.GetHandler(context, request.RequestType, request.FilePath, pathTranslated);
3273                     }
3274                     catch (FileNotFoundException e) {
3275                         if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated))
3276                             throw new HttpException(404, null, e);
3277                         else
3278                             throw new HttpException(404, null);
3279                     }
3280                     catch (DirectoryNotFoundException e) {
3281                         if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated))
3282                             throw new HttpException(404, null, e);
3283                         else
3284                             throw new HttpException(404, null);
3285                     }
3286                     catch (PathTooLongException e) {
3287                         if (HttpRuntime.HasPathDiscoveryPermission(pathTranslated))
3288                             throw new HttpException(414, null, e);
3289                         else
3290                             throw new HttpException(414, null);
3291                     }
3292
3293                     context.Handler = handler;
3294
3295                     // Remember for recycling
3296                     if (_application._handlerRecycleList == null)
3297                         _application._handlerRecycleList = new ArrayList();
3298                     _application._handlerRecycleList.Add(new HandlerWithFactory(handler, factory));
3299                 }
3300
3301                 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_MAPHANDLER_LEAVE, context.WorkerRequest);
3302             }
3303
3304             bool IExecutionStep.CompletedSynchronously {
3305                 get { return true;}
3306             }
3307
3308             bool IExecutionStep.IsCancellable {
3309                 get { return false; }
3310             }
3311         }
3312
3313
3314         // execution step -- map HTTP handler (used to be a separate module)
3315         internal class MapHandlerExecutionStep : IExecutionStep {
3316             private HttpApplication _application;
3317
3318             internal MapHandlerExecutionStep(HttpApplication app) {
3319                 _application = app;
3320             }
3321
3322             void IExecutionStep.Execute() {
3323                 HttpContext context = _application.Context;
3324                 HttpRequest request = context.Request;
3325
3326                 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_MAPHANDLER_ENTER, context.WorkerRequest);
3327
3328                 context.Handler = _application.MapHttpHandler(
3329                     context,
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 + ")");
3336
3337                 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_MAPHANDLER_LEAVE, context.WorkerRequest);
3338             }
3339
3340             bool IExecutionStep.CompletedSynchronously {
3341                 get { return true;}
3342             }
3343
3344             bool IExecutionStep.IsCancellable {
3345                 get { return false; }
3346             }
3347         }
3348
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
3356
3357             internal CallHandlerExecutionStep(HttpApplication app) {
3358                 _application = app;
3359                 _completionCallback = new AsyncCallback(this.OnAsyncHandlerCompletion);
3360             }
3361
3362             private void OnAsyncHandlerCompletion(IAsyncResult ar) {
3363                 if (ar.CompletedSynchronously) {
3364                     // Synchronous completions will be handled by IExecutionStep.Execute.
3365                     return;
3366                 }
3367
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.
3372
3373                 HttpContext context = _application.Context;
3374                 Exception error = null;
3375
3376                 // The asynchronous step has completed, so we should disallow further
3377                 // async operations until the next step.
3378                 context.SyncContext.ProhibitVoidAsyncOperations();
3379
3380                 try {
3381                     try {
3382                         _handler.EndProcessRequest(ar);
3383                     }
3384                     finally {
3385                         SuppressPostEndRequestIfNecessary(context);
3386
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();
3391                     }
3392                 }
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();
3397                     }
3398                     else {
3399                         error = e;
3400                     }
3401                 }
3402
3403                 bool shouldCallResumeSteps = _asyncStepCompletionInfo.RegisterAsyncCompletion(error);
3404                 if (!shouldCallResumeSteps) {
3405                     return;
3406                 }
3407
3408                 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Information, EtwTraceFlags.Page)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_HTTPHANDLER_LEAVE, context.WorkerRequest);
3409
3410                 _handler = null; // not to remember
3411
3412                 // re-set start time after an async completion (see VSWhidbey 231010)
3413                 context.SetStartTime();
3414
3415                 // Assert to disregard the user code up the stack
3416                 if (HttpRuntime.IsLegacyCas) {
3417                     ResumeStepsWithAssert(error);
3418                 }
3419                 else {
3420                     ResumeSteps(error);
3421                 }
3422             }
3423
3424             [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
3425             void ResumeStepsWithAssert(Exception error) {
3426                 ResumeSteps(error);
3427             }
3428
3429             void ResumeSteps(Exception error) {
3430                 _application.ResumeStepsFromThreadPoolThread(error);
3431             }
3432
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.
3438
3439                 if (!context.IsWebSocketRequestUpgrading) {
3440                     IIS7WorkerRequest wr = context.WorkerRequest as IIS7WorkerRequest;
3441                     if (wr != null) {
3442                         wr.DisableNotifications(notifications: 0, postNotifications: RequestNotification.EndRequest);
3443                     }
3444                 }
3445             }
3446
3447             void IExecutionStep.Execute() {
3448                 HttpContext context = _application.Context;
3449                 IHttpHandler handler = context.Handler;
3450
3451                 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Information, EtwTraceFlags.Page)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_HTTPHANDLER_ENTER, context.WorkerRequest);
3452
3453                 if (handler != null && HttpRuntime.UseIntegratedPipeline) {
3454                     IIS7WorkerRequest wr = context.WorkerRequest as IIS7WorkerRequest;
3455                     if (wr != null && wr.IsHandlerExecutionDenied()) {
3456                         _sync = true;
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)));
3459                         throw error;
3460                     }
3461                 }
3462
3463                 if (handler == null) {
3464                     _sync = true;
3465                 }
3466                 else if (handler is IHttpAsyncHandler) {
3467                     // asynchronous handler
3468                     IHttpAsyncHandler asyncHandler = (IHttpAsyncHandler)handler;
3469
3470                     _sync = false;
3471                     _handler = asyncHandler;
3472
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);
3476
3477                     _asyncStepCompletionInfo.Reset();
3478                     context.SyncContext.AllowVoidAsyncOperations();
3479                     IAsyncResult ar;
3480                     try {
3481                         ar = beginProcessRequestDelegate(context, _completionCallback, null);
3482                     }
3483                     catch {
3484                         // The asynchronous step has completed, so we should disallow further
3485                         // async operations until the next step.
3486                         context.SyncContext.ProhibitVoidAsyncOperations();
3487                         throw;
3488                     }
3489
3490                     bool operationCompleted;
3491                     bool mustCallEndHandler;
3492                     _asyncStepCompletionInfo.RegisterBeginUnwound(ar, out operationCompleted, out mustCallEndHandler);
3493
3494                     if (operationCompleted) {
3495                         _sync = true;
3496                         _handler = null; // not to remember
3497
3498                         // The asynchronous step has completed, so we should disallow further
3499                         // async operations until the next step.
3500                         context.SyncContext.ProhibitVoidAsyncOperations();
3501
3502                         try {
3503                             if (mustCallEndHandler) {
3504                                 asyncHandler.EndProcessRequest(ar);
3505                             }
3506
3507                             _asyncStepCompletionInfo.ReportError();
3508                         }
3509                         finally {
3510                             SuppressPostEndRequestIfNecessary(context);
3511
3512                             //  In Integrated mode, generate the necessary response headers
3513                             //  after the ASP.NET handler runs
3514                             context.Response.GenerateResponseHeadersForHandler();
3515                         }
3516
3517                         if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Information, EtwTraceFlags.Page)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_HTTPHANDLER_LEAVE, context.WorkerRequest);
3518                     }
3519                 }
3520                 else {
3521                     // synchronous handler
3522                     _sync = true;
3523
3524                     // disable async operations
3525                     //_application.SyncContext.Disable();
3526
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();
3532
3533                     try {
3534                         handler.ProcessRequest(context);
3535                     }
3536                     finally {
3537                         context.SyncContext.ResetSyncCaller();
3538                         if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Information, EtwTraceFlags.Page)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_HTTPHANDLER_LEAVE, context.WorkerRequest);
3539
3540                         SuppressPostEndRequestIfNecessary(context);
3541
3542                         // In Integrated mode, generate the necessary response headers
3543                         // after the ASP.NET handler runs
3544                         context.Response.GenerateResponseHeadersForHandler();
3545                     }
3546                 }
3547             }
3548
3549             bool IExecutionStep.CompletedSynchronously {
3550                 get { return _sync;}
3551             }
3552
3553             bool IExecutionStep.IsCancellable {
3554                 // launching of async handler should not be cancellable
3555                 get { return (_application.Context.Handler is IHttpAsyncHandler) ? false : true; }
3556             }
3557         }
3558
3559         // execution step -- initiate the transition to a WebSocket request
3560         internal class TransitionToWebSocketsExecutionStep : IExecutionStep {
3561             private readonly HttpApplication _application;
3562
3563             internal TransitionToWebSocketsExecutionStep(HttpApplication app) {
3564                 _application = app;
3565             }
3566
3567             void IExecutionStep.Execute() {
3568                 HttpContext context = _application.Context;
3569
3570                 if (context.RootedObjects == null
3571                     || context.RootedObjects.WebSocketPipeline == null
3572                     || context.Response.StatusCode != (int)HttpStatusCode.SwitchingProtocols) {
3573
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;
3577                 }
3578                 else {
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());
3582
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.
3587
3588                     // transition: AcceptWebSocketRequestCalled -> TransitionStarted
3589                     context.TransitionToWebSocketState(WebSocketTransitionState.TransitionStarted);
3590                     CompletedSynchronously = false;
3591                 }
3592             }
3593
3594             public bool CompletedSynchronously {
3595                 get;
3596                 private set;
3597             }
3598
3599             public bool IsCancellable {
3600                 // launching of async operation should not be cancellable
3601                 get { return false; }
3602             }
3603         }
3604
3605         // execution step -- call response filter
3606         internal class CallFilterExecutionStep : IExecutionStep {
3607             private HttpApplication _application;
3608
3609             internal CallFilterExecutionStep(HttpApplication app) {
3610                 _application = app;
3611             }
3612
3613             void IExecutionStep.Execute() {
3614                 try {
3615                     _application.Context.Response.FilterOutput();
3616                 }
3617                 finally {
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*/);
3621                     }
3622                 }
3623             }
3624
3625             bool IExecutionStep.CompletedSynchronously {
3626                 get { return true;}
3627             }
3628
3629             bool IExecutionStep.IsCancellable {
3630                 get { return true; }
3631             }
3632         }
3633
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;
3639
3640             internal SendResponseExecutionStep(HttpApplication app, EventHandler handler, bool isHeaders) {
3641                 _application = app;
3642                 _handler = handler;
3643                 _isHeaders = isHeaders;
3644             }
3645
3646             void IExecutionStep.Execute() {
3647
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
3652                     || !_isHeaders) {
3653
3654                     string targetTypeStr = null;
3655
3656                     if (_handler != null) {
3657                         if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Module)) {
3658                             targetTypeStr = _handler.Method.ReflectedType.ToString();
3659
3660                             EtwTrace.Trace(EtwTraceType.ETW_TYPE_PIPELINE_ENTER, _application.Context.WorkerRequest, targetTypeStr);
3661                         }
3662                         _handler(_application, _application.AppEvent);
3663                         if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Module)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_PIPELINE_LEAVE, _application.Context.WorkerRequest, targetTypeStr);
3664                     }
3665                 }
3666             }
3667
3668             bool IExecutionStep.CompletedSynchronously {
3669                 get { return true;}
3670             }
3671
3672             bool IExecutionStep.IsCancellable {
3673                 get { return true; }
3674             }
3675         }
3676
3677         internal class UrlMappingsExecutionStep : IExecutionStep {
3678             private HttpApplication _application;
3679
3680
3681             internal UrlMappingsExecutionStep(HttpApplication app) {
3682                 _application = app;
3683             }
3684
3685             void IExecutionStep.Execute() {
3686                 HttpContext context = _application.Context;
3687                 UrlMappingsModule.UrlMappingRewritePath(context);
3688             }
3689
3690             bool IExecutionStep.CompletedSynchronously {
3691                 get { return true;}
3692             }
3693
3694             bool IExecutionStep.IsCancellable {
3695                 get { return false; }
3696             }
3697         }
3698
3699         internal abstract class StepManager {
3700             protected HttpApplication _application;
3701             protected bool _requestCompleted;
3702
3703             internal StepManager(HttpApplication application) {
3704                 _application = application;
3705             }
3706
3707             internal bool IsCompleted { get { return _requestCompleted; } }
3708
3709             internal abstract void BuildSteps(WaitCallback stepCallback);
3710
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;
3717                     }
3718                 }
3719             }
3720
3721             internal abstract void InitRequest();
3722
3723             internal abstract void ResumeSteps(Exception error);
3724         }
3725
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;
3733
3734             internal ApplicationStepManager(HttpApplication app): base(app) {
3735             }
3736
3737             internal override void BuildSteps(WaitCallback stepCallback ) {
3738                 ArrayList steps = new ArrayList();
3739                 HttpApplication app = _application;
3740
3741                 bool urlMappingsEnabled = false;
3742                 UrlMappingsSection urlMappings = RuntimeConfig.GetConfig().UrlMappings;
3743                 urlMappingsEnabled = urlMappings.IsEnabled && ( urlMappings.UrlMappings.Count > 0 );
3744
3745                 steps.Add(new ValidateRequestExecutionStep(app));
3746                 steps.Add(new ValidatePathExecutionStep(app));
3747
3748                 if (urlMappingsEnabled)
3749                     steps.Add(new UrlMappingsExecutionStep(app)); // url mappings
3750
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
3775
3776                 _execSteps = new IExecutionStep[steps.Count];
3777                 steps.CopyTo(_execSteps);
3778
3779                 // callback for async completion when reposting to threadpool thread
3780                 _resumeStepsWaitCallback = stepCallback;
3781             }
3782
3783             internal override void InitRequest() {
3784                 _currentStepIndex   = -1;
3785                 _numStepCalls       = 0;
3786                 _numSyncStepCalls   = 0;
3787                 _requestCompleted   = false;
3788             }
3789
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;
3800
3801                 Debug.Trace("Async", "HttpApplication.ResumeSteps");
3802
3803                 try {
3804                     if (appInstanceConsumersCounter != null) {
3805                         appInstanceConsumersCounter.MarkOperationPending(); // ResumeSteps call started
3806                     }
3807
3808                     using (syncContext.AcquireThreadLock()) {
3809                         // avoid ---- between the app code and fast async completion from a module
3810
3811
3812                         try {
3813                             threadContext = app.OnThreadEnter();
3814                         }
3815                         catch (Exception e) {
3816                             if (error == null)
3817                                 error = e;
3818                         }
3819
3820                         try {
3821                             try {
3822                                 for (; ; ) {
3823                                     // record error
3824
3825                                     if (syncContext.Error != null) {
3826                                         error = syncContext.Error;
3827                                         syncContext.ClearError();
3828                                     }
3829
3830                                     if (error != null) {
3831                                         app.RecordError(error);
3832                                         error = null;
3833                                     }
3834
3835                                     // check for any outstanding async operations
3836
3837                                     if (syncContext.PendingCompletion(_resumeStepsWaitCallback)) {
3838                                         // wait until all pending async operations complete
3839                                         break;
3840                                     }
3841
3842                                     // advance to next step
3843
3844                                     if (_currentStepIndex < _endRequestStepIndex && (context.Error != null || _requestCompleted)) {
3845                                         // end request
3846                                         context.Response.FilterOutput();
3847                                         _currentStepIndex = _endRequestStepIndex;
3848                                     }
3849                                     else {
3850                                         _currentStepIndex++;
3851                                     }
3852
3853                                     if (_currentStepIndex >= _execSteps.Length) {
3854                                         appCompleted = true;
3855                                         break;
3856                                     }
3857
3858                                     // execute the current step
3859
3860                                     _numStepCalls++;          // count all calls
3861
3862                                     // enable launching async operations before each new step
3863                                     syncContext.Enable();
3864
3865                                     // call to execute current step catching thread abort exception
3866                                     error = app.ExecuteStep(_execSteps[_currentStepIndex], ref stepCompletedSynchronously);
3867
3868                                     // unwind the stack in the async case
3869                                     if (!stepCompletedSynchronously)
3870                                         break;
3871
3872                                     _numSyncStepCalls++;      // count synchronous calls
3873                                 }
3874                             }
3875                             finally {
3876                                 if (appCompleted) {
3877                                     // need to raise OnRequestCompleted while within the ThreadContext so that things like User, CurrentCulture, etc. are available
3878                                     context.RaiseOnRequestCompleted();
3879                                 }
3880
3881                                 if (threadContext != null) {
3882                                     try {
3883                                         threadContext.DisassociateFromCurrentThread();
3884                                     }
3885                                     catch {
3886                                     }
3887                                 }
3888                             }
3889                         }
3890                         catch { // Protect against exception filters
3891                             throw;
3892                         }
3893
3894                     }   // using
3895
3896                     if (appCompleted) {
3897                         // need to raise OnPipelineCompleted outside of the ThreadContext so that HttpContext.Current, User, etc. are unavailable
3898                         context.RaiseOnPipelineCompleted();
3899
3900                         // unroot context (async app operations ended)
3901                         context.Unroot();
3902
3903                         // async completion
3904                         app.AsyncResult.Complete((_numStepCalls == _numSyncStepCalls), null, null);
3905                         app.ReleaseAppInstance();
3906                     }
3907                 }
3908                 finally {
3909                     if (appInstanceConsumersCounter != null) {
3910                         appInstanceConsumersCounter.MarkOperationCompleted(); // ResumeSteps call complete
3911                     }
3912                 }
3913             }
3914         }
3915
3916         internal class PipelineStepManager : StepManager {
3917
3918             WaitCallback _resumeStepsWaitCallback;
3919             bool _validatePathCalled;
3920             bool _validateInputCalled;
3921
3922             internal PipelineStepManager(HttpApplication app): base(app) {
3923             }
3924
3925             internal override void BuildSteps(WaitCallback stepCallback) {
3926                 Debug.Trace("PipelineRuntime", "BuildSteps");
3927                 //ArrayList steps = new ArrayList();
3928                 HttpApplication app = _application;
3929
3930                 // add special steps that don't currently
3931                 // correspond to a configured handler
3932
3933                 IExecutionStep materializeStep = new MaterializeHandlerExecutionStep(app);
3934
3935                 // implicit map step
3936                 app.AddEventMapping(
3937                     HttpApplication.IMPLICIT_HANDLER,
3938                     RequestNotification.MapRequestHandler,
3939                     false, materializeStep);
3940
3941                 // implicit async preload step
3942                 app.AddEventMapping(
3943                     HttpApplication.IMPLICIT_HANDLER,
3944                     RequestNotification.ExecuteRequestHandler,
3945                     false, app.CreateImplicitAsyncPreloadExecutionStep());
3946
3947                 // implicit handler routing step
3948                 IExecutionStep handlerStep = new CallHandlerExecutionStep(app);
3949
3950                 app.AddEventMapping(
3951                     HttpApplication.IMPLICIT_HANDLER,
3952                     RequestNotification.ExecuteRequestHandler,
3953                     false, handlerStep);
3954
3955                 // implicit handler WebSockets step
3956                 IExecutionStep webSocketsStep = new TransitionToWebSocketsExecutionStep(app);
3957
3958                 app.AddEventMapping(
3959                     HttpApplication.IMPLICIT_HANDLER,
3960                     RequestNotification.EndRequest,
3961                     true /* isPostNotification */, webSocketsStep);
3962
3963                 // add implicit request filtering step
3964                 IExecutionStep filterStep = new CallFilterExecutionStep(app);
3965
3966                 // normally, this executes during UpdateRequestCache as a high priority module
3967                 app.AddEventMapping(
3968                     HttpApplication.IMPLICIT_FILTER_MODULE,
3969                     RequestNotification.UpdateRequestCache,
3970                     false, filterStep);
3971
3972                 // for error conditions, this executes during LogRequest as a high priority module
3973                 app.AddEventMapping(
3974                     HttpApplication.IMPLICIT_FILTER_MODULE,
3975                     RequestNotification.LogRequest,
3976                     false, filterStep);
3977
3978                 _resumeStepsWaitCallback = stepCallback;
3979             }
3980
3981             internal override void InitRequest() {
3982                 _requestCompleted = false;
3983                 _validatePathCalled = false;
3984                 _validateInputCalled = false;
3985             }
3986
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;
3996
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);
4006
4007                 CountdownTask appInstanceConsumersCounter = _application.ApplicationInstanceConsumersCounter;
4008
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
4012                     {
4013                         syncContext.AssociateWithCurrentThread();
4014                     }
4015                     try {
4016                         if (appInstanceConsumersCounter != null) {
4017                             appInstanceConsumersCounter.MarkOperationPending(); // ResumeSteps call started
4018                         }
4019
4020                         bool locked = false;
4021                         try {
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.
4025
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.
4030
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();
4042                                     }
4043                                 }
4044                                 else {
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;
4049                                 }
4050                             }
4051
4052                             for (; ; ) {
4053 #if DBG
4054                                 Debug.Trace("PipelineRuntime", "ResumeSteps: CurrentModuleEventIndex=" + context.CurrentModuleEventIndex);
4055 #endif
4056
4057                                 // check and record errors into the HttpContext
4058                                 if (syncContext.Error != null) {
4059                                     error = syncContext.Error;
4060                                     syncContext.ClearError();
4061                                 }
4062                                 if (error != null) {
4063                                     // the error can be cleared by the user
4064                                     _application.RecordError(error);
4065                                     error = null;
4066                                 }
4067
4068                                 if (!_validateInputCalled || !_validatePathCalled) {
4069                                     error = ValidateHelper(context);
4070                                     if (error != null) {
4071                                         continue;
4072                                     }
4073                                 }
4074
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);
4083
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;
4088                                     break;
4089                                 }
4090
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;
4095
4096                                 if (needToFinishRequest || context.CurrentModuleEventIndex == currentModuleLastEventIndex) {
4097
4098                                     // if an error occured or someone completed the request, set the status to FinishRequest
4099                                     status = needToFinishRequest ? RequestNotificationStatus.FinishRequest : RequestNotificationStatus.Continue;
4100
4101                                     // async case
4102                                     if (context.NotificationContext.PendingAsyncCompletion) {
4103                                         context.Response.SyncStatusIntegrated();
4104                                         context.NotificationContext.PendingAsyncCompletion = false;
4105                                         isSynchronousCompletion = false;
4106                                         needToComplete = true;
4107                                         break;
4108                                     }
4109
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;
4114                                         break;
4115                                     }
4116
4117                                     int currentModuleIndex = 0;
4118                                     bool isPostNotification = false;
4119                                     int currentNotification = 0;
4120
4121                                     UnsafeIISMethods.MgdGetCurrentNotificationInfo(wr.RequestContext, out currentModuleIndex, out isPostNotification, out currentNotification);
4122
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;
4129                                 }
4130
4131                                 context.CurrentModuleEventIndex++;
4132
4133                                 IExecutionStep step = _application.CurrentModuleContainer.GetNextEvent(context.CurrentNotification, context.IsPostNotification,
4134                                                                                                        context.CurrentModuleEventIndex);
4135
4136                                 // enable launching async operations before each new step
4137                                 context.SyncContext.Enable();
4138
4139                                 stepCompletedSynchronously = false;
4140                                 error = _application.ExecuteStep(step, ref stepCompletedSynchronously);
4141
4142 #if DBG
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);
4150 #endif
4151
4152
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;
4160                                     break;
4161                                 }
4162                                 else {
4163                                     context.Response.SyncStatusIntegrated();
4164                                 }
4165                             }
4166                         }
4167                         finally {
4168                             if (locked) {
4169                                 _application.ReleaseNotifcationContextLock();
4170                             }
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.
4179                                         //
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)
4184
4185                                         //always undo impersonation so that the token is removed before returning to IIS (DDB 156421)
4186                                         threadContext.UndoImpersonationContext();
4187                                     }
4188                                     else {
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;
4198                                                     // DevDiv 482614:
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;
4205                                                     }
4206                                                 }
4207                                             }
4208                                         }
4209                                     }
4210                                 }
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();
4226                                 }
4227                                 else {
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;
4234                                 }
4235
4236                                 // Cleanup the thread state unless we prepared to call IndicateCompletion or already cleaned up
4237                                 if (needToDisassociateThreadContext) {
4238                                     threadContext.DisassociateFromCurrentThread();
4239                                 }
4240                             }
4241                         }
4242
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);
4247                         }
4248                     } // end of try statement that begins after AssociateWithCurrentThread
4249                     finally {
4250                         if (!isReEntry) {
4251                             syncContext.DisassociateFromCurrentThread();
4252                         }
4253                         if (appInstanceConsumersCounter != null) {
4254                             appInstanceConsumersCounter.MarkOperationCompleted(); // ResumeSteps call completed
4255                         }
4256                     }
4257                 }
4258             }
4259             
4260             private Exception ValidateHelper(HttpContext context) {
4261                 if (!_validateInputCalled) {
4262                     _validateInputCalled = true;
4263                     try {
4264                         context.Request.ValidateInputIfRequiredByConfig();
4265                     }
4266                     catch(Exception e) {
4267                         return e;
4268                     }
4269                 }
4270                 if (!_validatePathCalled) {
4271                     _validatePathCalled = true;
4272                     try {
4273                         context.ValidatePath();
4274                     }
4275                     catch(Exception e) {
4276                         return e;
4277                     }
4278                 }
4279                 return null;
4280             }
4281         }
4282
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;
4290
4291             private volatile int _asyncState;
4292             private ExceptionDispatchInfo _error;
4293
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.
4306                 //
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.
4309
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
4316                 }
4317
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
4321             }
4322
4323             public void RegisterBeginUnwound(IAsyncResult asyncResult, out bool operationCompleted, out bool mustCallEndHandler) {
4324                 operationCompleted = false;
4325                 mustCallEndHandler = false;
4326
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;
4334                     }
4335
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.
4338                 }
4339                 else {
4340                     Debug.Assert(originalState == ASYNC_STATE_CALLBACK_COMPLETED, "Unexpected state.");
4341
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;
4346                 }
4347
4348                 // Interlocked performs a volatile read; if RethrowExceptionIfNecessary() is called after RegisterBeginUnwound(),
4349                 // the thread will see the correct value for the _error field.
4350             }
4351
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
4357                     error.Throw();
4358                 }
4359             }
4360
4361             public void Reset() {
4362                 // All processors see the _error field write as being no later than the _asyncState field write.
4363                 _error = null;
4364                 _asyncState = ASYNC_STATE_NONE;
4365             }
4366 #pragma warning restore 420 // volatile passed by reference
4367         }
4368     }
4369 }