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)
146 ModulesConfiguration modules;
147 modules = (ModulesConfiguration) HttpContext.GetAppConfig ("system.web/httpModules");
149 modcoll = modules.LoadModules (this);
152 HttpApplicationFactory.AttachEvents (this);
154 GlobalizationConfiguration cfg = GlobalizationConfiguration.GetInstance (null);
156 app_culture = cfg.Culture;
157 appui_culture = cfg.UICulture;
162 internal string AssemblyLocation {
164 if (assemblyLocation == null)
165 assemblyLocation = GetType ().Assembly.Location;
166 return assemblyLocation;
171 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
172 public HttpApplicationState Application {
174 return HttpApplicationFactory.ApplicationState;
179 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
180 public HttpContext Context {
186 protected EventHandlerList Events {
189 events = new EventHandlerList ();
196 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
197 public HttpModuleCollection Modules {
198 [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
201 modcoll = new HttpModuleCollection ();
208 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
209 public HttpRequest Request {
212 throw new HttpException (Locale.GetText ("No context is available."));
213 return context.Request;
218 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
219 public HttpResponse Response {
222 throw new HttpException (Locale.GetText ("No context is available."));
223 return context.Response;
228 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
229 public HttpServerUtility Server {
232 return context.Server;
235 // This is so we can get the Server and call a few methods
236 // which are not context sensitive, see HttpServerUtilityTest
238 return new HttpServerUtility ((HttpContext) null);
243 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
244 public HttpSessionState Session {
246 // Only used for Session_End
251 throw new HttpException (Locale.GetText ("No context is available."));
252 return context.Session;
257 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
258 public virtual ISite Site {
269 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
270 public IPrincipal User {
273 throw new HttpException (Locale.GetText ("No context is available."));
274 if (context.User == null)
275 throw new HttpException (Locale.GetText ("No currently authenticated user."));
281 public virtual event EventHandler Disposed;
282 public virtual event EventHandler Error;
284 public event EventHandler PreSendRequestHeaders;
285 internal void TriggerPreSendRequestHeaders ()
287 if (PreSendRequestHeaders != null)
288 PreSendRequestHeaders (this, EventArgs.Empty);
291 public event EventHandler PreSendRequestContent;
292 internal void TriggerPreSendRequestContent ()
294 if (PreSendRequestContent != null)
295 PreSendRequestContent (this, EventArgs.Empty);
298 public event EventHandler AcquireRequestState;
299 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
301 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
302 AcquireRequestState += new EventHandler (invoker.Invoke);
305 public event EventHandler AuthenticateRequest;
306 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
308 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
309 AuthenticateRequest += new EventHandler (invoker.Invoke);
312 public event EventHandler AuthorizeRequest;
313 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
315 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
316 AuthorizeRequest += new EventHandler (invoker.Invoke);
319 public event EventHandler BeginRequest;
320 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh)
322 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
323 BeginRequest += new EventHandler (invoker.Invoke);
326 public event EventHandler EndRequest;
327 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh)
329 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
330 EndRequest += new EventHandler (invoker.Invoke);
333 public event EventHandler PostRequestHandlerExecute;
334 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
336 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
337 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
340 public event EventHandler PreRequestHandlerExecute;
341 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
343 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
344 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
347 public event EventHandler ReleaseRequestState;
348 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
350 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
351 ReleaseRequestState += new EventHandler (invoker.Invoke);
354 public event EventHandler ResolveRequestCache;
355 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
357 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
358 ResolveRequestCache += new EventHandler (invoker.Invoke);
361 public event EventHandler UpdateRequestCache;
362 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
364 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
365 UpdateRequestCache += new EventHandler (invoker.Invoke);
369 public event EventHandler PostAuthenticateRequest;
370 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
372 AddOnPostAuthenticateRequestAsync (bh, eh, null);
375 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
377 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
378 PostAuthenticateRequest += new EventHandler (invoker.Invoke);
381 public event EventHandler PostAuthorizeRequest;
382 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
384 AddOnPostAuthorizeRequestAsync (bh, eh, null);
387 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
389 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
390 PostAuthorizeRequest += new EventHandler (invoker.Invoke);
393 public event EventHandler PostResolveRequestCache;
394 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
396 AddOnPostResolveRequestCacheAsync (bh, eh, null);
399 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
401 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
402 PostResolveRequestCache += new EventHandler (invoker.Invoke);
405 public event EventHandler PostMapRequestHandler;
406 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
408 AddOnPostMapRequestHandlerAsync (bh, eh, null);
411 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh, object data)
413 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
414 PostMapRequestHandler += new EventHandler (invoker.Invoke);
417 public event EventHandler PostAcquireRequestState;
418 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
420 AddOnPostAcquireRequestStateAsync (bh, eh, null);
423 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
425 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
426 PostAcquireRequestState += new EventHandler (invoker.Invoke);
429 public event EventHandler PostReleaseRequestState;
430 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
432 AddOnPostReleaseRequestStateAsync (bh, eh, null);
435 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
437 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
438 PostReleaseRequestState += new EventHandler (invoker.Invoke);
441 public event EventHandler PostUpdateRequestCache;
442 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
444 AddOnPostUpdateRequestCacheAsync (bh, eh, null);
447 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
449 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
450 PostUpdateRequestCache += new EventHandler (invoker.Invoke);
454 // The new overloads that take a data parameter
456 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
458 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
459 AcquireRequestState += new EventHandler (invoker.Invoke);
462 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
464 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
465 AuthenticateRequest += new EventHandler (invoker.Invoke);
468 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
470 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
471 AuthorizeRequest += new EventHandler (invoker.Invoke);
474 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
476 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
477 BeginRequest += new EventHandler (invoker.Invoke);
480 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
482 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
483 EndRequest += new EventHandler (invoker.Invoke);
486 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
488 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
489 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
492 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
494 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
495 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
498 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
500 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
501 ReleaseRequestState += new EventHandler (invoker.Invoke);
504 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
506 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
507 ResolveRequestCache += new EventHandler (invoker.Invoke);
510 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
512 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
513 UpdateRequestCache += new EventHandler (invoker.Invoke);
517 internal event EventHandler DefaultAuthentication;
520 // Bypass all the event on the Http pipeline and go directly to EndRequest
522 public void CompleteRequest ()
524 stop_processing = true;
527 public virtual void Dispose ()
529 if (modcoll != null) {
530 for (int i = modcoll.Count; i >= 0; i--) {
531 modcoll.Get (i).Dispose ();
536 if (Disposed != null)
537 Disposed (this, EventArgs.Empty);
543 public virtual string GetVaryByCustomString (HttpContext context, string custom)
545 if (custom == null) // Sigh
546 throw new NullReferenceException ();
548 if (0 == String.Compare (custom, "browser", true, CultureInfo.InvariantCulture))
549 return context.Request.Browser.Type;
555 // If we catch an error, queue this error
557 void ProcessError (Exception e)
559 bool first = context.Error == null;
561 context.AddError (e);
565 Error (this, EventArgs.Empty);
566 } catch (Exception ee){
567 context.AddError (ee);
571 stop_processing = true;
575 // Ticks the clock: next step on the pipeline.
580 // FIXME: We should use 'if' instead of 'while'!!
581 while (pipeline.MoveNext ()){
582 if ((bool)pipeline.Current) {
587 } catch (Exception e) {
588 Console.WriteLine ("Tick caught an exception that has not been propagated:\n" + e.GetType().FullName + e.Message + e.StackTrace);
601 // Invoked when our async callback called from RunHooks completes,
602 // we restart the pipeline here.
604 void async_callback_completed_cb (IAsyncResult ar)
606 if (current_ai.end != null){
609 } catch (Exception e) {
617 void async_handler_complete_cb (IAsyncResult ar)
619 IHttpAsyncHandler async_handler = ((IHttpAsyncHandler) ar.AsyncState);
622 async_handler.EndProcessRequest (ar);
623 } catch (Exception e){
631 // This enumerator yields whether processing must be stopped:
632 // true: processing of the pipeline must be stopped
633 // false: processing of the pipeline must not be stopped
635 internal class RunHooksEnumerator : IEnumerable, IEnumerator
637 Delegate [] delegates;
641 internal RunHooksEnumerator(HttpApplication app, Delegate list)
644 delegates = list.GetInvocationList ();
647 public virtual IEnumerator GetEnumerator() { return this; }
648 public virtual object Current { get{ return app.stop_processing; } }
649 public virtual void Reset()
651 throw new NotImplementedException("HttpApplication.RunHooksEnumerator.Reset called.");
653 public virtual bool MoveNext ()
655 while (currentStep < delegates.Length) {
656 if (ProcessDelegate((EventHandler)delegates[currentStep++]))
662 bool ProcessDelegate(EventHandler d)
664 if (d.Target != null && (d.Target is AsyncInvoker)){
665 app.current_ai = (AsyncInvoker) d.Target;
668 app.must_yield = true;
670 app.context.BeginTimeoutPossible ();
671 app.current_ai.begin (app, EventArgs.Empty, new AsyncCallback(app.async_callback_completed_cb), app.current_ai.data);
673 catch (ThreadAbortException taex){
674 object obj = taex.ExceptionState;
675 Thread.ResetAbort ();
676 app.stop_processing = true;
677 if (obj is StepTimeout)
678 app.ProcessError (new HttpException ("The request timed out."));
681 app.ProcessError (e);
684 app.in_begin = false;
685 app.context.EndTimeoutPossible ();
689 // If things are still moving forward, yield this
694 else if (app.stop_processing)
699 app.context.BeginTimeoutPossible ();
700 d (app, EventArgs.Empty);
701 } catch (ThreadAbortException taex){
702 object obj = taex.ExceptionState;
703 Thread.ResetAbort ();
704 app.stop_processing = true;
705 if (obj is StepTimeout)
706 app.ProcessError (new HttpException ("The request timed out."));
709 app.ProcessError (e);
712 app.context.EndTimeoutPossible ();
714 if (app.stop_processing)
721 IEnumerable RunHooks (Delegate list)
723 return new RunHooksEnumerator(this, list);
726 static void FinalErrorWrite (HttpResponse response, string error)
729 response.Write (error);
730 response.Flush (true);
738 if (context.Error == null){
740 context.Response.Flush (true);
741 } catch (Exception e){
742 context.AddError (e);
746 Exception error = context.Error;
748 HttpResponse response = context.Response;
750 if (!response.HeadersSent){
751 response.ClearHeaders ();
752 response.ClearContent ();
754 if (error is HttpException){
755 response.StatusCode = ((HttpException)error).GetHttpCode ();
757 error = new HttpException ("", error);
758 response.StatusCode = 500;
760 if (!RedirectCustomError ())
761 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
763 response.Flush (true);
765 if (!(error is HttpException))
766 error = new HttpException ("", error);
767 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
774 // Invoked at the end of the pipeline execution
779 if (EndRequest != null)
780 EndRequest (this, EventArgs.Empty);
781 } catch (Exception e){
788 } catch (Exception e) {
789 Console.WriteLine ("Internal error: OutputPage threw an exception " + e);
791 context.WorkerRequest.EndOfRequest();
792 if (begin_iar != null){
794 begin_iar.Complete ();
797 // TODO: if this throws an error, we have no way of reporting it
798 // Not really too bad, since the only failure might be
799 // `HttpRuntime.request_processed'
806 if (factory != null && context.Handler != null){
807 factory.ReleaseHandler (context.Handler);
811 context.Handler = null;
812 // context = null; -> moved to PostDone
819 class PipeLineEnumerator : IEnumerator
822 IEnumerator currentEnumerator = null;
824 bool pipelineFinished = false;
825 IHttpHandler handler = null;
827 InternalStepDelegate AllocateHandlerDel;
828 InternalStepDelegate ProcessHandlerDel;
829 InternalStepDelegate ReleaseHandlerDel;
831 // true means that we need to yield and return the current value;
832 // false means that we need to go on to the next delegate and return
833 // values from there.
834 delegate bool InternalStepDelegate();
836 internal PipeLineEnumerator(HttpApplication app)
839 AllocateHandlerDel = new InternalStepDelegate(AllocateHandler);
840 ProcessHandlerDel = new InternalStepDelegate(ProcessHandler);
841 ReleaseHandlerDel = new InternalStepDelegate(ReleaseHandler);
844 public virtual object Current
848 if (currentEnumerator != null)
849 return currentEnumerator.Current;
854 // See InternalStepDelegate for meaning of true/false return value
855 bool AllocateHandler()
857 // Obtain the handler for the request.
859 handler = app.GetHandler (app.context);
861 catch (FileNotFoundException fnf){
862 if (app.context.Request.IsLocal)
863 app.ProcessError (new HttpException (404, String.Format ("File not found {0}", fnf.FileName), fnf));
865 app.ProcessError (new HttpException (404, "File not found", fnf));
866 } catch (DirectoryNotFoundException dnf){
867 app.ProcessError (new HttpException (404, "Directory not found", dnf));
868 } catch (Exception e) {
869 app.ProcessError (e);
872 if (app.stop_processing) {
879 // See InternalStepDelegate for meaning of true/false return value
880 bool ProcessHandler()
883 // From this point on, we need to ensure that we call
884 // ReleaseRequestState, so the code below jumps to
885 // `release:' to guarantee it rather than yielding.
887 if (app.PreRequestHandlerExecute != null)
888 foreach (bool stop in app.RunHooks (app.PreRequestHandlerExecute))
893 app.context.BeginTimeoutPossible ();
894 if (handler != null){
895 IHttpAsyncHandler async_handler = handler as IHttpAsyncHandler;
897 if (async_handler != null){
898 app.must_yield = true;
900 async_handler.BeginProcessRequest (app.context, new AsyncCallback(app.async_handler_complete_cb), handler);
902 app.must_yield = false;
903 handler.ProcessRequest (app.context);
907 catch (ThreadAbortException taex){
908 object obj = taex.ExceptionState;
909 Thread.ResetAbort ();
910 app.stop_processing = true;
911 if (obj is StepTimeout)
912 app.ProcessError (new HttpException ("The request timed out."));
915 app.ProcessError (e);
918 app.in_begin = false;
919 app.context.EndTimeoutPossible ();
921 if (app.must_yield) {
922 currentVal = app.stop_processing;
925 else if (app.stop_processing)
928 // These are executed after the application has returned
929 if (app.PostRequestHandlerExecute != null)
930 foreach (bool stop in app.RunHooks (app.PostRequestHandlerExecute))
937 // See InternalStepDelegate for meaning of true/false return value
938 bool ReleaseHandler()
940 if (app.ReleaseRequestState != null){
941 foreach (bool stop in app.RunHooks (app.ReleaseRequestState)){
943 // Ignore the stop signal while release the state
948 if (app.stop_processing) {
955 Delegate FindNextDelegate ()
957 switch(currentStep++) {
958 case 1: return app.BeginRequest;
959 case 2: return app.AuthenticateRequest;
960 case 3: return app.DefaultAuthentication;
962 case 4: return app.PostAuthenticateRequest;
964 case 5: return app.AuthorizeRequest;
966 case 6: return app.PostAuthorizeRequest;
968 case 7: return app.ResolveRequestCache;
969 case 8: return AllocateHandlerDel;
971 case 9: return app.PostResolveRequestCache;
974 case 10: return app.PostMapRequestHandler;
976 case 11: return app.AcquireRequestState;
978 case 12: return app.PostAcquireRequestState;
980 case 13: return app.ResolveRequestCache;
981 case 14: return ProcessHandlerDel;
982 case 15: return ReleaseHandlerDel;
984 case 16: return app.PostReleaseRequestState;
986 case 17: return app.UpdateRequestCache;
988 case 18: return app.PostUpdateRequestCache;
990 case 19: pipelineFinished = true; return null;
995 public virtual bool MoveNext ()
997 while (!pipelineFinished) {
998 if (currentEnumerator != null && currentEnumerator.MoveNext())
1000 currentEnumerator = null;
1002 Delegate d = FindNextDelegate();
1003 InternalStepDelegate d1 = d as InternalStepDelegate;
1009 currentEnumerator = app.RunHooks(d).GetEnumerator();
1012 app.PipelineDone ();
1016 public virtual void Reset()
1018 throw new NotImplementedException("HttpApplication.PipelineEnumerator.Reset called.");
1022 IEnumerator Pipeline ()
1024 return new PipeLineEnumerator(this);
1030 HttpRuntime.TimeoutManager.Add (context);
1032 Thread th = Thread.CurrentThread;
1033 if (app_culture != null) {
1034 prev_app_culture = th.CurrentCulture;
1035 th.CurrentCulture = app_culture;
1038 if (appui_culture != null) {
1039 prev_appui_culture = th.CurrentUICulture;
1040 th.CurrentUICulture = appui_culture;
1044 prev_user = Thread.CurrentPrincipal;
1050 Thread th = Thread.CurrentThread;
1052 if (Thread.CurrentPrincipal != prev_user)
1053 Thread.CurrentPrincipal = prev_user;
1055 if (prev_appui_culture != null && prev_appui_culture != th.CurrentUICulture)
1056 th.CurrentUICulture = prev_appui_culture;
1057 if (prev_app_culture != null && prev_app_culture != th.CurrentCulture)
1058 th.CurrentCulture = prev_app_culture;
1061 HttpRuntime.TimeoutManager.Remove (context);
1065 HttpContext.Current = null;
1068 void Start (object x)
1072 stop_processing = false;
1073 pipeline = Pipeline ();
1077 // Used by HttpServerUtility.Execute
1078 internal IHttpHandler GetHandler (HttpContext context)
1080 HttpRequest request = context.Request;
1081 string verb = request.RequestType;
1082 string url = request.FilePath;
1084 HandlerFactoryConfiguration factory_config = (HandlerFactoryConfiguration) HttpContext.GetAppConfig ("system.web/httpHandlers");
1085 object o = factory_config.LocateHandler (verb, url);
1086 factory = o as IHttpHandlerFactory;
1087 IHttpHandler handler;
1089 if (factory == null) {
1090 handler = (IHttpHandler) o;
1092 handler = factory.GetHandler (context, verb, url, request.PhysicalPath);
1094 context.Handler = handler;
1099 void IHttpHandler.ProcessRequest (HttpContext context)
1102 this.context = context;
1110 // This is used by FireOnAppStart, when we init the application
1111 // as the context is required to be set at that point (the user
1112 // might call methods that require it on that hook).
1114 internal void SetContext (HttpContext context)
1116 this.context = context;
1119 internal void SetSession (HttpSessionState session)
1121 this.session = session;
1124 IAsyncResult IHttpAsyncHandler.BeginProcessRequest (HttpContext context, AsyncCallback cb, object extraData)
1126 this.context = context;
1129 begin_iar = new AsyncRequestState (done, cb, extraData);
1134 void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result)
1136 if (!result.IsCompleted)
1137 result.AsyncWaitHandle.WaitOne ();
1141 public virtual void Init ()
1145 bool IHttpHandler.IsReusable {
1152 internal void ClearError ()
1154 context.ClearError ();
1157 bool RedirectErrorPage (string error_page)
1159 if (context.Request.QueryString ["aspxerrorpath"] != null)
1162 Response.Redirect (error_page + "?aspxerrorpath=" + Request.Path, false);
1166 bool RedirectCustomError ()
1168 if (!context.IsCustomErrorEnabled)
1171 CustomErrorsConfig config = null;
1173 config = (CustomErrorsConfig) context.GetConfig ("system.web/customErrors");
1176 if (config == null) {
1177 if (context.ErrorPage != null)
1178 return RedirectErrorPage (context.ErrorPage);
1183 string redirect = config [context.Response.StatusCode];
1184 if (redirect == null) {
1185 redirect = context.ErrorPage;
1186 if (redirect == null)
1187 redirect = config.DefaultRedirect;
1190 if (redirect == null)
1193 return RedirectErrorPage (redirect);
1199 // Based on Fritz' Onion's AsyncRequestState class for asynchronous IHttpAsyncHandlers
1201 class AsyncRequestState : IAsyncResult {
1205 ManualResetEvent complete_event = null;
1207 internal AsyncRequestState (ManualResetEvent complete_event, AsyncCallback cb, object cb_data)
1210 this.cb_data = cb_data;
1211 this.complete_event = complete_event;
1214 internal void Complete ()
1220 complete_event.Set ();
1223 public object AsyncState {
1229 public bool CompletedSynchronously {
1235 public bool IsCompleted {
1241 public WaitHandle AsyncWaitHandle {
1243 return complete_event;
1248 #region Helper classes
1251 // A wrapper to keep track of begin/end pairs
1253 class AsyncInvoker {
1254 public BeginEventHandler begin;
1255 public EndEventHandler end;
1258 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, object d)
1265 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh)
1271 public void Invoke (object sender, EventArgs e)
1273 throw new Exception ("This is just a dummy");