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