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