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 - 1; 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)
600 context = HttpContext.Current;
602 bool first = context.Error == null;
603 context.AddError (e);
607 Error (this, EventArgs.Empty);
608 } catch (ThreadAbortException ee){
609 // This happens on Redirect() or End()
610 Thread.ResetAbort ();
611 } catch (Exception ee){
612 context.AddError (ee);
616 stop_processing = true;
620 // Ticks the clock: next step on the pipeline.
625 if (pipeline != null && pipeline.MoveNext ()){
626 if (pipeline == null || (bool)pipeline.Current)
629 } catch (Exception e) {
630 Console.WriteLine ("Tick caught an exception that has not been propagated:\n" + e);
643 // Invoked when our async callback called from RunHooks completes,
644 // we restart the pipeline here.
646 void async_callback_completed_cb (IAsyncResult ar)
648 if (current_ai.end != null){
651 } catch (Exception e) {
659 void async_handler_complete_cb (IAsyncResult ar)
661 IHttpAsyncHandler async_handler = ((IHttpAsyncHandler) ar.AsyncState);
664 async_handler.EndProcessRequest (ar);
665 } catch (Exception e){
673 // This enumerator yields whether processing must be stopped:
674 // true: processing of the pipeline must be stopped
675 // false: processing of the pipeline must not be stopped
677 IEnumerable RunHooks (Delegate list)
679 Delegate [] delegates = list.GetInvocationList ();
681 foreach (EventHandler d in delegates){
682 if (d.Target != null && (d.Target is AsyncInvoker)){
683 current_ai = (AsyncInvoker) d.Target;
688 context.BeginTimeoutPossible ();
689 current_ai.begin (this, EventArgs.Empty, async_callback_completed_cb, current_ai.data);
690 } catch (ThreadAbortException taex){
691 object obj = taex.ExceptionState;
692 Thread.ResetAbort ();
693 stop_processing = true;
694 if (obj is StepTimeout)
695 ProcessError (new HttpException ("The request timed out."));
696 } catch (Exception e){
700 context.EndTimeoutPossible ();
704 // If things are still moving forward, yield this
708 yield return stop_processing;
709 else if (stop_processing)
713 context.BeginTimeoutPossible ();
714 d (this, EventArgs.Empty);
715 } catch (ThreadAbortException taex){
716 object obj = taex.ExceptionState;
717 Thread.ResetAbort ();
718 stop_processing = true;
719 if (obj is StepTimeout)
720 ProcessError (new HttpException ("The request timed out."));
721 } catch (Exception e){
724 context.EndTimeoutPossible ();
732 static void FinalErrorWrite (HttpResponse response, string error)
735 response.Write (error);
736 response.Flush (true);
744 if (context.Error == null){
746 context.Response.Flush (true);
747 } catch (Exception e){
748 context.AddError (e);
752 Exception error = context.Error;
754 HttpResponse response = context.Response;
756 if (!response.HeadersSent){
757 response.ClearHeaders ();
758 response.ClearContent ();
760 if (error is HttpException){
761 response.StatusCode = ((HttpException)error).GetHttpCode ();
763 error = new HttpException ("", error);
764 response.StatusCode = 500;
766 if (!RedirectCustomError ())
767 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
769 response.Flush (true);
771 if (!(error is HttpException))
772 error = new HttpException ("", error);
773 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
780 // Invoked at the end of the pipeline execution
785 if (EndRequest != null)
786 EndRequest (this, EventArgs.Empty);
787 } catch (Exception e){
793 } catch (Exception e) {
794 Console.WriteLine ("Internal error: OutputPage threw an exception " + e);
797 context = HttpContext.Current;
798 context.WorkerRequest.EndOfRequest();
799 if (factory != null && context.Handler != null){
800 factory.ReleaseHandler (context.Handler);
801 context.Handler = null;
805 if (begin_iar != null){
807 begin_iar.Complete ();
810 // TODO: if this throws an error, we have no way of reporting it
811 // Not really too bad, since the only failure might be
812 // `HttpRuntime.request_processed'
821 // context = null; -> moved to PostDone
829 // Events fired as described in `Http Runtime Support, HttpModules,
830 // Handling Public Events'
832 IEnumerator Pipeline ()
837 if (BeginRequest != null)
838 foreach (bool stop in RunHooks (BeginRequest))
841 if (AuthenticateRequest != null)
842 foreach (bool stop in RunHooks (AuthenticateRequest))
845 if (DefaultAuthentication != null)
846 foreach (bool stop in RunHooks (DefaultAuthentication))
850 if (PostAuthenticateRequest != null)
851 foreach (bool stop in RunHooks (PostAuthenticateRequest))
854 if (AuthorizeRequest != null)
855 foreach (bool stop in RunHooks (AuthorizeRequest))
858 if (PostAuthorizeRequest != null)
859 foreach (bool stop in RunHooks (PostAuthorizeRequest))
863 if (ResolveRequestCache != null)
864 foreach (bool stop in RunHooks (ResolveRequestCache))
867 // Obtain the handler for the request.
868 IHttpHandler handler = null;
870 handler = GetHandler (context);
871 context.Handler = handler;
872 } catch (FileNotFoundException fnf){
873 if (context.Request.IsLocal)
874 ProcessError (new HttpException (404, String.Format ("File not found {0}", fnf.FileName), fnf));
876 ProcessError (new HttpException (404, "File not found: " + Path.GetFileName (fnf.FileName)));
877 } catch (DirectoryNotFoundException dnf){
878 ProcessError (new HttpException (404, "Directory not found", dnf));
879 } catch (Exception e) {
887 if (PostResolveRequestCache != null)
888 foreach (bool stop in RunHooks (PostResolveRequestCache))
891 if (PostMapRequestHandler != null)
892 foreach (bool stop in RunHooks (PostMapRequestHandler))
896 if (AcquireRequestState != null){
897 foreach (bool stop in RunHooks (AcquireRequestState))
902 if (PostAcquireRequestState != null){
903 foreach (bool stop in RunHooks (PostAcquireRequestState))
909 // From this point on, we need to ensure that we call
910 // ReleaseRequestState, so the code below jumps to
911 // `release:' to guarantee it rather than yielding.
913 if (PreRequestHandlerExecute != null)
914 foreach (bool stop in RunHooks (PreRequestHandlerExecute))
919 context.BeginTimeoutPossible ();
920 if (handler != null){
921 IHttpAsyncHandler async_handler = handler as IHttpAsyncHandler;
923 if (async_handler != null){
926 async_handler.BeginProcessRequest (context, async_handler_complete_cb, handler);
929 handler.ProcessRequest (context);
932 } catch (ThreadAbortException taex){
933 object obj = taex.ExceptionState;
934 Thread.ResetAbort ();
935 stop_processing = true;
936 if (obj is StepTimeout)
937 ProcessError (new HttpException ("The request timed out."));
938 } catch (Exception e){
942 context.EndTimeoutPossible ();
945 yield return stop_processing;
946 else if (stop_processing)
949 // These are executed after the application has returned
951 if (PostRequestHandlerExecute != null)
952 foreach (bool stop in RunHooks (PostRequestHandlerExecute))
957 if (ReleaseRequestState != null){
958 #pragma warning disable 168
959 foreach (bool stop in RunHooks (ReleaseRequestState)){
961 // Ignore the stop signal while release the state
965 #pragma warning restore 168
972 if (PostReleaseRequestState != null)
973 foreach (bool stop in RunHooks (PostReleaseRequestState))
977 if (context.Error == null)
978 context.Response.DoFilter (true);
980 if (UpdateRequestCache != null)
981 foreach (bool stop in RunHooks (UpdateRequestCache))
985 if (PostUpdateRequestCache != null)
986 foreach (bool stop in RunHooks (PostUpdateRequestCache))
995 HttpRuntime.TimeoutManager.Add (context);
997 Thread th = Thread.CurrentThread;
998 if (app_culture != null) {
999 prev_app_culture = th.CurrentCulture;
1000 th.CurrentCulture = app_culture;
1003 if (appui_culture != null) {
1004 prev_appui_culture = th.CurrentUICulture;
1005 th.CurrentUICulture = appui_culture;
1009 prev_user = Thread.CurrentPrincipal;
1015 Thread th = Thread.CurrentThread;
1017 if (Thread.CurrentPrincipal != prev_user)
1018 Thread.CurrentPrincipal = prev_user;
1020 if (prev_appui_culture != null && prev_appui_culture != th.CurrentUICulture)
1021 th.CurrentUICulture = prev_appui_culture;
1022 if (prev_app_culture != null && prev_app_culture != th.CurrentCulture)
1023 th.CurrentCulture = prev_app_culture;
1026 if (context == null)
1027 context = HttpContext.Current;
1028 HttpRuntime.TimeoutManager.Remove (context);
1032 HttpContext.Current = null;
1035 void Start (object x)
1039 } catch (Exception e) {
1041 initialization_exception = e;
1043 FinalErrorWrite (context.Response, new HttpException ("", e).GetHtmlErrorMessage ());
1047 HttpContext.Current = Context;
1049 pipeline = Pipeline ();
1053 // Used by HttpServerUtility.Execute
1054 internal IHttpHandler GetHandler (HttpContext context)
1056 HttpRequest request = context.Request;
1057 string verb = request.RequestType;
1058 string url = request.FilePath;
1060 IHttpHandler handler = null;
1062 HttpHandlersSection section = (HttpHandlersSection) WebConfigurationManager.GetSection ("system.web/httpHandlers");
1063 object o = section.LocateHandler (verb, url);
1065 HandlerFactoryConfiguration factory_config = (HandlerFactoryConfiguration) HttpContext.GetAppConfig ("system.web/httpHandlers");
1066 object o = factory_config.LocateHandler (verb, url);
1069 factory = o as IHttpHandlerFactory;
1071 if (factory == null) {
1072 handler = (IHttpHandler) o;
1074 handler = factory.GetHandler (context, verb, url, request.PhysicalPath);
1080 void IHttpHandler.ProcessRequest (HttpContext context)
1083 this.context = context;
1091 // This is used by FireOnAppStart, when we init the application
1092 // as the context is required to be set at that point (the user
1093 // might call methods that require it on that hook).
1095 internal void SetContext (HttpContext context)
1097 this.context = context;
1100 internal void SetSession (HttpSessionState session)
1102 this.session = session;
1105 IAsyncResult IHttpAsyncHandler.BeginProcessRequest (HttpContext context, AsyncCallback cb, object extraData)
1107 this.context = context;
1110 begin_iar = new AsyncRequestState (done, cb, extraData);
1114 if (Thread.CurrentThread.IsThreadPoolThread)
1118 ThreadPool.QueueUserWorkItem (new WaitCallback (Start), null);
1123 void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result)
1125 if (!result.IsCompleted)
1126 result.AsyncWaitHandle.WaitOne ();
1130 public virtual void Init ()
1134 bool IHttpHandler.IsReusable {
1141 internal void ClearError ()
1143 context.ClearError ();
1146 bool RedirectErrorPage (string error_page)
1148 if (context.Request.QueryString ["aspxerrorpath"] != null)
1151 Response.Redirect (error_page + "?aspxerrorpath=" + Request.Path, false);
1155 bool RedirectCustomError ()
1157 if (!context.IsCustomErrorEnabled)
1161 CustomErrorsSection config = (CustomErrorsSection)WebConfigurationManager.GetSection ("system.web/customErrors");
1163 CustomErrorsConfig config = null;
1165 config = (CustomErrorsConfig) context.GetConfig ("system.web/customErrors");
1169 if (config == null) {
1170 if (context.ErrorPage != null)
1171 return RedirectErrorPage (context.ErrorPage);
1177 CustomError err = config.Errors [context.Response.StatusCode.ToString()];
1178 string redirect = err == null ? null : err.Redirect;
1180 string redirect = config [context.Response.StatusCode];
1182 if (redirect == null) {
1183 redirect = context.ErrorPage;
1184 if (redirect == null)
1185 redirect = config.DefaultRedirect;
1188 if (redirect == null)
1191 return RedirectErrorPage (redirect);
1197 // Based on Fritz' Onion's AsyncRequestState class for asynchronous IHttpAsyncHandlers
1199 class AsyncRequestState : IAsyncResult {
1203 ManualResetEvent complete_event = null;
1205 internal AsyncRequestState (ManualResetEvent complete_event, AsyncCallback cb, object cb_data)
1208 this.cb_data = cb_data;
1209 this.complete_event = complete_event;
1212 internal void Complete ()
1218 complete_event.Set ();
1221 public object AsyncState {
1227 public bool CompletedSynchronously {
1233 public bool IsCompleted {
1239 public WaitHandle AsyncWaitHandle {
1241 return complete_event;
1246 #region Helper classes
1249 // A wrapper to keep track of begin/end pairs
1251 class AsyncInvoker {
1252 public BeginEventHandler begin;
1253 public EndEventHandler end;
1256 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, object d)
1263 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh)
1269 public void Invoke (object sender, EventArgs e)
1271 throw new Exception ("This is just a dummy");