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;
149 HandlerFactoryConfiguration factory_config;
153 // These are used to detect the case where the EndXXX method is invoked
154 // from within the BeginXXXX delegate, so we detect whether we kick the
155 // pipeline from here, or from the the RunHook routine
160 public HttpApplication ()
162 done = new ManualResetEvent (false);
165 internal void InitOnce (bool full_init)
172 HttpModulesSection modules;
173 modules = (HttpModulesSection) WebConfigurationManager.GetSection ("system.web/httpModules", HttpRuntime.AppDomainAppVirtualPath);
175 ModulesConfiguration modules;
177 modules = (ModulesConfiguration) HttpContext.GetAppConfig ("system.web/httpModules");
180 modcoll = modules.LoadModules (this);
183 HttpApplicationFactory.AttachEvents (this);
186 GlobalizationSection cfg;
187 cfg = (GlobalizationSection) WebConfigurationManager.GetSection ("system.web/globalization");
188 app_culture = cfg.GetCulture();
189 autoCulture = cfg.IsAutoCulture;
190 appui_culture = cfg.GetUICulture();
191 autoUICulture = cfg.IsAutoUICulture;
193 GlobalizationConfiguration cfg;
194 cfg = GlobalizationConfiguration.GetInstance (null);
196 app_culture = cfg.Culture;
197 appui_culture = cfg.UICulture;
202 factory_config = (HandlerFactoryConfiguration) HttpContext.GetAppConfig ("system.web/httpHandlers");
207 internal string AssemblyLocation {
209 if (assemblyLocation == null)
210 assemblyLocation = GetType ().Assembly.Location;
211 return assemblyLocation;
216 internal static Exception InitializationException {
217 get { return initialization_exception; }
222 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
223 public HttpApplicationState Application {
225 return HttpApplicationFactory.ApplicationState;
230 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
231 public HttpContext Context {
237 protected EventHandlerList Events {
240 events = new EventHandlerList ();
247 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
248 public HttpModuleCollection Modules {
249 [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
252 modcoll = new HttpModuleCollection ();
259 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
260 public HttpRequest Request {
263 throw new HttpException (Locale.GetText ("No context is available."));
265 if (false == HttpApplicationFactory.ContextAvailable)
266 throw new HttpException (Locale.GetText ("Request is not available in this context."));
268 return context.Request;
273 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
274 public HttpResponse Response {
277 throw new HttpException (Locale.GetText ("No context is available."));
279 if (false == HttpApplicationFactory.ContextAvailable)
280 throw new HttpException (Locale.GetText ("Response is not available in this context."));
282 return context.Response;
287 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
288 public HttpServerUtility Server {
291 return context.Server;
294 // This is so we can get the Server and call a few methods
295 // which are not context sensitive, see HttpServerUtilityTest
297 return new HttpServerUtility ((HttpContext) null);
302 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
303 public HttpSessionState Session {
305 // Only used for Session_End
310 throw new HttpException (Locale.GetText ("No context is available."));
311 return context.Session;
316 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
320 public virtual ISite Site {
332 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
333 public IPrincipal User {
336 throw new HttpException (Locale.GetText ("No context is available."));
337 if (context.User == null)
338 throw new HttpException (Locale.GetText ("No currently authenticated user."));
344 public virtual event EventHandler Disposed;
345 public virtual event EventHandler Error;
347 public event EventHandler PreSendRequestHeaders;
348 internal void TriggerPreSendRequestHeaders ()
350 if (PreSendRequestHeaders != null)
351 PreSendRequestHeaders (this, EventArgs.Empty);
354 public event EventHandler PreSendRequestContent;
355 internal void TriggerPreSendRequestContent ()
357 if (PreSendRequestContent != null)
358 PreSendRequestContent (this, EventArgs.Empty);
361 public event EventHandler AcquireRequestState;
362 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
364 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
365 AcquireRequestState += new EventHandler (invoker.Invoke);
368 public event EventHandler AuthenticateRequest;
369 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
371 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
372 AuthenticateRequest += new EventHandler (invoker.Invoke);
375 public event EventHandler AuthorizeRequest;
376 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
378 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
379 AuthorizeRequest += new EventHandler (invoker.Invoke);
382 public event EventHandler BeginRequest;
383 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh)
385 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
386 BeginRequest += new EventHandler (invoker.Invoke);
389 public event EventHandler EndRequest;
390 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh)
392 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
393 EndRequest += new EventHandler (invoker.Invoke);
396 public event EventHandler PostRequestHandlerExecute;
397 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
399 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
400 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
403 public event EventHandler PreRequestHandlerExecute;
404 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
406 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
407 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
410 public event EventHandler ReleaseRequestState;
411 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
413 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
414 ReleaseRequestState += new EventHandler (invoker.Invoke);
417 public event EventHandler ResolveRequestCache;
418 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
420 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
421 ResolveRequestCache += new EventHandler (invoker.Invoke);
424 public event EventHandler UpdateRequestCache;
425 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
427 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
428 UpdateRequestCache += new EventHandler (invoker.Invoke);
432 public event EventHandler PostAuthenticateRequest;
433 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
435 AddOnPostAuthenticateRequestAsync (bh, eh, null);
438 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
440 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
441 PostAuthenticateRequest += new EventHandler (invoker.Invoke);
444 public event EventHandler PostAuthorizeRequest;
445 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
447 AddOnPostAuthorizeRequestAsync (bh, eh, null);
450 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
452 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
453 PostAuthorizeRequest += new EventHandler (invoker.Invoke);
456 public event EventHandler PostResolveRequestCache;
457 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
459 AddOnPostResolveRequestCacheAsync (bh, eh, null);
462 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
464 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
465 PostResolveRequestCache += new EventHandler (invoker.Invoke);
468 public event EventHandler PostMapRequestHandler;
469 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
471 AddOnPostMapRequestHandlerAsync (bh, eh, null);
474 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh, object data)
476 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
477 PostMapRequestHandler += new EventHandler (invoker.Invoke);
480 public event EventHandler PostAcquireRequestState;
481 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
483 AddOnPostAcquireRequestStateAsync (bh, eh, null);
486 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
488 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
489 PostAcquireRequestState += new EventHandler (invoker.Invoke);
492 public event EventHandler PostReleaseRequestState;
493 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
495 AddOnPostReleaseRequestStateAsync (bh, eh, null);
498 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
500 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
501 PostReleaseRequestState += new EventHandler (invoker.Invoke);
504 public event EventHandler PostUpdateRequestCache;
505 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
507 AddOnPostUpdateRequestCacheAsync (bh, eh, null);
510 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
512 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
513 PostUpdateRequestCache += new EventHandler (invoker.Invoke);
517 // The new overloads that take a data parameter
519 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
521 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
522 AcquireRequestState += new EventHandler (invoker.Invoke);
525 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
527 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
528 AuthenticateRequest += new EventHandler (invoker.Invoke);
531 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
533 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
534 AuthorizeRequest += new EventHandler (invoker.Invoke);
537 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
539 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
540 BeginRequest += new EventHandler (invoker.Invoke);
543 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
545 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
546 EndRequest += new EventHandler (invoker.Invoke);
549 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
551 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
552 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
555 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
557 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
558 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
561 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
563 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
564 ReleaseRequestState += new EventHandler (invoker.Invoke);
567 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
569 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
570 ResolveRequestCache += new EventHandler (invoker.Invoke);
573 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
575 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
576 UpdateRequestCache += new EventHandler (invoker.Invoke);
580 internal event EventHandler DefaultAuthentication;
583 // Bypass all the event on the Http pipeline and go directly to EndRequest
585 public void CompleteRequest ()
587 stop_processing = true;
590 internal bool RequestCompleted {
591 set { stop_processing = value; }
594 public virtual void Dispose ()
596 if (modcoll != null) {
597 for (int i = modcoll.Count - 1; i >= 0; i--) {
598 modcoll.Get (i).Dispose ();
603 if (Disposed != null)
604 Disposed (this, EventArgs.Empty);
610 public virtual string GetVaryByCustomString (HttpContext context, string custom)
612 if (custom == null) // Sigh
613 throw new NullReferenceException ();
615 if (0 == String.Compare (custom, "browser", true, CultureInfo.InvariantCulture))
616 return context.Request.Browser.Type;
622 // If we catch an error, queue this error
624 void ProcessError (Exception e)
627 context = HttpContext.Current;
629 bool first = context.Error == null;
630 context.AddError (e);
634 Error (this, EventArgs.Empty);
635 } catch (ThreadAbortException){
636 // This happens on Redirect() or End()
637 Thread.ResetAbort ();
638 } catch (Exception ee){
639 context.AddError (ee);
643 stop_processing = true;
647 // Ticks the clock: next step on the pipeline.
652 if (pipeline != null && pipeline.MoveNext ()){
653 if (pipeline == null || (bool)pipeline.Current)
656 } catch (ThreadAbortException taex) {
657 object obj = taex.ExceptionState;
658 Thread.ResetAbort ();
659 stop_processing = true;
660 if (obj is StepTimeout)
661 ProcessError (new HttpException ("The request timed out."));
664 } catch (Exception e) {
665 Console.WriteLine ("Tick caught an exception that has not been propagated:\n" + e);
678 // Invoked when our async callback called from RunHooks completes,
679 // we restart the pipeline here.
681 void async_callback_completed_cb (IAsyncResult ar)
683 if (current_ai.end != null){
686 } catch (Exception e) {
694 void async_handler_complete_cb (IAsyncResult ar)
696 IHttpAsyncHandler async_handler = ((IHttpAsyncHandler) ar.AsyncState);
699 async_handler.EndProcessRequest (ar);
700 } catch (Exception e){
708 // This enumerator yields whether processing must be stopped:
709 // true: processing of the pipeline must be stopped
710 // false: processing of the pipeline must not be stopped
712 IEnumerable RunHooks (Delegate list)
714 Delegate [] delegates = list.GetInvocationList ();
716 foreach (EventHandler d in delegates){
717 if (d.Target != null && (d.Target is AsyncInvoker)){
718 current_ai = (AsyncInvoker) d.Target;
723 context.BeginTimeoutPossible ();
724 current_ai.begin (this, EventArgs.Empty, async_callback_completed_cb, current_ai.data);
725 } catch (ThreadAbortException taex){
726 object obj = taex.ExceptionState;
727 Thread.ResetAbort ();
728 stop_processing = true;
729 if (obj is StepTimeout)
730 ProcessError (new HttpException ("The request timed out."));
731 } catch (Exception e){
735 context.EndTimeoutPossible ();
739 // If things are still moving forward, yield this
743 yield return stop_processing;
744 else if (stop_processing)
748 context.BeginTimeoutPossible ();
749 d (this, EventArgs.Empty);
750 } catch (ThreadAbortException taex){
751 object obj = taex.ExceptionState;
752 Thread.ResetAbort ();
753 stop_processing = true;
754 if (obj is StepTimeout)
755 ProcessError (new HttpException ("The request timed out."));
756 } catch (Exception e){
759 context.EndTimeoutPossible ();
767 static void FinalErrorWrite (HttpResponse response, string error)
770 response.Write (error);
771 response.Flush (true);
779 if (context.Error == null){
781 context.Response.Flush (true);
782 } catch (Exception e){
783 context.AddError (e);
787 Exception error = context.Error;
789 HttpResponse response = context.Response;
792 IPortletActionRequest actionRequest = context.ServletRequest as IPortletActionRequest;
793 IPortletActionResponse actionResponse = context.ServletResponse as IPortletActionResponse;
794 if (actionRequest != null && actionResponse != null && actionRequest.processActionOnly ()) {
795 string exception = "Exception of type " + context.Error.GetType () +
796 " during processAction: " + context.Error.Message + Console.Out.NewLine +
797 context.Error.StackTrace;
798 actionResponse.setRenderParameter ("vmw.action.exception", exception);
802 if (!response.HeadersSent){
803 response.ClearHeaders ();
804 response.ClearContent ();
806 if (error is HttpException){
807 response.StatusCode = ((HttpException)error).GetHttpCode ();
809 error = new HttpException ("", error);
810 response.StatusCode = 500;
812 if (!RedirectCustomError ())
813 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
815 response.Flush (true);
817 if (!(error is HttpException))
818 error = new HttpException ("", error);
819 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
826 // Invoked at the end of the pipeline execution
831 if (EndRequest != null)
832 EndRequest (this, EventArgs.Empty);
833 } catch (Exception e){
839 } catch (Exception e) {
840 Console.WriteLine ("Internal error: OutputPage threw an exception " + e);
843 context = HttpContext.Current;
844 context.WorkerRequest.EndOfRequest();
845 if (factory != null && context.Handler != null){
846 factory.ReleaseHandler (context.Handler);
847 context.Handler = null;
851 context.PopHandler ();
853 if (begin_iar != null){
855 begin_iar.Complete ();
858 // TODO: if this throws an error, we have no way of reporting it
859 // Not really too bad, since the only failure might be
860 // `HttpRuntime.request_processed'
869 // context = null; -> moved to PostDone
877 // Events fired as described in `Http Runtime Support, HttpModules,
878 // Handling Public Events'
880 IEnumerator Pipeline ()
885 if (BeginRequest != null)
886 foreach (bool stop in RunHooks (BeginRequest))
889 if (AuthenticateRequest != null)
890 foreach (bool stop in RunHooks (AuthenticateRequest))
893 if (DefaultAuthentication != null)
894 foreach (bool stop in RunHooks (DefaultAuthentication))
898 if (PostAuthenticateRequest != null)
899 foreach (bool stop in RunHooks (PostAuthenticateRequest))
902 if (AuthorizeRequest != null)
903 foreach (bool stop in RunHooks (AuthorizeRequest))
906 if (PostAuthorizeRequest != null)
907 foreach (bool stop in RunHooks (PostAuthorizeRequest))
911 if (ResolveRequestCache != null)
912 foreach (bool stop in RunHooks (ResolveRequestCache))
916 if (PostResolveRequestCache != null)
917 foreach (bool stop in RunHooks (PostResolveRequestCache))
921 // Obtain the handler for the request.
922 IHttpHandler handler = null;
924 handler = GetHandler (context);
925 context.Handler = handler;
927 context.PushHandler (handler);
929 } catch (FileNotFoundException fnf){
930 if (context.Request.IsLocal)
931 ProcessError (new HttpException (404, String.Format ("File not found {0}", fnf.FileName), fnf));
933 ProcessError (new HttpException (404, "File not found: " + Path.GetFileName (fnf.FileName)));
934 } catch (DirectoryNotFoundException dnf){
935 if (!context.Request.IsLocal)
936 dnf = null; // Do not "leak" real path information
937 ProcessError (new HttpException (404, "Directory not found", dnf));
938 } catch (Exception e) {
946 if (PostMapRequestHandler != null)
947 foreach (bool stop in RunHooks (PostMapRequestHandler))
951 if (AcquireRequestState != null){
952 foreach (bool stop in RunHooks (AcquireRequestState))
957 if (PostAcquireRequestState != null){
958 foreach (bool stop in RunHooks (PostAcquireRequestState))
964 // From this point on, we need to ensure that we call
965 // ReleaseRequestState, so the code below jumps to
966 // `release:' to guarantee it rather than yielding.
968 if (PreRequestHandlerExecute != null)
969 foreach (bool stop in RunHooks (PreRequestHandlerExecute))
974 context.BeginTimeoutPossible ();
975 if (handler != null){
976 IHttpAsyncHandler async_handler = handler as IHttpAsyncHandler;
978 if (async_handler != null){
981 async_handler.BeginProcessRequest (context, async_handler_complete_cb, handler);
984 handler.ProcessRequest (context);
987 } catch (ThreadAbortException taex){
988 object obj = taex.ExceptionState;
989 Thread.ResetAbort ();
990 stop_processing = true;
991 if (obj is StepTimeout)
992 ProcessError (new HttpException ("The request timed out."));
993 } catch (Exception e){
997 context.EndTimeoutPossible ();
1000 yield return stop_processing;
1001 else if (stop_processing)
1004 // These are executed after the application has returned
1006 if (PostRequestHandlerExecute != null)
1007 foreach (bool stop in RunHooks (PostRequestHandlerExecute))
1012 if (ReleaseRequestState != null){
1013 #pragma warning disable 168
1014 foreach (bool stop in RunHooks (ReleaseRequestState)){
1016 // Ignore the stop signal while release the state
1020 #pragma warning restore 168
1023 if (stop_processing)
1027 if (PostReleaseRequestState != null)
1028 foreach (bool stop in RunHooks (PostReleaseRequestState))
1032 if (context.Error == null)
1033 context.Response.DoFilter (true);
1035 if (UpdateRequestCache != null)
1036 foreach (bool stop in RunHooks (UpdateRequestCache))
1040 if (PostUpdateRequestCache != null)
1041 foreach (bool stop in RunHooks (PostUpdateRequestCache))
1048 internal CultureInfo GetThreadCulture (HttpRequest request, CultureInfo culture, bool isAuto)
1053 CultureInfo ret = null;
1054 string[] languages = request.UserLanguages;
1056 if (languages != null && languages.Length > 0)
1057 ret = CultureInfo.CreateSpecificCulture (languages[0]);
1074 HttpRuntime.TimeoutManager.Add (context);
1076 Thread th = Thread.CurrentThread;
1077 if (app_culture != null) {
1078 prev_app_culture = th.CurrentCulture;
1079 CultureInfo new_app_culture = GetThreadCulture (Request, app_culture, autoCulture);
1080 if (!new_app_culture.Equals (CultureInfo.InvariantCulture))
1081 th.CurrentCulture = new_app_culture;
1084 if (appui_culture != null) {
1085 prev_appui_culture = th.CurrentUICulture;
1086 CultureInfo new_app_culture = GetThreadCulture (Request, appui_culture, autoUICulture);
1087 if (!new_app_culture.Equals (CultureInfo.InvariantCulture))
1088 th.CurrentUICulture = new_app_culture;
1092 prev_user = Thread.CurrentPrincipal;
1098 Thread th = Thread.CurrentThread;
1100 if (Thread.CurrentPrincipal != prev_user)
1101 Thread.CurrentPrincipal = prev_user;
1103 if (prev_appui_culture != null && prev_appui_culture != th.CurrentUICulture)
1104 th.CurrentUICulture = prev_appui_culture;
1105 if (prev_app_culture != null && prev_app_culture != th.CurrentCulture)
1106 th.CurrentCulture = prev_app_culture;
1109 if (context == null)
1110 context = HttpContext.Current;
1111 HttpRuntime.TimeoutManager.Remove (context);
1115 HttpContext.Current = null;
1118 void Start (object x)
1122 } catch (Exception e) {
1124 initialization_exception = e;
1126 FinalErrorWrite (context.Response, new HttpException ("", e).GetHtmlErrorMessage ());
1131 HttpContext.Current = Context;
1133 pipeline = Pipeline ();
1137 // Used by HttpServerUtility.Execute
1138 internal IHttpHandler GetHandler (HttpContext context)
1140 HttpRequest request = context.Request;
1141 string verb = request.RequestType;
1142 string url = request.FilePath;
1144 IHttpHandler handler = null;
1146 HttpHandlersSection httpHandlersSection = (HttpHandlersSection) WebConfigurationManager.GetSection ("system.web/httpHandlers");
1147 object o = httpHandlersSection.LocateHandler (verb, url);
1149 object o = factory_config.LocateHandler (verb, url);
1152 factory = o as IHttpHandlerFactory;
1154 if (factory == null) {
1155 handler = (IHttpHandler) o;
1157 handler = factory.GetHandler (context, verb, url, request.PhysicalPath);
1163 void IHttpHandler.ProcessRequest (HttpContext context)
1166 this.context = context;
1174 // This is used by FireOnAppStart, when we init the application
1175 // as the context is required to be set at that point (the user
1176 // might call methods that require it on that hook).
1178 internal void SetContext (HttpContext context)
1180 this.context = context;
1183 internal void SetSession (HttpSessionState session)
1185 this.session = session;
1188 IAsyncResult IHttpAsyncHandler.BeginProcessRequest (HttpContext context, AsyncCallback cb, object extraData)
1190 this.context = context;
1193 begin_iar = new AsyncRequestState (done, cb, extraData);
1196 IPortletRenderRequest renderRequest = context.ServletRequest as IPortletRenderRequest;
1197 if (renderRequest != null) {
1198 string actionException = context.ServletRequest.getParameter ("vmw.action.exception");
1199 if (actionException != null && actionException.Length > 0) {
1200 FinalErrorWrite (context.Response, actionException.Replace("\n", "<br>"));
1201 begin_iar.Complete ();
1210 if (Thread.CurrentThread.IsThreadPoolThread)
1214 ThreadPool.QueueUserWorkItem (new WaitCallback (Start), null);
1219 void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result)
1221 if (!result.IsCompleted)
1222 result.AsyncWaitHandle.WaitOne ();
1226 public virtual void Init ()
1230 bool IHttpHandler.IsReusable {
1237 internal void ClearError ()
1239 context.ClearError ();
1242 bool RedirectErrorPage (string error_page)
1244 if (context.Request.QueryString ["aspxerrorpath"] != null)
1247 Response.Redirect (error_page + "?aspxerrorpath=" + Request.Path, false);
1251 bool RedirectCustomError ()
1253 if (!context.IsCustomErrorEnabled)
1257 CustomErrorsSection config = (CustomErrorsSection)WebConfigurationManager.GetSection ("system.web/customErrors");
1259 CustomErrorsConfig config = null;
1261 config = (CustomErrorsConfig) context.GetConfig ("system.web/customErrors");
1265 if (config == null) {
1266 if (context.ErrorPage != null)
1267 return RedirectErrorPage (context.ErrorPage);
1273 CustomError err = config.Errors [context.Response.StatusCode.ToString()];
1274 string redirect = err == null ? null : err.Redirect;
1276 string redirect = config [context.Response.StatusCode];
1278 if (redirect == null) {
1279 redirect = context.ErrorPage;
1280 if (redirect == null)
1281 redirect = config.DefaultRedirect;
1284 if (redirect == null)
1287 return RedirectErrorPage (redirect);
1293 // Based on Fritz' Onion's AsyncRequestState class for asynchronous IHttpAsyncHandlers
1295 class AsyncRequestState : IAsyncResult {
1299 ManualResetEvent complete_event = null;
1301 internal AsyncRequestState (ManualResetEvent complete_event, AsyncCallback cb, object cb_data)
1304 this.cb_data = cb_data;
1305 this.complete_event = complete_event;
1308 internal void Complete ()
1314 complete_event.Set ();
1317 public object AsyncState {
1323 public bool CompletedSynchronously {
1329 public bool IsCompleted {
1335 public WaitHandle AsyncWaitHandle {
1337 return complete_event;
1342 #region Helper classes
1345 // A wrapper to keep track of begin/end pairs
1347 class AsyncInvoker {
1348 public BeginEventHandler begin;
1349 public EndEventHandler end;
1352 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, object d)
1359 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh)
1365 public void Invoke (object sender, EventArgs e)
1367 throw new Exception ("This is just a dummy");