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