ee795721a7fb80862765ad72516944cb984baed4
[mono.git] / mcs / class / System.Web / System.Web / HttpApplication.cs
1 //
2 // System.Web.HttpApplication.cs 
3 //
4 // Author:
5 //      Miguel de Icaza (miguel@novell.com)
6 //      Gonzalo Paniagua (gonzalo@ximian.com)
7 //    
8 //
9 // Copyright (C) 2005-2009 Novell, Inc (http://www.novell.com)
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 // The Application Processing Pipeline.
31 // 
32 //     The Http application pipeline implemented in this file is a
33 //     beautiful thing.  The application pipeline invokes a number of
34 //     hooks at various stages of the processing of a request.  These
35 //     hooks can be either synchronous or can be asynchronous.
36 //     
37 //     The pipeline must ensure that every step is completed before
38 //     moving to the next step.  A trivial thing for synchronous
39 //     hooks, but asynchronous hooks introduce an extra layer of
40 //     complexity: when the hook is invoked, the thread must
41 //     relinquish its control so that the thread can be reused in
42 //     another operation while waiting.
43 //
44 //     To implement this functionality we used C# iterators manually;
45 //     we drive the pipeline by executing the various hooks from the
46 //     `RunHooks' routine which is an enumerator that will yield the
47 //     value `false' if execution must proceed or `true' if execution
48 //     must be stopped.
49 //
50 //     By yielding values we can suspend execution of RunHooks.
51 //
52 //     Special attention must be given to `in_begin' and `must_yield'
53 //     variables.  These are used in the case that an async hook
54 //     completes synchronously as its important to not yield in that
55 //     case or we would hang.
56 //    
57 //     Many of Mono modules used to be declared async, but they would
58 //     actually be completely synchronous, this might resurface in the
59 //     future with other modules.
60 //
61 // TODO:
62 //    Events Disposed
63 //
64
65 using System.IO;
66 using System.Collections;
67 using System.ComponentModel;
68 using System.Configuration;
69 using System.Diagnostics;
70 using System.Globalization;
71 using System.Reflection;
72 using System.Security.Permissions;
73 using System.Security.Principal;
74 using System.Threading;
75 using System.Web.Caching;
76 using System.Web.Compilation;
77 using System.Web.Configuration;
78 using System.Web.Management;
79 using System.Web.SessionState;
80 using System.Web.UI;
81 using System.Web.Util;
82
83         
84 namespace System.Web
85 {
86         // CAS
87         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
88         [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
89         // attributes
90         [ToolboxItem(false)]
91         public class HttpApplication : IHttpAsyncHandler, IHttpHandler, IComponent, IDisposable
92         {
93                 static readonly object disposedEvent = new object ();
94                 static readonly object errorEvent = new object ();
95                 
96                 // we do this static rather than per HttpApplication because
97                 // mono's perfcounters use the counter instance parameter for
98                 // the process to access shared memory.
99                 internal static PerformanceCounter requests_total_counter = new PerformanceCounter ("ASP.NET", "Requests Total");
100                 
101                 internal static readonly string [] BinDirs = {"Bin", "bin"};
102                 object this_lock = new object();
103                 
104                 HttpContext context;
105                 HttpSessionState session;
106                 ISite isite;
107
108                 // The source, and the exposed API (cache).
109                 volatile HttpModuleCollection modcoll;
110
111                 string assemblyLocation;
112
113                 //
114                 // The factory for the handler currently running.
115                 //
116                 IHttpHandlerFactory factory;
117
118                 //
119                 // Whether the thread culture is to be auto-set.
120                 // Used only in the 2.0 profile, always false for 1.x
121                 //
122                 bool autoCulture;
123                 bool autoUICulture;
124                 
125                 //
126                 // Whether the pipeline should be stopped
127                 //
128                 bool stop_processing;
129
130                 //
131                 // See https://bugzilla.novell.com/show_bug.cgi?id=381971
132                 //
133                 bool in_application_start;
134                 
135                 //
136                 // The Pipeline
137                 //
138                 IEnumerator pipeline;
139
140                 // To flag when we are done processing a request from BeginProcessRequest.
141                 ManualResetEvent done;
142
143                 // The current IAsyncResult for the running async request handler in the pipeline
144                 AsyncRequestState begin_iar;
145
146                 // Tracks the current AsyncInvocation being dispatched
147                 AsyncInvoker current_ai;
148
149                 EventHandlerList events;
150                 EventHandlerList nonApplicationEvents = new EventHandlerList ();
151                 
152                 // Culture and IPrincipal
153                 CultureInfo app_culture;
154                 CultureInfo appui_culture;
155                 CultureInfo prev_app_culture;
156                 CultureInfo prev_appui_culture;
157                 IPrincipal prev_user;
158
159                 static string binDirectory;
160                 
161                 static volatile Exception initialization_exception;
162                 bool removeConfigurationFromCache;
163                 bool fullInitComplete = false;
164                 
165                 //
166                 // These are used to detect the case where the EndXXX method is invoked
167                 // from within the BeginXXXX delegate, so we detect whether we kick the
168                 // pipeline from here, or from the the RunHook routine
169                 //
170                 bool must_yield;
171                 bool in_begin;
172
173                 public virtual event EventHandler Disposed {
174                         add { nonApplicationEvents.AddHandler (disposedEvent, value); }
175                         remove { nonApplicationEvents.RemoveHandler (disposedEvent, value); }
176                 }
177                 
178                 public virtual event EventHandler Error {
179                         add { nonApplicationEvents.AddHandler (errorEvent, value); }
180                         remove { nonApplicationEvents.RemoveHandler (errorEvent, value); }
181                 }
182
183                 public HttpApplication ()
184                 {
185                         done = new ManualResetEvent (false);
186                 }
187                 
188                 internal void InitOnce (bool full_init)
189                 {
190                         if (initialization_exception != null)
191                                 return;
192
193                         if (modcoll != null)
194                                 return;
195
196                         lock (this_lock) {
197                                 if (initialization_exception != null)
198                                         return;
199
200                                 if (modcoll != null)
201                                         return;
202
203                                 bool mustNullContext = context == null;
204                                 try {
205                                         HttpModulesSection modules;
206                                         modules = (HttpModulesSection) WebConfigurationManager.GetWebApplicationSection ("system.web/httpModules");
207                                         HttpContext saved = HttpContext.Current;
208                                         HttpContext.Current = new HttpContext (new System.Web.Hosting.SimpleWorkerRequest (String.Empty, String.Empty, new StringWriter()));
209                                         if (context == null)
210                                                 context = HttpContext.Current;
211                                         HttpModuleCollection coll = modules.LoadModules (this);
212                                         Interlocked.CompareExchange (ref modcoll, coll, null);
213                                         HttpContext.Current = saved;
214
215                                         if (full_init) {
216                                                 HttpApplicationFactory.AttachEvents (this);
217                                                 Init ();
218                                                 fullInitComplete = true;
219                                         }
220                                 } catch (Exception e) {
221                                         initialization_exception = e;
222                                         Console.Error.WriteLine("Exception while initOnce: "+e.ToString());
223                                         // Once initialization_exception != null, we always respond with this exception
224                                         // You have to restart the HttpApplication to "unlock" it
225                                         Console.Error.WriteLine("Please restart your app to unlock it");
226                                 } finally {
227                                         if (mustNullContext)
228                                                 context = null;
229                                 }
230                         }
231                 }
232
233                 internal bool InApplicationStart {
234                         get { return in_application_start; }
235                         set { in_application_start = value; }
236                 }
237                 
238                 internal string AssemblyLocation {
239                         get {
240                                 if (assemblyLocation == null)
241                                         assemblyLocation = GetType ().Assembly.Location;
242                                 return assemblyLocation;
243                         }
244                 }
245
246                 internal static Exception InitializationException {
247                         get { return initialization_exception; }
248                 }
249
250                 [Browsable (false)]
251                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
252                 public HttpApplicationState Application {
253                         get {
254                                 return HttpApplicationFactory.ApplicationState;
255                         }
256                 }
257
258                 [Browsable (false)]
259                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
260                 public HttpContext Context {
261                         get {
262                                 return context;
263                         }
264                 }
265                                          
266                 protected EventHandlerList Events {
267                         get {
268                                 if (events == null)
269                                         events = new EventHandlerList ();
270
271                                 return events;
272                         }
273                 }
274
275                 [Browsable (false)]
276                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
277                 public HttpModuleCollection Modules {
278                         [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
279                         get {
280                                 if (modcoll == null)
281                                         modcoll = new HttpModuleCollection ();
282                                 
283                                 return modcoll;
284                         }
285                 }
286
287                 [Browsable (false)]
288                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
289                 public HttpRequest Request {
290                         get {
291                                 if (context == null)
292                                         throw HttpException.NewWithCode (Locale.GetText ("No context is available."), WebEventCodes.RuntimeErrorRequestAbort);
293
294                                 if (false == HttpApplicationFactory.ContextAvailable)
295                                         throw HttpException.NewWithCode (Locale.GetText ("Request is not available in this context."), WebEventCodes.RuntimeErrorRequestAbort);
296
297                                 return context.Request;
298                         }
299                 }
300
301                 [Browsable (false)]
302                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
303                 public HttpResponse Response {
304                         get {
305                                 if (context == null)
306                                         throw HttpException.NewWithCode (Locale.GetText ("No context is available."), WebEventCodes.RuntimeErrorRequestAbort);
307
308                                 if (false == HttpApplicationFactory.ContextAvailable)
309                                         throw HttpException.NewWithCode (Locale.GetText ("Response is not available in this context."), WebEventCodes.RuntimeErrorRequestAbort);
310
311                                 return context.Response;
312                         }
313                 }
314
315                 [Browsable (false)]
316                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
317                 public HttpServerUtility Server {
318                         get {
319                                 if (context != null)
320                                         return context.Server;
321
322                                 //
323                                 // This is so we can get the Server and call a few methods
324                                 // which are not context sensitive, see HttpServerUtilityTest
325                                 //
326                                 return new HttpServerUtility ((HttpContext) null);
327                         }
328                 }
329
330                 [Browsable (false)]
331                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
332                 public HttpSessionState Session {
333                         get {
334                                 // Only used for Session_End
335                                 if (session != null)
336                                         return session;
337
338                                 if (context == null)
339                                         throw HttpException.NewWithCode (Locale.GetText ("No context is available."), WebEventCodes.RuntimeErrorRequestAbort);
340
341                                 HttpSessionState ret = context.Session;
342                                 if (ret == null)
343                                         throw HttpException.NewWithCode (Locale.GetText ("Session state is not available in the context."), WebEventCodes.RuntimeErrorRequestAbort);
344                                 
345                                 return ret;
346                         }
347                 }
348
349                 [Browsable (false)]
350                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
351                 public ISite Site {
352                         get { return isite; }
353
354                         set { isite = value; }
355                 }
356
357                 [Browsable (false)]
358                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
359                 public IPrincipal User {
360                         get {
361                                 if (context == null)
362                                         throw new HttpException (Locale.GetText ("No context is available."));
363                                 if (context.User == null)
364                                         throw new HttpException (Locale.GetText ("No currently authenticated user."));
365                                 
366                                 return context.User;
367                         }
368                 }
369                 
370                 static object PreSendRequestHeadersEvent = new object ();
371                 public event EventHandler PreSendRequestHeaders
372                 {
373                         add { AddEventHandler (PreSendRequestHeadersEvent, value); }
374                         remove { RemoveEventHandler (PreSendRequestHeadersEvent, value); }
375                 }
376                 
377                 internal void TriggerPreSendRequestHeaders ()
378                 {
379                         EventHandler handler = Events [PreSendRequestHeadersEvent] as EventHandler;
380                         if (handler != null)
381                                 handler (this, EventArgs.Empty);
382                 }
383
384                 static object PreSendRequestContentEvent = new object ();
385                 public event EventHandler PreSendRequestContent
386                 {
387                         add { AddEventHandler (PreSendRequestContentEvent, value); }
388                         remove { RemoveEventHandler (PreSendRequestContentEvent, value); }
389                 }
390                 
391                 internal void TriggerPreSendRequestContent ()
392                 {
393                         EventHandler handler = Events [PreSendRequestContentEvent] as EventHandler;
394                         if (handler != null)
395                                 handler (this, EventArgs.Empty);
396                 }
397
398                 static object AcquireRequestStateEvent = new object ();
399                 public event EventHandler AcquireRequestState
400                 {
401                         add { AddEventHandler (AcquireRequestStateEvent, value); }
402                         remove { RemoveEventHandler (AcquireRequestStateEvent, value); }
403                 }
404                 
405                 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
406                 {
407                         AsyncInvoker invoker = new AsyncInvoker (bh, eh);
408                         AcquireRequestState += new EventHandler (invoker.Invoke);
409                 }
410
411                 static object AuthenticateRequestEvent = new object ();
412                 public event EventHandler AuthenticateRequest
413                 {
414                         add { AddEventHandler (AuthenticateRequestEvent, value); }
415                         remove { RemoveEventHandler (AuthenticateRequestEvent, value); }
416                 }
417                 
418                 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
419                 {
420                         AsyncInvoker invoker = new AsyncInvoker (bh, eh);
421                         AuthenticateRequest += new EventHandler (invoker.Invoke);
422                 }
423
424                 static object AuthorizeRequestEvent = new object ();
425                 public event EventHandler AuthorizeRequest
426                 {
427                         add { AddEventHandler (AuthorizeRequestEvent, value); }
428                         remove { RemoveEventHandler (AuthorizeRequestEvent, value); }
429                 }
430                 
431                 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
432                 {
433                         AsyncInvoker invoker = new AsyncInvoker (bh, eh);
434                         AuthorizeRequest += new EventHandler (invoker.Invoke);
435                 }
436
437                 static object BeginRequestEvent = new object ();
438                 public event EventHandler BeginRequest          
439                 {
440                         add {
441                                 // See https://bugzilla.novell.com/show_bug.cgi?id=381971
442                                 if (InApplicationStart)
443                                         return;
444                                 AddEventHandler (BeginRequestEvent, value);
445                         }
446                         remove {
447                                 if (InApplicationStart)
448                                         return;
449                                 RemoveEventHandler (BeginRequestEvent, value);
450                         }
451                 }
452                 
453                 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh)
454                 {
455                         AsyncInvoker invoker = new AsyncInvoker (bh, eh);
456                         BeginRequest += new EventHandler (invoker.Invoke);
457                 }
458
459                 static object EndRequestEvent = new object ();
460                 public event EventHandler EndRequest
461                 {
462                         add {
463                                 // See https://bugzilla.novell.com/show_bug.cgi?id=381971
464                                 if (InApplicationStart)
465                                         return;
466                                 AddEventHandler (EndRequestEvent, value);
467                         }
468                         remove {
469                                 if (InApplicationStart)
470                                         return;
471                                 RemoveEventHandler (EndRequestEvent, value);
472                         }
473                 }
474                 
475                 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh)
476                 {
477                         AsyncInvoker invoker = new AsyncInvoker (bh, eh);
478                         EndRequest += new EventHandler (invoker.Invoke);
479                 }
480
481                 static object PostRequestHandlerExecuteEvent = new object ();
482                 public event EventHandler PostRequestHandlerExecute
483                 {
484                         add { AddEventHandler (PostRequestHandlerExecuteEvent, value); }
485                         remove { RemoveEventHandler (PostRequestHandlerExecuteEvent, value); }
486                 }
487                 
488                 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
489                 {
490                         AsyncInvoker invoker = new AsyncInvoker (bh, eh);
491                         PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
492                 }
493
494                 static object PreRequestHandlerExecuteEvent = new object ();
495                 public event EventHandler PreRequestHandlerExecute
496                 {
497                         add { AddEventHandler (PreRequestHandlerExecuteEvent, value); }
498                         remove { RemoveEventHandler (PreRequestHandlerExecuteEvent, value); }
499                 }
500                 
501                 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
502                 {
503                         AsyncInvoker invoker = new AsyncInvoker (bh, eh);
504                         PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
505                 }
506
507                 static object ReleaseRequestStateEvent = new object ();
508                 public event EventHandler ReleaseRequestState
509                 {
510                         add { AddEventHandler (ReleaseRequestStateEvent, value); }
511                         remove { RemoveEventHandler (ReleaseRequestStateEvent, value); }
512                 }
513                 
514                 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
515                 {
516                         AsyncInvoker invoker = new AsyncInvoker (bh, eh);
517                         ReleaseRequestState += new EventHandler (invoker.Invoke);
518                 }
519
520                 static object ResolveRequestCacheEvent = new object ();
521                 public event EventHandler ResolveRequestCache
522                 {
523                         add { AddEventHandler (ResolveRequestCacheEvent, value); }
524                         remove { RemoveEventHandler (ResolveRequestCacheEvent, value); }
525                 }
526                 
527                 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
528                 {
529                         AsyncInvoker invoker = new AsyncInvoker (bh, eh);
530                         ResolveRequestCache += new EventHandler (invoker.Invoke);
531                 }
532
533                 static object UpdateRequestCacheEvent = new object ();
534                 public event EventHandler UpdateRequestCache
535                 {
536                         add { AddEventHandler (UpdateRequestCacheEvent, value); }
537                         remove { RemoveEventHandler (UpdateRequestCacheEvent, value); }
538                 }
539                 
540                 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
541                 {
542                         AsyncInvoker invoker = new AsyncInvoker (bh, eh);
543                         UpdateRequestCache += new EventHandler (invoker.Invoke);
544                 }
545
546                 static object PostAuthenticateRequestEvent = new object ();
547                 public event EventHandler PostAuthenticateRequest
548                 {
549                         add { AddEventHandler (PostAuthenticateRequestEvent, value); }
550                         remove { RemoveEventHandler (PostAuthenticateRequestEvent, value); }
551                 }
552                 
553                 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
554                 {
555                         AddOnPostAuthenticateRequestAsync (bh, eh, null);
556                 }
557                         
558                 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
559                 {
560                         AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
561                         PostAuthenticateRequest += new EventHandler (invoker.Invoke);
562                 }
563
564                 static object PostAuthorizeRequestEvent = new object ();
565                 public event EventHandler PostAuthorizeRequest
566                 {
567                         add { AddEventHandler (PostAuthorizeRequestEvent, value); }
568                         remove { RemoveEventHandler (PostAuthorizeRequestEvent, value); }
569                 }
570                 
571                 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
572                 {
573                         AddOnPostAuthorizeRequestAsync (bh, eh, null);
574                 }
575                 
576                 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
577                 {
578                         AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
579                         PostAuthorizeRequest += new EventHandler (invoker.Invoke);
580                 }
581                 
582                 static object PostResolveRequestCacheEvent = new object ();
583                 public event EventHandler PostResolveRequestCache
584                 {
585                         add { AddEventHandler (PostResolveRequestCacheEvent, value); }
586                         remove { RemoveEventHandler (PostResolveRequestCacheEvent, value); }
587                 }
588                 
589                 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
590                 {
591                         AddOnPostResolveRequestCacheAsync (bh, eh, null);
592                 }
593                 
594                 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
595                 {
596                         AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
597                         PostResolveRequestCache += new EventHandler (invoker.Invoke);
598                 }
599
600                 static object PostMapRequestHandlerEvent = new object ();
601                 public event EventHandler PostMapRequestHandler
602                 {
603                         add { AddEventHandler (PostMapRequestHandlerEvent, value); }
604                         remove { RemoveEventHandler (PostMapRequestHandlerEvent, value); }
605                 }
606                 
607                 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
608                 {
609                         AddOnPostMapRequestHandlerAsync (bh, eh, null);
610                 }
611                 
612                 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh, object data)
613                 {
614                         AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
615                         PostMapRequestHandler += new EventHandler (invoker.Invoke);
616                 }
617
618                 static object PostAcquireRequestStateEvent = new object ();
619                 public event EventHandler PostAcquireRequestState
620                 {
621                         add { AddEventHandler (PostAcquireRequestStateEvent, value); }
622                         remove { RemoveEventHandler (PostAcquireRequestStateEvent, value); }
623                 }
624                 
625                 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
626                 {
627                         AddOnPostAcquireRequestStateAsync (bh, eh, null);
628                 }
629                 
630                 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
631                 {
632                         AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
633                         PostAcquireRequestState += new EventHandler (invoker.Invoke);
634                 }
635
636                 static object PostReleaseRequestStateEvent = new object ();
637                 public event EventHandler PostReleaseRequestState
638                 {
639                         add { AddEventHandler (PostReleaseRequestStateEvent, value); }
640                         remove { RemoveEventHandler (PostReleaseRequestStateEvent, value); }
641                 }
642                 
643                 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
644                 {
645                         AddOnPostReleaseRequestStateAsync (bh, eh, null);
646                 }
647                 
648                 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
649                 {
650                         AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
651                         PostReleaseRequestState += new EventHandler (invoker.Invoke);
652                 }
653
654                 static object PostUpdateRequestCacheEvent = new object ();
655                 public event EventHandler PostUpdateRequestCache
656                 {
657                         add { AddEventHandler (PostUpdateRequestCacheEvent, value); }
658                         remove { RemoveEventHandler (PostUpdateRequestCacheEvent, value); }
659                 }
660                 
661                 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
662                 {
663                         AddOnPostUpdateRequestCacheAsync (bh, eh, null);
664                 }
665                 
666                 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
667                 {
668                         AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
669                         PostUpdateRequestCache += new EventHandler (invoker.Invoke);
670                 }
671
672                 //
673                 // The new overloads that take a data parameter
674                 //
675                 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
676                 {
677                         AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
678                         AcquireRequestState += new EventHandler (invoker.Invoke);
679                 }
680
681                 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
682                 {
683                         AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
684                         AuthenticateRequest += new EventHandler (invoker.Invoke);
685                 }
686
687                 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
688                 {
689                         AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
690                         AuthorizeRequest += new EventHandler (invoker.Invoke);
691                 }
692
693                 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
694                 {
695                         AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
696                         BeginRequest += new EventHandler (invoker.Invoke);
697                 }
698
699                 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
700                 {
701                         AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
702                         EndRequest += new EventHandler (invoker.Invoke);
703                 }
704                 
705                 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
706                 {
707                         AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
708                         PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
709                 }
710
711                 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
712                 {
713                         AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
714                         PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
715                 }
716
717                 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
718                 {
719                         AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
720                         ReleaseRequestState += new EventHandler (invoker.Invoke);
721                 }
722
723                 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
724                 {
725                         AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
726                         ResolveRequestCache += new EventHandler (invoker.Invoke);
727                 }
728
729                 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
730                 {
731                         AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
732                         UpdateRequestCache += new EventHandler (invoker.Invoke);
733                 }
734
735                 // Added in 2.0 SP1
736                 // They are for use with the IIS7 integrated mode, but have been added for
737                 // compatibility
738                 static object LogRequestEvent = new object ();
739                 public event EventHandler LogRequest
740                 {
741                         add { AddEventHandler (LogRequestEvent, value); }
742                         remove { RemoveEventHandler (LogRequestEvent, value); }
743                 }
744                 
745                 public void AddOnLogRequestAsync (BeginEventHandler bh, EndEventHandler eh)
746                 {
747                         AddOnLogRequestAsync (bh, eh, null);
748                 }
749                 
750                 public void AddOnLogRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state)
751                 {
752                         AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state);
753                         LogRequest += new EventHandler (invoker.Invoke);
754                 }
755
756                 static object MapRequestHandlerEvent = new object ();
757                 public event EventHandler MapRequestHandler
758                 {
759                         add { AddEventHandler (MapRequestHandlerEvent, value); }
760                         remove { RemoveEventHandler (MapRequestHandlerEvent, value); }
761                 }
762                 
763                 public void AddOnMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
764                 {
765                         AddOnMapRequestHandlerAsync (bh, eh, null);
766                 }
767
768                 public void AddOnMapRequestHandlerAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state)
769                 {
770                         AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state);
771                         MapRequestHandler += new EventHandler (invoker.Invoke);
772                 }
773
774                 static object PostLogRequestEvent = new object ();
775                 public event EventHandler PostLogRequest
776                 {
777                         add { AddEventHandler (PostLogRequestEvent, value); }
778                         remove { RemoveEventHandler (PostLogRequestEvent, value); }
779                 }
780                 
781                 public void AddOnPostLogRequestAsync (BeginEventHandler bh, EndEventHandler eh)
782                 {
783                         AddOnPostLogRequestAsync (bh, eh, null);
784                 }
785
786                 public void AddOnPostLogRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state)
787                 {
788                         AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state);
789                         PostLogRequest += new EventHandler (invoker.Invoke);
790                 }
791                 
792                 internal event EventHandler DefaultAuthentication;
793
794                 void AddEventHandler (object key, EventHandler handler)
795                 {
796                         if (fullInitComplete)
797                                 return;
798
799                         Events.AddHandler (key, handler);
800                 }
801
802                 void RemoveEventHandler (object key, EventHandler handler)
803                 {
804                         if (fullInitComplete)
805                                 return;
806
807                         Events.RemoveHandler (key, handler);
808                 }
809                 
810                 //
811                 // Bypass all the event on the Http pipeline and go directly to EndRequest
812                 //
813                 public void CompleteRequest ()
814                 {
815                         stop_processing = true;
816                 }
817
818                 internal bool RequestCompleted {
819                         set { stop_processing = value; }
820                 }
821
822                 internal void DisposeInternal ()
823                 {
824                         Dispose ();
825                         HttpModuleCollection coll = new HttpModuleCollection ();
826                         Interlocked.Exchange (ref modcoll, coll);
827                         if (coll != null) {
828                                 for (int i = coll.Count - 1; i >= 0; i--) {
829                                         coll.Get (i).Dispose ();
830                                 }
831                                 coll = null;
832                         }
833
834                         EventHandler eh = nonApplicationEvents [disposedEvent] as EventHandler;
835                         if (eh != null)
836                                 eh (this, EventArgs.Empty);
837                         
838                         done.Close ();
839                         done = null;
840                 }
841                 
842                 public virtual void Dispose ()
843                 {
844                 }
845
846 #if NET_4_0
847                 public virtual string GetOutputCacheProviderName (HttpContext context)
848                 {
849                         // LAMESPEC: doesn't throw ProviderException if context is null
850                         return OutputCache.DefaultProviderName;
851                 }
852 #endif
853                 
854                 public virtual string GetVaryByCustomString (HttpContext context, string custom)
855                 {
856                         if (custom == null) // Sigh
857                                 throw new NullReferenceException ();
858
859                         if (0 == String.Compare (custom, "browser", true, Helpers.InvariantCulture))
860                                 return context.Request.Browser.Type;
861
862                         return null;
863                 }
864
865                 bool ShouldHandleException (Exception e)
866                 {
867                         if (e is ParseException)
868                                 return false;
869
870                         return true;
871                 }
872                 
873                 //
874                 // If we catch an error, queue this error
875                 //
876                 void ProcessError (Exception e)
877                 {
878                         bool first = context.Error == null;
879                         context.AddError (e);
880                         if (first && ShouldHandleException (e)) {
881                                 EventHandler eh = nonApplicationEvents [errorEvent] as EventHandler;
882                                 if (eh != null){
883                                         try {
884                                                 eh (this, EventArgs.Empty);
885                                                 if (stop_processing)
886                                                         context.ClearError ();
887                                         } catch (ThreadAbortException taex){
888                                                 context.ClearError ();
889                                                 if (FlagEnd.Value == taex.ExceptionState || HttpRuntime.DomainUnloading)
890                                                         // This happens on Redirect(), End() and
891                                                         // when unloading the AppDomain
892                                                         Thread.ResetAbort ();
893                                                 else
894                                                         // This happens on Thread.Abort()
895                                                         context.AddError (taex);
896                                         } catch (Exception ee){
897                                                 context.AddError (ee);
898                                         }
899                                 }
900                         }
901                         stop_processing = true;
902
903                         // we want to remove configuration from the cache in case of 
904                         // invalid resource not exists to prevent DOS attack.
905                         HttpException httpEx = e as HttpException;
906                         if (httpEx != null && httpEx.GetHttpCode () == 404) {
907                                 removeConfigurationFromCache = true;
908                         }
909                 }
910                 
911                 //
912                 // Ticks the clock: next step on the pipeline.
913                 //
914                 internal void Tick ()
915                 {
916                         try {
917                                 if (pipeline.MoveNext ()){
918                                         if ((bool)pipeline.Current)
919                                                 PipelineDone ();
920                                 }
921                         } catch (ThreadAbortException taex) {
922                                 object obj = taex.ExceptionState;
923                                 Thread.ResetAbort ();
924                                 if (obj is StepTimeout)
925                                         ProcessError (HttpException.NewWithCode ("The request timed out.", WebEventCodes.RequestTransactionAbort));
926                                 else {
927                                         context.ClearError ();
928                                         if (FlagEnd.Value != obj && !HttpRuntime.DomainUnloading)
929                                                 context.AddError (taex);
930                                 }
931                                 
932                                 stop_processing = true;
933                                 PipelineDone ();
934                         } catch (Exception e) {
935                                 ThreadAbortException inner = e.InnerException as ThreadAbortException;
936                                 if (inner != null && FlagEnd.Value == inner.ExceptionState && !HttpRuntime.DomainUnloading) {
937                                         context.ClearError ();
938                                         Thread.ResetAbort ();
939                                 } else {
940                                         ProcessError (e);
941                                 }
942                                 stop_processing = true;
943                                 PipelineDone ();
944                         }
945                 }
946
947                 void Resume ()
948                 {
949                         if (in_begin)
950                                 must_yield = false;
951                         else
952                                 Tick ();
953                 }
954                 
955                 //
956                 // Invoked when our async callback called from RunHooks completes,
957                 // we restart the pipeline here.
958                 //
959                 void async_callback_completed_cb (IAsyncResult ar)
960                 {
961                         if (current_ai.end != null){
962                                 try {
963                                         current_ai.end (ar);
964                                 } catch (Exception e) {
965                                         ProcessError (e);
966                                 }
967                         }
968
969                         Resume ();
970                 }
971
972                 void async_handler_complete_cb (IAsyncResult ar)
973                 {
974                         IHttpAsyncHandler async_handler = ar != null ? ar.AsyncState as IHttpAsyncHandler : null;
975
976                         try {
977                                 if (async_handler != null)
978                                         async_handler.EndProcessRequest (ar);
979                         } catch (Exception e){
980                                 ProcessError (e);
981                         }
982                         
983                         Resume ();
984                 }
985                 
986                 //
987                 // This enumerator yields whether processing must be stopped:
988                 //    true:  processing of the pipeline must be stopped
989                 //    false: processing of the pipeline must not be stopped
990                 //
991                 IEnumerable RunHooks (Delegate list)
992                 {
993                         Delegate [] delegates = list.GetInvocationList ();
994
995                         foreach (EventHandler d in delegates){
996                                 if (d.Target != null && (d.Target is AsyncInvoker)){
997                                         current_ai = (AsyncInvoker) d.Target;
998
999                                         try {
1000                                                 must_yield = true;
1001                                                 in_begin = true;
1002                                                 context.BeginTimeoutPossible ();
1003                                                 current_ai.begin (this, EventArgs.Empty, async_callback_completed_cb, current_ai.data);
1004                                         } finally {
1005                                                 in_begin = false;
1006                                                 context.EndTimeoutPossible ();
1007                                         }
1008
1009                                         //
1010                                         // If things are still moving forward, yield this
1011                                         // thread now
1012                                         //
1013                                         if (must_yield)
1014                                                 yield return stop_processing;
1015                                         else if (stop_processing)
1016                                                 yield return true;
1017                                 } else {
1018                                         try {
1019                                                 context.BeginTimeoutPossible ();
1020                                                 d (this, EventArgs.Empty);
1021                                         } finally {
1022                                                 context.EndTimeoutPossible ();
1023                                         }
1024                                         if (stop_processing)
1025                                                 yield return true;
1026                                 }
1027                         }
1028                 }
1029
1030                 static void FinalErrorWrite (HttpResponse response, string error)
1031                 {
1032                         try {
1033                                 response.Write (error);
1034                                 response.Flush (true);
1035                         } catch {
1036                                 response.Close ();
1037                         }
1038                 }
1039
1040                 void OutputPage ()
1041                 {
1042                         if (context.Error == null){
1043                                 try {
1044                                         context.Response.Flush (true);
1045                                 } catch (Exception e){
1046                                         context.AddError (e);
1047                                 }
1048                         }
1049
1050                         Exception error = context.Error;
1051                         if (error != null){
1052                                 HttpResponse response = context.Response;
1053
1054                                 if (!response.HeadersSent){
1055                                         response.ClearHeaders ();
1056                                         response.ClearContent ();
1057
1058                                         if (error is HttpException){
1059                                                 response.StatusCode = ((HttpException)error).GetHttpCode ();
1060                                         } else {
1061                                                 error = HttpException.NewWithCode (String.Empty, error, WebEventCodes.WebErrorOtherError);
1062                                                 response.StatusCode = 500;
1063                                         }
1064                                         HttpException httpEx = (HttpException) error;
1065                                         if (!RedirectCustomError (ref httpEx))
1066                                                 FinalErrorWrite (response, httpEx.GetHtmlErrorMessage ());
1067                                         else
1068                                                 response.Flush (true);
1069                                 } else {
1070                                         if (!(error is HttpException))
1071                                                 error = HttpException.NewWithCode (String.Empty, error, WebEventCodes.WebErrorOtherError);
1072                                         FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
1073                                 }
1074                         }
1075                         
1076                 }
1077                 
1078                 //
1079                 // Invoked at the end of the pipeline execution
1080                 //
1081                 void PipelineDone ()
1082                 {
1083                         try {
1084                                 EventHandler handler = Events [EndRequestEvent] as EventHandler;
1085                                 if (handler != null)
1086                                         handler (this, EventArgs.Empty);
1087                         } catch (Exception e){
1088                                 ProcessError (e);
1089                         }
1090
1091                         try {
1092                                 OutputPage ();
1093                         } catch (ThreadAbortException taex) {
1094                                 ProcessError (taex);
1095                                 Thread.ResetAbort ();
1096                         } catch (Exception e) {
1097                                 Console.WriteLine ("Internal error: OutputPage threw an exception " + e);
1098                         } finally {
1099                                 context.WorkerRequest.EndOfRequest();
1100                                 if (factory != null && context.Handler != null){
1101                                         factory.ReleaseHandler (context.Handler);
1102                                         context.Handler = null;
1103                                         factory = null;
1104                                 }
1105                                 context.PopHandler ();
1106
1107                                 // context = null; -> moved to PostDone
1108                                 pipeline = null;
1109                                 current_ai = null;
1110                         }
1111                         PostDone ();
1112
1113                         if (begin_iar != null)
1114                                 begin_iar.Complete ();
1115                         else
1116                                 done.Set ();
1117
1118                         requests_total_counter.Increment ();
1119                 }
1120
1121                 class Tim {
1122                         string name;
1123                         DateTime start;
1124
1125                         public Tim () {
1126                         }
1127
1128                         public Tim (string name) {
1129                                 this.name = name;
1130                         }
1131
1132                         public string Name {
1133                                 get { return name; }
1134                                 set { name = value; }
1135                         }
1136
1137                         public void Start () {
1138                                 start = DateTime.UtcNow;
1139                         }
1140
1141                         public void Stop () {
1142                                 Console.WriteLine ("{0}: {1}ms", name, (DateTime.UtcNow - start).TotalMilliseconds);
1143                         }
1144                 }
1145
1146                 Tim tim;
1147                 [Conditional ("PIPELINE_TIMER")]
1148                 void StartTimer (string name)
1149                 {
1150                         if (tim == null)
1151                                 tim = new Tim ();
1152                         tim.Name = name;
1153                         tim.Start ();
1154                 }
1155
1156                 [Conditional ("PIPELINE_TIMER")]
1157                 void StopTimer ()
1158                 {
1159                         tim.Stop ();
1160                 }
1161
1162                 //
1163                 // Events fired as described in `Http Runtime Support, HttpModules,
1164                 // Handling Public Events'
1165                 //
1166                 IEnumerator Pipeline ()
1167                 {
1168                         Delegate eventHandler;
1169                         if (stop_processing)
1170                                 yield return true;
1171 #if NET_4_0
1172                         HttpRequest req = context.Request;
1173                         if (req != null)
1174                                 req.Validate ();
1175 #endif
1176                         context.MapRequestHandlerDone = false;
1177                         StartTimer ("BeginRequest");
1178                         eventHandler = Events [BeginRequestEvent];
1179                         if (eventHandler != null) {
1180                                 foreach (bool stop in RunHooks (eventHandler))
1181                                         yield return stop;
1182                         }
1183                         StopTimer ();
1184                         
1185                         StartTimer ("AuthenticateRequest");
1186                         eventHandler = Events [AuthenticateRequestEvent];
1187                         if (eventHandler != null)
1188                                 foreach (bool stop in RunHooks (eventHandler))
1189                                         yield return stop;
1190                         StopTimer ();
1191
1192                         StartTimer ("DefaultAuthentication");
1193                         if (DefaultAuthentication != null)
1194                                 foreach (bool stop in RunHooks (DefaultAuthentication))
1195                                         yield return stop;
1196                         StopTimer ();
1197
1198                         StartTimer ("PostAuthenticateRequest");
1199                         eventHandler = Events [PostAuthenticateRequestEvent];
1200                         if (eventHandler != null)
1201                                 foreach (bool stop in RunHooks (eventHandler))
1202                                         yield return stop;
1203                         StopTimer ();
1204
1205                         StartTimer ("AuthorizeRequest");
1206                         eventHandler = Events [AuthorizeRequestEvent];
1207                         if (eventHandler != null)
1208                                 foreach (bool stop in RunHooks (eventHandler))
1209                                         yield return stop;
1210                         StopTimer ();
1211
1212                         StartTimer ("PostAuthorizeRequest");
1213                         eventHandler = Events [PostAuthorizeRequestEvent];
1214                         if (eventHandler != null)
1215                                 foreach (bool stop in RunHooks (eventHandler))
1216                                         yield return stop;
1217                         StopTimer ();
1218
1219                         StartTimer ("ResolveRequestCache");
1220                         eventHandler = Events [ResolveRequestCacheEvent];
1221                         if (eventHandler != null)
1222                                 foreach (bool stop in RunHooks (eventHandler))
1223                                         yield return stop;
1224                         StopTimer ();
1225
1226                         StartTimer ("PostResolveRequestCache");
1227                         eventHandler = Events [PostResolveRequestCacheEvent];
1228                         if (eventHandler != null)
1229                                 foreach (bool stop in RunHooks (eventHandler))
1230                                         yield return stop;
1231                         StopTimer ();
1232
1233                         StartTimer ("MapRequestHandler");
1234                         // As per http://msdn2.microsoft.com/en-us/library/bb470252(VS.90).aspx
1235                         eventHandler = Events [MapRequestHandlerEvent];
1236                         if (eventHandler != null)
1237                                 foreach (bool stop in RunHooks (eventHandler))
1238                                         yield return stop;
1239                         StopTimer ();
1240                         context.MapRequestHandlerDone = true;
1241                         
1242                         StartTimer ("GetHandler");
1243                         // Obtain the handler for the request.
1244                         IHttpHandler handler = null;
1245                         try {
1246                                 handler = GetHandler (context, context.Request.CurrentExecutionFilePath);
1247                                 context.Handler = handler;
1248                                 context.PushHandler (handler);
1249                         } catch (FileNotFoundException fnf){
1250                                 if (context.Request.IsLocal)
1251                                         ProcessError (HttpException.NewWithCode (404,
1252                                                                                  String.Format ("File not found {0}", fnf.FileName),
1253                                                                                  fnf,
1254                                                                                  context.Request.FilePath,
1255                                                                                  WebEventCodes.RuntimeErrorRequestAbort));
1256                                 else
1257                                         ProcessError (HttpException.NewWithCode (404,
1258                                                                                  "File not found: " + Path.GetFileName (fnf.FileName),
1259                                                                                  context.Request.FilePath,
1260                                                                                  WebEventCodes.RuntimeErrorRequestAbort));
1261                         } catch (DirectoryNotFoundException dnf){
1262                                 if (!context.Request.IsLocal)
1263                                         dnf = null; // Do not "leak" real path information
1264                                 ProcessError (HttpException.NewWithCode (404, "Directory not found", dnf, WebEventCodes.RuntimeErrorRequestAbort));
1265                         } catch (Exception e) {
1266                                 ProcessError (e);
1267                         }
1268
1269                         StopTimer ();
1270                         if (stop_processing)
1271                                 yield return true;
1272
1273                         StartTimer ("PostMapRequestHandler");
1274                         eventHandler = Events [PostMapRequestHandlerEvent];
1275                         if (eventHandler != null)
1276                                 foreach (bool stop in RunHooks (eventHandler))
1277                                         yield return stop;
1278                         StopTimer ();
1279
1280                         StartTimer ("AcquireRequestState");
1281                         eventHandler = Events [AcquireRequestStateEvent];
1282                         if (eventHandler != null){
1283                                 foreach (bool stop in RunHooks (eventHandler))
1284                                         yield return stop;
1285                         }
1286                         StopTimer ();
1287                         
1288                         StartTimer ("PostAcquireRequestState");
1289                         eventHandler = Events [PostAcquireRequestStateEvent];
1290                         if (eventHandler != null){
1291                                 foreach (bool stop in RunHooks (eventHandler))
1292                                         yield return stop;
1293                         }
1294                         StopTimer ();
1295                         
1296                         //
1297                         // From this point on, we need to ensure that we call
1298                         // ReleaseRequestState, so the code below jumps to
1299                         // `release:' to guarantee it rather than yielding.
1300                         //
1301                         StartTimer ("PreRequestHandlerExecute");
1302                         eventHandler = Events [PreRequestHandlerExecuteEvent];
1303                         if (eventHandler != null)
1304                                 foreach (bool stop in RunHooks (eventHandler))
1305                                         if (stop)
1306                                                 goto release;
1307                         StopTimer ();
1308                         
1309                                 
1310                         
1311                         IHttpHandler ctxHandler = context.Handler;
1312                         if (ctxHandler != null && handler != ctxHandler) {
1313                                 context.PopHandler ();
1314                                 handler = ctxHandler;
1315                                 context.PushHandler (handler);
1316                         }
1317
1318                         StartTimer ("ProcessRequest");
1319                         try {
1320                                 context.BeginTimeoutPossible ();
1321                                 if (handler != null){
1322                                         IHttpAsyncHandler async_handler = handler as IHttpAsyncHandler;
1323                                         
1324                                         if (async_handler != null){
1325                                                 must_yield = true;
1326                                                 in_begin = true;
1327                                                 async_handler.BeginProcessRequest (context, async_handler_complete_cb, handler);
1328                                         } else {
1329                                                 must_yield = false;
1330                                                 handler.ProcessRequest (context);
1331                                         }
1332                                 } else
1333                                         throw new InvalidOperationException ("No handler for the current request.");
1334                                 if (context.Error != null)
1335                                         throw new TargetInvocationException(context.Error);
1336                         } finally {
1337                                 in_begin = false;
1338                                 context.EndTimeoutPossible ();
1339                         }
1340                         StopTimer ();
1341                         if (must_yield)
1342                                 yield return stop_processing;
1343                         else if (stop_processing)
1344                                 goto release;
1345                         
1346                         // These are executed after the application has returned
1347                         
1348                         StartTimer ("PostRequestHandlerExecute");
1349                         eventHandler = Events [PostRequestHandlerExecuteEvent];
1350                         if (eventHandler != null)
1351                                 foreach (bool stop in RunHooks (eventHandler))
1352                                         if (stop)
1353                                                 goto release;
1354                         StopTimer ();
1355                         
1356                 release:
1357                         StartTimer ("ReleaseRequestState");
1358                         eventHandler = Events [ReleaseRequestStateEvent];
1359                         if (eventHandler != null){
1360 #pragma warning disable 219
1361                                 foreach (bool stop in RunHooks (eventHandler)) {
1362                                         //
1363                                         // Ignore the stop signal while release the state
1364                                         //
1365                                         
1366                                 }
1367 #pragma warning restore 219
1368                         }
1369                         StopTimer ();
1370                         
1371                         if (stop_processing)
1372                                 yield return true;
1373
1374                         StartTimer ("PostReleaseRequestState");
1375                         eventHandler = Events [PostReleaseRequestStateEvent];
1376                         if (eventHandler != null)
1377                                 foreach (bool stop in RunHooks (eventHandler))
1378                                         yield return stop;
1379                         StopTimer ();
1380
1381                         StartTimer ("Filter");
1382                         if (context.Error == null)
1383                                 context.Response.DoFilter (true);
1384                         StopTimer ();
1385
1386                         StartTimer ("UpdateRequestCache");
1387                         eventHandler = Events [UpdateRequestCacheEvent];
1388                         if (eventHandler != null)
1389                                 foreach (bool stop in RunHooks (eventHandler))
1390                                         yield return stop;
1391                         StopTimer ();
1392
1393                         StartTimer ("PostUpdateRequestCache");
1394                         eventHandler = Events [PostUpdateRequestCacheEvent];
1395                         if (eventHandler != null)
1396                                 foreach (bool stop in RunHooks (eventHandler))
1397                                         yield return stop;
1398                         StopTimer ();
1399
1400                         StartTimer ("LogRequest");
1401                         eventHandler = Events [LogRequestEvent];
1402                         if (eventHandler != null)
1403                                 foreach (bool stop in RunHooks (eventHandler))
1404                                         yield return stop;
1405                         StopTimer ();
1406
1407                         StartTimer ("PostLogRequest");
1408                         eventHandler = Events [PostLogRequestEvent];
1409                         if (eventHandler != null)
1410                                 foreach (bool stop in RunHooks (eventHandler))
1411                                         yield return stop;
1412                         StopTimer ();
1413
1414                         StartTimer ("PipelineDone");
1415                         PipelineDone ();
1416                         StopTimer ();
1417                 }
1418
1419
1420                 internal CultureInfo GetThreadCulture (HttpRequest request, CultureInfo culture, bool isAuto)
1421                 {
1422                         if (!isAuto)
1423                                 return culture;
1424                         CultureInfo ret = null;
1425                         string[] languages = request.UserLanguages;
1426                         try {
1427                                 if (languages != null && languages.Length > 0)
1428                                         ret = CultureInfo.CreateSpecificCulture (languages[0]);
1429                         } catch {
1430                         }
1431                         
1432                         if (ret == null)
1433                                 ret = culture;
1434                         
1435                         return ret;
1436                 }
1437
1438
1439                 void PreStart ()
1440                 {
1441                         GlobalizationSection cfg;
1442                         cfg = (GlobalizationSection) WebConfigurationManager.GetSection ("system.web/globalization");
1443                         app_culture = cfg.GetCulture ();
1444                         autoCulture = cfg.IsAutoCulture;
1445                         appui_culture = cfg.GetUICulture ();
1446                         autoUICulture = cfg.IsAutoUICulture;
1447                         context.StartTimeoutTimer ();
1448                         Thread th = Thread.CurrentThread;
1449                         if (app_culture != null) {
1450                                 prev_app_culture = th.CurrentCulture;
1451                                 CultureInfo new_app_culture = GetThreadCulture (Request, app_culture, autoCulture);
1452                                 if (!new_app_culture.Equals (Helpers.InvariantCulture))
1453                                         th.CurrentCulture = new_app_culture;
1454                         }
1455
1456                         if (appui_culture != null) {
1457                                 prev_appui_culture = th.CurrentUICulture;
1458                                 CultureInfo new_app_culture = GetThreadCulture (Request, appui_culture, autoUICulture);
1459                                 if (!new_app_culture.Equals (Helpers.InvariantCulture))
1460                                         th.CurrentUICulture = new_app_culture;
1461                         }
1462
1463                         prev_user = Thread.CurrentPrincipal;
1464                 }
1465
1466                 void PostDone ()
1467                 {
1468                         if (removeConfigurationFromCache) {
1469                                 WebConfigurationManager.RemoveConfigurationFromCache (context);
1470                                 removeConfigurationFromCache = false;
1471                         }
1472
1473                         Thread th = Thread.CurrentThread;
1474                         if (Thread.CurrentPrincipal != prev_user)
1475                                 Thread.CurrentPrincipal = prev_user;
1476                         if (prev_appui_culture != null && prev_appui_culture != th.CurrentUICulture)
1477                                 th.CurrentUICulture = prev_appui_culture;
1478                         if (prev_app_culture != null && prev_app_culture != th.CurrentCulture)
1479                                 th.CurrentCulture = prev_app_culture;
1480
1481                         if (context == null)
1482                                 context = HttpContext.Current;
1483                         context.StopTimeoutTimer ();
1484                         context.Request.ReleaseResources ();
1485                         context.Response.ReleaseResources ();
1486                         context = null;
1487                         session = null;
1488                         HttpContext.Current = null;
1489                 }
1490
1491                 void Start (object x)
1492                 {
1493                         var cultures = x as CultureInfo [];
1494                         if (cultures != null && cultures.Length == 2) {
1495                                 Thread ct = Thread.CurrentThread;
1496                                 ct.CurrentCulture = cultures [0];
1497                                 ct.CurrentUICulture = cultures [1];
1498                         }
1499
1500                         InitOnce (true);
1501                         if (initialization_exception != null) {
1502                                 Exception e = initialization_exception;
1503                                 HttpException exc = HttpException.NewWithCode (String.Empty, e, WebEventCodes.RuntimeErrorRequestAbort);
1504                                 context.Response.StatusCode = 500;
1505                                 FinalErrorWrite (context.Response, exc.GetHtmlErrorMessage ());
1506                                 PipelineDone ();
1507                                 return;
1508                         }
1509
1510                         HttpContext.Current = Context;
1511                         PreStart ();
1512                         pipeline = Pipeline ();
1513                         Tick ();
1514                 }
1515
1516                 const string HANDLER_CACHE = "@@HttpHandlerCache@@";
1517
1518                 internal static Hashtable GetHandlerCache ()
1519                 {
1520                         Cache cache = HttpRuntime.InternalCache;
1521                         Hashtable ret = cache [HANDLER_CACHE] as Hashtable;
1522
1523                         if (ret == null) {
1524                                 ret = new Hashtable ();
1525                                 cache.Insert (HANDLER_CACHE, ret);
1526                         }
1527
1528                         return ret;
1529                 }
1530                 
1531                 internal static void ClearHandlerCache ()
1532                 {
1533                         Hashtable cache = GetHandlerCache ();
1534                         cache.Clear ();
1535                 }
1536                 
1537                 object LocateHandler (HttpRequest req, string verb, string url)
1538                 {
1539                         Hashtable cache = GetHandlerCache ();
1540                         string id = String.Concat (verb, url);
1541                         object ret = cache [id];
1542
1543                         if (ret != null)
1544                                 return ret;
1545
1546                         bool allowCache;
1547                         HttpHandlersSection httpHandlersSection = WebConfigurationManager.GetSection ("system.web/httpHandlers", req.Path, req.Context) as HttpHandlersSection;
1548                         ret = httpHandlersSection.LocateHandler (verb, url, out allowCache);
1549
1550                         IHttpHandler handler = ret as IHttpHandler;
1551                         if (allowCache && handler != null && handler.IsReusable)
1552                                 cache [id] = ret;
1553                         
1554                         return ret;
1555                 }
1556
1557                 internal IHttpHandler GetHandler (HttpContext context, string url)
1558                 {
1559                         return GetHandler (context, url, false);
1560                 }
1561                 
1562                 // Used by HttpServerUtility.Execute
1563                 internal IHttpHandler GetHandler (HttpContext context, string url, bool ignoreContextHandler)
1564                 {
1565                         if (!ignoreContextHandler && context.Handler != null)
1566                                 return context.Handler;
1567                         
1568                         HttpRequest request = context.Request;
1569                         string verb = request.RequestType;
1570                         
1571                         IHttpHandler handler = null;
1572                         object o = LocateHandler (request, verb, url);
1573                         
1574                         factory = o as IHttpHandlerFactory;
1575                         if (factory == null) {
1576                                 handler = (IHttpHandler) o;
1577                         } else {
1578                                 handler = factory.GetHandler (context, verb, url, request.MapPath (url));
1579                         }
1580
1581                         return handler;
1582                 }
1583                 
1584                 void IHttpHandler.ProcessRequest (HttpContext context)
1585                 {
1586                         begin_iar = null;
1587                         this.context = context;
1588                         done.Reset ();
1589
1590                         Start (null);
1591                         done.WaitOne ();
1592                 }
1593
1594                 //
1595                 // This is used by FireOnAppStart, when we init the application
1596                 // as the context is required to be set at that point (the user
1597                 // might call methods that require it on that hook).
1598                 //
1599                 internal void SetContext (HttpContext context)
1600                 {
1601                         this.context = context;
1602                 }
1603
1604                 internal void SetSession (HttpSessionState session)
1605                 {
1606                         this.session = session;
1607                 }
1608
1609                 IAsyncResult IHttpAsyncHandler.BeginProcessRequest (HttpContext context, AsyncCallback cb, object extraData)
1610                 {
1611                         this.context = context;
1612                         done.Reset ();
1613                         
1614                         begin_iar = new AsyncRequestState (done, cb, extraData);
1615
1616                         CultureInfo[] cultures = new CultureInfo [2];
1617                         cultures [0] = Thread.CurrentThread.CurrentCulture;
1618                         cultures [1] = Thread.CurrentThread.CurrentUICulture;
1619                         
1620                         if (Thread.CurrentThread.IsThreadPoolThread)
1621                                 Start (null);
1622                         else
1623                                 ThreadPool.QueueUserWorkItem (x => {
1624                                         try {
1625                                                 Start (x);
1626                                         } catch (Exception e) {
1627                                                 Console.Error.WriteLine (e);
1628                                         }
1629                                 });
1630                         
1631                         return begin_iar;
1632                 }
1633
1634                 void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result)
1635                 {
1636                         if (!result.IsCompleted)
1637                                 result.AsyncWaitHandle.WaitOne ();
1638                         begin_iar = null;
1639                 }
1640
1641                 public virtual void Init ()
1642                 {
1643                 }
1644
1645                 bool IHttpHandler.IsReusable {
1646                         get {
1647                                 return true;
1648                         }
1649                 }
1650                 
1651 #region internals
1652                 internal void ClearError ()
1653                 {
1654                         context.ClearError ();
1655                 }
1656
1657                 bool RedirectErrorPage (string error_page)
1658                 {
1659                         if (context.Request.QueryString ["aspxerrorpath"] != null)
1660                                 return false;
1661
1662                         Response.Redirect (error_page + "?aspxerrorpath=" + Request.Path, false);
1663                         return true;
1664                 }
1665                                                         
1666                 bool RedirectCustomError (ref HttpException httpEx)
1667                 {
1668                         try {
1669                                 if (!context.IsCustomErrorEnabledUnsafe)
1670                                         return false;
1671                         
1672                                 CustomErrorsSection config = (CustomErrorsSection)WebConfigurationManager.GetSection ("system.web/customErrors");                       
1673                                 if (config == null) {
1674                                         if (context.ErrorPage != null)
1675                                                 return RedirectErrorPage (context.ErrorPage);
1676                                 
1677                                         return false;
1678                                 }
1679                         
1680                                 CustomError err = config.Errors [context.Response.StatusCode.ToString()];
1681                                 string redirect = err == null ? null : err.Redirect;
1682                                 if (redirect == null) {
1683                                         redirect = context.ErrorPage;
1684                                         if (redirect == null)
1685                                                 redirect = config.DefaultRedirect;
1686                                 }
1687                         
1688                                 if (redirect == null)
1689                                         return false;
1690
1691                                 if (config.RedirectMode == CustomErrorsRedirectMode.ResponseRewrite) {
1692                                         context.Server.Execute (redirect);
1693                                         return true;
1694                                 }
1695                                 
1696                                 return RedirectErrorPage (redirect);
1697                         }
1698                         catch (Exception ex) {
1699                                 httpEx = HttpException.NewWithCode (500, String.Empty, ex, WebEventCodes.WebErrorOtherError);
1700                                 return false;
1701                         }
1702                 }
1703 #endregion              
1704                 internal static string BinDirectory
1705                 {
1706                         get {
1707                                 if (binDirectory == null) {
1708                                         AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
1709                                         string baseDir = setup.ApplicationBase;
1710                                         string bindir;
1711                                         
1712                                         foreach (string dir in BinDirs) {
1713                                                 bindir = Path.Combine (baseDir, dir);
1714                                                 if (!Directory.Exists (bindir))
1715                                                         continue;
1716                                                 binDirectory = bindir;
1717                                                 break;
1718                                         }
1719                                 }
1720
1721                                 return binDirectory;
1722                         }
1723                 }
1724
1725                 internal static string[] BinDirectoryAssemblies
1726                 {
1727                         get {
1728                                 ArrayList binDlls = null;
1729                                 string[] dlls;
1730                                 
1731                                 string bindir = BinDirectory;
1732                                 if (bindir != null) {
1733                                         binDlls = new ArrayList ();
1734                                         dlls = Directory.GetFiles (bindir, "*.dll");
1735                                         binDlls.AddRange (dlls);
1736                                 }
1737
1738                                 if (binDlls == null)
1739                                         return new string[] {};
1740                                 
1741                                 return (string[]) binDlls.ToArray (typeof (string));
1742                         }
1743                 }
1744                                         
1745                 internal static Type LoadType (string typeName)
1746                 {
1747                         return LoadType (typeName, false);
1748                 }
1749                 
1750                 internal static Type LoadType (string typeName, bool throwOnMissing)
1751                 {
1752                         Type type = Type.GetType (typeName);
1753                         if (type != null)
1754                                 return type;
1755
1756                         Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
1757                         foreach (Assembly ass in assemblies) {
1758                                 type = ass.GetType (typeName, false);
1759                                 if (type != null)
1760                                         return type;
1761                         }
1762
1763                         IList tla = System.Web.Compilation.BuildManager.TopLevelAssemblies;
1764                         if (tla != null && tla.Count > 0) {
1765                                 foreach (Assembly asm in tla) {
1766                                         if (asm == null)
1767                                                 continue;
1768                                         type = asm.GetType (typeName, false);
1769                                         if (type != null)
1770                                                 return type;
1771                                 }
1772                         }
1773
1774                         Exception loadException = null;
1775                         try {
1776                                 type = null;
1777                                 type = LoadTypeFromBin (typeName);
1778                         } catch (Exception ex) {
1779                                 loadException = ex;
1780                         }
1781                         
1782                         if (type != null)
1783                                 return type;
1784                         if (throwOnMissing)
1785                                 throw new TypeLoadException (String.Format ("Type '{0}' cannot be found", typeName), loadException);
1786                         
1787                         return null;
1788                 }
1789
1790                 internal static Type LoadType <TBaseType> (string typeName, bool throwOnMissing)
1791                 {
1792                         Type ret = LoadType (typeName, throwOnMissing);
1793
1794                         if (typeof (TBaseType).IsAssignableFrom (ret))
1795                                 return ret;
1796
1797                         if (throwOnMissing)
1798                                 throw new TypeLoadException (String.Format ("Type '{0}' found but it doesn't derive from base type '{1}'.", typeName, typeof (TBaseType)));
1799
1800                         return null;
1801                 }
1802                 
1803                 internal static Type LoadTypeFromBin (string typeName)
1804                 {
1805                         Type type = null;
1806                         
1807                         foreach (string s in BinDirectoryAssemblies) {
1808                                 Assembly binA = null;
1809                                 
1810                                 try {
1811                                         binA = Assembly.LoadFrom (s);
1812                                 } catch (FileLoadException) {
1813                                         // ignore
1814                                         continue;
1815                                 } catch (BadImageFormatException) {
1816                                         // ignore
1817                                         continue;
1818                                 }
1819                                 
1820                                 type = binA.GetType (typeName, false);
1821                                 if (type == null)
1822                                         continue;
1823                                 
1824                                 return type;
1825                         }
1826
1827                         return null;
1828                 }
1829         }
1830
1831         //
1832         // Based on Fritz' Onion's AsyncRequestState class for asynchronous IHttpAsyncHandlers
1833         // 
1834         class AsyncRequestState : IAsyncResult {
1835                 AsyncCallback cb;
1836                 object cb_data;
1837                 bool completed;
1838                 ManualResetEvent complete_event = null;
1839                 
1840                 internal AsyncRequestState (ManualResetEvent complete_event, AsyncCallback cb, object cb_data)
1841                 {
1842                         this.cb = cb;
1843                         this.cb_data = cb_data;
1844                         this.complete_event = complete_event;
1845                 }
1846
1847                 internal void Complete ()
1848                 {
1849                         completed = true;
1850                         try {
1851                                 //
1852                                 // TODO: if this throws an error, we have no way of reporting it
1853                                 // Not really too bad, since the only failure might be
1854                                 // `HttpRuntime.request_processed'.   
1855                                 //
1856                                 if (cb != null)
1857                                         cb (this);
1858                         } catch {
1859                         }
1860                         
1861                         complete_event.Set ();
1862                 }
1863
1864                 public object AsyncState {
1865                         get {
1866                                 return cb_data;
1867                         }
1868                 }
1869
1870                 public bool CompletedSynchronously {
1871                         get {
1872                                 return false;
1873                         }
1874                 }
1875
1876                 public bool IsCompleted {
1877                         get {
1878                                 return completed;
1879                         }
1880                 }
1881
1882                 public WaitHandle AsyncWaitHandle {
1883                         get {
1884                                 return complete_event;
1885                         }
1886                 }
1887         }
1888
1889 #region Helper classes
1890         
1891         //
1892         // A wrapper to keep track of begin/end pairs
1893         //
1894         class AsyncInvoker {
1895                 public BeginEventHandler begin;
1896                 public EndEventHandler end;
1897                 public object data;
1898                 
1899                 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, object d)
1900                 {
1901                         begin = bh;
1902                         end = eh;
1903                         data = d;
1904                 }
1905
1906                 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh)
1907                 {
1908                         begin = bh;
1909                         end = eh;
1910                 }
1911                 
1912                 public void Invoke (object sender, EventArgs e)
1913                 {
1914                         throw new Exception ("This is just a dummy");
1915                 }
1916         }
1917 #endregion
1918 }