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.Configuration;
69 using System.Globalization;
70 using System.Security.Permissions;
71 using System.Security.Principal;
72 using System.Threading;
73 using System.Web.Configuration;
74 using System.Web.SessionState;
77 namespace System.Web {
80 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
81 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
84 public class HttpApplication : IHttpAsyncHandler, IHttpHandler, IComponent, IDisposable {
86 HttpSessionState session;
89 // The source, and the exposed API (cache).
90 HttpModuleCollection modcoll;
92 string assemblyLocation;
95 // The factory for the handler currently running.
97 IHttpHandlerFactory factory;
100 // Whether the pipeline should be stopped
102 bool stop_processing;
107 IEnumerator pipeline;
109 // To flag when we are done processing a request from BeginProcessRequest.
110 ManualResetEvent done;
112 // The current IAsyncResult for the running async request handler in the pipeline
113 AsyncRequestState begin_iar;
115 // Tracks the current AsyncInvocation being dispatched
116 AsyncInvoker current_ai;
118 // We don't use the EventHandlerList here, but derived classes might do
119 EventHandlerList events;
121 // Culture and IPrincipal
122 CultureInfo app_culture;
123 CultureInfo appui_culture;
124 CultureInfo prev_app_culture;
125 CultureInfo prev_appui_culture;
126 IPrincipal prev_user;
128 static Exception initialization_exception;
132 // These are used to detect the case where the EndXXX method is invoked
133 // from within the BeginXXXX delegate, so we detect whether we kick the
134 // pipeline from here, or from the the RunHook routine
139 public HttpApplication ()
141 done = new ManualResetEvent (false);
144 internal void InitOnce (bool full_init)
151 HttpModulesSection modules;
152 modules = (HttpModulesSection) WebConfigurationManager.GetSection ("system.web/httpModules");
154 ModulesConfiguration modules;
156 modules = (ModulesConfiguration) HttpContext.GetAppConfig ("system.web/httpModules");
159 modcoll = modules.LoadModules (this);
162 HttpApplicationFactory.AttachEvents (this);
165 GlobalizationSection cfg;
166 cfg = (GlobalizationSection) WebConfigurationManager.GetSection ("system.web/globalization");
167 app_culture = cfg.GetCulture();
168 appui_culture = cfg.GetUICulture();
170 GlobalizationConfiguration cfg;
171 cfg = GlobalizationConfiguration.GetInstance (null);
173 app_culture = cfg.Culture;
174 appui_culture = cfg.UICulture;
180 internal string AssemblyLocation {
182 if (assemblyLocation == null)
183 assemblyLocation = GetType ().Assembly.Location;
184 return assemblyLocation;
189 internal static Exception InitializationException {
190 get { return initialization_exception; }
195 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
196 public HttpApplicationState Application {
198 return HttpApplicationFactory.ApplicationState;
203 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
204 public HttpContext Context {
210 protected EventHandlerList Events {
213 events = new EventHandlerList ();
220 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
221 public HttpModuleCollection Modules {
222 [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
225 modcoll = new HttpModuleCollection ();
232 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
233 public HttpRequest Request {
236 throw new HttpException (Locale.GetText ("No context is available."));
238 if (false == HttpApplicationFactory.ContextAvailable)
239 throw new HttpException (Locale.GetText ("Request is not available in this context."));
241 return context.Request;
246 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
247 public HttpResponse Response {
250 throw new HttpException (Locale.GetText ("No context is available."));
252 if (false == HttpApplicationFactory.ContextAvailable)
253 throw new HttpException (Locale.GetText ("Response is not available in this context."));
255 return context.Response;
260 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
261 public HttpServerUtility Server {
264 return context.Server;
267 // This is so we can get the Server and call a few methods
268 // which are not context sensitive, see HttpServerUtilityTest
270 return new HttpServerUtility ((HttpContext) null);
275 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
276 public HttpSessionState Session {
278 // Only used for Session_End
283 throw new HttpException (Locale.GetText ("No context is available."));
284 return context.Session;
289 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
293 public virtual ISite Site {
305 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
306 public IPrincipal User {
309 throw new HttpException (Locale.GetText ("No context is available."));
310 if (context.User == null)
311 throw new HttpException (Locale.GetText ("No currently authenticated user."));
317 public virtual event EventHandler Disposed;
318 public virtual event EventHandler Error;
320 public event EventHandler PreSendRequestHeaders;
321 internal void TriggerPreSendRequestHeaders ()
323 if (PreSendRequestHeaders != null)
324 PreSendRequestHeaders (this, EventArgs.Empty);
327 public event EventHandler PreSendRequestContent;
328 internal void TriggerPreSendRequestContent ()
330 if (PreSendRequestContent != null)
331 PreSendRequestContent (this, EventArgs.Empty);
334 public event EventHandler AcquireRequestState;
335 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
337 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
338 AcquireRequestState += new EventHandler (invoker.Invoke);
341 public event EventHandler AuthenticateRequest;
342 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
344 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
345 AuthenticateRequest += new EventHandler (invoker.Invoke);
348 public event EventHandler AuthorizeRequest;
349 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
351 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
352 AuthorizeRequest += new EventHandler (invoker.Invoke);
355 public event EventHandler BeginRequest;
356 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh)
358 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
359 BeginRequest += new EventHandler (invoker.Invoke);
362 public event EventHandler EndRequest;
363 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh)
365 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
366 EndRequest += new EventHandler (invoker.Invoke);
369 public event EventHandler PostRequestHandlerExecute;
370 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
372 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
373 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
376 public event EventHandler PreRequestHandlerExecute;
377 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
379 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
380 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
383 public event EventHandler ReleaseRequestState;
384 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
386 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
387 ReleaseRequestState += new EventHandler (invoker.Invoke);
390 public event EventHandler ResolveRequestCache;
391 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
393 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
394 ResolveRequestCache += new EventHandler (invoker.Invoke);
397 public event EventHandler UpdateRequestCache;
398 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
400 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
401 UpdateRequestCache += new EventHandler (invoker.Invoke);
405 public event EventHandler PostAuthenticateRequest;
406 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
408 AddOnPostAuthenticateRequestAsync (bh, eh, null);
411 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
413 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
414 PostAuthenticateRequest += new EventHandler (invoker.Invoke);
417 public event EventHandler PostAuthorizeRequest;
418 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
420 AddOnPostAuthorizeRequestAsync (bh, eh, null);
423 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
425 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
426 PostAuthorizeRequest += new EventHandler (invoker.Invoke);
429 public event EventHandler PostResolveRequestCache;
430 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
432 AddOnPostResolveRequestCacheAsync (bh, eh, null);
435 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
437 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
438 PostResolveRequestCache += new EventHandler (invoker.Invoke);
441 public event EventHandler PostMapRequestHandler;
442 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
444 AddOnPostMapRequestHandlerAsync (bh, eh, null);
447 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh, object data)
449 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
450 PostMapRequestHandler += new EventHandler (invoker.Invoke);
453 public event EventHandler PostAcquireRequestState;
454 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
456 AddOnPostAcquireRequestStateAsync (bh, eh, null);
459 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
461 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
462 PostAcquireRequestState += new EventHandler (invoker.Invoke);
465 public event EventHandler PostReleaseRequestState;
466 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
468 AddOnPostReleaseRequestStateAsync (bh, eh, null);
471 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
473 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
474 PostReleaseRequestState += new EventHandler (invoker.Invoke);
477 public event EventHandler PostUpdateRequestCache;
478 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
480 AddOnPostUpdateRequestCacheAsync (bh, eh, null);
483 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
485 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
486 PostUpdateRequestCache += new EventHandler (invoker.Invoke);
490 // The new overloads that take a data parameter
492 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
494 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
495 AcquireRequestState += new EventHandler (invoker.Invoke);
498 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
500 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
501 AuthenticateRequest += new EventHandler (invoker.Invoke);
504 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
506 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
507 AuthorizeRequest += new EventHandler (invoker.Invoke);
510 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
512 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
513 BeginRequest += new EventHandler (invoker.Invoke);
516 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
518 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
519 EndRequest += new EventHandler (invoker.Invoke);
522 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
524 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
525 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
528 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
530 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
531 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
534 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
536 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
537 ReleaseRequestState += new EventHandler (invoker.Invoke);
540 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
542 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
543 ResolveRequestCache += new EventHandler (invoker.Invoke);
546 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
548 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
549 UpdateRequestCache += new EventHandler (invoker.Invoke);
553 internal event EventHandler DefaultAuthentication;
556 // Bypass all the event on the Http pipeline and go directly to EndRequest
558 public void CompleteRequest ()
560 stop_processing = true;
563 internal bool RequestCompleted {
564 set { stop_processing = value; }
567 public virtual void Dispose ()
569 if (modcoll != null) {
570 for (int i = modcoll.Count; i >= 0; i--) {
571 modcoll.Get (i).Dispose ();
576 if (Disposed != null)
577 Disposed (this, EventArgs.Empty);
583 public virtual string GetVaryByCustomString (HttpContext context, string custom)
585 if (custom == null) // Sigh
586 throw new NullReferenceException ();
588 if (0 == String.Compare (custom, "browser", true, CultureInfo.InvariantCulture))
589 return context.Request.Browser.Type;
595 // If we catch an error, queue this error
597 void ProcessError (Exception e)
599 bool first = context.Error == null;
601 context.AddError (e);
605 Error (this, EventArgs.Empty);
606 } catch (ThreadAbortException ee){
607 // This happens on Redirect() or End()
608 Thread.ResetAbort ();
609 } catch (Exception ee){
610 context.AddError (ee);
614 stop_processing = true;
618 // Ticks the clock: next step on the pipeline.
623 if (pipeline.MoveNext ()){
624 if ((bool)pipeline.Current)
627 } catch (Exception e) {
628 Console.WriteLine ("Tick caught an exception that has not been propagated:\n" + e);
641 // Invoked when our async callback called from RunHooks completes,
642 // we restart the pipeline here.
644 void async_callback_completed_cb (IAsyncResult ar)
646 if (current_ai.end != null){
649 } catch (Exception e) {
657 void async_handler_complete_cb (IAsyncResult ar)
659 IHttpAsyncHandler async_handler = ((IHttpAsyncHandler) ar.AsyncState);
662 async_handler.EndProcessRequest (ar);
663 } catch (Exception e){
671 // This enumerator yields whether processing must be stopped:
672 // true: processing of the pipeline must be stopped
673 // false: processing of the pipeline must not be stopped
675 IEnumerable RunHooks (Delegate list)
677 Delegate [] delegates = list.GetInvocationList ();
679 foreach (EventHandler d in delegates){
680 if (d.Target != null && (d.Target is AsyncInvoker)){
681 current_ai = (AsyncInvoker) d.Target;
686 context.BeginTimeoutPossible ();
687 current_ai.begin (this, EventArgs.Empty, async_callback_completed_cb, current_ai.data);
688 } catch (ThreadAbortException taex){
689 object obj = taex.ExceptionState;
690 Thread.ResetAbort ();
691 stop_processing = true;
692 if (obj is StepTimeout)
693 ProcessError (new HttpException ("The request timed out."));
694 } catch (Exception e){
698 context.EndTimeoutPossible ();
702 // If things are still moving forward, yield this
706 yield return stop_processing;
707 else if (stop_processing)
711 context.BeginTimeoutPossible ();
712 d (this, EventArgs.Empty);
713 } catch (ThreadAbortException taex){
714 object obj = taex.ExceptionState;
715 Thread.ResetAbort ();
716 stop_processing = true;
717 if (obj is StepTimeout)
718 ProcessError (new HttpException ("The request timed out."));
719 } catch (Exception e){
722 context.EndTimeoutPossible ();
730 static void FinalErrorWrite (HttpResponse response, string error)
733 response.Write (error);
734 response.Flush (true);
742 if (context.Error == null){
744 context.Response.Flush (true);
745 } catch (Exception e){
746 context.AddError (e);
750 Exception error = context.Error;
752 HttpResponse response = context.Response;
754 if (!response.HeadersSent){
755 response.ClearHeaders ();
756 response.ClearContent ();
758 if (error is HttpException){
759 response.StatusCode = ((HttpException)error).GetHttpCode ();
761 error = new HttpException ("", error);
762 response.StatusCode = 500;
764 if (!RedirectCustomError ())
765 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
767 response.Flush (true);
769 if (!(error is HttpException))
770 error = new HttpException ("", error);
771 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
778 // Invoked at the end of the pipeline execution
783 if (EndRequest != null)
784 EndRequest (this, EventArgs.Empty);
785 } catch (Exception e){
792 } catch (Exception e) {
793 Console.WriteLine ("Internal error: OutputPage threw an exception " + e);
795 context.WorkerRequest.EndOfRequest();
796 if (begin_iar != null){
798 begin_iar.Complete ();
801 // TODO: if this throws an error, we have no way of reporting it
802 // Not really too bad, since the only failure might be
803 // `HttpRuntime.request_processed'
810 if (factory != null && context.Handler != null){
811 factory.ReleaseHandler (context.Handler);
815 context.Handler = null;
816 // context = null; -> moved to PostDone
824 // Events fired as described in `Http Runtime Support, HttpModules,
825 // Handling Public Events'
827 IEnumerator Pipeline ()
832 if (BeginRequest != null)
833 foreach (bool stop in RunHooks (BeginRequest))
836 if (AuthenticateRequest != null)
837 foreach (bool stop in RunHooks (AuthenticateRequest))
840 if (DefaultAuthentication != null)
841 foreach (bool stop in RunHooks (DefaultAuthentication))
845 if (PostAuthenticateRequest != null)
846 foreach (bool stop in RunHooks (AuthenticateRequest))
849 if (AuthorizeRequest != null)
850 foreach (bool stop in RunHooks (AuthorizeRequest))
853 if (PostAuthorizeRequest != null)
854 foreach (bool stop in RunHooks (PostAuthorizeRequest))
858 if (ResolveRequestCache != null)
859 foreach (bool stop in RunHooks (ResolveRequestCache))
862 // Obtain the handler for the request.
863 IHttpHandler handler = null;
865 handler = GetHandler (context);
866 } catch (FileNotFoundException fnf){
867 if (context.Request.IsLocal)
868 ProcessError (new HttpException (404, String.Format ("File not found {0}", fnf.FileName), fnf));
870 ProcessError (new HttpException (404, "File not found", fnf));
871 } catch (DirectoryNotFoundException dnf){
872 ProcessError (new HttpException (404, "Directory not found", dnf));
873 } catch (Exception e) {
881 if (PostResolveRequestCache != null)
882 foreach (bool stop in RunHooks (PostResolveRequestCache))
885 if (PostMapRequestHandler != null)
886 foreach (bool stop in RunHooks (PostMapRequestHandler))
890 if (AcquireRequestState != null){
891 foreach (bool stop in RunHooks (AcquireRequestState))
896 if (PostAcquireRequestState != null){
897 foreach (bool stop in RunHooks (PostAcquireRequestState))
903 // From this point on, we need to ensure that we call
904 // ReleaseRequestState, so the code below jumps to
905 // `release:' to guarantee it rather than yielding.
907 if (PreRequestHandlerExecute != null)
908 foreach (bool stop in RunHooks (PreRequestHandlerExecute))
913 context.BeginTimeoutPossible ();
914 if (handler != null){
915 IHttpAsyncHandler async_handler = handler as IHttpAsyncHandler;
917 if (async_handler != null){
920 async_handler.BeginProcessRequest (context, async_handler_complete_cb, handler);
923 handler.ProcessRequest (context);
926 } catch (ThreadAbortException taex){
927 object obj = taex.ExceptionState;
928 Thread.ResetAbort ();
929 stop_processing = true;
930 if (obj is StepTimeout)
931 ProcessError (new HttpException ("The request timed out."));
932 } catch (Exception e){
936 context.EndTimeoutPossible ();
939 yield return stop_processing;
940 else if (stop_processing)
943 // These are executed after the application has returned
945 if (PostRequestHandlerExecute != null)
946 foreach (bool stop in RunHooks (PostRequestHandlerExecute))
951 if (ReleaseRequestState != null){
952 #pragma warning disable 168
953 foreach (bool stop in RunHooks (ReleaseRequestState)){
955 // Ignore the stop signal while release the state
959 #pragma warning restore 168
966 if (PostReleaseRequestState != null)
967 foreach (bool stop in RunHooks (PostReleaseRequestState))
971 if (context.Error == null)
972 context.Response.DoFilter (true);
974 if (UpdateRequestCache != null)
975 foreach (bool stop in RunHooks (UpdateRequestCache))
979 if (PostUpdateRequestCache != null)
980 foreach (bool stop in RunHooks (PostUpdateRequestCache))
989 HttpRuntime.TimeoutManager.Add (context);
991 Thread th = Thread.CurrentThread;
992 if (app_culture != null) {
993 prev_app_culture = th.CurrentCulture;
994 th.CurrentCulture = app_culture;
997 if (appui_culture != null) {
998 prev_appui_culture = th.CurrentUICulture;
999 th.CurrentUICulture = appui_culture;
1003 prev_user = Thread.CurrentPrincipal;
1009 Thread th = Thread.CurrentThread;
1011 if (Thread.CurrentPrincipal != prev_user)
1012 Thread.CurrentPrincipal = prev_user;
1014 if (prev_appui_culture != null && prev_appui_culture != th.CurrentUICulture)
1015 th.CurrentUICulture = prev_appui_culture;
1016 if (prev_app_culture != null && prev_app_culture != th.CurrentCulture)
1017 th.CurrentCulture = prev_app_culture;
1020 HttpRuntime.TimeoutManager.Remove (context);
1024 HttpContext.Current = null;
1027 void Start (object x)
1031 } catch (Exception e) {
1033 initialization_exception = e;
1035 FinalErrorWrite (context.Response, new HttpException ("", e).GetHtmlErrorMessage ());
1040 pipeline = Pipeline ();
1044 // Used by HttpServerUtility.Execute
1045 internal IHttpHandler GetHandler (HttpContext context)
1047 HttpRequest request = context.Request;
1048 string verb = request.RequestType;
1049 string url = request.FilePath;
1051 IHttpHandler handler = null;
1053 HttpHandlersSection section = (HttpHandlersSection) WebConfigurationManager.GetSection ("system.web/httpHandlers");
1054 object o = section.LocateHandler (verb, url);
1056 HandlerFactoryConfiguration factory_config = (HandlerFactoryConfiguration) HttpContext.GetAppConfig ("system.web/httpHandlers");
1057 object o = factory_config.LocateHandler (verb, url);
1060 factory = o as IHttpHandlerFactory;
1062 if (factory == null) {
1063 handler = (IHttpHandler) o;
1065 handler = factory.GetHandler (context, verb, url, request.PhysicalPath);
1067 context.Handler = handler;
1072 void IHttpHandler.ProcessRequest (HttpContext context)
1075 this.context = context;
1083 // This is used by FireOnAppStart, when we init the application
1084 // as the context is required to be set at that point (the user
1085 // might call methods that require it on that hook).
1087 internal void SetContext (HttpContext context)
1089 this.context = context;
1092 internal void SetSession (HttpSessionState session)
1094 this.session = session;
1097 IAsyncResult IHttpAsyncHandler.BeginProcessRequest (HttpContext context, AsyncCallback cb, object extraData)
1099 this.context = context;
1102 begin_iar = new AsyncRequestState (done, cb, extraData);
1104 if (Thread.CurrentThread.IsThreadPoolThread)
1107 ThreadPool.QueueUserWorkItem (new WaitCallback (Start), null);
1112 void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result)
1114 if (!result.IsCompleted)
1115 result.AsyncWaitHandle.WaitOne ();
1119 public virtual void Init ()
1123 bool IHttpHandler.IsReusable {
1130 internal void ClearError ()
1132 context.ClearError ();
1135 bool RedirectErrorPage (string error_page)
1137 if (context.Request.QueryString ["aspxerrorpath"] != null)
1140 Response.Redirect (error_page + "?aspxerrorpath=" + Request.Path, false);
1144 bool RedirectCustomError ()
1146 if (!context.IsCustomErrorEnabled)
1150 CustomErrorsSection config = (CustomErrorsSection)WebConfigurationManager.GetSection ("system.web/customErrors");
1152 CustomErrorsConfig config = null;
1154 config = (CustomErrorsConfig) context.GetConfig ("system.web/customErrors");
1158 if (config == null) {
1159 if (context.ErrorPage != null)
1160 return RedirectErrorPage (context.ErrorPage);
1166 CustomError err = config.Errors [context.Response.StatusCode.ToString()];
1167 string redirect = err == null ? null : err.Redirect;
1169 string redirect = config [context.Response.StatusCode];
1171 if (redirect == null) {
1172 redirect = context.ErrorPage;
1173 if (redirect == null)
1174 redirect = config.DefaultRedirect;
1177 if (redirect == null)
1180 return RedirectErrorPage (redirect);
1186 // Based on Fritz' Onion's AsyncRequestState class for asynchronous IHttpAsyncHandlers
1188 class AsyncRequestState : IAsyncResult {
1192 ManualResetEvent complete_event = null;
1194 internal AsyncRequestState (ManualResetEvent complete_event, AsyncCallback cb, object cb_data)
1197 this.cb_data = cb_data;
1198 this.complete_event = complete_event;
1201 internal void Complete ()
1207 complete_event.Set ();
1210 public object AsyncState {
1216 public bool CompletedSynchronously {
1222 public bool IsCompleted {
1228 public WaitHandle AsyncWaitHandle {
1230 return complete_event;
1235 #region Helper classes
1238 // A wrapper to keep track of begin/end pairs
1240 class AsyncInvoker {
1241 public BeginEventHandler begin;
1242 public EndEventHandler end;
1245 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, object d)
1252 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh)
1258 public void Invoke (object sender, EventArgs e)
1260 throw new Exception ("This is just a dummy");