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 (ThreadAbortException ee){
567 // This happens on Redirect() or End()
568 Thread.ResetAbort ();
569 } catch (Exception ee){
570 context.AddError (ee);
574 stop_processing = true;
578 // Ticks the clock: next step on the pipeline.
583 if (pipeline.MoveNext ()){
584 if ((bool)pipeline.Current)
587 } catch (Exception e) {
588 Console.WriteLine ("Tick caught an exception that has not been propagated:\n" + e);
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 IEnumerable RunHooks (Delegate list)
637 Delegate [] delegates = list.GetInvocationList ();
639 foreach (EventHandler d in delegates){
640 if (d.Target != null && (d.Target is AsyncInvoker)){
641 current_ai = (AsyncInvoker) d.Target;
646 context.BeginTimeoutPossible ();
647 current_ai.begin (this, EventArgs.Empty, async_callback_completed_cb, current_ai.data);
648 } catch (ThreadAbortException taex){
649 object obj = taex.ExceptionState;
650 Thread.ResetAbort ();
651 stop_processing = true;
652 if (obj is StepTimeout)
653 ProcessError (new HttpException ("The request timed out."));
654 } catch (Exception e){
658 context.EndTimeoutPossible ();
662 // If things are still moving forward, yield this
666 yield return stop_processing;
667 else if (stop_processing)
671 context.BeginTimeoutPossible ();
672 d (this, EventArgs.Empty);
673 } catch (ThreadAbortException taex){
674 object obj = taex.ExceptionState;
675 Thread.ResetAbort ();
676 stop_processing = true;
677 if (obj is StepTimeout)
678 ProcessError (new HttpException ("The request timed out."));
679 } catch (Exception e){
682 context.EndTimeoutPossible ();
690 static void FinalErrorWrite (HttpResponse response, string error)
693 response.Write (error);
694 response.Flush (true);
702 if (context.Error == null){
704 context.Response.Flush (true);
705 } catch (Exception e){
706 context.AddError (e);
710 Exception error = context.Error;
712 HttpResponse response = context.Response;
714 if (!response.HeadersSent){
715 response.ClearHeaders ();
716 response.ClearContent ();
718 if (error is HttpException){
719 response.StatusCode = ((HttpException)error).GetHttpCode ();
721 error = new HttpException ("", error);
722 response.StatusCode = 500;
724 if (!RedirectCustomError ())
725 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
727 response.Flush (true);
729 if (!(error is HttpException))
730 error = new HttpException ("", error);
731 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
738 // Invoked at the end of the pipeline execution
743 if (EndRequest != null)
744 EndRequest (this, EventArgs.Empty);
745 } catch (Exception e){
752 } catch (Exception e) {
753 Console.WriteLine ("Internal error: OutputPage threw an exception " + e);
755 context.WorkerRequest.EndOfRequest();
756 if (begin_iar != null){
758 begin_iar.Complete ();
761 // TODO: if this throws an error, we have no way of reporting it
762 // Not really too bad, since the only failure might be
763 // `HttpRuntime.request_processed'
770 if (factory != null && context.Handler != null){
771 factory.ReleaseHandler (context.Handler);
775 context.Handler = null;
776 // context = null; -> moved to PostDone
784 // Events fired as described in `Http Runtime Support, HttpModules,
785 // Handling Public Events'
787 IEnumerator Pipeline ()
789 if (BeginRequest != null)
790 foreach (bool stop in RunHooks (BeginRequest))
793 if (AuthenticateRequest != null)
794 foreach (bool stop in RunHooks (AuthenticateRequest))
797 if (DefaultAuthentication != null)
798 foreach (bool stop in RunHooks (DefaultAuthentication))
802 if (PostAuthenticateRequest != null)
803 foreach (bool stop in RunHooks (AuthenticateRequest))
806 if (AuthorizeRequest != null)
807 foreach (bool stop in RunHooks (AuthorizeRequest))
810 if (PostAuthorizeRequest != null)
811 foreach (bool stop in RunHooks (PostAuthorizeRequest))
815 if (ResolveRequestCache != null)
816 foreach (bool stop in RunHooks (ResolveRequestCache))
819 // Obtain the handler for the request.
820 IHttpHandler handler = null;
822 handler = GetHandler (context);
823 } catch (FileNotFoundException fnf){
824 if (context.Request.IsLocal)
825 ProcessError (new HttpException (404, String.Format ("File not found {0}", fnf.FileName), fnf));
827 ProcessError (new HttpException (404, "File not found", fnf));
828 } catch (DirectoryNotFoundException dnf){
829 ProcessError (new HttpException (404, "Directory not found", dnf));
830 } catch (Exception e) {
838 if (PostResolveRequestCache != null)
839 foreach (bool stop in RunHooks (PostResolveRequestCache))
842 if (PostMapRequestHandler != null)
843 foreach (bool stop in RunHooks (PostMapRequestHandler))
847 if (AcquireRequestState != null){
848 foreach (bool stop in RunHooks (AcquireRequestState))
853 if (PostAcquireRequestState != null){
854 foreach (bool stop in RunHooks (PostAcquireRequestState))
860 // From this point on, we need to ensure that we call
861 // ReleaseRequestState, so the code below jumps to
862 // `release:' to guarantee it rather than yielding.
864 if (PreRequestHandlerExecute != null)
865 foreach (bool stop in RunHooks (PreRequestHandlerExecute))
870 context.BeginTimeoutPossible ();
871 if (handler != null){
872 IHttpAsyncHandler async_handler = handler as IHttpAsyncHandler;
874 if (async_handler != null){
877 async_handler.BeginProcessRequest (context, async_handler_complete_cb, handler);
880 handler.ProcessRequest (context);
883 } catch (ThreadAbortException taex){
884 object obj = taex.ExceptionState;
885 Thread.ResetAbort ();
886 stop_processing = true;
887 if (obj is StepTimeout)
888 ProcessError (new HttpException ("The request timed out."));
889 } catch (Exception e){
893 context.EndTimeoutPossible ();
896 yield return stop_processing;
897 else if (stop_processing)
900 // These are executed after the application has returned
902 if (PostRequestHandlerExecute != null)
903 foreach (bool stop in RunHooks (PostRequestHandlerExecute))
908 if (ReleaseRequestState != null){
909 #pragma warning disable 168
910 foreach (bool stop in RunHooks (ReleaseRequestState)){
912 // Ignore the stop signal while release the state
916 #pragma warning restore 168
923 if (PostReleaseRequestState != null)
924 foreach (bool stop in RunHooks (PostReleaseRequestState))
928 if (context.Error == null)
929 context.Response.DoFilter (true);
931 if (UpdateRequestCache != null)
932 foreach (bool stop in RunHooks (UpdateRequestCache))
936 if (PostUpdateRequestCache != null)
937 foreach (bool stop in RunHooks (PostUpdateRequestCache))
946 HttpRuntime.TimeoutManager.Add (context);
948 Thread th = Thread.CurrentThread;
949 if (app_culture != null) {
950 prev_app_culture = th.CurrentCulture;
951 th.CurrentCulture = app_culture;
954 if (appui_culture != null) {
955 prev_appui_culture = th.CurrentUICulture;
956 th.CurrentUICulture = appui_culture;
960 prev_user = Thread.CurrentPrincipal;
966 Thread th = Thread.CurrentThread;
968 if (Thread.CurrentPrincipal != prev_user)
969 Thread.CurrentPrincipal = prev_user;
971 if (prev_appui_culture != null && prev_appui_culture != th.CurrentUICulture)
972 th.CurrentUICulture = prev_appui_culture;
973 if (prev_app_culture != null && prev_app_culture != th.CurrentCulture)
974 th.CurrentCulture = prev_app_culture;
977 HttpRuntime.TimeoutManager.Remove (context);
981 HttpContext.Current = null;
984 void Start (object x)
988 stop_processing = false;
989 pipeline = Pipeline ();
993 // Used by HttpServerUtility.Execute
994 internal IHttpHandler GetHandler (HttpContext context)
996 HttpRequest request = context.Request;
997 string verb = request.RequestType;
998 string url = request.FilePath;
1000 IHttpHandler handler = null;
1002 System.Configuration.Configuration config = WebConfiguration.OpenWebConfiguration (request.PhysicalApplicationPath);
1003 HttpHandlersSection section;
1004 /* XXX once SystemWebSectionGroup is working, use the following:
1005 section = ((SystemWebSectionGroup)config.GetSection ("system.web")).HttpHandlers;
1007 section = (HttpHandlersSection)config.GetSection ("system.web/httpHandlers");
1009 HandlerFactoryConfiguration factory_config = (HandlerFactoryConfiguration) HttpContext.GetAppConfig ("system.web/httpHandlers");
1010 object o = factory_config.LocateHandler (verb, url);
1011 factory = o as IHttpHandlerFactory;
1013 if (factory == null) {
1014 handler = (IHttpHandler) o;
1016 handler = factory.GetHandler (context, verb, url, request.PhysicalPath);
1019 context.Handler = handler;
1024 void IHttpHandler.ProcessRequest (HttpContext context)
1027 this.context = context;
1035 // This is used by FireOnAppStart, when we init the application
1036 // as the context is required to be set at that point (the user
1037 // might call methods that require it on that hook).
1039 internal void SetContext (HttpContext context)
1041 this.context = context;
1044 internal void SetSession (HttpSessionState session)
1046 this.session = session;
1049 IAsyncResult IHttpAsyncHandler.BeginProcessRequest (HttpContext context, AsyncCallback cb, object extraData)
1051 this.context = context;
1054 begin_iar = new AsyncRequestState (done, cb, extraData);
1056 if (Thread.CurrentThread.IsThreadPoolThread)
1059 ThreadPool.QueueUserWorkItem (new WaitCallback (Start), null);
1064 void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result)
1066 if (!result.IsCompleted)
1067 result.AsyncWaitHandle.WaitOne ();
1071 public virtual void Init ()
1075 bool IHttpHandler.IsReusable {
1082 internal void ClearError ()
1084 context.ClearError ();
1087 bool RedirectErrorPage (string error_page)
1089 if (context.Request.QueryString ["aspxerrorpath"] != null)
1092 Response.Redirect (error_page + "?aspxerrorpath=" + Request.Path, false);
1096 bool RedirectCustomError ()
1098 if (!context.IsCustomErrorEnabled)
1101 CustomErrorsConfig config = null;
1103 config = (CustomErrorsConfig) context.GetConfig ("system.web/customErrors");
1106 if (config == null) {
1107 if (context.ErrorPage != null)
1108 return RedirectErrorPage (context.ErrorPage);
1113 string redirect = config [context.Response.StatusCode];
1114 if (redirect == null) {
1115 redirect = context.ErrorPage;
1116 if (redirect == null)
1117 redirect = config.DefaultRedirect;
1120 if (redirect == null)
1123 return RedirectErrorPage (redirect);
1129 // Based on Fritz' Onion's AsyncRequestState class for asynchronous IHttpAsyncHandlers
1131 class AsyncRequestState : IAsyncResult {
1135 ManualResetEvent complete_event = null;
1137 internal AsyncRequestState (ManualResetEvent complete_event, AsyncCallback cb, object cb_data)
1140 this.cb_data = cb_data;
1141 this.complete_event = complete_event;
1144 internal void Complete ()
1150 complete_event.Set ();
1153 public object AsyncState {
1159 public bool CompletedSynchronously {
1165 public bool IsCompleted {
1171 public WaitHandle AsyncWaitHandle {
1173 return complete_event;
1178 #region Helper classes
1181 // A wrapper to keep track of begin/end pairs
1183 class AsyncInvoker {
1184 public BeginEventHandler begin;
1185 public EndEventHandler end;
1188 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, object d)
1195 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh)
1201 public void Invoke (object sender, EventArgs e)
1203 throw new Exception ("This is just a dummy");