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