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