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.Caching;
75 using System.Web.Configuration;
76 using System.Web.SessionState;
80 using vmw.@internal.j2ee;
83 namespace System.Web {
86 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
87 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
90 public class HttpApplication : IHttpAsyncHandler, IHttpHandler, IComponent, IDisposable {
91 object this_lock = new object();
93 internal static readonly string [] BinDirs = {"Bin", "bin"};
96 HttpSessionState session;
99 // The source, and the exposed API (cache).
100 HttpModuleCollection modcoll;
102 string assemblyLocation;
105 // The factory for the handler currently running.
107 IHttpHandlerFactory factory;
110 // Whether the thread culture is to be auto-set.
111 // Used only in the 2.0 profile, always false for 1.x
117 // Whether the pipeline should be stopped
119 bool stop_processing;
124 IEnumerator pipeline;
126 // To flag when we are done processing a request from BeginProcessRequest.
127 ManualResetEvent done;
129 // The current IAsyncResult for the running async request handler in the pipeline
130 AsyncRequestState begin_iar;
132 // Tracks the current AsyncInvocation being dispatched
133 AsyncInvoker current_ai;
135 // We don't use the EventHandlerList here, but derived classes might do
136 EventHandlerList events;
138 // Culture and IPrincipal
139 CultureInfo app_culture;
140 CultureInfo appui_culture;
141 CultureInfo prev_app_culture;
142 CultureInfo prev_appui_culture;
143 IPrincipal prev_user;
146 const string initialization_exception_key = "System.Web.HttpApplication.initialization_exception";
147 static Exception initialization_exception {
148 get { return (Exception) AppDomain.CurrentDomain.GetData (initialization_exception_key); }
149 set { AppDomain.CurrentDomain.SetData (initialization_exception_key, value); }
152 static Exception initialization_exception;
154 bool removeConfigurationFromCache;
158 // These are used to detect the case where the EndXXX method is invoked
159 // from within the BeginXXXX delegate, so we detect whether we kick the
160 // pipeline from here, or from the the RunHook routine
165 public HttpApplication ()
167 done = new ManualResetEvent (false);
170 internal void InitOnce (bool full_init)
177 HttpModulesSection modules;
178 modules = (HttpModulesSection) WebConfigurationManager.GetSection ("system.web/httpModules", HttpRuntime.AppDomainAppVirtualPath);
180 ModulesConfiguration modules;
182 modules = (ModulesConfiguration) HttpContext.GetAppConfig ("system.web/httpModules");
185 modcoll = modules.LoadModules (this);
188 HttpApplicationFactory.AttachEvents (this);
193 GlobalizationSection cfg;
194 cfg = (GlobalizationSection) WebConfigurationManager.GetSection ("system.web/globalization");
195 app_culture = cfg.GetCulture();
196 autoCulture = cfg.IsAutoCulture;
197 appui_culture = cfg.GetUICulture();
198 autoUICulture = cfg.IsAutoUICulture;
200 GlobalizationConfiguration cfg;
201 cfg = GlobalizationConfiguration.GetInstance (null);
203 app_culture = cfg.Culture;
204 appui_culture = cfg.UICulture;
210 internal string AssemblyLocation {
212 if (assemblyLocation == null)
213 assemblyLocation = GetType ().Assembly.Location;
214 return assemblyLocation;
219 internal static Exception InitializationException {
220 get { return initialization_exception; }
225 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
226 public HttpApplicationState Application {
228 return HttpApplicationFactory.ApplicationState;
233 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
234 public HttpContext Context {
240 protected EventHandlerList Events {
243 events = new EventHandlerList ();
250 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
251 public HttpModuleCollection Modules {
252 [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
255 modcoll = new HttpModuleCollection ();
262 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
263 public HttpRequest Request {
266 throw new HttpException (Locale.GetText ("No context is available."));
268 if (false == HttpApplicationFactory.ContextAvailable)
269 throw new HttpException (Locale.GetText ("Request is not available in this context."));
271 return context.Request;
276 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
277 public HttpResponse Response {
280 throw new HttpException (Locale.GetText ("No context is available."));
282 if (false == HttpApplicationFactory.ContextAvailable)
283 throw new HttpException (Locale.GetText ("Response is not available in this context."));
285 return context.Response;
290 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
291 public HttpServerUtility Server {
294 return context.Server;
297 // This is so we can get the Server and call a few methods
298 // which are not context sensitive, see HttpServerUtilityTest
300 return new HttpServerUtility ((HttpContext) null);
305 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
306 public HttpSessionState Session {
308 // Only used for Session_End
313 throw new HttpException (Locale.GetText ("No context is available."));
314 return context.Session;
319 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
323 public virtual ISite Site {
335 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
336 public IPrincipal User {
339 throw new HttpException (Locale.GetText ("No context is available."));
340 if (context.User == null)
341 throw new HttpException (Locale.GetText ("No currently authenticated user."));
347 public virtual event EventHandler Disposed;
348 public virtual event EventHandler Error;
350 public event EventHandler PreSendRequestHeaders;
351 internal void TriggerPreSendRequestHeaders ()
353 if (PreSendRequestHeaders != null)
354 PreSendRequestHeaders (this, EventArgs.Empty);
357 public event EventHandler PreSendRequestContent;
358 internal void TriggerPreSendRequestContent ()
360 if (PreSendRequestContent != null)
361 PreSendRequestContent (this, EventArgs.Empty);
364 public event EventHandler AcquireRequestState;
365 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
367 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
368 AcquireRequestState += new EventHandler (invoker.Invoke);
371 public event EventHandler AuthenticateRequest;
372 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
374 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
375 AuthenticateRequest += new EventHandler (invoker.Invoke);
378 public event EventHandler AuthorizeRequest;
379 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
381 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
382 AuthorizeRequest += new EventHandler (invoker.Invoke);
385 public event EventHandler BeginRequest;
386 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh)
388 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
389 BeginRequest += new EventHandler (invoker.Invoke);
392 public event EventHandler EndRequest;
393 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh)
395 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
396 EndRequest += new EventHandler (invoker.Invoke);
399 public event EventHandler PostRequestHandlerExecute;
400 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
402 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
403 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
406 public event EventHandler PreRequestHandlerExecute;
407 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
409 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
410 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
413 public event EventHandler ReleaseRequestState;
414 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
416 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
417 ReleaseRequestState += new EventHandler (invoker.Invoke);
420 public event EventHandler ResolveRequestCache;
421 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
423 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
424 ResolveRequestCache += new EventHandler (invoker.Invoke);
427 public event EventHandler UpdateRequestCache;
428 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
430 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
431 UpdateRequestCache += new EventHandler (invoker.Invoke);
435 public event EventHandler PostAuthenticateRequest;
436 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
438 AddOnPostAuthenticateRequestAsync (bh, eh, null);
441 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
443 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
444 PostAuthenticateRequest += new EventHandler (invoker.Invoke);
447 public event EventHandler PostAuthorizeRequest;
448 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
450 AddOnPostAuthorizeRequestAsync (bh, eh, null);
453 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
455 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
456 PostAuthorizeRequest += new EventHandler (invoker.Invoke);
459 public event EventHandler PostResolveRequestCache;
460 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
462 AddOnPostResolveRequestCacheAsync (bh, eh, null);
465 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
467 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
468 PostResolveRequestCache += new EventHandler (invoker.Invoke);
471 public event EventHandler PostMapRequestHandler;
472 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
474 AddOnPostMapRequestHandlerAsync (bh, eh, null);
477 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh, object data)
479 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
480 PostMapRequestHandler += new EventHandler (invoker.Invoke);
483 public event EventHandler PostAcquireRequestState;
484 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
486 AddOnPostAcquireRequestStateAsync (bh, eh, null);
489 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
491 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
492 PostAcquireRequestState += new EventHandler (invoker.Invoke);
495 public event EventHandler PostReleaseRequestState;
496 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
498 AddOnPostReleaseRequestStateAsync (bh, eh, null);
501 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
503 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
504 PostReleaseRequestState += new EventHandler (invoker.Invoke);
507 public event EventHandler PostUpdateRequestCache;
508 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
510 AddOnPostUpdateRequestCacheAsync (bh, eh, null);
513 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
515 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
516 PostUpdateRequestCache += new EventHandler (invoker.Invoke);
520 // The new overloads that take a data parameter
522 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
524 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
525 AcquireRequestState += new EventHandler (invoker.Invoke);
528 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
530 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
531 AuthenticateRequest += new EventHandler (invoker.Invoke);
534 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
536 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
537 AuthorizeRequest += new EventHandler (invoker.Invoke);
540 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
542 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
543 BeginRequest += new EventHandler (invoker.Invoke);
546 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
548 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
549 EndRequest += new EventHandler (invoker.Invoke);
552 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
554 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
555 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
558 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
560 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
561 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
564 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
566 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
567 ReleaseRequestState += new EventHandler (invoker.Invoke);
570 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
572 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
573 ResolveRequestCache += new EventHandler (invoker.Invoke);
576 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
578 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
579 UpdateRequestCache += new EventHandler (invoker.Invoke);
583 internal event EventHandler DefaultAuthentication;
586 // Bypass all the event on the Http pipeline and go directly to EndRequest
588 public void CompleteRequest ()
590 stop_processing = true;
593 internal bool RequestCompleted {
594 set { stop_processing = value; }
597 public virtual void Dispose ()
599 if (modcoll != null) {
600 for (int i = modcoll.Count - 1; i >= 0; i--) {
601 modcoll.Get (i).Dispose ();
606 if (Disposed != null)
607 Disposed (this, EventArgs.Empty);
613 public virtual string GetVaryByCustomString (HttpContext context, string custom)
615 if (custom == null) // Sigh
616 throw new NullReferenceException ();
618 if (0 == String.Compare (custom, "browser", true, CultureInfo.InvariantCulture))
619 return context.Request.Browser.Type;
625 // If we catch an error, queue this error
627 void ProcessError (Exception e)
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;
645 // we want to remove configuration from the cache in case of
646 // invalid resource not exists to prevent DOS attack.
647 HttpException httpEx = e as HttpException;
648 if (httpEx != null && httpEx.GetHttpCode () == 404) {
649 removeConfigurationFromCache = true;
655 // Ticks the clock: next step on the pipeline.
657 internal void Tick ()
660 if (pipeline.MoveNext ()){
661 if ((bool)pipeline.Current)
664 } catch (ThreadAbortException taex) {
665 object obj = taex.ExceptionState;
666 Thread.ResetAbort ();
667 stop_processing = true;
668 if (obj is StepTimeout)
669 ProcessError (new HttpException ("The request timed out."));
672 } catch (Exception e) {
673 Console.WriteLine ("Tick caught an exception that has not been propagated:\n" + e);
686 // Invoked when our async callback called from RunHooks completes,
687 // we restart the pipeline here.
689 void async_callback_completed_cb (IAsyncResult ar)
691 if (current_ai.end != null){
694 } catch (Exception e) {
702 void async_handler_complete_cb (IAsyncResult ar)
704 IHttpAsyncHandler async_handler = ((IHttpAsyncHandler) ar.AsyncState);
707 async_handler.EndProcessRequest (ar);
708 } catch (Exception e){
716 // This enumerator yields whether processing must be stopped:
717 // true: processing of the pipeline must be stopped
718 // false: processing of the pipeline must not be stopped
720 IEnumerable RunHooks (Delegate list)
722 Delegate [] delegates = list.GetInvocationList ();
724 foreach (EventHandler d in delegates){
725 if (d.Target != null && (d.Target is AsyncInvoker)){
726 current_ai = (AsyncInvoker) d.Target;
731 context.BeginTimeoutPossible ();
732 current_ai.begin (this, EventArgs.Empty, async_callback_completed_cb, current_ai.data);
733 } catch (ThreadAbortException taex){
734 object obj = taex.ExceptionState;
735 Thread.ResetAbort ();
736 stop_processing = true;
737 if (obj is StepTimeout)
738 ProcessError (new HttpException ("The request timed out."));
739 } catch (Exception e){
743 context.EndTimeoutPossible ();
747 // If things are still moving forward, yield this
751 yield return stop_processing;
752 else if (stop_processing)
756 context.BeginTimeoutPossible ();
757 d (this, EventArgs.Empty);
758 } catch (ThreadAbortException taex){
759 object obj = taex.ExceptionState;
760 Thread.ResetAbort ();
761 stop_processing = true;
762 if (obj is StepTimeout)
763 ProcessError (new HttpException ("The request timed out."));
764 } catch (Exception e){
767 context.EndTimeoutPossible ();
775 static void FinalErrorWrite (HttpResponse response, string error)
778 response.Write (error);
779 response.Flush (true);
787 if (context.Error == null){
789 context.Response.Flush (true);
790 } catch (Exception e){
791 context.AddError (e);
795 Exception error = context.Error;
797 HttpResponse response = context.Response;
800 IPortletActionRequest actionRequest = context.ServletRequest as IPortletActionRequest;
801 IPortletActionResponse actionResponse = context.ServletResponse as IPortletActionResponse;
802 if (actionRequest != null && actionResponse != null && actionRequest.processActionOnly ()) {
803 string exception = "Exception of type " + context.Error.GetType () +
804 " during processAction: " + context.Error.Message + Console.Out.NewLine +
805 context.Error.StackTrace;
806 actionResponse.setRenderParameter ("vmw.action.exception", exception);
810 if (!response.HeadersSent){
811 response.ClearHeaders ();
812 response.ClearContent ();
814 if (error is HttpException){
815 response.StatusCode = ((HttpException)error).GetHttpCode ();
817 error = new HttpException ("", error);
818 response.StatusCode = 500;
820 HttpException httpEx = (HttpException) error;
821 if (!RedirectCustomError (ref httpEx))
822 FinalErrorWrite (response, httpEx.GetHtmlErrorMessage ());
824 response.Flush (true);
826 if (!(error is HttpException))
827 error = new HttpException ("", error);
828 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
835 // Invoked at the end of the pipeline execution
840 if (EndRequest != null)
841 EndRequest (this, EventArgs.Empty);
842 } catch (Exception e){
848 } catch (Exception e) {
849 Console.WriteLine ("Internal error: OutputPage threw an exception " + e);
851 context.WorkerRequest.EndOfRequest();
852 if (factory != null && context.Handler != null){
853 factory.ReleaseHandler (context.Handler);
854 context.Handler = null;
858 context.PopHandler ();
860 // context = null; -> moved to PostDone
866 if (begin_iar != null)
867 begin_iar.Complete ();
873 // Events fired as described in `Http Runtime Support, HttpModules,
874 // Handling Public Events'
876 IEnumerator Pipeline ()
881 if (BeginRequest != null)
882 foreach (bool stop in RunHooks (BeginRequest))
885 if (AuthenticateRequest != null)
886 foreach (bool stop in RunHooks (AuthenticateRequest))
889 if (DefaultAuthentication != null)
890 foreach (bool stop in RunHooks (DefaultAuthentication))
894 if (PostAuthenticateRequest != null)
895 foreach (bool stop in RunHooks (PostAuthenticateRequest))
898 if (AuthorizeRequest != null)
899 foreach (bool stop in RunHooks (AuthorizeRequest))
902 if (PostAuthorizeRequest != null)
903 foreach (bool stop in RunHooks (PostAuthorizeRequest))
907 if (ResolveRequestCache != null)
908 foreach (bool stop in RunHooks (ResolveRequestCache))
912 if (PostResolveRequestCache != null)
913 foreach (bool stop in RunHooks (PostResolveRequestCache))
917 // Obtain the handler for the request.
918 IHttpHandler handler = null;
920 handler = GetHandler (context);
921 context.Handler = handler;
923 context.PushHandler (handler);
925 } catch (FileNotFoundException fnf){
926 if (context.Request.IsLocal)
927 ProcessError (new HttpException (404, String.Format ("File not found {0}", fnf.FileName), fnf));
929 ProcessError (new HttpException (404, "File not found: " + Path.GetFileName (fnf.FileName)));
930 } catch (DirectoryNotFoundException dnf){
931 if (!context.Request.IsLocal)
932 dnf = null; // Do not "leak" real path information
933 ProcessError (new HttpException (404, "Directory not found", dnf));
934 } catch (Exception e) {
942 if (PostMapRequestHandler != null)
943 foreach (bool stop in RunHooks (PostMapRequestHandler))
947 if (AcquireRequestState != null){
948 foreach (bool stop in RunHooks (AcquireRequestState))
953 if (PostAcquireRequestState != null){
954 foreach (bool stop in RunHooks (PostAcquireRequestState))
960 // From this point on, we need to ensure that we call
961 // ReleaseRequestState, so the code below jumps to
962 // `release:' to guarantee it rather than yielding.
964 if (PreRequestHandlerExecute != null)
965 foreach (bool stop in RunHooks (PreRequestHandlerExecute))
970 bool doProcessHandler = false;
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);
986 IHttpExtendedHandler extHandler=handler as IHttpExtendedHandler;
987 doProcessHandler = extHandler != null && !extHandler.getCompleted ();
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 if (doProcessHandler) {
1006 goto processHandler;
1010 yield return stop_processing;
1011 else if (stop_processing)
1014 // These are executed after the application has returned
1016 if (PostRequestHandlerExecute != null)
1017 foreach (bool stop in RunHooks (PostRequestHandlerExecute))
1022 if (ReleaseRequestState != null){
1023 #pragma warning disable 168
1024 foreach (bool stop in RunHooks (ReleaseRequestState)){
1026 // Ignore the stop signal while release the state
1030 #pragma warning restore 168
1033 if (stop_processing)
1037 if (PostReleaseRequestState != null)
1038 foreach (bool stop in RunHooks (PostReleaseRequestState))
1042 if (context.Error == null)
1043 context.Response.DoFilter (true);
1045 if (UpdateRequestCache != null)
1046 foreach (bool stop in RunHooks (UpdateRequestCache))
1050 if (PostUpdateRequestCache != null)
1051 foreach (bool stop in RunHooks (PostUpdateRequestCache))
1058 internal CultureInfo GetThreadCulture (HttpRequest request, CultureInfo culture, bool isAuto)
1063 CultureInfo ret = null;
1064 string[] languages = request.UserLanguages;
1066 if (languages != null && languages.Length > 0)
1067 ret = CultureInfo.CreateSpecificCulture (languages[0]);
1084 HttpRuntime.TimeoutManager.Add (context);
1086 Thread th = Thread.CurrentThread;
1087 if (app_culture != null) {
1088 prev_app_culture = th.CurrentCulture;
1089 CultureInfo new_app_culture = GetThreadCulture (Request, app_culture, autoCulture);
1090 if (!new_app_culture.Equals (CultureInfo.InvariantCulture))
1091 th.CurrentCulture = new_app_culture;
1094 if (appui_culture != null) {
1095 prev_appui_culture = th.CurrentUICulture;
1096 CultureInfo new_app_culture = GetThreadCulture (Request, appui_culture, autoUICulture);
1097 if (!new_app_culture.Equals (CultureInfo.InvariantCulture))
1098 th.CurrentUICulture = new_app_culture;
1102 prev_user = Thread.CurrentPrincipal;
1109 if (removeConfigurationFromCache) {
1110 WebConfigurationManager.RemoveConfigurationFromCache (context);
1111 removeConfigurationFromCache = false;
1114 Thread th = Thread.CurrentThread;
1116 if (Thread.CurrentPrincipal != prev_user)
1117 Thread.CurrentPrincipal = prev_user;
1119 if (prev_appui_culture != null && prev_appui_culture != th.CurrentUICulture)
1120 th.CurrentUICulture = prev_appui_culture;
1121 if (prev_app_culture != null && prev_app_culture != th.CurrentCulture)
1122 th.CurrentCulture = prev_app_culture;
1125 if (context == null)
1126 context = HttpContext.Current;
1127 HttpRuntime.TimeoutManager.Remove (context);
1131 HttpContext.Current = null;
1134 void Start (object x)
1138 } catch (Exception e) {
1140 initialization_exception = e;
1142 FinalErrorWrite (context.Response, new HttpException ("", e).GetHtmlErrorMessage ());
1147 HttpContext.Current = Context;
1149 pipeline = Pipeline ();
1153 const string HANDLER_CACHE = "@@HttpHandlerCache@@";
1155 internal static Hashtable GetHandlerCache ()
1157 Cache cache = HttpRuntime.InternalCache;
1158 Hashtable ret = cache [HANDLER_CACHE] as Hashtable;
1161 ret = new Hashtable ();
1162 cache.Insert (HANDLER_CACHE, ret);
1168 internal static void ClearHandlerCache ()
1170 Hashtable cache = GetHandlerCache ();
1174 internal object LocateHandler (string verb, string url)
1176 Hashtable cache = GetHandlerCache ();
1177 string id = String.Format ("{0}{1}", verb, url);
1178 object ret = cache [id];
1184 HttpHandlersSection httpHandlersSection = (HttpHandlersSection) WebConfigurationManager.GetSection ("system.web/httpHandlers");
1185 ret = httpHandlersSection.LocateHandler (verb, url);
1187 HandlerFactoryConfiguration factory_config = (HandlerFactoryConfiguration) HttpContext.GetAppConfig ("system.web/httpHandlers");
1188 ret = factory_config.LocateHandler (verb, url);
1195 // Used by HttpServerUtility.Execute
1196 internal IHttpHandler GetHandler (HttpContext context)
1198 HttpRequest request = context.Request;
1199 string verb = request.RequestType;
1200 string url = request.FilePath;
1202 IHttpHandler handler = null;
1203 object o = LocateHandler (verb, url);
1205 factory = o as IHttpHandlerFactory;
1207 if (factory == null) {
1208 handler = (IHttpHandler) o;
1210 handler = factory.GetHandler (context, verb, url, request.PhysicalPath);
1216 void IHttpHandler.ProcessRequest (HttpContext context)
1219 this.context = context;
1227 // This is used by FireOnAppStart, when we init the application
1228 // as the context is required to be set at that point (the user
1229 // might call methods that require it on that hook).
1231 internal void SetContext (HttpContext context)
1233 this.context = context;
1236 internal void SetSession (HttpSessionState session)
1238 this.session = session;
1241 IAsyncResult IHttpAsyncHandler.BeginProcessRequest (HttpContext context, AsyncCallback cb, object extraData)
1243 this.context = context;
1246 begin_iar = new AsyncRequestState (done, cb, extraData);
1249 IPortletRenderRequest renderRequest = context.ServletRequest as IPortletRenderRequest;
1250 if (renderRequest != null) {
1251 string actionException = context.ServletRequest.getParameter ("vmw.action.exception");
1252 if (actionException != null && actionException.Length > 0) {
1253 FinalErrorWrite (context.Response, actionException.Replace("\n", "<br>"));
1254 begin_iar.Complete ();
1263 if (Thread.CurrentThread.IsThreadPoolThread)
1267 ThreadPool.QueueUserWorkItem (new WaitCallback (Start), null);
1272 void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result)
1278 if (!result.IsCompleted)
1279 result.AsyncWaitHandle.WaitOne ();
1283 public virtual void Init ()
1287 bool IHttpHandler.IsReusable {
1294 internal void ClearError ()
1296 context.ClearError ();
1299 bool RedirectErrorPage (string error_page)
1301 if (context.Request.QueryString ["aspxerrorpath"] != null)
1304 Response.Redirect (error_page + "?aspxerrorpath=" + Request.Path, false);
1308 bool RedirectCustomError (ref HttpException httpEx)
1311 if (!context.IsCustomErrorEnabledUnsafe)
1315 CustomErrorsSection config = (CustomErrorsSection)WebConfigurationManager.GetSection ("system.web/customErrors");
1317 CustomErrorsConfig config = null;
1319 config = (CustomErrorsConfig) context.GetConfig ("system.web/customErrors");
1323 if (config == null) {
1324 if (context.ErrorPage != null)
1325 return RedirectErrorPage (context.ErrorPage);
1331 CustomError err = config.Errors [context.Response.StatusCode.ToString()];
1332 string redirect = err == null ? null : err.Redirect;
1334 string redirect = config [context.Response.StatusCode];
1336 if (redirect == null) {
1337 redirect = context.ErrorPage;
1338 if (redirect == null)
1339 redirect = config.DefaultRedirect;
1342 if (redirect == null)
1345 return RedirectErrorPage (redirect);
1347 catch (Exception ex) {
1348 httpEx = new HttpException (500, "", ex);
1353 internal static bool IsRunningOnWindows {
1355 PlatformID pid = Environment.OSVersion.Platform;
1356 return ((int) pid != 128 && (int) pid != 4);
1360 internal static IEnumerable BinDirectories
1363 AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
1364 string baseDir = setup.ApplicationBase;
1367 if (Environment.GetEnvironmentVariable ("MONO_IOMAP") != null || IsRunningOnWindows) {
1368 bindir = Path.Combine (baseDir, "bin");
1369 if (Directory.Exists (bindir))
1370 yield return bindir;
1372 foreach (string dir in BinDirs) {
1373 bindir = Path.Combine (baseDir, dir);
1374 if (!Directory.Exists (bindir))
1376 yield return bindir;
1382 internal static string[] BinDirectoryAssemblies
1385 ArrayList binDlls = null;
1388 foreach (string bindir in BinDirectories) {
1389 if (binDlls == null)
1390 binDlls = new ArrayList ();
1391 dlls = Directory.GetFiles (bindir, "*.dll");
1392 binDlls.AddRange (dlls);
1395 if (binDlls == null)
1396 return new string[] {};
1397 return (string[])binDlls.ToArray (typeof (string));
1401 internal static Type LoadType (string typeName)
1403 return LoadType (typeName, false);
1406 internal static Type LoadType (string typeName, bool throwOnMissing)
1408 Type type = Type.GetType (typeName);
1412 Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
1413 foreach (Assembly ass in assemblies) {
1414 type = ass.GetType (typeName, false);
1420 IList tla = System.Web.Compilation.BuildManager.TopLevelAssemblies;
1421 if (tla != null && tla.Count > 0) {
1422 foreach (Assembly asm in tla) {
1425 type = asm.GetType (typeName, false);
1432 type = LoadTypeFromBin (typeName);
1437 throw new TypeLoadException (String.Format ("Type '{0}' cannot be found", typeName));
1442 internal static Type LoadTypeFromBin (string typeName)
1446 foreach (string s in BinDirectoryAssemblies) {
1447 Assembly binA = Assembly.LoadFrom (s);
1448 type = binA.GetType (typeName, false);
1460 // Based on Fritz' Onion's AsyncRequestState class for asynchronous IHttpAsyncHandlers
1462 class AsyncRequestState : IAsyncResult {
1466 ManualResetEvent complete_event = null;
1468 internal AsyncRequestState (ManualResetEvent complete_event, AsyncCallback cb, object cb_data)
1471 this.cb_data = cb_data;
1472 this.complete_event = complete_event;
1475 internal void Complete ()
1480 // TODO: if this throws an error, we have no way of reporting it
1481 // Not really too bad, since the only failure might be
1482 // `HttpRuntime.request_processed'.
1489 complete_event.Set ();
1492 public object AsyncState {
1498 public bool CompletedSynchronously {
1504 public bool IsCompleted {
1510 public WaitHandle AsyncWaitHandle {
1512 return complete_event;
1517 #region Helper classes
1520 // A wrapper to keep track of begin/end pairs
1522 class AsyncInvoker {
1523 public BeginEventHandler begin;
1524 public EndEventHandler end;
1527 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, object d)
1534 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh)
1540 public void Invoke (object sender, EventArgs e)
1542 throw new Exception ("This is just a dummy");