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