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