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 thread culture is to be auto-set.
101 // Used only in the 2.0 profile, always false for 1.x
107 // Whether the pipeline should be stopped
109 bool stop_processing;
114 IEnumerator pipeline;
116 // To flag when we are done processing a request from BeginProcessRequest.
117 ManualResetEvent done;
119 // The current IAsyncResult for the running async request handler in the pipeline
120 AsyncRequestState begin_iar;
122 // Tracks the current AsyncInvocation being dispatched
123 AsyncInvoker current_ai;
125 // We don't use the EventHandlerList here, but derived classes might do
126 EventHandlerList events;
128 // Culture and IPrincipal
129 CultureInfo app_culture;
130 CultureInfo appui_culture;
131 CultureInfo prev_app_culture;
132 CultureInfo prev_appui_culture;
133 IPrincipal prev_user;
135 static Exception initialization_exception;
139 // These are used to detect the case where the EndXXX method is invoked
140 // from within the BeginXXXX delegate, so we detect whether we kick the
141 // pipeline from here, or from the the RunHook routine
146 public HttpApplication ()
148 done = new ManualResetEvent (false);
151 internal void InitOnce (bool full_init)
158 HttpModulesSection modules;
159 modules = (HttpModulesSection) WebConfigurationManager.GetSection ("system.web/httpModules");
161 ModulesConfiguration modules;
163 modules = (ModulesConfiguration) HttpContext.GetAppConfig ("system.web/httpModules");
166 modcoll = modules.LoadModules (this);
169 HttpApplicationFactory.AttachEvents (this);
172 GlobalizationSection cfg;
173 cfg = (GlobalizationSection) WebConfigurationManager.GetSection ("system.web/globalization");
174 app_culture = cfg.GetCulture();
175 autoCulture = cfg.IsAutoCulture;
176 appui_culture = cfg.GetUICulture();
177 autoUICulture = cfg.IsAutoUICulture;
179 GlobalizationConfiguration cfg;
180 cfg = GlobalizationConfiguration.GetInstance (null);
182 app_culture = cfg.Culture;
183 appui_culture = cfg.UICulture;
189 internal string AssemblyLocation {
191 if (assemblyLocation == null)
192 assemblyLocation = GetType ().Assembly.Location;
193 return assemblyLocation;
198 internal static Exception InitializationException {
199 get { return initialization_exception; }
204 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
205 public HttpApplicationState Application {
207 return HttpApplicationFactory.ApplicationState;
212 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
213 public HttpContext Context {
219 protected EventHandlerList Events {
222 events = new EventHandlerList ();
229 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
230 public HttpModuleCollection Modules {
231 [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
234 modcoll = new HttpModuleCollection ();
241 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
242 public HttpRequest Request {
245 throw new HttpException (Locale.GetText ("No context is available."));
247 if (false == HttpApplicationFactory.ContextAvailable)
248 throw new HttpException (Locale.GetText ("Request is not available in this context."));
250 return context.Request;
255 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
256 public HttpResponse Response {
259 throw new HttpException (Locale.GetText ("No context is available."));
261 if (false == HttpApplicationFactory.ContextAvailable)
262 throw new HttpException (Locale.GetText ("Response is not available in this context."));
264 return context.Response;
269 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
270 public HttpServerUtility Server {
273 return context.Server;
276 // This is so we can get the Server and call a few methods
277 // which are not context sensitive, see HttpServerUtilityTest
279 return new HttpServerUtility ((HttpContext) null);
284 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
285 public HttpSessionState Session {
287 // Only used for Session_End
292 throw new HttpException (Locale.GetText ("No context is available."));
293 return context.Session;
298 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
302 public virtual ISite Site {
314 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
315 public IPrincipal User {
318 throw new HttpException (Locale.GetText ("No context is available."));
319 if (context.User == null)
320 throw new HttpException (Locale.GetText ("No currently authenticated user."));
326 public virtual event EventHandler Disposed;
327 public virtual event EventHandler Error;
329 public event EventHandler PreSendRequestHeaders;
330 internal void TriggerPreSendRequestHeaders ()
332 if (PreSendRequestHeaders != null)
333 PreSendRequestHeaders (this, EventArgs.Empty);
336 public event EventHandler PreSendRequestContent;
337 internal void TriggerPreSendRequestContent ()
339 if (PreSendRequestContent != null)
340 PreSendRequestContent (this, EventArgs.Empty);
343 public event EventHandler AcquireRequestState;
344 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
346 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
347 AcquireRequestState += new EventHandler (invoker.Invoke);
350 public event EventHandler AuthenticateRequest;
351 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
353 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
354 AuthenticateRequest += new EventHandler (invoker.Invoke);
357 public event EventHandler AuthorizeRequest;
358 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
360 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
361 AuthorizeRequest += new EventHandler (invoker.Invoke);
364 public event EventHandler BeginRequest;
365 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh)
367 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
368 BeginRequest += new EventHandler (invoker.Invoke);
371 public event EventHandler EndRequest;
372 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh)
374 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
375 EndRequest += new EventHandler (invoker.Invoke);
378 public event EventHandler PostRequestHandlerExecute;
379 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
381 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
382 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
385 public event EventHandler PreRequestHandlerExecute;
386 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
388 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
389 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
392 public event EventHandler ReleaseRequestState;
393 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
395 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
396 ReleaseRequestState += new EventHandler (invoker.Invoke);
399 public event EventHandler ResolveRequestCache;
400 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
402 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
403 ResolveRequestCache += new EventHandler (invoker.Invoke);
406 public event EventHandler UpdateRequestCache;
407 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
409 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
410 UpdateRequestCache += new EventHandler (invoker.Invoke);
414 public event EventHandler PostAuthenticateRequest;
415 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
417 AddOnPostAuthenticateRequestAsync (bh, eh, null);
420 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
422 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
423 PostAuthenticateRequest += new EventHandler (invoker.Invoke);
426 public event EventHandler PostAuthorizeRequest;
427 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
429 AddOnPostAuthorizeRequestAsync (bh, eh, null);
432 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
434 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
435 PostAuthorizeRequest += new EventHandler (invoker.Invoke);
438 public event EventHandler PostResolveRequestCache;
439 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
441 AddOnPostResolveRequestCacheAsync (bh, eh, null);
444 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
446 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
447 PostResolveRequestCache += new EventHandler (invoker.Invoke);
450 public event EventHandler PostMapRequestHandler;
451 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
453 AddOnPostMapRequestHandlerAsync (bh, eh, null);
456 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh, object data)
458 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
459 PostMapRequestHandler += new EventHandler (invoker.Invoke);
462 public event EventHandler PostAcquireRequestState;
463 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
465 AddOnPostAcquireRequestStateAsync (bh, eh, null);
468 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
470 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
471 PostAcquireRequestState += new EventHandler (invoker.Invoke);
474 public event EventHandler PostReleaseRequestState;
475 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
477 AddOnPostReleaseRequestStateAsync (bh, eh, null);
480 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
482 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
483 PostReleaseRequestState += new EventHandler (invoker.Invoke);
486 public event EventHandler PostUpdateRequestCache;
487 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
489 AddOnPostUpdateRequestCacheAsync (bh, eh, null);
492 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
494 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
495 PostUpdateRequestCache += new EventHandler (invoker.Invoke);
499 // The new overloads that take a data parameter
501 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
503 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
504 AcquireRequestState += new EventHandler (invoker.Invoke);
507 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
509 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
510 AuthenticateRequest += new EventHandler (invoker.Invoke);
513 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
515 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
516 AuthorizeRequest += new EventHandler (invoker.Invoke);
519 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
521 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
522 BeginRequest += new EventHandler (invoker.Invoke);
525 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
527 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
528 EndRequest += new EventHandler (invoker.Invoke);
531 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
533 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
534 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
537 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
539 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
540 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
543 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
545 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
546 ReleaseRequestState += new EventHandler (invoker.Invoke);
549 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
551 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
552 ResolveRequestCache += new EventHandler (invoker.Invoke);
555 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
557 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
558 UpdateRequestCache += new EventHandler (invoker.Invoke);
562 internal event EventHandler DefaultAuthentication;
565 // Bypass all the event on the Http pipeline and go directly to EndRequest
567 public void CompleteRequest ()
569 stop_processing = true;
572 internal bool RequestCompleted {
573 set { stop_processing = value; }
576 public virtual void Dispose ()
578 if (modcoll != null) {
579 for (int i = modcoll.Count - 1; i >= 0; i--) {
580 modcoll.Get (i).Dispose ();
585 if (Disposed != null)
586 Disposed (this, EventArgs.Empty);
592 public virtual string GetVaryByCustomString (HttpContext context, string custom)
594 if (custom == null) // Sigh
595 throw new NullReferenceException ();
597 if (0 == String.Compare (custom, "browser", true, CultureInfo.InvariantCulture))
598 return context.Request.Browser.Type;
604 // If we catch an error, queue this error
606 void ProcessError (Exception e)
609 context = HttpContext.Current;
611 bool first = context.Error == null;
612 context.AddError (e);
616 Error (this, EventArgs.Empty);
617 } catch (ThreadAbortException ee){
618 // This happens on Redirect() or End()
619 Thread.ResetAbort ();
620 } catch (Exception ee){
621 context.AddError (ee);
625 stop_processing = true;
629 // Ticks the clock: next step on the pipeline.
634 if (pipeline != null && pipeline.MoveNext ()){
635 if (pipeline == null || (bool)pipeline.Current)
638 } catch (ThreadAbortException taex) {
639 object obj = taex.ExceptionState;
640 Thread.ResetAbort ();
641 stop_processing = true;
642 if (obj is StepTimeout)
643 ProcessError (new HttpException ("The request timed out."));
646 } catch (Exception e) {
647 Console.WriteLine ("Tick caught an exception that has not been propagated:\n" + e);
660 // Invoked when our async callback called from RunHooks completes,
661 // we restart the pipeline here.
663 void async_callback_completed_cb (IAsyncResult ar)
665 if (current_ai.end != null){
668 } catch (Exception e) {
676 void async_handler_complete_cb (IAsyncResult ar)
678 IHttpAsyncHandler async_handler = ((IHttpAsyncHandler) ar.AsyncState);
681 async_handler.EndProcessRequest (ar);
682 } catch (Exception e){
690 // This enumerator yields whether processing must be stopped:
691 // true: processing of the pipeline must be stopped
692 // false: processing of the pipeline must not be stopped
694 IEnumerable RunHooks (Delegate list)
696 Delegate [] delegates = list.GetInvocationList ();
698 foreach (EventHandler d in delegates){
699 if (d.Target != null && (d.Target is AsyncInvoker)){
700 current_ai = (AsyncInvoker) d.Target;
705 context.BeginTimeoutPossible ();
706 current_ai.begin (this, EventArgs.Empty, async_callback_completed_cb, current_ai.data);
707 } catch (ThreadAbortException taex){
708 object obj = taex.ExceptionState;
709 Thread.ResetAbort ();
710 stop_processing = true;
711 if (obj is StepTimeout)
712 ProcessError (new HttpException ("The request timed out."));
713 } catch (Exception e){
717 context.EndTimeoutPossible ();
721 // If things are still moving forward, yield this
725 yield return stop_processing;
726 else if (stop_processing)
730 context.BeginTimeoutPossible ();
731 d (this, EventArgs.Empty);
732 } catch (ThreadAbortException taex){
733 object obj = taex.ExceptionState;
734 Thread.ResetAbort ();
735 stop_processing = true;
736 if (obj is StepTimeout)
737 ProcessError (new HttpException ("The request timed out."));
738 } catch (Exception e){
741 context.EndTimeoutPossible ();
749 static void FinalErrorWrite (HttpResponse response, string error)
752 response.Write (error);
753 response.Flush (true);
761 if (context.Error == null){
763 context.Response.Flush (true);
764 } catch (Exception e){
765 context.AddError (e);
769 Exception error = context.Error;
771 HttpResponse response = context.Response;
773 if (!response.HeadersSent){
774 response.ClearHeaders ();
775 response.ClearContent ();
777 if (error is HttpException){
778 response.StatusCode = ((HttpException)error).GetHttpCode ();
780 error = new HttpException ("", error);
781 response.StatusCode = 500;
783 if (!RedirectCustomError ())
784 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
786 response.Flush (true);
788 if (!(error is HttpException))
789 error = new HttpException ("", error);
790 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
797 // Invoked at the end of the pipeline execution
802 if (EndRequest != null)
803 EndRequest (this, EventArgs.Empty);
804 } catch (Exception e){
810 } catch (Exception e) {
811 Console.WriteLine ("Internal error: OutputPage threw an exception " + e);
814 context = HttpContext.Current;
815 context.WorkerRequest.EndOfRequest();
816 if (factory != null && context.Handler != null){
817 factory.ReleaseHandler (context.Handler);
818 context.Handler = null;
822 if (begin_iar != null){
824 begin_iar.Complete ();
827 // TODO: if this throws an error, we have no way of reporting it
828 // Not really too bad, since the only failure might be
829 // `HttpRuntime.request_processed'
838 // context = null; -> moved to PostDone
846 // Events fired as described in `Http Runtime Support, HttpModules,
847 // Handling Public Events'
849 IEnumerator Pipeline ()
854 if (BeginRequest != null)
855 foreach (bool stop in RunHooks (BeginRequest))
858 if (AuthenticateRequest != null)
859 foreach (bool stop in RunHooks (AuthenticateRequest))
862 if (DefaultAuthentication != null)
863 foreach (bool stop in RunHooks (DefaultAuthentication))
867 if (PostAuthenticateRequest != null)
868 foreach (bool stop in RunHooks (PostAuthenticateRequest))
871 if (AuthorizeRequest != null)
872 foreach (bool stop in RunHooks (AuthorizeRequest))
875 if (PostAuthorizeRequest != null)
876 foreach (bool stop in RunHooks (PostAuthorizeRequest))
880 if (ResolveRequestCache != null)
881 foreach (bool stop in RunHooks (ResolveRequestCache))
885 if (PostResolveRequestCache != null)
886 foreach (bool stop in RunHooks (PostResolveRequestCache))
890 // Obtain the handler for the request.
891 IHttpHandler handler = null;
893 handler = GetHandler (context);
894 context.Handler = handler;
895 } catch (FileNotFoundException fnf){
896 if (context.Request.IsLocal)
897 ProcessError (new HttpException (404, String.Format ("File not found {0}", fnf.FileName), fnf));
899 ProcessError (new HttpException (404, "File not found: " + Path.GetFileName (fnf.FileName)));
900 } catch (DirectoryNotFoundException dnf){
901 if (!context.Request.IsLocal)
902 dnf = null; // Do not "leak" real path information
903 ProcessError (new HttpException (404, "Directory not found", dnf));
904 } catch (Exception e) {
912 if (PostMapRequestHandler != null)
913 foreach (bool stop in RunHooks (PostMapRequestHandler))
917 if (AcquireRequestState != null){
918 foreach (bool stop in RunHooks (AcquireRequestState))
923 if (PostAcquireRequestState != null){
924 foreach (bool stop in RunHooks (PostAcquireRequestState))
930 // From this point on, we need to ensure that we call
931 // ReleaseRequestState, so the code below jumps to
932 // `release:' to guarantee it rather than yielding.
934 if (PreRequestHandlerExecute != null)
935 foreach (bool stop in RunHooks (PreRequestHandlerExecute))
940 context.BeginTimeoutPossible ();
941 if (handler != null){
942 IHttpAsyncHandler async_handler = handler as IHttpAsyncHandler;
944 if (async_handler != null){
947 async_handler.BeginProcessRequest (context, async_handler_complete_cb, handler);
950 handler.ProcessRequest (context);
953 } catch (ThreadAbortException taex){
954 object obj = taex.ExceptionState;
955 Thread.ResetAbort ();
956 stop_processing = true;
957 if (obj is StepTimeout)
958 ProcessError (new HttpException ("The request timed out."));
959 } catch (Exception e){
963 context.EndTimeoutPossible ();
966 yield return stop_processing;
967 else if (stop_processing)
970 // These are executed after the application has returned
972 if (PostRequestHandlerExecute != null)
973 foreach (bool stop in RunHooks (PostRequestHandlerExecute))
978 if (ReleaseRequestState != null){
979 #pragma warning disable 168
980 foreach (bool stop in RunHooks (ReleaseRequestState)){
982 // Ignore the stop signal while release the state
986 #pragma warning restore 168
993 if (PostReleaseRequestState != null)
994 foreach (bool stop in RunHooks (PostReleaseRequestState))
998 if (context.Error == null)
999 context.Response.DoFilter (true);
1001 if (UpdateRequestCache != null)
1002 foreach (bool stop in RunHooks (UpdateRequestCache))
1006 if (PostUpdateRequestCache != null)
1007 foreach (bool stop in RunHooks (PostUpdateRequestCache))
1014 internal CultureInfo GetThreadCulture (HttpRequest request, CultureInfo culture, bool isAuto)
1019 CultureInfo ret = null;
1020 string[] languages = request.UserLanguages;
1022 if (languages != null && languages.Length > 0)
1023 ret = new CultureInfo (languages[0]);
1040 HttpRuntime.TimeoutManager.Add (context);
1042 Thread th = Thread.CurrentThread;
1043 if (app_culture != null) {
1044 prev_app_culture = th.CurrentCulture;
1045 th.CurrentCulture = GetThreadCulture (Request, app_culture, autoCulture);
1048 if (appui_culture != null) {
1049 prev_appui_culture = th.CurrentUICulture;
1050 th.CurrentUICulture = GetThreadCulture (Request, appui_culture, autoUICulture);
1054 prev_user = Thread.CurrentPrincipal;
1060 Thread th = Thread.CurrentThread;
1062 if (Thread.CurrentPrincipal != prev_user)
1063 Thread.CurrentPrincipal = prev_user;
1065 if (prev_appui_culture != null && prev_appui_culture != th.CurrentUICulture)
1066 th.CurrentUICulture = prev_appui_culture;
1067 if (prev_app_culture != null && prev_app_culture != th.CurrentCulture)
1068 th.CurrentCulture = prev_app_culture;
1071 if (context == null)
1072 context = HttpContext.Current;
1073 HttpRuntime.TimeoutManager.Remove (context);
1077 HttpContext.Current = null;
1080 void Start (object x)
1084 } catch (Exception e) {
1086 initialization_exception = e;
1088 FinalErrorWrite (context.Response, new HttpException ("", e).GetHtmlErrorMessage ());
1092 HttpContext.Current = Context;
1094 pipeline = Pipeline ();
1098 // Used by HttpServerUtility.Execute
1099 internal IHttpHandler GetHandler (HttpContext context)
1101 HttpRequest request = context.Request;
1102 string verb = request.RequestType;
1103 string url = request.FilePath;
1105 IHttpHandler handler = null;
1107 HttpHandlersSection section = (HttpHandlersSection) WebConfigurationManager.GetSection ("system.web/httpHandlers");
1108 object o = section.LocateHandler (verb, url);
1110 HandlerFactoryConfiguration factory_config = (HandlerFactoryConfiguration) HttpContext.GetAppConfig ("system.web/httpHandlers");
1111 object o = factory_config.LocateHandler (verb, url);
1114 factory = o as IHttpHandlerFactory;
1116 if (factory == null) {
1117 handler = (IHttpHandler) o;
1119 handler = factory.GetHandler (context, verb, url, request.PhysicalPath);
1125 void IHttpHandler.ProcessRequest (HttpContext context)
1128 this.context = context;
1136 // This is used by FireOnAppStart, when we init the application
1137 // as the context is required to be set at that point (the user
1138 // might call methods that require it on that hook).
1140 internal void SetContext (HttpContext context)
1142 this.context = context;
1145 internal void SetSession (HttpSessionState session)
1147 this.session = session;
1150 IAsyncResult IHttpAsyncHandler.BeginProcessRequest (HttpContext context, AsyncCallback cb, object extraData)
1152 this.context = context;
1155 begin_iar = new AsyncRequestState (done, cb, extraData);
1159 if (Thread.CurrentThread.IsThreadPoolThread)
1163 ThreadPool.QueueUserWorkItem (new WaitCallback (Start), null);
1168 void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result)
1170 if (!result.IsCompleted)
1171 result.AsyncWaitHandle.WaitOne ();
1175 public virtual void Init ()
1179 bool IHttpHandler.IsReusable {
1186 internal void ClearError ()
1188 context.ClearError ();
1191 bool RedirectErrorPage (string error_page)
1193 if (context.Request.QueryString ["aspxerrorpath"] != null)
1196 Response.Redirect (error_page + "?aspxerrorpath=" + Request.Path, false);
1200 bool RedirectCustomError ()
1202 if (!context.IsCustomErrorEnabled)
1206 CustomErrorsSection config = (CustomErrorsSection)WebConfigurationManager.GetSection ("system.web/customErrors");
1208 CustomErrorsConfig config = null;
1210 config = (CustomErrorsConfig) context.GetConfig ("system.web/customErrors");
1214 if (config == null) {
1215 if (context.ErrorPage != null)
1216 return RedirectErrorPage (context.ErrorPage);
1222 CustomError err = config.Errors [context.Response.StatusCode.ToString()];
1223 string redirect = err == null ? null : err.Redirect;
1225 string redirect = config [context.Response.StatusCode];
1227 if (redirect == null) {
1228 redirect = context.ErrorPage;
1229 if (redirect == null)
1230 redirect = config.DefaultRedirect;
1233 if (redirect == null)
1236 return RedirectErrorPage (redirect);
1242 // Based on Fritz' Onion's AsyncRequestState class for asynchronous IHttpAsyncHandlers
1244 class AsyncRequestState : IAsyncResult {
1248 ManualResetEvent complete_event = null;
1250 internal AsyncRequestState (ManualResetEvent complete_event, AsyncCallback cb, object cb_data)
1253 this.cb_data = cb_data;
1254 this.complete_event = complete_event;
1257 internal void Complete ()
1263 complete_event.Set ();
1266 public object AsyncState {
1272 public bool CompletedSynchronously {
1278 public bool IsCompleted {
1284 public WaitHandle AsyncWaitHandle {
1286 return complete_event;
1291 #region Helper classes
1294 // A wrapper to keep track of begin/end pairs
1296 class AsyncInvoker {
1297 public BeginEventHandler begin;
1298 public EndEventHandler end;
1301 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, object d)
1308 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh)
1314 public void Invoke (object sender, EventArgs e)
1316 throw new Exception ("This is just a dummy");