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;
78 using vmw.@internal.j2ee;
81 namespace System.Web {
84 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
85 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
88 public class HttpApplication : IHttpAsyncHandler, IHttpHandler, IComponent, IDisposable {
90 HttpSessionState session;
93 // The source, and the exposed API (cache).
94 HttpModuleCollection modcoll;
96 string assemblyLocation;
99 // The factory for the handler currently running.
101 IHttpHandlerFactory factory;
104 // Whether the thread culture is to be auto-set.
105 // Used only in the 2.0 profile, always false for 1.x
111 // Whether the pipeline should be stopped
113 bool stop_processing;
118 IEnumerator pipeline;
120 // To flag when we are done processing a request from BeginProcessRequest.
121 ManualResetEvent done;
123 // The current IAsyncResult for the running async request handler in the pipeline
124 AsyncRequestState begin_iar;
126 // Tracks the current AsyncInvocation being dispatched
127 AsyncInvoker current_ai;
129 // We don't use the EventHandlerList here, but derived classes might do
130 EventHandlerList events;
132 // Culture and IPrincipal
133 CultureInfo app_culture;
134 CultureInfo appui_culture;
135 CultureInfo prev_app_culture;
136 CultureInfo prev_appui_culture;
137 IPrincipal prev_user;
140 const string initialization_exception_key = "System.Web.HttpApplication.initialization_exception";
141 static Exception initialization_exception {
142 get { return (Exception) AppDomain.CurrentDomain.GetData (initialization_exception_key); }
143 set { AppDomain.CurrentDomain.SetData (initialization_exception_key, value); }
146 static Exception initialization_exception;
148 bool removeConfigurationFromCache;
152 // These are used to detect the case where the EndXXX method is invoked
153 // from within the BeginXXXX delegate, so we detect whether we kick the
154 // pipeline from here, or from the the RunHook routine
159 public HttpApplication ()
161 done = new ManualResetEvent (false);
164 internal void InitOnce (bool full_init)
171 HttpModulesSection modules;
172 modules = (HttpModulesSection) WebConfigurationManager.GetSection ("system.web/httpModules", HttpRuntime.AppDomainAppVirtualPath);
174 ModulesConfiguration modules;
176 modules = (ModulesConfiguration) HttpContext.GetAppConfig ("system.web/httpModules");
179 modcoll = modules.LoadModules (this);
182 HttpApplicationFactory.AttachEvents (this);
185 GlobalizationSection cfg;
186 cfg = (GlobalizationSection) WebConfigurationManager.GetSection ("system.web/globalization");
187 app_culture = cfg.GetCulture();
188 autoCulture = cfg.IsAutoCulture;
189 appui_culture = cfg.GetUICulture();
190 autoUICulture = cfg.IsAutoUICulture;
192 GlobalizationConfiguration cfg;
193 cfg = GlobalizationConfiguration.GetInstance (null);
195 app_culture = cfg.Culture;
196 appui_culture = cfg.UICulture;
202 internal string AssemblyLocation {
204 if (assemblyLocation == null)
205 assemblyLocation = GetType ().Assembly.Location;
206 return assemblyLocation;
211 internal static Exception InitializationException {
212 get { return initialization_exception; }
217 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
218 public HttpApplicationState Application {
220 return HttpApplicationFactory.ApplicationState;
225 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
226 public HttpContext Context {
232 protected EventHandlerList Events {
235 events = new EventHandlerList ();
242 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
243 public HttpModuleCollection Modules {
244 [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
247 modcoll = new HttpModuleCollection ();
254 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
255 public HttpRequest Request {
258 throw new HttpException (Locale.GetText ("No context is available."));
260 if (false == HttpApplicationFactory.ContextAvailable)
261 throw new HttpException (Locale.GetText ("Request is not available in this context."));
263 return context.Request;
268 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
269 public HttpResponse Response {
272 throw new HttpException (Locale.GetText ("No context is available."));
274 if (false == HttpApplicationFactory.ContextAvailable)
275 throw new HttpException (Locale.GetText ("Response is not available in this context."));
277 return context.Response;
282 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
283 public HttpServerUtility Server {
286 return context.Server;
289 // This is so we can get the Server and call a few methods
290 // which are not context sensitive, see HttpServerUtilityTest
292 return new HttpServerUtility ((HttpContext) null);
297 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
298 public HttpSessionState Session {
300 // Only used for Session_End
305 throw new HttpException (Locale.GetText ("No context is available."));
306 return context.Session;
311 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
315 public virtual ISite Site {
327 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
328 public IPrincipal User {
331 throw new HttpException (Locale.GetText ("No context is available."));
332 if (context.User == null)
333 throw new HttpException (Locale.GetText ("No currently authenticated user."));
339 public virtual event EventHandler Disposed;
340 public virtual event EventHandler Error;
342 public event EventHandler PreSendRequestHeaders;
343 internal void TriggerPreSendRequestHeaders ()
345 if (PreSendRequestHeaders != null)
346 PreSendRequestHeaders (this, EventArgs.Empty);
349 public event EventHandler PreSendRequestContent;
350 internal void TriggerPreSendRequestContent ()
352 if (PreSendRequestContent != null)
353 PreSendRequestContent (this, EventArgs.Empty);
356 public event EventHandler AcquireRequestState;
357 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
359 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
360 AcquireRequestState += new EventHandler (invoker.Invoke);
363 public event EventHandler AuthenticateRequest;
364 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
366 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
367 AuthenticateRequest += new EventHandler (invoker.Invoke);
370 public event EventHandler AuthorizeRequest;
371 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
373 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
374 AuthorizeRequest += new EventHandler (invoker.Invoke);
377 public event EventHandler BeginRequest;
378 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh)
380 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
381 BeginRequest += new EventHandler (invoker.Invoke);
384 public event EventHandler EndRequest;
385 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh)
387 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
388 EndRequest += new EventHandler (invoker.Invoke);
391 public event EventHandler PostRequestHandlerExecute;
392 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
394 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
395 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
398 public event EventHandler PreRequestHandlerExecute;
399 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
401 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
402 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
405 public event EventHandler ReleaseRequestState;
406 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
408 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
409 ReleaseRequestState += new EventHandler (invoker.Invoke);
412 public event EventHandler ResolveRequestCache;
413 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
415 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
416 ResolveRequestCache += new EventHandler (invoker.Invoke);
419 public event EventHandler UpdateRequestCache;
420 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
422 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
423 UpdateRequestCache += new EventHandler (invoker.Invoke);
427 public event EventHandler PostAuthenticateRequest;
428 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
430 AddOnPostAuthenticateRequestAsync (bh, eh, null);
433 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
435 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
436 PostAuthenticateRequest += new EventHandler (invoker.Invoke);
439 public event EventHandler PostAuthorizeRequest;
440 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
442 AddOnPostAuthorizeRequestAsync (bh, eh, null);
445 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
447 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
448 PostAuthorizeRequest += new EventHandler (invoker.Invoke);
451 public event EventHandler PostResolveRequestCache;
452 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
454 AddOnPostResolveRequestCacheAsync (bh, eh, null);
457 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
459 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
460 PostResolveRequestCache += new EventHandler (invoker.Invoke);
463 public event EventHandler PostMapRequestHandler;
464 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
466 AddOnPostMapRequestHandlerAsync (bh, eh, null);
469 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh, object data)
471 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
472 PostMapRequestHandler += new EventHandler (invoker.Invoke);
475 public event EventHandler PostAcquireRequestState;
476 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
478 AddOnPostAcquireRequestStateAsync (bh, eh, null);
481 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
483 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
484 PostAcquireRequestState += new EventHandler (invoker.Invoke);
487 public event EventHandler PostReleaseRequestState;
488 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
490 AddOnPostReleaseRequestStateAsync (bh, eh, null);
493 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
495 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
496 PostReleaseRequestState += new EventHandler (invoker.Invoke);
499 public event EventHandler PostUpdateRequestCache;
500 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
502 AddOnPostUpdateRequestCacheAsync (bh, eh, null);
505 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
507 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
508 PostUpdateRequestCache += new EventHandler (invoker.Invoke);
512 // The new overloads that take a data parameter
514 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
516 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
517 AcquireRequestState += new EventHandler (invoker.Invoke);
520 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
522 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
523 AuthenticateRequest += new EventHandler (invoker.Invoke);
526 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
528 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
529 AuthorizeRequest += new EventHandler (invoker.Invoke);
532 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
534 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
535 BeginRequest += new EventHandler (invoker.Invoke);
538 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
540 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
541 EndRequest += new EventHandler (invoker.Invoke);
544 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
546 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
547 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
550 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
552 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
553 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
556 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
558 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
559 ReleaseRequestState += new EventHandler (invoker.Invoke);
562 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
564 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
565 ResolveRequestCache += new EventHandler (invoker.Invoke);
568 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
570 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
571 UpdateRequestCache += new EventHandler (invoker.Invoke);
575 internal event EventHandler DefaultAuthentication;
578 // Bypass all the event on the Http pipeline and go directly to EndRequest
580 public void CompleteRequest ()
582 stop_processing = true;
585 internal bool RequestCompleted {
586 set { stop_processing = value; }
589 public virtual void Dispose ()
591 if (modcoll != null) {
592 for (int i = modcoll.Count - 1; i >= 0; i--) {
593 modcoll.Get (i).Dispose ();
598 if (Disposed != null)
599 Disposed (this, EventArgs.Empty);
605 public virtual string GetVaryByCustomString (HttpContext context, string custom)
607 if (custom == null) // Sigh
608 throw new NullReferenceException ();
610 if (0 == String.Compare (custom, "browser", true, CultureInfo.InvariantCulture))
611 return context.Request.Browser.Type;
617 // If we catch an error, queue this error
619 void ProcessError (Exception e)
622 context = HttpContext.Current;
624 bool first = context.Error == null;
625 context.AddError (e);
629 Error (this, EventArgs.Empty);
630 } catch (ThreadAbortException){
631 // This happens on Redirect() or End()
632 Thread.ResetAbort ();
633 } catch (Exception ee){
634 context.AddError (ee);
638 stop_processing = true;
640 // we want to remove configuration from the cache in case of
641 // invalid resource not exists to prevent DOS attack.
642 HttpException httpEx = e as HttpException;
643 if (httpEx != null && httpEx.GetHttpCode () == 404) {
644 removeConfigurationFromCache = true;
650 // Ticks the clock: next step on the pipeline.
655 if (pipeline != null && pipeline.MoveNext ()){
656 if (pipeline == null || (bool)pipeline.Current)
659 } catch (ThreadAbortException taex) {
660 object obj = taex.ExceptionState;
661 Thread.ResetAbort ();
662 stop_processing = true;
663 if (obj is StepTimeout)
664 ProcessError (new HttpException ("The request timed out."));
667 } catch (Exception e) {
668 Console.WriteLine ("Tick caught an exception that has not been propagated:\n" + e);
681 // Invoked when our async callback called from RunHooks completes,
682 // we restart the pipeline here.
684 void async_callback_completed_cb (IAsyncResult ar)
686 if (current_ai.end != null){
689 } catch (Exception e) {
697 void async_handler_complete_cb (IAsyncResult ar)
699 IHttpAsyncHandler async_handler = ((IHttpAsyncHandler) ar.AsyncState);
702 async_handler.EndProcessRequest (ar);
703 } catch (Exception e){
711 // This enumerator yields whether processing must be stopped:
712 // true: processing of the pipeline must be stopped
713 // false: processing of the pipeline must not be stopped
715 IEnumerable RunHooks (Delegate list)
717 Delegate [] delegates = list.GetInvocationList ();
719 foreach (EventHandler d in delegates){
720 if (d.Target != null && (d.Target is AsyncInvoker)){
721 current_ai = (AsyncInvoker) d.Target;
726 context.BeginTimeoutPossible ();
727 current_ai.begin (this, EventArgs.Empty, async_callback_completed_cb, current_ai.data);
728 } catch (ThreadAbortException taex){
729 object obj = taex.ExceptionState;
730 Thread.ResetAbort ();
731 stop_processing = true;
732 if (obj is StepTimeout)
733 ProcessError (new HttpException ("The request timed out."));
734 } catch (Exception e){
738 context.EndTimeoutPossible ();
742 // If things are still moving forward, yield this
746 yield return stop_processing;
747 else if (stop_processing)
751 context.BeginTimeoutPossible ();
752 d (this, EventArgs.Empty);
753 } catch (ThreadAbortException taex){
754 object obj = taex.ExceptionState;
755 Thread.ResetAbort ();
756 stop_processing = true;
757 if (obj is StepTimeout)
758 ProcessError (new HttpException ("The request timed out."));
759 } catch (Exception e){
762 context.EndTimeoutPossible ();
770 static void FinalErrorWrite (HttpResponse response, string error)
773 response.Write (error);
774 response.Flush (true);
782 if (context.Error == null){
784 context.Response.Flush (true);
785 } catch (Exception e){
786 context.AddError (e);
790 Exception error = context.Error;
792 HttpResponse response = context.Response;
795 IPortletActionRequest actionRequest = context.ServletRequest as IPortletActionRequest;
796 IPortletActionResponse actionResponse = context.ServletResponse as IPortletActionResponse;
797 if (actionRequest != null && actionResponse != null && actionRequest.processActionOnly ()) {
798 string exception = "Exception of type " + context.Error.GetType () +
799 " during processAction: " + context.Error.Message + Console.Out.NewLine +
800 context.Error.StackTrace;
801 actionResponse.setRenderParameter ("vmw.action.exception", exception);
805 if (!response.HeadersSent){
806 response.ClearHeaders ();
807 response.ClearContent ();
809 if (error is HttpException){
810 response.StatusCode = ((HttpException)error).GetHttpCode ();
812 error = new HttpException ("", error);
813 response.StatusCode = 500;
815 HttpException httpEx = (HttpException) error;
816 if (!RedirectCustomError (ref httpEx))
817 FinalErrorWrite (response, httpEx.GetHtmlErrorMessage ());
819 response.Flush (true);
821 if (!(error is HttpException))
822 error = new HttpException ("", error);
823 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
830 // Invoked at the end of the pipeline execution
835 if (EndRequest != null)
836 EndRequest (this, EventArgs.Empty);
837 } catch (Exception e){
843 } catch (Exception e) {
844 Console.WriteLine ("Internal error: OutputPage threw an exception " + e);
847 context = HttpContext.Current;
848 context.WorkerRequest.EndOfRequest();
849 if (factory != null && context.Handler != null){
850 factory.ReleaseHandler (context.Handler);
851 context.Handler = null;
855 context.PopHandler ();
857 if (begin_iar != null){
859 begin_iar.Complete ();
862 // TODO: if this throws an error, we have no way of reporting it
863 // Not really too bad, since the only failure might be
864 // `HttpRuntime.request_processed'
873 // context = null; -> moved to PostDone
881 // Events fired as described in `Http Runtime Support, HttpModules,
882 // Handling Public Events'
884 IEnumerator Pipeline ()
889 if (BeginRequest != null)
890 foreach (bool stop in RunHooks (BeginRequest))
893 if (AuthenticateRequest != null)
894 foreach (bool stop in RunHooks (AuthenticateRequest))
897 if (DefaultAuthentication != null)
898 foreach (bool stop in RunHooks (DefaultAuthentication))
902 if (PostAuthenticateRequest != null)
903 foreach (bool stop in RunHooks (PostAuthenticateRequest))
906 if (AuthorizeRequest != null)
907 foreach (bool stop in RunHooks (AuthorizeRequest))
910 if (PostAuthorizeRequest != null)
911 foreach (bool stop in RunHooks (PostAuthorizeRequest))
915 if (ResolveRequestCache != null)
916 foreach (bool stop in RunHooks (ResolveRequestCache))
920 if (PostResolveRequestCache != null)
921 foreach (bool stop in RunHooks (PostResolveRequestCache))
925 // Obtain the handler for the request.
926 IHttpHandler handler = null;
928 handler = GetHandler (context);
929 context.Handler = handler;
931 context.PushHandler (handler);
933 } catch (FileNotFoundException fnf){
934 if (context.Request.IsLocal)
935 ProcessError (new HttpException (404, String.Format ("File not found {0}", fnf.FileName), fnf));
937 ProcessError (new HttpException (404, "File not found: " + Path.GetFileName (fnf.FileName)));
938 } catch (DirectoryNotFoundException dnf){
939 if (!context.Request.IsLocal)
940 dnf = null; // Do not "leak" real path information
941 ProcessError (new HttpException (404, "Directory not found", dnf));
942 } catch (Exception e) {
950 if (PostMapRequestHandler != null)
951 foreach (bool stop in RunHooks (PostMapRequestHandler))
955 if (AcquireRequestState != null){
956 foreach (bool stop in RunHooks (AcquireRequestState))
961 if (PostAcquireRequestState != null){
962 foreach (bool stop in RunHooks (PostAcquireRequestState))
968 // From this point on, we need to ensure that we call
969 // ReleaseRequestState, so the code below jumps to
970 // `release:' to guarantee it rather than yielding.
972 if (PreRequestHandlerExecute != null)
973 foreach (bool stop in RunHooks (PreRequestHandlerExecute))
978 context.BeginTimeoutPossible ();
979 if (handler != null){
980 IHttpAsyncHandler async_handler = handler as IHttpAsyncHandler;
982 if (async_handler != null){
985 async_handler.BeginProcessRequest (context, async_handler_complete_cb, handler);
988 handler.ProcessRequest (context);
991 } catch (ThreadAbortException taex){
992 object obj = taex.ExceptionState;
993 Thread.ResetAbort ();
994 stop_processing = true;
995 if (obj is StepTimeout)
996 ProcessError (new HttpException ("The request timed out."));
997 } catch (Exception e){
1001 context.EndTimeoutPossible ();
1004 yield return stop_processing;
1005 else if (stop_processing)
1008 // These are executed after the application has returned
1010 if (PostRequestHandlerExecute != null)
1011 foreach (bool stop in RunHooks (PostRequestHandlerExecute))
1016 if (ReleaseRequestState != null){
1017 #pragma warning disable 168
1018 foreach (bool stop in RunHooks (ReleaseRequestState)){
1020 // Ignore the stop signal while release the state
1024 #pragma warning restore 168
1027 if (stop_processing)
1031 if (PostReleaseRequestState != null)
1032 foreach (bool stop in RunHooks (PostReleaseRequestState))
1036 if (context.Error == null)
1037 context.Response.DoFilter (true);
1039 if (UpdateRequestCache != null)
1040 foreach (bool stop in RunHooks (UpdateRequestCache))
1044 if (PostUpdateRequestCache != null)
1045 foreach (bool stop in RunHooks (PostUpdateRequestCache))
1052 internal CultureInfo GetThreadCulture (HttpRequest request, CultureInfo culture, bool isAuto)
1057 CultureInfo ret = null;
1058 string[] languages = request.UserLanguages;
1060 if (languages != null && languages.Length > 0)
1061 ret = CultureInfo.CreateSpecificCulture (languages[0]);
1078 HttpRuntime.TimeoutManager.Add (context);
1080 Thread th = Thread.CurrentThread;
1081 if (app_culture != null) {
1082 prev_app_culture = th.CurrentCulture;
1083 CultureInfo new_app_culture = GetThreadCulture (Request, app_culture, autoCulture);
1084 if (!new_app_culture.Equals (CultureInfo.InvariantCulture))
1085 th.CurrentCulture = new_app_culture;
1088 if (appui_culture != null) {
1089 prev_appui_culture = th.CurrentUICulture;
1090 CultureInfo new_app_culture = GetThreadCulture (Request, appui_culture, autoUICulture);
1091 if (!new_app_culture.Equals (CultureInfo.InvariantCulture))
1092 th.CurrentUICulture = new_app_culture;
1096 prev_user = Thread.CurrentPrincipal;
1103 if (removeConfigurationFromCache) {
1104 WebConfigurationManager.RemoveConfigurationFromCache (context);
1105 removeConfigurationFromCache = false;
1108 Thread th = Thread.CurrentThread;
1110 if (Thread.CurrentPrincipal != prev_user)
1111 Thread.CurrentPrincipal = prev_user;
1113 if (prev_appui_culture != null && prev_appui_culture != th.CurrentUICulture)
1114 th.CurrentUICulture = prev_appui_culture;
1115 if (prev_app_culture != null && prev_app_culture != th.CurrentCulture)
1116 th.CurrentCulture = prev_app_culture;
1119 if (context == null)
1120 context = HttpContext.Current;
1121 HttpRuntime.TimeoutManager.Remove (context);
1125 HttpContext.Current = null;
1128 void Start (object x)
1132 } catch (Exception e) {
1134 initialization_exception = e;
1136 FinalErrorWrite (context.Response, new HttpException ("", e).GetHtmlErrorMessage ());
1141 HttpContext.Current = Context;
1143 pipeline = Pipeline ();
1147 // Used by HttpServerUtility.Execute
1148 internal IHttpHandler GetHandler (HttpContext context)
1150 HttpRequest request = context.Request;
1151 string verb = request.RequestType;
1152 string url = request.FilePath;
1154 IHttpHandler handler = null;
1156 HttpHandlersSection httpHandlersSection = (HttpHandlersSection) WebConfigurationManager.GetSection ("system.web/httpHandlers");
1157 object o = httpHandlersSection.LocateHandler (verb, url);
1159 HandlerFactoryConfiguration factory_config = (HandlerFactoryConfiguration) HttpContext.GetAppConfig ("system.web/httpHandlers");
1160 object o = factory_config.LocateHandler (verb, url);
1163 factory = o as IHttpHandlerFactory;
1165 if (factory == null) {
1166 handler = (IHttpHandler) o;
1168 handler = factory.GetHandler (context, verb, url, request.PhysicalPath);
1174 void IHttpHandler.ProcessRequest (HttpContext context)
1177 this.context = context;
1185 // This is used by FireOnAppStart, when we init the application
1186 // as the context is required to be set at that point (the user
1187 // might call methods that require it on that hook).
1189 internal void SetContext (HttpContext context)
1191 this.context = context;
1194 internal void SetSession (HttpSessionState session)
1196 this.session = session;
1199 IAsyncResult IHttpAsyncHandler.BeginProcessRequest (HttpContext context, AsyncCallback cb, object extraData)
1201 this.context = context;
1204 begin_iar = new AsyncRequestState (done, cb, extraData);
1207 IPortletRenderRequest renderRequest = context.ServletRequest as IPortletRenderRequest;
1208 if (renderRequest != null) {
1209 string actionException = context.ServletRequest.getParameter ("vmw.action.exception");
1210 if (actionException != null && actionException.Length > 0) {
1211 FinalErrorWrite (context.Response, actionException.Replace("\n", "<br>"));
1212 begin_iar.Complete ();
1221 if (Thread.CurrentThread.IsThreadPoolThread)
1225 ThreadPool.QueueUserWorkItem (new WaitCallback (Start), null);
1230 void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result)
1232 if (!result.IsCompleted)
1233 result.AsyncWaitHandle.WaitOne ();
1237 public virtual void Init ()
1241 bool IHttpHandler.IsReusable {
1248 internal void ClearError ()
1250 context.ClearError ();
1253 bool RedirectErrorPage (string error_page)
1255 if (context.Request.QueryString ["aspxerrorpath"] != null)
1258 Response.Redirect (error_page + "?aspxerrorpath=" + Request.Path, false);
1262 bool RedirectCustomError (ref HttpException httpEx)
1265 if (!context.IsCustomErrorEnabledUnsafe)
1269 CustomErrorsSection config = (CustomErrorsSection)WebConfigurationManager.GetSection ("system.web/customErrors");
1271 CustomErrorsConfig config = null;
1273 config = (CustomErrorsConfig) context.GetConfig ("system.web/customErrors");
1277 if (config == null) {
1278 if (context.ErrorPage != null)
1279 return RedirectErrorPage (context.ErrorPage);
1285 CustomError err = config.Errors [context.Response.StatusCode.ToString()];
1286 string redirect = err == null ? null : err.Redirect;
1288 string redirect = config [context.Response.StatusCode];
1290 if (redirect == null) {
1291 redirect = context.ErrorPage;
1292 if (redirect == null)
1293 redirect = config.DefaultRedirect;
1296 if (redirect == null)
1299 return RedirectErrorPage (redirect);
1301 catch (Exception ex) {
1302 httpEx = new HttpException (500, "", ex);
1310 // Based on Fritz' Onion's AsyncRequestState class for asynchronous IHttpAsyncHandlers
1312 class AsyncRequestState : IAsyncResult {
1316 ManualResetEvent complete_event = null;
1318 internal AsyncRequestState (ManualResetEvent complete_event, AsyncCallback cb, object cb_data)
1321 this.cb_data = cb_data;
1322 this.complete_event = complete_event;
1325 internal void Complete ()
1331 complete_event.Set ();
1334 public object AsyncState {
1340 public bool CompletedSynchronously {
1346 public bool IsCompleted {
1352 public WaitHandle AsyncWaitHandle {
1354 return complete_event;
1359 #region Helper classes
1362 // A wrapper to keep track of begin/end pairs
1364 class AsyncInvoker {
1365 public BeginEventHandler begin;
1366 public EndEventHandler end;
1369 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, object d)
1376 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh)
1382 public void Invoke (object sender, EventArgs e)
1384 throw new Exception ("This is just a dummy");