Normalize line endings.
[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                                 }
1351                                 if (context.Error != null)
1352                                         throw new TargetInvocationException(context.Error);
1353                         } finally {
1354                                 in_begin = false;
1355                                 context.EndTimeoutPossible ();
1356                         }
1357                         StopTimer ();
1358 #if TARGET_J2EE
1359                         if (doProcessHandler) {
1360                                 yield return false;
1361                                 goto processHandler;
1362                         }
1363 #endif
1364                         if (must_yield)
1365                                 yield return stop_processing;
1366                         else if (stop_processing)
1367                                 goto release;
1368                         
1369                         // These are executed after the application has returned
1370                         
1371                         StartTimer ("PostRequestHandlerExecute");
1372                         eventHandler = Events [PostRequestHandlerExecuteEvent];
1373                         if (eventHandler != null)
1374                                 foreach (bool stop in RunHooks (eventHandler))
1375                                         if (stop)
1376                                                 goto release;
1377                         StopTimer ();
1378                         
1379                 release:
1380                         StartTimer ("ReleaseRequestState");
1381                         eventHandler = Events [ReleaseRequestStateEvent];
1382                         if (eventHandler != null){
1383 #pragma warning disable 219
1384                                 foreach (bool stop in RunHooks (eventHandler)) {
1385                                         //
1386                                         // Ignore the stop signal while release the state
1387                                         //
1388                                         
1389                                 }
1390 #pragma warning restore 219
1391                         }
1392                         StopTimer ();
1393                         
1394                         if (stop_processing)
1395                                 yield return true;
1396
1397                         StartTimer ("PostReleaseRequestState");
1398                         eventHandler = Events [PostReleaseRequestStateEvent];
1399                         if (eventHandler != null)
1400                                 foreach (bool stop in RunHooks (eventHandler))
1401                                         yield return stop;
1402                         StopTimer ();
1403
1404                         StartTimer ("Filter");
1405                         if (context.Error == null)
1406                                 context.Response.DoFilter (true);
1407                         StopTimer ();
1408
1409                         StartTimer ("UpdateRequestCache");
1410                         eventHandler = Events [UpdateRequestCacheEvent];
1411                         if (eventHandler != null)
1412                                 foreach (bool stop in RunHooks (eventHandler))
1413                                         yield return stop;
1414                         StopTimer ();
1415
1416                         StartTimer ("PostUpdateRequestCache");
1417                         eventHandler = Events [PostUpdateRequestCacheEvent];
1418                         if (eventHandler != null)
1419                                 foreach (bool stop in RunHooks (eventHandler))
1420                                         yield return stop;
1421                         StopTimer ();
1422
1423                         StartTimer ("LogRequest");
1424                         eventHandler = Events [LogRequestEvent];
1425                         if (eventHandler != null)
1426                                 foreach (bool stop in RunHooks (eventHandler))
1427                                         yield return stop;
1428                         StopTimer ();
1429
1430                         StartTimer ("PostLogRequest");
1431                         eventHandler = Events [PostLogRequestEvent];
1432                         if (eventHandler != null)
1433                                 foreach (bool stop in RunHooks (eventHandler))
1434                                         yield return stop;
1435                         StopTimer ();
1436
1437                         StartTimer ("PipelineDone");
1438                         PipelineDone ();
1439                         StopTimer ();
1440                 }
1441
1442
1443                 internal CultureInfo GetThreadCulture (HttpRequest request, CultureInfo culture, bool isAuto)
1444                 {
1445                         if (!isAuto)
1446                                 return culture;
1447                         CultureInfo ret = null;
1448                         string[] languages = request.UserLanguages;
1449                         try {
1450                                 if (languages != null && languages.Length > 0)
1451                                         ret = CultureInfo.CreateSpecificCulture (languages[0]);
1452                         } catch {
1453                         }
1454                         
1455                         if (ret == null)
1456                                 ret = culture;
1457                         
1458                         return ret;
1459                 }
1460
1461
1462                 void PreStart ()
1463                 {
1464                         GlobalizationSection cfg;
1465                         cfg = (GlobalizationSection) WebConfigurationManager.GetSection ("system.web/globalization");
1466                         app_culture = cfg.GetCulture ();
1467                         autoCulture = cfg.IsAutoCulture;
1468                         appui_culture = cfg.GetUICulture ();
1469                         autoUICulture = cfg.IsAutoUICulture;
1470 #if !TARGET_J2EE
1471                         context.StartTimeoutTimer ();
1472 #endif
1473                         Thread th = Thread.CurrentThread;
1474                         if (app_culture != null) {
1475                                 prev_app_culture = th.CurrentCulture;
1476                                 CultureInfo new_app_culture = GetThreadCulture (Request, app_culture, autoCulture);
1477                                 if (!new_app_culture.Equals (Helpers.InvariantCulture))
1478                                         th.CurrentCulture = new_app_culture;
1479                         }
1480
1481                         if (appui_culture != null) {
1482                                 prev_appui_culture = th.CurrentUICulture;
1483                                 CultureInfo new_app_culture = GetThreadCulture (Request, appui_culture, autoUICulture);
1484                                 if (!new_app_culture.Equals (Helpers.InvariantCulture))
1485                                         th.CurrentUICulture = new_app_culture;
1486                         }
1487
1488 #if !TARGET_JVM
1489                         prev_user = Thread.CurrentPrincipal;
1490 #endif
1491                 }
1492
1493                 void PostDone ()
1494                 {
1495                         if (removeConfigurationFromCache) {
1496                                 WebConfigurationManager.RemoveConfigurationFromCache (context);
1497                                 removeConfigurationFromCache = false;
1498                         }
1499
1500                         Thread th = Thread.CurrentThread;
1501 #if !TARGET_JVM
1502                         if (Thread.CurrentPrincipal != prev_user)
1503                                 Thread.CurrentPrincipal = prev_user;
1504 #endif
1505                         if (prev_appui_culture != null && prev_appui_culture != th.CurrentUICulture)
1506                                 th.CurrentUICulture = prev_appui_culture;
1507                         if (prev_app_culture != null && prev_app_culture != th.CurrentCulture)
1508                                 th.CurrentCulture = prev_app_culture;
1509
1510 #if !TARGET_J2EE
1511                         if (context == null)
1512                                 context = HttpContext.Current;
1513                         context.StopTimeoutTimer ();
1514 #endif
1515                         context.Request.ReleaseResources ();
1516                         context.Response.ReleaseResources ();
1517                         context = null;
1518                         session = null;
1519                         HttpContext.Current = null;
1520                 }
1521
1522                 void Start (object x)
1523                 {
1524                         var cultures = x as CultureInfo [];
1525                         if (cultures != null && cultures.Length == 2) {
1526                                 Thread ct = Thread.CurrentThread;
1527                                 ct.CurrentCulture = cultures [0];
1528                                 ct.CurrentUICulture = cultures [1];
1529                         }
1530                         
1531                         try {
1532                                 InitOnce (true);
1533                         } catch (Exception e) {
1534                                 initialization_exception = e;
1535                                 FinalErrorWrite (context.Response, HttpException.NewWithCode (String.Empty, e, WebEventCodes.RuntimeErrorRequestAbort).GetHtmlErrorMessage ());
1536                                 PipelineDone ();
1537                                 return;
1538                         }
1539
1540                         HttpContext.Current = Context;
1541                         PreStart ();
1542                         pipeline = Pipeline ();
1543                         Tick ();
1544                 }
1545
1546                 const string HANDLER_CACHE = "@@HttpHandlerCache@@";
1547
1548                 internal static Hashtable GetHandlerCache ()
1549                 {
1550                         Cache cache = HttpRuntime.InternalCache;
1551                         Hashtable ret = cache [HANDLER_CACHE] as Hashtable;
1552
1553                         if (ret == null) {
1554                                 ret = new Hashtable ();
1555                                 cache.Insert (HANDLER_CACHE, ret);
1556                         }
1557
1558                         return ret;
1559                 }
1560                 
1561                 internal static void ClearHandlerCache ()
1562                 {
1563                         Hashtable cache = GetHandlerCache ();
1564                         cache.Clear ();
1565                 }
1566                 
1567                 object LocateHandler (HttpRequest req, string verb, string url)
1568                 {
1569                         Hashtable cache = GetHandlerCache ();
1570                         string id = String.Concat (verb, url);
1571                         object ret = cache [id];
1572
1573                         if (ret != null)
1574                                 return ret;
1575
1576                         bool allowCache;
1577                         HttpHandlersSection httpHandlersSection = WebConfigurationManager.GetSection ("system.web/httpHandlers", req.Path, req.Context) as HttpHandlersSection;
1578                         ret = httpHandlersSection.LocateHandler (verb, url, out allowCache);
1579
1580                         IHttpHandler handler = ret as IHttpHandler;
1581                         if (allowCache && handler != null && handler.IsReusable)
1582                                 cache [id] = ret;
1583                         
1584                         return ret;
1585                 }
1586
1587                 internal IHttpHandler GetHandler (HttpContext context, string url)
1588                 {
1589                         return GetHandler (context, url, false);
1590                 }
1591                 
1592                 // Used by HttpServerUtility.Execute
1593                 internal IHttpHandler GetHandler (HttpContext context, string url, bool ignoreContextHandler)
1594                 {
1595                         if (!ignoreContextHandler && context.Handler != null)
1596                                 return context.Handler;
1597                         
1598                         HttpRequest request = context.Request;
1599                         string verb = request.RequestType;
1600                         
1601                         IHttpHandler handler = null;
1602                         object o = LocateHandler (request, verb, url);
1603                         
1604                         factory = o as IHttpHandlerFactory;
1605                         if (factory == null) {
1606                                 handler = (IHttpHandler) o;
1607                         } else {
1608                                 handler = factory.GetHandler (context, verb, url, request.MapPath (url));
1609                         }
1610
1611                         return handler;
1612                 }
1613                 
1614                 void IHttpHandler.ProcessRequest (HttpContext context)
1615                 {
1616                         begin_iar = null;
1617                         this.context = context;
1618                         done.Reset ();
1619
1620                         Start (null);
1621                         done.WaitOne ();
1622                 }
1623
1624                 //
1625                 // This is used by FireOnAppStart, when we init the application
1626                 // as the context is required to be set at that point (the user
1627                 // might call methods that require it on that hook).
1628                 //
1629                 internal void SetContext (HttpContext context)
1630                 {
1631                         this.context = context;
1632                 }
1633
1634                 internal void SetSession (HttpSessionState session)
1635                 {
1636                         this.session = session;
1637                 }
1638
1639                 IAsyncResult IHttpAsyncHandler.BeginProcessRequest (HttpContext context, AsyncCallback cb, object extraData)
1640                 {
1641                         this.context = context;
1642                         done.Reset ();
1643                         
1644                         begin_iar = new AsyncRequestState (done, cb, extraData);
1645
1646                         CultureInfo[] cultures = new CultureInfo [2];
1647                         cultures [0] = Thread.CurrentThread.CurrentCulture;
1648                         cultures [1] = Thread.CurrentThread.CurrentUICulture;
1649                         
1650 #if TARGET_JVM
1651                         if (true)
1652 #else
1653                         if (Thread.CurrentThread.IsThreadPoolThread)
1654 #endif
1655                                 Start (null);
1656                         else
1657                                 ThreadPool.QueueUserWorkItem (x => {
1658                                         try {
1659                                                 Start (x);
1660                                         } catch (Exception e) {
1661                                                 Console.Error.WriteLine (e);
1662                                         }
1663                                 });
1664                         
1665                         return begin_iar;
1666                 }
1667
1668                 void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result)
1669                 {
1670 #if TARGET_J2EE
1671                         if (result == null)
1672                                 result = begin_iar;
1673 #endif
1674                         if (!result.IsCompleted)
1675                                 result.AsyncWaitHandle.WaitOne ();
1676                         begin_iar = null;
1677                 }
1678
1679                 public virtual void Init ()
1680                 {
1681                 }
1682
1683                 bool IHttpHandler.IsReusable {
1684                         get {
1685                                 return true;
1686                         }
1687                 }
1688                 
1689 #region internals
1690                 internal void ClearError ()
1691                 {
1692                         context.ClearError ();
1693                 }
1694
1695                 bool RedirectErrorPage (string error_page)
1696                 {
1697                         if (context.Request.QueryString ["aspxerrorpath"] != null)
1698                                 return false;
1699
1700                         Response.Redirect (error_page + "?aspxerrorpath=" + Request.Path, false);
1701                         return true;
1702                 }
1703                                                         
1704                 bool RedirectCustomError (ref HttpException httpEx)
1705                 {
1706                         try {
1707                         if (!context.IsCustomErrorEnabledUnsafe)
1708                                 return false;
1709                         
1710                         CustomErrorsSection config = (CustomErrorsSection)WebConfigurationManager.GetSection ("system.web/customErrors");                       
1711                         if (config == null) {
1712                                 if (context.ErrorPage != null)
1713                                         return RedirectErrorPage (context.ErrorPage);
1714                                 
1715                                 return false;
1716                         }
1717                         
1718                         CustomError err = config.Errors [context.Response.StatusCode.ToString()];
1719                         string redirect = err == null ? null : err.Redirect;
1720                         if (redirect == null) {
1721                                 redirect = context.ErrorPage;
1722                                 if (redirect == null)
1723                                         redirect = config.DefaultRedirect;
1724                         }
1725                         
1726                         if (redirect == null)
1727                                 return false;
1728                         
1729                         return RedirectErrorPage (redirect);
1730                         }
1731                         catch (Exception ex) {
1732                                 httpEx = HttpException.NewWithCode (500, String.Empty, ex, WebEventCodes.WebErrorOtherError);
1733                                 return false;
1734                         }
1735                 }
1736 #endregion              
1737                 internal static string BinDirectory
1738                 {
1739                         get {
1740                                 if (binDirectory == null) {
1741                                         AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
1742                                         string baseDir = setup.ApplicationBase;
1743                                         string bindir;
1744                                         
1745                                         foreach (string dir in BinDirs) {
1746                                                 bindir = Path.Combine (baseDir, dir);
1747                                                 if (!Directory.Exists (bindir))
1748                                                         continue;
1749                                                 binDirectory = bindir;
1750                                                 break;
1751                                         }
1752                                 }
1753
1754                                 return binDirectory;
1755                         }
1756                 }
1757
1758                 internal static string[] BinDirectoryAssemblies
1759                 {
1760                         get {
1761                                 ArrayList binDlls = null;
1762                                 string[] dlls;
1763                                 
1764                                 string bindir = BinDirectory;
1765                                 if (bindir != null) {
1766                                         binDlls = new ArrayList ();
1767                                         dlls = Directory.GetFiles (bindir, "*.dll");
1768                                         binDlls.AddRange (dlls);
1769                                 }
1770
1771                                 if (binDlls == null)
1772                                         return new string[] {};
1773                                 
1774                                 return (string[]) binDlls.ToArray (typeof (string));
1775                         }
1776                 }
1777                                         
1778                 internal static Type LoadType (string typeName)
1779                 {
1780                         return LoadType (typeName, false);
1781                 }
1782                 
1783                 internal static Type LoadType (string typeName, bool throwOnMissing)
1784                 {
1785                         Type type = Type.GetType (typeName);
1786                         if (type != null)
1787                                 return type;
1788
1789 #if !TARGET_JVM
1790                         Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
1791                         foreach (Assembly ass in assemblies) {
1792                                 type = ass.GetType (typeName, false);
1793                                 if (type != null)
1794                                         return type;
1795                         }
1796
1797                         IList tla = System.Web.Compilation.BuildManager.TopLevelAssemblies;
1798                         if (tla != null && tla.Count > 0) {
1799                                 foreach (Assembly asm in tla) {
1800                                         if (asm == null)
1801                                                 continue;
1802                                         type = asm.GetType (typeName, false);
1803                                         if (type != null)
1804                                                 return type;
1805                                 }
1806                         }
1807
1808                         Exception loadException = null;
1809                         try {
1810                                 type = null;
1811                                 type = LoadTypeFromBin (typeName);
1812                         } catch (Exception ex) {
1813                                 loadException = ex;
1814                         }
1815                         
1816                         if (type != null)
1817                                 return type;
1818 #endif
1819                         if (throwOnMissing)
1820                                 throw new TypeLoadException (String.Format ("Type '{0}' cannot be found", typeName), loadException);
1821                         
1822                         return null;
1823                 }
1824
1825                 internal static Type LoadType <TBaseType> (string typeName, bool throwOnMissing)
1826                 {
1827                         Type ret = LoadType (typeName, throwOnMissing);
1828
1829                         if (typeof (TBaseType).IsAssignableFrom (ret))
1830                                 return ret;
1831
1832                         if (throwOnMissing)
1833                                 throw new TypeLoadException (String.Format ("Type '{0}' found but it doesn't derive from base type '{1}'.", typeName, typeof (TBaseType)));
1834
1835                         return null;
1836                 }
1837                 
1838                 internal static Type LoadTypeFromBin (string typeName)
1839                 {
1840                         Type type = null;
1841                         
1842                         foreach (string s in BinDirectoryAssemblies) {
1843                                 Assembly binA = null;
1844                                 
1845                                 try {
1846                                         binA = Assembly.LoadFrom (s);
1847                                 } catch (FileLoadException) {
1848                                         // ignore
1849                                         continue;
1850                                 } catch (BadImageFormatException) {
1851                                         // ignore
1852                                         continue;
1853                                 }
1854                                 
1855                                 type = binA.GetType (typeName, false);
1856                                 if (type == null)
1857                                         continue;
1858                                 
1859                                 return type;
1860                         }
1861
1862                         return null;
1863                 }
1864         }
1865
1866         //
1867         // Based on Fritz' Onion's AsyncRequestState class for asynchronous IHttpAsyncHandlers
1868         // 
1869         class AsyncRequestState : IAsyncResult {
1870                 AsyncCallback cb;
1871                 object cb_data;
1872                 bool completed;
1873                 ManualResetEvent complete_event = null;
1874                 
1875                 internal AsyncRequestState (ManualResetEvent complete_event, AsyncCallback cb, object cb_data)
1876                 {
1877                         this.cb = cb;
1878                         this.cb_data = cb_data;
1879                         this.complete_event = complete_event;
1880                 }
1881
1882                 internal void Complete ()
1883                 {
1884                         completed = true;
1885                         try {
1886                                 //
1887                                 // TODO: if this throws an error, we have no way of reporting it
1888                                 // Not really too bad, since the only failure might be
1889                                 // `HttpRuntime.request_processed'.   
1890                                 //
1891                                 if (cb != null)
1892                                         cb (this);
1893                         } catch {
1894                         }
1895                         
1896                         complete_event.Set ();
1897                 }
1898
1899                 public object AsyncState {
1900                         get {
1901                                 return cb_data;
1902                         }
1903                 }
1904
1905                 public bool CompletedSynchronously {
1906                         get {
1907                                 return false;
1908                         }
1909                 }
1910
1911                 public bool IsCompleted {
1912                         get {
1913                                 return completed;
1914                         }
1915                 }
1916
1917                 public WaitHandle AsyncWaitHandle {
1918                         get {
1919                                 return complete_event;
1920                         }
1921                 }
1922         }
1923
1924 #region Helper classes
1925         
1926         //
1927         // A wrapper to keep track of begin/end pairs
1928         //
1929         class AsyncInvoker {
1930                 public BeginEventHandler begin;
1931                 public EndEventHandler end;
1932                 public object data;
1933                 
1934                 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, object d)
1935                 {
1936                         begin = bh;
1937                         end = eh;
1938                         data = d;
1939                 }
1940
1941                 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh)
1942                 {
1943                         begin = bh;
1944                         end = eh;
1945                 }
1946                 
1947                 public void Invoke (object sender, EventArgs e)
1948                 {
1949                         throw new Exception ("This is just a dummy");
1950                 }
1951         }
1952 #endregion
1953 }