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