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