2 // System.Web.HttpApplication.cs
5 // Miguel de Icaza (miguel@novell.com)
6 // Gonzalo Paniagua (gonzalo@ximian.com)
9 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
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:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
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.
30 // The Application Processing Pipeline.
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.
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.
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
50 // By yielding values we can suspend execution of RunHooks.
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.
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.
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;
76 namespace System.Web {
79 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
80 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
83 public class HttpApplication : IHttpAsyncHandler, IHttpHandler, IComponent, IDisposable {
85 HttpSessionState session;
88 // The source, and the exposed API (cache).
89 HttpModuleCollection modcoll;
91 string assemblyLocation;
94 // The factory for the handler currently running.
96 IHttpHandlerFactory factory;
99 // Whether the pipeline should be stopped
101 bool stop_processing;
106 IEnumerator pipeline;
108 // To flag when we are done processing a request from BeginProcessRequest.
109 ManualResetEvent done;
111 // The current IAsyncResult for the running async request handler in the pipeline
112 AsyncRequestState begin_iar;
114 // Tracks the current AsyncInvocation being dispatched
115 AsyncInvoker current_ai;
117 // We don't use the EventHandlerList here, but derived classes might do
118 EventHandlerList events;
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;
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
135 public HttpApplication ()
137 done = new ManualResetEvent (false);
140 internal void InitOnce (bool full_init)
147 HttpModulesSection modules;
148 modules = (HttpModulesSection) WebConfigurationManager.GetSection ("system.web/httpModules");
150 ModulesConfiguration modules;
152 modules = (ModulesConfiguration) HttpContext.GetAppConfig ("system.web/httpModules");
155 modcoll = modules.LoadModules (this);
158 HttpApplicationFactory.AttachEvents (this);
161 GlobalizationSection cfg;
162 cfg = (GlobalizationSection) WebConfigurationManager.GetSection ("system.web/globalization");
163 app_culture = cfg.GetCulture();
164 appui_culture = cfg.GetUICulture();
166 GlobalizationConfiguration cfg;
167 cfg = GlobalizationConfiguration.GetInstance (null);
169 app_culture = cfg.Culture;
170 appui_culture = cfg.UICulture;
176 internal string AssemblyLocation {
178 if (assemblyLocation == null)
179 assemblyLocation = GetType ().Assembly.Location;
180 return assemblyLocation;
185 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
186 public HttpApplicationState Application {
188 return HttpApplicationFactory.ApplicationState;
193 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
194 public HttpContext Context {
200 protected EventHandlerList Events {
203 events = new EventHandlerList ();
210 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
211 public HttpModuleCollection Modules {
212 [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
215 modcoll = new HttpModuleCollection ();
222 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
223 public HttpRequest Request {
226 throw new HttpException (Locale.GetText ("No context is available."));
228 if (false == HttpApplicationFactory.ContextAvailable)
229 throw new HttpException (Locale.GetText ("Request is not available in this context."));
231 return context.Request;
236 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
237 public HttpResponse Response {
240 throw new HttpException (Locale.GetText ("No context is available."));
242 if (false == HttpApplicationFactory.ContextAvailable)
243 throw new HttpException (Locale.GetText ("Response is not available in this context."));
245 return context.Response;
250 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
251 public HttpServerUtility Server {
254 return context.Server;
257 // This is so we can get the Server and call a few methods
258 // which are not context sensitive, see HttpServerUtilityTest
260 return new HttpServerUtility ((HttpContext) null);
265 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
266 public HttpSessionState Session {
268 // Only used for Session_End
273 throw new HttpException (Locale.GetText ("No context is available."));
274 return context.Session;
279 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
280 public virtual ISite Site {
291 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
292 public IPrincipal User {
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."));
303 public virtual event EventHandler Disposed;
304 public virtual event EventHandler Error;
306 public event EventHandler PreSendRequestHeaders;
307 internal void TriggerPreSendRequestHeaders ()
309 if (PreSendRequestHeaders != null)
310 PreSendRequestHeaders (this, EventArgs.Empty);
313 public event EventHandler PreSendRequestContent;
314 internal void TriggerPreSendRequestContent ()
316 if (PreSendRequestContent != null)
317 PreSendRequestContent (this, EventArgs.Empty);
320 public event EventHandler AcquireRequestState;
321 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
323 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
324 AcquireRequestState += new EventHandler (invoker.Invoke);
327 public event EventHandler AuthenticateRequest;
328 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
330 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
331 AuthenticateRequest += new EventHandler (invoker.Invoke);
334 public event EventHandler AuthorizeRequest;
335 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
337 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
338 AuthorizeRequest += new EventHandler (invoker.Invoke);
341 public event EventHandler BeginRequest;
342 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh)
344 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
345 BeginRequest += new EventHandler (invoker.Invoke);
348 public event EventHandler EndRequest;
349 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh)
351 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
352 EndRequest += new EventHandler (invoker.Invoke);
355 public event EventHandler PostRequestHandlerExecute;
356 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
358 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
359 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
362 public event EventHandler PreRequestHandlerExecute;
363 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
365 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
366 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
369 public event EventHandler ReleaseRequestState;
370 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
372 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
373 ReleaseRequestState += new EventHandler (invoker.Invoke);
376 public event EventHandler ResolveRequestCache;
377 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
379 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
380 ResolveRequestCache += new EventHandler (invoker.Invoke);
383 public event EventHandler UpdateRequestCache;
384 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
386 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
387 UpdateRequestCache += new EventHandler (invoker.Invoke);
391 public event EventHandler PostAuthenticateRequest;
392 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
394 AddOnPostAuthenticateRequestAsync (bh, eh, null);
397 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
399 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
400 PostAuthenticateRequest += new EventHandler (invoker.Invoke);
403 public event EventHandler PostAuthorizeRequest;
404 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
406 AddOnPostAuthorizeRequestAsync (bh, eh, null);
409 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
411 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
412 PostAuthorizeRequest += new EventHandler (invoker.Invoke);
415 public event EventHandler PostResolveRequestCache;
416 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
418 AddOnPostResolveRequestCacheAsync (bh, eh, null);
421 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
423 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
424 PostResolveRequestCache += new EventHandler (invoker.Invoke);
427 public event EventHandler PostMapRequestHandler;
428 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
430 AddOnPostMapRequestHandlerAsync (bh, eh, null);
433 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh, object data)
435 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
436 PostMapRequestHandler += new EventHandler (invoker.Invoke);
439 public event EventHandler PostAcquireRequestState;
440 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
442 AddOnPostAcquireRequestStateAsync (bh, eh, null);
445 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
447 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
448 PostAcquireRequestState += new EventHandler (invoker.Invoke);
451 public event EventHandler PostReleaseRequestState;
452 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
454 AddOnPostReleaseRequestStateAsync (bh, eh, null);
457 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
459 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
460 PostReleaseRequestState += new EventHandler (invoker.Invoke);
463 public event EventHandler PostUpdateRequestCache;
464 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
466 AddOnPostUpdateRequestCacheAsync (bh, eh, null);
469 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
471 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
472 PostUpdateRequestCache += new EventHandler (invoker.Invoke);
476 // The new overloads that take a data parameter
478 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
480 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
481 AcquireRequestState += new EventHandler (invoker.Invoke);
484 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
486 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
487 AuthenticateRequest += new EventHandler (invoker.Invoke);
490 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
492 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
493 AuthorizeRequest += new EventHandler (invoker.Invoke);
496 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
498 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
499 BeginRequest += new EventHandler (invoker.Invoke);
502 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
504 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
505 EndRequest += new EventHandler (invoker.Invoke);
508 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
510 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
511 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
514 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
516 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
517 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
520 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
522 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
523 ReleaseRequestState += new EventHandler (invoker.Invoke);
526 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
528 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
529 ResolveRequestCache += new EventHandler (invoker.Invoke);
532 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
534 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
535 UpdateRequestCache += new EventHandler (invoker.Invoke);
539 internal event EventHandler DefaultAuthentication;
542 // Bypass all the event on the Http pipeline and go directly to EndRequest
544 public void CompleteRequest ()
546 stop_processing = true;
549 internal bool RequestCompleted {
550 set { stop_processing = value; }
553 public virtual void Dispose ()
555 if (modcoll != null) {
556 for (int i = modcoll.Count; i >= 0; i--) {
557 modcoll.Get (i).Dispose ();
562 if (Disposed != null)
563 Disposed (this, EventArgs.Empty);
569 public virtual string GetVaryByCustomString (HttpContext context, string custom)
571 if (custom == null) // Sigh
572 throw new NullReferenceException ();
574 if (0 == String.Compare (custom, "browser", true, CultureInfo.InvariantCulture))
575 return context.Request.Browser.Type;
581 // If we catch an error, queue this error
583 void ProcessError (Exception e)
585 bool first = context.Error == null;
587 context.AddError (e);
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);
600 stop_processing = true;
604 // Ticks the clock: next step on the pipeline.
609 if (pipeline.MoveNext ()){
610 if ((bool)pipeline.Current)
613 } catch (Exception e) {
614 Console.WriteLine ("Tick caught an exception that has not been propagated:\n" + e);
627 // Invoked when our async callback called from RunHooks completes,
628 // we restart the pipeline here.
630 void async_callback_completed_cb (IAsyncResult ar)
632 if (current_ai.end != null){
635 } catch (Exception e) {
643 void async_handler_complete_cb (IAsyncResult ar)
645 IHttpAsyncHandler async_handler = ((IHttpAsyncHandler) ar.AsyncState);
648 async_handler.EndProcessRequest (ar);
649 } catch (Exception e){
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
661 #if TARGET_JVM && !NET_2_0
662 sealed class RunHooksEnumerator : IEnumerable, IEnumerator
664 Delegate [] delegates;
668 internal RunHooksEnumerator(HttpApplication app, Delegate list)
671 delegates = list.GetInvocationList ();
674 public IEnumerator GetEnumerator() { return this; }
675 public object Current { get{ return app.stop_processing; } }
678 throw new NotImplementedException("HttpApplication.RunHooksEnumerator.Reset called.");
680 public bool MoveNext ()
682 while (currentStep < delegates.Length) {
683 if (ProcessDelegate((EventHandler)delegates[currentStep++]))
689 bool ProcessDelegate(EventHandler d)
691 if (d.Target != null && (d.Target is AsyncInvoker)){
692 app.current_ai = (AsyncInvoker) d.Target;
695 app.must_yield = true;
697 app.context.BeginTimeoutPossible ();
698 app.current_ai.begin (app, EventArgs.Empty, new AsyncCallback(app.async_callback_completed_cb), app.current_ai.data);
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."));
708 app.ProcessError (e);
711 app.in_begin = false;
712 app.context.EndTimeoutPossible ();
716 // If things are still moving forward, yield this
721 else if (app.stop_processing)
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."));
736 app.ProcessError (e);
739 app.context.EndTimeoutPossible ();
741 if (app.stop_processing)
748 IEnumerable RunHooks (Delegate list)
750 return new RunHooksEnumerator(this, list);
753 IEnumerable RunHooks (Delegate list)
755 Delegate [] delegates = list.GetInvocationList ();
757 foreach (EventHandler d in delegates){
758 if (d.Target != null && (d.Target is AsyncInvoker)){
759 current_ai = (AsyncInvoker) d.Target;
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){
776 context.EndTimeoutPossible ();
780 // If things are still moving forward, yield this
784 yield return stop_processing;
785 else if (stop_processing)
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){
800 context.EndTimeoutPossible ();
809 static void FinalErrorWrite (HttpResponse response, string error)
812 response.Write (error);
813 response.Flush (true);
821 if (context.Error == null){
823 context.Response.Flush (true);
824 } catch (Exception e){
825 context.AddError (e);
829 Exception error = context.Error;
831 HttpResponse response = context.Response;
833 if (!response.HeadersSent){
834 response.ClearHeaders ();
835 response.ClearContent ();
837 if (error is HttpException){
838 response.StatusCode = ((HttpException)error).GetHttpCode ();
840 error = new HttpException ("", error);
841 response.StatusCode = 500;
843 if (!RedirectCustomError ())
844 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
846 response.Flush (true);
848 if (!(error is HttpException))
849 error = new HttpException ("", error);
850 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
857 // Invoked at the end of the pipeline execution
862 if (EndRequest != null)
863 EndRequest (this, EventArgs.Empty);
864 } catch (Exception e){
871 } catch (Exception e) {
872 Console.WriteLine ("Internal error: OutputPage threw an exception " + e);
874 context.WorkerRequest.EndOfRequest();
875 if (begin_iar != null){
877 begin_iar.Complete ();
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'
889 if (factory != null && context.Handler != null){
890 factory.ReleaseHandler (context.Handler);
894 context.Handler = null;
895 // context = null; -> moved to PostDone
903 // Events fired as described in `Http Runtime Support, HttpModules,
904 // Handling Public Events'
906 #if TARGET_JVM && !NET_2_0
907 sealed class PipeLineEnumerator : IEnumerator
909 readonly HttpApplication _this;
913 IEnumerator currentEnumerator;
915 IHttpHandler handler = null;
917 internal PipeLineEnumerator(HttpApplication app) {
921 public object Current { get{ return currentEnumerator != null ? currentEnumerator.Current : current; } }
922 public void Reset() {
923 currentEnumerator = null;
927 void ResetEnumerator() {
928 if (currentEnumerator != null) {
929 current = currentEnumerator.Current;
930 currentEnumerator = null;
934 public bool MoveNext () {
935 switch (currentYield) {
937 case 1: goto yield_1;
938 case 2: goto yield_2;
939 case 3: goto yield_3;
940 case 4: goto yield_4;
942 case 5: goto yield_5;
944 case 6: goto yield_6;
946 case 7: goto yield_7;
948 case 8: goto yield_8;
949 case 9: goto yield_9;
951 case 10: goto yield_10;
952 case 11: goto yield_11;
954 case 12: goto yield_12;
956 case 13: goto yield_13;
958 case 14: goto yield_14;
959 case 15: goto yield_15;
961 case 16: goto yield_16;
963 case 17: goto yield_17;
965 case 18: goto yield_18;
967 default: goto yield_19;
970 if (_this.stop_processing) {
978 if (_this.BeginRequest != null) {
979 //foreach (bool stop in RunHooks (BeginRequest))
980 // yield return stop;
981 if (currentEnumerator == null) {
983 currentEnumerator = _this.RunHooks(_this.BeginRequest).GetEnumerator();
985 while (currentEnumerator.MoveNext())
991 if (_this.AuthenticateRequest != null) {
992 //foreach (bool stop in RunHooks (AuthenticateRequest))
993 // yield return stop;
994 if (currentEnumerator == null) {
996 currentEnumerator = _this.RunHooks(_this.AuthenticateRequest).GetEnumerator();
998 while (currentEnumerator.MoveNext())
1004 if (_this.DefaultAuthentication != null) {
1005 //foreach (bool stop in RunHooks (DefaultAuthentication))
1006 // yield return stop;
1007 if (currentEnumerator == null) {
1009 currentEnumerator = _this.RunHooks(_this.DefaultAuthentication).GetEnumerator();
1011 while (currentEnumerator.MoveNext())
1019 if (_this.PostAuthenticateRequest != null) {
1020 //foreach (bool stop in RunHooks (AuthenticateRequest))
1021 // yield return stop;
1022 if (currentEnumerator == null) {
1024 currentEnumerator = _this.RunHooks(_this.PostAuthenticateRequest).GetEnumerator();
1026 while (currentEnumerator.MoveNext())
1033 if (_this.AuthorizeRequest != null) {
1034 //foreach (bool stop in RunHooks (AuthorizeRequest))
1035 // yield return stop;
1036 if (currentEnumerator == null) {
1038 currentEnumerator = _this.RunHooks(_this.AuthorizeRequest).GetEnumerator();
1040 while (currentEnumerator.MoveNext())
1047 if (_this.PostAuthorizeRequest != null) {
1048 //foreach (bool stop in RunHooks (PostAuthorizeRequest))
1049 // yield return stop;
1050 if (currentEnumerator == null) {
1052 currentEnumerator = _this.RunHooks(_this.PostAuthorizeRequest).GetEnumerator();
1054 while (currentEnumerator.MoveNext())
1061 if (_this.ResolveRequestCache != null) {
1062 //foreach (bool stop in RunHooks (ResolveRequestCache))
1063 // yield return stop;
1064 if (currentEnumerator == null) {
1066 currentEnumerator = _this.RunHooks(_this.ResolveRequestCache).GetEnumerator();
1068 while (currentEnumerator.MoveNext())
1074 // Obtain the handler for the request.
1075 //IHttpHandler handler = null;
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));
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);
1089 if (_this.stop_processing) {
1090 //yield return true;
1098 if (_this.PostResolveRequestCache != null) {
1099 //foreach (bool stop in RunHooks (PostResolveRequestCache))
1100 // yield return stop;
1101 if (currentEnumerator == null) {
1103 currentEnumerator = _this.RunHooks(_this.PostResolveRequestCache).GetEnumerator();
1105 while (currentEnumerator.MoveNext())
1111 if (_this.PostMapRequestHandler != null) {
1112 //foreach (bool stop in RunHooks (PostMapRequestHandler))
1113 // yield return stop;
1114 if (currentEnumerator == null) {
1116 currentEnumerator = _this.RunHooks(_this.PostMapRequestHandler).GetEnumerator();
1118 while (currentEnumerator.MoveNext())
1126 if (_this.AcquireRequestState != null){
1127 //foreach (bool stop in RunHooks (AcquireRequestState))
1128 // yield return stop;
1129 if (currentEnumerator == null) {
1131 currentEnumerator = _this.RunHooks(_this.AcquireRequestState).GetEnumerator();
1133 while (currentEnumerator.MoveNext())
1141 if (_this.PostAcquireRequestState != null){
1142 //foreach (bool stop in RunHooks (PostAcquireRequestState))
1143 // yield return stop;
1144 if (currentEnumerator == null) {
1146 currentEnumerator = _this.RunHooks(_this.PostAcquireRequestState).GetEnumerator();
1148 while (currentEnumerator.MoveNext())
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.
1160 if (_this.PreRequestHandlerExecute != null)
1161 foreach (bool stop in _this.RunHooks (_this.PreRequestHandlerExecute))
1166 _this.context.BeginTimeoutPossible ();
1167 if (handler != null){
1168 IHttpAsyncHandler async_handler = handler as IHttpAsyncHandler;
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);
1175 _this.must_yield = false;
1176 handler.ProcessRequest (_this.context);
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);
1188 _this.in_begin = false;
1189 _this.context.EndTimeoutPossible ();
1191 if (_this.must_yield) {
1192 //yield return stop_processing;
1193 current = _this.stop_processing;
1197 else if (_this.stop_processing)
1200 // These are executed after the application has returned
1202 if (_this.PostRequestHandlerExecute != null)
1203 foreach (bool stop in _this.RunHooks (_this.PostRequestHandlerExecute))
1208 if (_this.ReleaseRequestState != null){
1209 foreach (bool stop in _this.RunHooks (_this.ReleaseRequestState)){
1211 // Ignore the stop signal while release the state
1217 if (_this.stop_processing) {
1218 //yield return true;
1226 if (_this.PostReleaseRequestState != null) {
1227 //foreach (bool stop in RunHooks (PostReleaseRequestState))
1228 // yield return stop;
1229 if (currentEnumerator == null) {
1231 currentEnumerator = _this.RunHooks(_this.PostReleaseRequestState).GetEnumerator();
1233 while (currentEnumerator.MoveNext())
1240 if (_this.context.Error == null)
1241 _this.context.Response.DoFilter (true);
1243 if (_this.UpdateRequestCache != null) {
1244 //foreach (bool stop in RunHooks (UpdateRequestCache))
1245 // yield return stop;
1246 if (currentEnumerator == null) {
1248 currentEnumerator = _this.RunHooks(_this.UpdateRequestCache).GetEnumerator();
1250 while (currentEnumerator.MoveNext())
1258 if (_this.PostUpdateRequestCache != null) {
1259 //foreach (bool stop in RunHooks (PostUpdateRequestCache))
1260 // yield return stop;
1261 if (currentEnumerator == null) {
1263 currentEnumerator = _this.RunHooks(_this.PostUpdateRequestCache).GetEnumerator();
1265 while (currentEnumerator.MoveNext())
1271 _this.PipelineDone ();
1278 IEnumerator Pipeline ()
1280 return new PipeLineEnumerator(this);
1283 IEnumerator Pipeline ()
1285 if (stop_processing)
1288 if (BeginRequest != null)
1289 foreach (bool stop in RunHooks (BeginRequest))
1292 if (AuthenticateRequest != null)
1293 foreach (bool stop in RunHooks (AuthenticateRequest))
1296 if (DefaultAuthentication != null)
1297 foreach (bool stop in RunHooks (DefaultAuthentication))
1301 if (PostAuthenticateRequest != null)
1302 foreach (bool stop in RunHooks (AuthenticateRequest))
1305 if (AuthorizeRequest != null)
1306 foreach (bool stop in RunHooks (AuthorizeRequest))
1309 if (PostAuthorizeRequest != null)
1310 foreach (bool stop in RunHooks (PostAuthorizeRequest))
1314 if (ResolveRequestCache != null)
1315 foreach (bool stop in RunHooks (ResolveRequestCache))
1318 // Obtain the handler for the request.
1319 IHttpHandler handler = null;
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));
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) {
1333 if (stop_processing)
1337 if (PostResolveRequestCache != null)
1338 foreach (bool stop in RunHooks (PostResolveRequestCache))
1341 if (PostMapRequestHandler != null)
1342 foreach (bool stop in RunHooks (PostMapRequestHandler))
1346 if (AcquireRequestState != null){
1347 foreach (bool stop in RunHooks (AcquireRequestState))
1352 if (PostAcquireRequestState != null){
1353 foreach (bool stop in RunHooks (PostAcquireRequestState))
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.
1363 if (PreRequestHandlerExecute != null)
1364 foreach (bool stop in RunHooks (PreRequestHandlerExecute))
1369 context.BeginTimeoutPossible ();
1370 if (handler != null){
1371 IHttpAsyncHandler async_handler = handler as IHttpAsyncHandler;
1373 if (async_handler != null){
1376 async_handler.BeginProcessRequest (context, async_handler_complete_cb, handler);
1379 handler.ProcessRequest (context);
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){
1392 context.EndTimeoutPossible ();
1395 yield return stop_processing;
1396 else if (stop_processing)
1399 // These are executed after the application has returned
1401 if (PostRequestHandlerExecute != null)
1402 foreach (bool stop in RunHooks (PostRequestHandlerExecute))
1407 if (ReleaseRequestState != null){
1408 foreach (bool stop in RunHooks (ReleaseRequestState)){
1410 // Ignore the stop signal while release the state
1416 if (stop_processing)
1420 if (PostReleaseRequestState != null)
1421 foreach (bool stop in RunHooks (PostReleaseRequestState))
1425 if (context.Error == null)
1426 context.Response.DoFilter (true);
1428 if (UpdateRequestCache != null)
1429 foreach (bool stop in RunHooks (UpdateRequestCache))
1433 if (PostUpdateRequestCache != null)
1434 foreach (bool stop in RunHooks (PostUpdateRequestCache))
1444 HttpRuntime.TimeoutManager.Add (context);
1446 Thread th = Thread.CurrentThread;
1447 if (app_culture != null) {
1448 prev_app_culture = th.CurrentCulture;
1449 th.CurrentCulture = app_culture;
1452 if (appui_culture != null) {
1453 prev_appui_culture = th.CurrentUICulture;
1454 th.CurrentUICulture = appui_culture;
1458 prev_user = Thread.CurrentPrincipal;
1464 Thread th = Thread.CurrentThread;
1466 if (Thread.CurrentPrincipal != prev_user)
1467 Thread.CurrentPrincipal = prev_user;
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;
1475 HttpRuntime.TimeoutManager.Remove (context);
1479 HttpContext.Current = null;
1482 void Start (object x)
1486 pipeline = Pipeline ();
1490 // Used by HttpServerUtility.Execute
1491 internal IHttpHandler GetHandler (HttpContext context)
1493 HttpRequest request = context.Request;
1494 string verb = request.RequestType;
1495 string url = request.FilePath;
1497 IHttpHandler handler = null;
1499 HttpHandlersSection section = (HttpHandlersSection) WebConfigurationManager.GetSection ("system.web/httpHandlers");
1500 object o = section.LocateHandler (verb, url);
1502 HandlerFactoryConfiguration factory_config = (HandlerFactoryConfiguration) HttpContext.GetAppConfig ("system.web/httpHandlers");
1503 object o = factory_config.LocateHandler (verb, url);
1506 factory = o as IHttpHandlerFactory;
1508 if (factory == null) {
1509 handler = (IHttpHandler) o;
1511 handler = factory.GetHandler (context, verb, url, request.PhysicalPath);
1513 context.Handler = handler;
1518 void IHttpHandler.ProcessRequest (HttpContext context)
1521 this.context = context;
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).
1533 internal void SetContext (HttpContext context)
1535 this.context = context;
1538 internal void SetSession (HttpSessionState session)
1540 this.session = session;
1543 IAsyncResult IHttpAsyncHandler.BeginProcessRequest (HttpContext context, AsyncCallback cb, object extraData)
1545 this.context = context;
1548 begin_iar = new AsyncRequestState (done, cb, extraData);
1552 if (Thread.CurrentThread.IsThreadPoolThread)
1556 ThreadPool.QueueUserWorkItem (new WaitCallback (Start), null);
1561 void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result)
1563 if (!result.IsCompleted)
1564 result.AsyncWaitHandle.WaitOne ();
1568 public virtual void Init ()
1572 bool IHttpHandler.IsReusable {
1579 internal void ClearError ()
1581 context.ClearError ();
1584 bool RedirectErrorPage (string error_page)
1586 if (context.Request.QueryString ["aspxerrorpath"] != null)
1589 Response.Redirect (error_page + "?aspxerrorpath=" + Request.Path, false);
1593 bool RedirectCustomError ()
1595 if (!context.IsCustomErrorEnabled)
1599 CustomErrorsSection config = (CustomErrorsSection)WebConfigurationManager.GetSection ("system.web/customErrors");
1601 CustomErrorsConfig config = null;
1603 config = (CustomErrorsConfig) context.GetConfig ("system.web/customErrors");
1607 if (config == null) {
1608 if (context.ErrorPage != null)
1609 return RedirectErrorPage (context.ErrorPage);
1615 CustomError err = config.Errors [context.Response.StatusCode.ToString()];
1616 string redirect = err == null ? null : err.Redirect;
1618 string redirect = config [context.Response.StatusCode];
1620 if (redirect == null) {
1621 redirect = context.ErrorPage;
1622 if (redirect == null)
1623 redirect = config.DefaultRedirect;
1626 if (redirect == null)
1629 return RedirectErrorPage (redirect);
1635 // Based on Fritz' Onion's AsyncRequestState class for asynchronous IHttpAsyncHandlers
1637 class AsyncRequestState : IAsyncResult {
1641 ManualResetEvent complete_event = null;
1643 internal AsyncRequestState (ManualResetEvent complete_event, AsyncCallback cb, object cb_data)
1646 this.cb_data = cb_data;
1647 this.complete_event = complete_event;
1650 internal void Complete ()
1656 complete_event.Set ();
1659 public object AsyncState {
1665 public bool CompletedSynchronously {
1671 public bool IsCompleted {
1677 public WaitHandle AsyncWaitHandle {
1679 return complete_event;
1684 #region Helper classes
1687 // A wrapper to keep track of begin/end pairs
1689 class AsyncInvoker {
1690 public BeginEventHandler begin;
1691 public EndEventHandler end;
1694 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, object d)
1701 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh)
1707 public void Invoke (object sender, EventArgs e)
1709 throw new Exception ("This is just a dummy");