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.Reflection;
71 using System.Security.Permissions;
72 using System.Security.Principal;
73 using System.Threading;
74 using System.Web.Configuration;
75 using System.Web.SessionState;
79 using vmw.@internal.j2ee;
82 namespace System.Web {
85 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
86 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
89 public class HttpApplication : IHttpAsyncHandler, IHttpHandler, IComponent, IDisposable {
90 object this_lock = new object();
93 HttpSessionState session;
96 // The source, and the exposed API (cache).
97 HttpModuleCollection modcoll;
99 string assemblyLocation;
102 // The factory for the handler currently running.
104 IHttpHandlerFactory factory;
107 // Whether the thread culture is to be auto-set.
108 // Used only in the 2.0 profile, always false for 1.x
114 // Whether the pipeline should be stopped
116 bool stop_processing;
121 IEnumerator pipeline;
123 // To flag when we are done processing a request from BeginProcessRequest.
124 ManualResetEvent done;
126 // The current IAsyncResult for the running async request handler in the pipeline
127 AsyncRequestState begin_iar;
129 // Tracks the current AsyncInvocation being dispatched
130 AsyncInvoker current_ai;
132 // We don't use the EventHandlerList here, but derived classes might do
133 EventHandlerList events;
135 // Culture and IPrincipal
136 CultureInfo app_culture;
137 CultureInfo appui_culture;
138 CultureInfo prev_app_culture;
139 CultureInfo prev_appui_culture;
140 IPrincipal prev_user;
143 const string initialization_exception_key = "System.Web.HttpApplication.initialization_exception";
144 static Exception initialization_exception {
145 get { return (Exception) AppDomain.CurrentDomain.GetData (initialization_exception_key); }
146 set { AppDomain.CurrentDomain.SetData (initialization_exception_key, value); }
149 static Exception initialization_exception;
151 bool removeConfigurationFromCache;
155 // These are used to detect the case where the EndXXX method is invoked
156 // from within the BeginXXXX delegate, so we detect whether we kick the
157 // pipeline from here, or from the the RunHook routine
162 public HttpApplication ()
164 done = new ManualResetEvent (false);
167 internal void InitOnce (bool full_init)
174 HttpModulesSection modules;
175 modules = (HttpModulesSection) WebConfigurationManager.GetSection ("system.web/httpModules", HttpRuntime.AppDomainAppVirtualPath);
177 ModulesConfiguration modules;
179 modules = (ModulesConfiguration) HttpContext.GetAppConfig ("system.web/httpModules");
182 modcoll = modules.LoadModules (this);
185 HttpApplicationFactory.AttachEvents (this);
188 GlobalizationSection cfg;
189 cfg = (GlobalizationSection) WebConfigurationManager.GetSection ("system.web/globalization");
190 app_culture = cfg.GetCulture();
191 autoCulture = cfg.IsAutoCulture;
192 appui_culture = cfg.GetUICulture();
193 autoUICulture = cfg.IsAutoUICulture;
195 GlobalizationConfiguration cfg;
196 cfg = GlobalizationConfiguration.GetInstance (null);
198 app_culture = cfg.Culture;
199 appui_culture = cfg.UICulture;
205 internal string AssemblyLocation {
207 if (assemblyLocation == null)
208 assemblyLocation = GetType ().Assembly.Location;
209 return assemblyLocation;
214 internal static Exception InitializationException {
215 get { return initialization_exception; }
220 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
221 public HttpApplicationState Application {
223 return HttpApplicationFactory.ApplicationState;
228 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
229 public HttpContext Context {
235 protected EventHandlerList Events {
238 events = new EventHandlerList ();
245 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
246 public HttpModuleCollection Modules {
247 [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
250 modcoll = new HttpModuleCollection ();
257 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
258 public HttpRequest Request {
261 throw new HttpException (Locale.GetText ("No context is available."));
263 if (false == HttpApplicationFactory.ContextAvailable)
264 throw new HttpException (Locale.GetText ("Request is not available in this context."));
266 return context.Request;
271 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
272 public HttpResponse Response {
275 throw new HttpException (Locale.GetText ("No context is available."));
277 if (false == HttpApplicationFactory.ContextAvailable)
278 throw new HttpException (Locale.GetText ("Response is not available in this context."));
280 return context.Response;
285 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
286 public HttpServerUtility Server {
289 return context.Server;
292 // This is so we can get the Server and call a few methods
293 // which are not context sensitive, see HttpServerUtilityTest
295 return new HttpServerUtility ((HttpContext) null);
300 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
301 public HttpSessionState Session {
303 // Only used for Session_End
308 throw new HttpException (Locale.GetText ("No context is available."));
309 return context.Session;
314 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
318 public virtual ISite Site {
330 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
331 public IPrincipal User {
334 throw new HttpException (Locale.GetText ("No context is available."));
335 if (context.User == null)
336 throw new HttpException (Locale.GetText ("No currently authenticated user."));
342 public virtual event EventHandler Disposed;
343 public virtual event EventHandler Error;
345 public event EventHandler PreSendRequestHeaders;
346 internal void TriggerPreSendRequestHeaders ()
348 if (PreSendRequestHeaders != null)
349 PreSendRequestHeaders (this, EventArgs.Empty);
352 public event EventHandler PreSendRequestContent;
353 internal void TriggerPreSendRequestContent ()
355 if (PreSendRequestContent != null)
356 PreSendRequestContent (this, EventArgs.Empty);
359 public event EventHandler AcquireRequestState;
360 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
362 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
363 AcquireRequestState += new EventHandler (invoker.Invoke);
366 public event EventHandler AuthenticateRequest;
367 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
369 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
370 AuthenticateRequest += new EventHandler (invoker.Invoke);
373 public event EventHandler AuthorizeRequest;
374 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
376 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
377 AuthorizeRequest += new EventHandler (invoker.Invoke);
380 public event EventHandler BeginRequest;
381 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh)
383 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
384 BeginRequest += new EventHandler (invoker.Invoke);
387 public event EventHandler EndRequest;
388 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh)
390 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
391 EndRequest += new EventHandler (invoker.Invoke);
394 public event EventHandler PostRequestHandlerExecute;
395 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
397 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
398 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
401 public event EventHandler PreRequestHandlerExecute;
402 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
404 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
405 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
408 public event EventHandler ReleaseRequestState;
409 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
411 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
412 ReleaseRequestState += new EventHandler (invoker.Invoke);
415 public event EventHandler ResolveRequestCache;
416 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
418 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
419 ResolveRequestCache += new EventHandler (invoker.Invoke);
422 public event EventHandler UpdateRequestCache;
423 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
425 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
426 UpdateRequestCache += new EventHandler (invoker.Invoke);
430 public event EventHandler PostAuthenticateRequest;
431 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
433 AddOnPostAuthenticateRequestAsync (bh, eh, null);
436 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
438 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
439 PostAuthenticateRequest += new EventHandler (invoker.Invoke);
442 public event EventHandler PostAuthorizeRequest;
443 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
445 AddOnPostAuthorizeRequestAsync (bh, eh, null);
448 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
450 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
451 PostAuthorizeRequest += new EventHandler (invoker.Invoke);
454 public event EventHandler PostResolveRequestCache;
455 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
457 AddOnPostResolveRequestCacheAsync (bh, eh, null);
460 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
462 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
463 PostResolveRequestCache += new EventHandler (invoker.Invoke);
466 public event EventHandler PostMapRequestHandler;
467 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
469 AddOnPostMapRequestHandlerAsync (bh, eh, null);
472 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh, object data)
474 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
475 PostMapRequestHandler += new EventHandler (invoker.Invoke);
478 public event EventHandler PostAcquireRequestState;
479 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
481 AddOnPostAcquireRequestStateAsync (bh, eh, null);
484 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
486 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
487 PostAcquireRequestState += new EventHandler (invoker.Invoke);
490 public event EventHandler PostReleaseRequestState;
491 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
493 AddOnPostReleaseRequestStateAsync (bh, eh, null);
496 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
498 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
499 PostReleaseRequestState += new EventHandler (invoker.Invoke);
502 public event EventHandler PostUpdateRequestCache;
503 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
505 AddOnPostUpdateRequestCacheAsync (bh, eh, null);
508 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
510 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
511 PostUpdateRequestCache += new EventHandler (invoker.Invoke);
515 // The new overloads that take a data parameter
517 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
519 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
520 AcquireRequestState += new EventHandler (invoker.Invoke);
523 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
525 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
526 AuthenticateRequest += new EventHandler (invoker.Invoke);
529 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
531 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
532 AuthorizeRequest += new EventHandler (invoker.Invoke);
535 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
537 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
538 BeginRequest += new EventHandler (invoker.Invoke);
541 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
543 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
544 EndRequest += new EventHandler (invoker.Invoke);
547 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
549 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
550 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
553 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
555 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
556 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
559 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
561 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
562 ReleaseRequestState += new EventHandler (invoker.Invoke);
565 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
567 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
568 ResolveRequestCache += new EventHandler (invoker.Invoke);
571 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
573 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
574 UpdateRequestCache += new EventHandler (invoker.Invoke);
578 internal event EventHandler DefaultAuthentication;
581 // Bypass all the event on the Http pipeline and go directly to EndRequest
583 public void CompleteRequest ()
585 stop_processing = true;
588 internal bool RequestCompleted {
589 set { stop_processing = value; }
592 public virtual void Dispose ()
594 if (modcoll != null) {
595 for (int i = modcoll.Count - 1; i >= 0; i--) {
596 modcoll.Get (i).Dispose ();
601 if (Disposed != null)
602 Disposed (this, EventArgs.Empty);
608 public virtual string GetVaryByCustomString (HttpContext context, string custom)
610 if (custom == null) // Sigh
611 throw new NullReferenceException ();
613 if (0 == String.Compare (custom, "browser", true, CultureInfo.InvariantCulture))
614 return context.Request.Browser.Type;
620 // If we catch an error, queue this error
622 void ProcessError (Exception e)
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.MoveNext ()){
656 if ((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);
846 context.WorkerRequest.EndOfRequest();
847 if (factory != null && context.Handler != null){
848 factory.ReleaseHandler (context.Handler);
849 context.Handler = null;
853 context.PopHandler ();
855 // context = null; -> moved to PostDone
861 if (begin_iar != null)
862 begin_iar.Complete ();
868 // Events fired as described in `Http Runtime Support, HttpModules,
869 // Handling Public Events'
871 IEnumerator Pipeline ()
876 if (BeginRequest != null)
877 foreach (bool stop in RunHooks (BeginRequest))
880 if (AuthenticateRequest != null)
881 foreach (bool stop in RunHooks (AuthenticateRequest))
884 if (DefaultAuthentication != null)
885 foreach (bool stop in RunHooks (DefaultAuthentication))
889 if (PostAuthenticateRequest != null)
890 foreach (bool stop in RunHooks (PostAuthenticateRequest))
893 if (AuthorizeRequest != null)
894 foreach (bool stop in RunHooks (AuthorizeRequest))
897 if (PostAuthorizeRequest != null)
898 foreach (bool stop in RunHooks (PostAuthorizeRequest))
902 if (ResolveRequestCache != null)
903 foreach (bool stop in RunHooks (ResolveRequestCache))
907 if (PostResolveRequestCache != null)
908 foreach (bool stop in RunHooks (PostResolveRequestCache))
912 // Obtain the handler for the request.
913 IHttpHandler handler = null;
915 handler = GetHandler (context);
916 context.Handler = handler;
918 context.PushHandler (handler);
920 } catch (FileNotFoundException fnf){
921 if (context.Request.IsLocal)
922 ProcessError (new HttpException (404, String.Format ("File not found {0}", fnf.FileName), fnf));
924 ProcessError (new HttpException (404, "File not found: " + Path.GetFileName (fnf.FileName)));
925 } catch (DirectoryNotFoundException dnf){
926 if (!context.Request.IsLocal)
927 dnf = null; // Do not "leak" real path information
928 ProcessError (new HttpException (404, "Directory not found", dnf));
929 } catch (Exception e) {
937 if (PostMapRequestHandler != null)
938 foreach (bool stop in RunHooks (PostMapRequestHandler))
942 if (AcquireRequestState != null){
943 foreach (bool stop in RunHooks (AcquireRequestState))
948 if (PostAcquireRequestState != null){
949 foreach (bool stop in RunHooks (PostAcquireRequestState))
955 // From this point on, we need to ensure that we call
956 // ReleaseRequestState, so the code below jumps to
957 // `release:' to guarantee it rather than yielding.
959 if (PreRequestHandlerExecute != null)
960 foreach (bool stop in RunHooks (PreRequestHandlerExecute))
965 context.BeginTimeoutPossible ();
966 if (handler != null){
967 IHttpAsyncHandler async_handler = handler as IHttpAsyncHandler;
969 if (async_handler != null){
972 async_handler.BeginProcessRequest (context, async_handler_complete_cb, handler);
975 handler.ProcessRequest (context);
978 } catch (ThreadAbortException taex){
979 object obj = taex.ExceptionState;
980 Thread.ResetAbort ();
981 stop_processing = true;
982 if (obj is StepTimeout)
983 ProcessError (new HttpException ("The request timed out."));
984 } catch (Exception e){
988 context.EndTimeoutPossible ();
991 yield return stop_processing;
992 else if (stop_processing)
995 // These are executed after the application has returned
997 if (PostRequestHandlerExecute != null)
998 foreach (bool stop in RunHooks (PostRequestHandlerExecute))
1003 if (ReleaseRequestState != null){
1004 #pragma warning disable 168
1005 foreach (bool stop in RunHooks (ReleaseRequestState)){
1007 // Ignore the stop signal while release the state
1011 #pragma warning restore 168
1014 if (stop_processing)
1018 if (PostReleaseRequestState != null)
1019 foreach (bool stop in RunHooks (PostReleaseRequestState))
1023 if (context.Error == null)
1024 context.Response.DoFilter (true);
1026 if (UpdateRequestCache != null)
1027 foreach (bool stop in RunHooks (UpdateRequestCache))
1031 if (PostUpdateRequestCache != null)
1032 foreach (bool stop in RunHooks (PostUpdateRequestCache))
1039 internal CultureInfo GetThreadCulture (HttpRequest request, CultureInfo culture, bool isAuto)
1044 CultureInfo ret = null;
1045 string[] languages = request.UserLanguages;
1047 if (languages != null && languages.Length > 0)
1048 ret = CultureInfo.CreateSpecificCulture (languages[0]);
1065 HttpRuntime.TimeoutManager.Add (context);
1067 Thread th = Thread.CurrentThread;
1068 if (app_culture != null) {
1069 prev_app_culture = th.CurrentCulture;
1070 CultureInfo new_app_culture = GetThreadCulture (Request, app_culture, autoCulture);
1071 if (!new_app_culture.Equals (CultureInfo.InvariantCulture))
1072 th.CurrentCulture = new_app_culture;
1075 if (appui_culture != null) {
1076 prev_appui_culture = th.CurrentUICulture;
1077 CultureInfo new_app_culture = GetThreadCulture (Request, appui_culture, autoUICulture);
1078 if (!new_app_culture.Equals (CultureInfo.InvariantCulture))
1079 th.CurrentUICulture = new_app_culture;
1083 prev_user = Thread.CurrentPrincipal;
1090 if (removeConfigurationFromCache) {
1091 WebConfigurationManager.RemoveConfigurationFromCache (context);
1092 removeConfigurationFromCache = false;
1095 Thread th = Thread.CurrentThread;
1097 if (Thread.CurrentPrincipal != prev_user)
1098 Thread.CurrentPrincipal = prev_user;
1100 if (prev_appui_culture != null && prev_appui_culture != th.CurrentUICulture)
1101 th.CurrentUICulture = prev_appui_culture;
1102 if (prev_app_culture != null && prev_app_culture != th.CurrentCulture)
1103 th.CurrentCulture = prev_app_culture;
1106 if (context == null)
1107 context = HttpContext.Current;
1108 HttpRuntime.TimeoutManager.Remove (context);
1112 HttpContext.Current = null;
1115 void Start (object x)
1119 } catch (Exception e) {
1121 initialization_exception = e;
1123 FinalErrorWrite (context.Response, new HttpException ("", e).GetHtmlErrorMessage ());
1128 HttpContext.Current = Context;
1130 pipeline = Pipeline ();
1134 // Used by HttpServerUtility.Execute
1135 internal IHttpHandler GetHandler (HttpContext context)
1137 HttpRequest request = context.Request;
1138 string verb = request.RequestType;
1139 string url = request.FilePath;
1141 IHttpHandler handler = null;
1143 HttpHandlersSection httpHandlersSection = (HttpHandlersSection) WebConfigurationManager.GetSection ("system.web/httpHandlers");
1144 object o = httpHandlersSection.LocateHandler (verb, url);
1146 HandlerFactoryConfiguration factory_config = (HandlerFactoryConfiguration) HttpContext.GetAppConfig ("system.web/httpHandlers");
1147 object o = factory_config.LocateHandler (verb, url);
1150 factory = o as IHttpHandlerFactory;
1152 if (factory == null) {
1153 handler = (IHttpHandler) o;
1155 handler = factory.GetHandler (context, verb, url, request.PhysicalPath);
1161 void IHttpHandler.ProcessRequest (HttpContext context)
1164 this.context = context;
1172 // This is used by FireOnAppStart, when we init the application
1173 // as the context is required to be set at that point (the user
1174 // might call methods that require it on that hook).
1176 internal void SetContext (HttpContext context)
1178 this.context = context;
1181 internal void SetSession (HttpSessionState session)
1183 this.session = session;
1186 IAsyncResult IHttpAsyncHandler.BeginProcessRequest (HttpContext context, AsyncCallback cb, object extraData)
1188 this.context = context;
1191 begin_iar = new AsyncRequestState (done, cb, extraData);
1194 IPortletRenderRequest renderRequest = context.ServletRequest as IPortletRenderRequest;
1195 if (renderRequest != null) {
1196 string actionException = context.ServletRequest.getParameter ("vmw.action.exception");
1197 if (actionException != null && actionException.Length > 0) {
1198 FinalErrorWrite (context.Response, actionException.Replace("\n", "<br>"));
1199 begin_iar.Complete ();
1208 if (Thread.CurrentThread.IsThreadPoolThread)
1212 ThreadPool.QueueUserWorkItem (new WaitCallback (Start), null);
1217 void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result)
1219 if (!result.IsCompleted)
1220 result.AsyncWaitHandle.WaitOne ();
1224 public virtual void Init ()
1228 bool IHttpHandler.IsReusable {
1235 internal void ClearError ()
1237 context.ClearError ();
1240 bool RedirectErrorPage (string error_page)
1242 if (context.Request.QueryString ["aspxerrorpath"] != null)
1245 Response.Redirect (error_page + "?aspxerrorpath=" + Request.Path, false);
1249 bool RedirectCustomError (ref HttpException httpEx)
1252 if (!context.IsCustomErrorEnabledUnsafe)
1256 CustomErrorsSection config = (CustomErrorsSection)WebConfigurationManager.GetSection ("system.web/customErrors");
1258 CustomErrorsConfig config = null;
1260 config = (CustomErrorsConfig) context.GetConfig ("system.web/customErrors");
1264 if (config == null) {
1265 if (context.ErrorPage != null)
1266 return RedirectErrorPage (context.ErrorPage);
1272 CustomError err = config.Errors [context.Response.StatusCode.ToString()];
1273 string redirect = err == null ? null : err.Redirect;
1275 string redirect = config [context.Response.StatusCode];
1277 if (redirect == null) {
1278 redirect = context.ErrorPage;
1279 if (redirect == null)
1280 redirect = config.DefaultRedirect;
1283 if (redirect == null)
1286 return RedirectErrorPage (redirect);
1288 catch (Exception ex) {
1289 httpEx = new HttpException (500, "", ex);
1295 internal static IEnumerable PrivateBinPath
1298 AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
1299 string baseDir = setup.ApplicationBase;
1301 string pbp = setup.PrivateBinPath;
1302 if (pbp == null || pbp.Length == 0)
1304 foreach (string d in pbp.Split (Path.PathSeparator))
1305 yield return Path.Combine (baseDir, d);
1309 internal static Type LoadType (string typeName)
1311 return LoadType (typeName, false);
1314 internal static Type LoadType (string typeName, bool throwOnMissing)
1316 Type type = Type.GetType (typeName);
1320 Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
1321 foreach (Assembly ass in assemblies) {
1322 type = ass.GetType (typeName, false);
1328 IList tla = System.Web.Compilation.BuildManager.TopLevelAssemblies;
1329 if (tla != null && tla.Count > 0) {
1330 foreach (Assembly asm in tla) {
1333 type = asm.GetType (typeName, false);
1340 type = LoadTypeFromPrivateBin (typeName);
1345 throw new TypeLoadException (String.Format ("Type '{0}' cannot be found", typeName));
1350 internal static Type LoadTypeFromPrivateBin (string typeName)
1354 foreach (string dir in PrivateBinPath) {
1355 if (!Directory.Exists (dir))
1358 string[] binDlls = Directory.GetFiles(dir, "*.dll");
1359 foreach (string s in binDlls) {
1360 Assembly binA = Assembly.LoadFrom (s);
1361 type = binA.GetType (typeName, false);
1374 // Based on Fritz' Onion's AsyncRequestState class for asynchronous IHttpAsyncHandlers
1376 class AsyncRequestState : IAsyncResult {
1380 ManualResetEvent complete_event = null;
1382 internal AsyncRequestState (ManualResetEvent complete_event, AsyncCallback cb, object cb_data)
1385 this.cb_data = cb_data;
1386 this.complete_event = complete_event;
1389 internal void Complete ()
1394 // TODO: if this throws an error, we have no way of reporting it
1395 // Not really too bad, since the only failure might be
1396 // `HttpRuntime.request_processed'.
1403 complete_event.Set ();
1406 public object AsyncState {
1412 public bool CompletedSynchronously {
1418 public bool IsCompleted {
1424 public WaitHandle AsyncWaitHandle {
1426 return complete_event;
1431 #region Helper classes
1434 // A wrapper to keep track of begin/end pairs
1436 class AsyncInvoker {
1437 public BeginEventHandler begin;
1438 public EndEventHandler end;
1441 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, object d)
1448 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh)
1454 public void Invoke (object sender, EventArgs e)
1456 throw new Exception ("This is just a dummy");