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