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();
92 internal static readonly string [] BinDirs = {"Bin", "bin"};
95 HttpSessionState session;
98 // The source, and the exposed API (cache).
99 HttpModuleCollection modcoll;
101 string assemblyLocation;
104 // The factory for the handler currently running.
106 IHttpHandlerFactory factory;
109 // Whether the thread culture is to be auto-set.
110 // Used only in the 2.0 profile, always false for 1.x
116 // Whether the pipeline should be stopped
118 bool stop_processing;
123 IEnumerator pipeline;
125 // To flag when we are done processing a request from BeginProcessRequest.
126 ManualResetEvent done;
128 // The current IAsyncResult for the running async request handler in the pipeline
129 AsyncRequestState begin_iar;
131 // Tracks the current AsyncInvocation being dispatched
132 AsyncInvoker current_ai;
134 // We don't use the EventHandlerList here, but derived classes might do
135 EventHandlerList events;
137 // Culture and IPrincipal
138 CultureInfo app_culture;
139 CultureInfo appui_culture;
140 CultureInfo prev_app_culture;
141 CultureInfo prev_appui_culture;
142 IPrincipal prev_user;
145 const string initialization_exception_key = "System.Web.HttpApplication.initialization_exception";
146 static Exception initialization_exception {
147 get { return (Exception) AppDomain.CurrentDomain.GetData (initialization_exception_key); }
148 set { AppDomain.CurrentDomain.SetData (initialization_exception_key, value); }
151 static Exception initialization_exception;
153 bool removeConfigurationFromCache;
157 // These are used to detect the case where the EndXXX method is invoked
158 // from within the BeginXXXX delegate, so we detect whether we kick the
159 // pipeline from here, or from the the RunHook routine
164 public HttpApplication ()
166 done = new ManualResetEvent (false);
169 internal void InitOnce (bool full_init)
176 HttpModulesSection modules;
177 modules = (HttpModulesSection) WebConfigurationManager.GetSection ("system.web/httpModules", HttpRuntime.AppDomainAppVirtualPath);
179 ModulesConfiguration modules;
181 modules = (ModulesConfiguration) HttpContext.GetAppConfig ("system.web/httpModules");
184 modcoll = modules.LoadModules (this);
187 HttpApplicationFactory.AttachEvents (this);
192 GlobalizationSection cfg;
193 cfg = (GlobalizationSection) WebConfigurationManager.GetSection ("system.web/globalization");
194 app_culture = cfg.GetCulture();
195 autoCulture = cfg.IsAutoCulture;
196 appui_culture = cfg.GetUICulture();
197 autoUICulture = cfg.IsAutoUICulture;
199 GlobalizationConfiguration cfg;
200 cfg = GlobalizationConfiguration.GetInstance (null);
202 app_culture = cfg.Culture;
203 appui_culture = cfg.UICulture;
209 internal string AssemblyLocation {
211 if (assemblyLocation == null)
212 assemblyLocation = GetType ().Assembly.Location;
213 return assemblyLocation;
218 internal static Exception InitializationException {
219 get { return initialization_exception; }
224 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
225 public HttpApplicationState Application {
227 return HttpApplicationFactory.ApplicationState;
232 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
233 public HttpContext Context {
239 protected EventHandlerList Events {
242 events = new EventHandlerList ();
249 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
250 public HttpModuleCollection Modules {
251 [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
254 modcoll = new HttpModuleCollection ();
261 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
262 public HttpRequest Request {
265 throw new HttpException (Locale.GetText ("No context is available."));
267 if (false == HttpApplicationFactory.ContextAvailable)
268 throw new HttpException (Locale.GetText ("Request is not available in this context."));
270 return context.Request;
275 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
276 public HttpResponse Response {
279 throw new HttpException (Locale.GetText ("No context is available."));
281 if (false == HttpApplicationFactory.ContextAvailable)
282 throw new HttpException (Locale.GetText ("Response is not available in this context."));
284 return context.Response;
289 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
290 public HttpServerUtility Server {
293 return context.Server;
296 // This is so we can get the Server and call a few methods
297 // which are not context sensitive, see HttpServerUtilityTest
299 return new HttpServerUtility ((HttpContext) null);
304 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
305 public HttpSessionState Session {
307 // Only used for Session_End
312 throw new HttpException (Locale.GetText ("No context is available."));
313 return context.Session;
318 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
322 public virtual ISite Site {
334 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
335 public IPrincipal User {
338 throw new HttpException (Locale.GetText ("No context is available."));
339 if (context.User == null)
340 throw new HttpException (Locale.GetText ("No currently authenticated user."));
346 public virtual event EventHandler Disposed;
347 public virtual event EventHandler Error;
349 public event EventHandler PreSendRequestHeaders;
350 internal void TriggerPreSendRequestHeaders ()
352 if (PreSendRequestHeaders != null)
353 PreSendRequestHeaders (this, EventArgs.Empty);
356 public event EventHandler PreSendRequestContent;
357 internal void TriggerPreSendRequestContent ()
359 if (PreSendRequestContent != null)
360 PreSendRequestContent (this, EventArgs.Empty);
363 public event EventHandler AcquireRequestState;
364 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
366 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
367 AcquireRequestState += new EventHandler (invoker.Invoke);
370 public event EventHandler AuthenticateRequest;
371 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
373 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
374 AuthenticateRequest += new EventHandler (invoker.Invoke);
377 public event EventHandler AuthorizeRequest;
378 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
380 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
381 AuthorizeRequest += new EventHandler (invoker.Invoke);
384 public event EventHandler BeginRequest;
385 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh)
387 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
388 BeginRequest += new EventHandler (invoker.Invoke);
391 public event EventHandler EndRequest;
392 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh)
394 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
395 EndRequest += new EventHandler (invoker.Invoke);
398 public event EventHandler PostRequestHandlerExecute;
399 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
401 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
402 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
405 public event EventHandler PreRequestHandlerExecute;
406 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
408 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
409 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
412 public event EventHandler ReleaseRequestState;
413 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
415 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
416 ReleaseRequestState += new EventHandler (invoker.Invoke);
419 public event EventHandler ResolveRequestCache;
420 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
422 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
423 ResolveRequestCache += new EventHandler (invoker.Invoke);
426 public event EventHandler UpdateRequestCache;
427 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
429 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
430 UpdateRequestCache += new EventHandler (invoker.Invoke);
434 public event EventHandler PostAuthenticateRequest;
435 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
437 AddOnPostAuthenticateRequestAsync (bh, eh, null);
440 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
442 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
443 PostAuthenticateRequest += new EventHandler (invoker.Invoke);
446 public event EventHandler PostAuthorizeRequest;
447 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
449 AddOnPostAuthorizeRequestAsync (bh, eh, null);
452 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
454 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
455 PostAuthorizeRequest += new EventHandler (invoker.Invoke);
458 public event EventHandler PostResolveRequestCache;
459 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
461 AddOnPostResolveRequestCacheAsync (bh, eh, null);
464 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
466 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
467 PostResolveRequestCache += new EventHandler (invoker.Invoke);
470 public event EventHandler PostMapRequestHandler;
471 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
473 AddOnPostMapRequestHandlerAsync (bh, eh, null);
476 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh, object data)
478 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
479 PostMapRequestHandler += new EventHandler (invoker.Invoke);
482 public event EventHandler PostAcquireRequestState;
483 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
485 AddOnPostAcquireRequestStateAsync (bh, eh, null);
488 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
490 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
491 PostAcquireRequestState += new EventHandler (invoker.Invoke);
494 public event EventHandler PostReleaseRequestState;
495 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
497 AddOnPostReleaseRequestStateAsync (bh, eh, null);
500 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
502 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
503 PostReleaseRequestState += new EventHandler (invoker.Invoke);
506 public event EventHandler PostUpdateRequestCache;
507 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
509 AddOnPostUpdateRequestCacheAsync (bh, eh, null);
512 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
514 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
515 PostUpdateRequestCache += new EventHandler (invoker.Invoke);
519 // The new overloads that take a data parameter
521 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
523 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
524 AcquireRequestState += new EventHandler (invoker.Invoke);
527 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
529 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
530 AuthenticateRequest += new EventHandler (invoker.Invoke);
533 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
535 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
536 AuthorizeRequest += new EventHandler (invoker.Invoke);
539 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
541 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
542 BeginRequest += new EventHandler (invoker.Invoke);
545 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
547 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
548 EndRequest += new EventHandler (invoker.Invoke);
551 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
553 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
554 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
557 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
559 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
560 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
563 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
565 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
566 ReleaseRequestState += new EventHandler (invoker.Invoke);
569 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
571 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
572 ResolveRequestCache += new EventHandler (invoker.Invoke);
575 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
577 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
578 UpdateRequestCache += new EventHandler (invoker.Invoke);
582 internal event EventHandler DefaultAuthentication;
585 // Bypass all the event on the Http pipeline and go directly to EndRequest
587 public void CompleteRequest ()
589 stop_processing = true;
592 internal bool RequestCompleted {
593 set { stop_processing = value; }
596 public virtual void Dispose ()
598 if (modcoll != null) {
599 for (int i = modcoll.Count - 1; i >= 0; i--) {
600 modcoll.Get (i).Dispose ();
605 if (Disposed != null)
606 Disposed (this, EventArgs.Empty);
612 public virtual string GetVaryByCustomString (HttpContext context, string custom)
614 if (custom == null) // Sigh
615 throw new NullReferenceException ();
617 if (0 == String.Compare (custom, "browser", true, CultureInfo.InvariantCulture))
618 return context.Request.Browser.Type;
624 // If we catch an error, queue this error
626 void ProcessError (Exception e)
628 bool first = context.Error == null;
629 context.AddError (e);
633 Error (this, EventArgs.Empty);
634 } catch (ThreadAbortException){
635 // This happens on Redirect() or End()
636 Thread.ResetAbort ();
637 } catch (Exception ee){
638 context.AddError (ee);
642 stop_processing = true;
644 // we want to remove configuration from the cache in case of
645 // invalid resource not exists to prevent DOS attack.
646 HttpException httpEx = e as HttpException;
647 if (httpEx != null && httpEx.GetHttpCode () == 404) {
648 removeConfigurationFromCache = true;
654 // Ticks the clock: next step on the pipeline.
659 if (pipeline.MoveNext ()){
660 if ((bool)pipeline.Current)
663 } catch (ThreadAbortException taex) {
664 object obj = taex.ExceptionState;
665 Thread.ResetAbort ();
666 stop_processing = true;
667 if (obj is StepTimeout)
668 ProcessError (new HttpException ("The request timed out."));
671 } catch (Exception e) {
672 Console.WriteLine ("Tick caught an exception that has not been propagated:\n" + e);
685 // Invoked when our async callback called from RunHooks completes,
686 // we restart the pipeline here.
688 void async_callback_completed_cb (IAsyncResult ar)
690 if (current_ai.end != null){
693 } catch (Exception e) {
701 void async_handler_complete_cb (IAsyncResult ar)
703 IHttpAsyncHandler async_handler = ((IHttpAsyncHandler) ar.AsyncState);
706 async_handler.EndProcessRequest (ar);
707 } catch (Exception e){
715 // This enumerator yields whether processing must be stopped:
716 // true: processing of the pipeline must be stopped
717 // false: processing of the pipeline must not be stopped
719 IEnumerable RunHooks (Delegate list)
721 Delegate [] delegates = list.GetInvocationList ();
723 foreach (EventHandler d in delegates){
724 if (d.Target != null && (d.Target is AsyncInvoker)){
725 current_ai = (AsyncInvoker) d.Target;
730 context.BeginTimeoutPossible ();
731 current_ai.begin (this, EventArgs.Empty, async_callback_completed_cb, current_ai.data);
732 } catch (ThreadAbortException taex){
733 object obj = taex.ExceptionState;
734 Thread.ResetAbort ();
735 stop_processing = true;
736 if (obj is StepTimeout)
737 ProcessError (new HttpException ("The request timed out."));
738 } catch (Exception e){
742 context.EndTimeoutPossible ();
746 // If things are still moving forward, yield this
750 yield return stop_processing;
751 else if (stop_processing)
755 context.BeginTimeoutPossible ();
756 d (this, EventArgs.Empty);
757 } catch (ThreadAbortException taex){
758 object obj = taex.ExceptionState;
759 Thread.ResetAbort ();
760 stop_processing = true;
761 if (obj is StepTimeout)
762 ProcessError (new HttpException ("The request timed out."));
763 } catch (Exception e){
766 context.EndTimeoutPossible ();
774 static void FinalErrorWrite (HttpResponse response, string error)
777 response.Write (error);
778 response.Flush (true);
786 if (context.Error == null){
788 context.Response.Flush (true);
789 } catch (Exception e){
790 context.AddError (e);
794 Exception error = context.Error;
796 HttpResponse response = context.Response;
799 IPortletActionRequest actionRequest = context.ServletRequest as IPortletActionRequest;
800 IPortletActionResponse actionResponse = context.ServletResponse as IPortletActionResponse;
801 if (actionRequest != null && actionResponse != null && actionRequest.processActionOnly ()) {
802 string exception = "Exception of type " + context.Error.GetType () +
803 " during processAction: " + context.Error.Message + Console.Out.NewLine +
804 context.Error.StackTrace;
805 actionResponse.setRenderParameter ("vmw.action.exception", exception);
809 if (!response.HeadersSent){
810 response.ClearHeaders ();
811 response.ClearContent ();
813 if (error is HttpException){
814 response.StatusCode = ((HttpException)error).GetHttpCode ();
816 error = new HttpException ("", error);
817 response.StatusCode = 500;
819 HttpException httpEx = (HttpException) error;
820 if (!RedirectCustomError (ref httpEx))
821 FinalErrorWrite (response, httpEx.GetHtmlErrorMessage ());
823 response.Flush (true);
825 if (!(error is HttpException))
826 error = new HttpException ("", error);
827 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
834 // Invoked at the end of the pipeline execution
839 if (EndRequest != null)
840 EndRequest (this, EventArgs.Empty);
841 } catch (Exception e){
847 } catch (Exception e) {
848 Console.WriteLine ("Internal error: OutputPage threw an exception " + e);
850 context.WorkerRequest.EndOfRequest();
851 if (factory != null && context.Handler != null){
852 factory.ReleaseHandler (context.Handler);
853 context.Handler = null;
857 context.PopHandler ();
859 // context = null; -> moved to PostDone
865 if (begin_iar != null)
866 begin_iar.Complete ();
872 // Events fired as described in `Http Runtime Support, HttpModules,
873 // Handling Public Events'
875 IEnumerator Pipeline ()
880 if (BeginRequest != null)
881 foreach (bool stop in RunHooks (BeginRequest))
884 if (AuthenticateRequest != null)
885 foreach (bool stop in RunHooks (AuthenticateRequest))
888 if (DefaultAuthentication != null)
889 foreach (bool stop in RunHooks (DefaultAuthentication))
893 if (PostAuthenticateRequest != null)
894 foreach (bool stop in RunHooks (PostAuthenticateRequest))
897 if (AuthorizeRequest != null)
898 foreach (bool stop in RunHooks (AuthorizeRequest))
901 if (PostAuthorizeRequest != null)
902 foreach (bool stop in RunHooks (PostAuthorizeRequest))
906 if (ResolveRequestCache != null)
907 foreach (bool stop in RunHooks (ResolveRequestCache))
911 if (PostResolveRequestCache != null)
912 foreach (bool stop in RunHooks (PostResolveRequestCache))
916 // Obtain the handler for the request.
917 IHttpHandler handler = null;
919 handler = GetHandler (context);
920 context.Handler = handler;
922 context.PushHandler (handler);
924 } catch (FileNotFoundException fnf){
925 if (context.Request.IsLocal)
926 ProcessError (new HttpException (404, String.Format ("File not found {0}", fnf.FileName), fnf));
928 ProcessError (new HttpException (404, "File not found: " + Path.GetFileName (fnf.FileName)));
929 } catch (DirectoryNotFoundException dnf){
930 if (!context.Request.IsLocal)
931 dnf = null; // Do not "leak" real path information
932 ProcessError (new HttpException (404, "Directory not found", dnf));
933 } catch (Exception e) {
941 if (PostMapRequestHandler != null)
942 foreach (bool stop in RunHooks (PostMapRequestHandler))
946 if (AcquireRequestState != null){
947 foreach (bool stop in RunHooks (AcquireRequestState))
952 if (PostAcquireRequestState != null){
953 foreach (bool stop in RunHooks (PostAcquireRequestState))
959 // From this point on, we need to ensure that we call
960 // ReleaseRequestState, so the code below jumps to
961 // `release:' to guarantee it rather than yielding.
963 if (PreRequestHandlerExecute != null)
964 foreach (bool stop in RunHooks (PreRequestHandlerExecute))
969 context.BeginTimeoutPossible ();
970 if (handler != null){
971 IHttpAsyncHandler async_handler = handler as IHttpAsyncHandler;
973 if (async_handler != null){
976 async_handler.BeginProcessRequest (context, async_handler_complete_cb, handler);
979 handler.ProcessRequest (context);
982 } catch (ThreadAbortException taex){
983 object obj = taex.ExceptionState;
984 Thread.ResetAbort ();
985 stop_processing = true;
986 if (obj is StepTimeout)
987 ProcessError (new HttpException ("The request timed out."));
988 } catch (Exception e){
992 context.EndTimeoutPossible ();
995 yield return stop_processing;
996 else if (stop_processing)
999 // These are executed after the application has returned
1001 if (PostRequestHandlerExecute != null)
1002 foreach (bool stop in RunHooks (PostRequestHandlerExecute))
1007 if (ReleaseRequestState != null){
1008 #pragma warning disable 168
1009 foreach (bool stop in RunHooks (ReleaseRequestState)){
1011 // Ignore the stop signal while release the state
1015 #pragma warning restore 168
1018 if (stop_processing)
1022 if (PostReleaseRequestState != null)
1023 foreach (bool stop in RunHooks (PostReleaseRequestState))
1027 if (context.Error == null)
1028 context.Response.DoFilter (true);
1030 if (UpdateRequestCache != null)
1031 foreach (bool stop in RunHooks (UpdateRequestCache))
1035 if (PostUpdateRequestCache != null)
1036 foreach (bool stop in RunHooks (PostUpdateRequestCache))
1043 internal CultureInfo GetThreadCulture (HttpRequest request, CultureInfo culture, bool isAuto)
1048 CultureInfo ret = null;
1049 string[] languages = request.UserLanguages;
1051 if (languages != null && languages.Length > 0)
1052 ret = CultureInfo.CreateSpecificCulture (languages[0]);
1069 HttpRuntime.TimeoutManager.Add (context);
1071 Thread th = Thread.CurrentThread;
1072 if (app_culture != null) {
1073 prev_app_culture = th.CurrentCulture;
1074 CultureInfo new_app_culture = GetThreadCulture (Request, app_culture, autoCulture);
1075 if (!new_app_culture.Equals (CultureInfo.InvariantCulture))
1076 th.CurrentCulture = new_app_culture;
1079 if (appui_culture != null) {
1080 prev_appui_culture = th.CurrentUICulture;
1081 CultureInfo new_app_culture = GetThreadCulture (Request, appui_culture, autoUICulture);
1082 if (!new_app_culture.Equals (CultureInfo.InvariantCulture))
1083 th.CurrentUICulture = new_app_culture;
1087 prev_user = Thread.CurrentPrincipal;
1094 if (removeConfigurationFromCache) {
1095 WebConfigurationManager.RemoveConfigurationFromCache (context);
1096 removeConfigurationFromCache = false;
1099 Thread th = Thread.CurrentThread;
1101 if (Thread.CurrentPrincipal != prev_user)
1102 Thread.CurrentPrincipal = prev_user;
1104 if (prev_appui_culture != null && prev_appui_culture != th.CurrentUICulture)
1105 th.CurrentUICulture = prev_appui_culture;
1106 if (prev_app_culture != null && prev_app_culture != th.CurrentCulture)
1107 th.CurrentCulture = prev_app_culture;
1110 if (context == null)
1111 context = HttpContext.Current;
1112 HttpRuntime.TimeoutManager.Remove (context);
1116 HttpContext.Current = null;
1119 void Start (object x)
1123 } catch (Exception e) {
1125 initialization_exception = e;
1127 FinalErrorWrite (context.Response, new HttpException ("", e).GetHtmlErrorMessage ());
1132 HttpContext.Current = Context;
1134 pipeline = Pipeline ();
1138 // Used by HttpServerUtility.Execute
1139 internal IHttpHandler GetHandler (HttpContext context)
1141 HttpRequest request = context.Request;
1142 string verb = request.RequestType;
1143 string url = request.FilePath;
1145 IHttpHandler handler = null;
1147 HttpHandlersSection httpHandlersSection = (HttpHandlersSection) WebConfigurationManager.GetSection ("system.web/httpHandlers");
1148 object o = httpHandlersSection.LocateHandler (verb, url);
1150 HandlerFactoryConfiguration factory_config = (HandlerFactoryConfiguration) HttpContext.GetAppConfig ("system.web/httpHandlers");
1151 object o = factory_config.LocateHandler (verb, url);
1154 factory = o as IHttpHandlerFactory;
1156 if (factory == null) {
1157 handler = (IHttpHandler) o;
1159 handler = factory.GetHandler (context, verb, url, request.PhysicalPath);
1165 void IHttpHandler.ProcessRequest (HttpContext context)
1168 this.context = context;
1176 // This is used by FireOnAppStart, when we init the application
1177 // as the context is required to be set at that point (the user
1178 // might call methods that require it on that hook).
1180 internal void SetContext (HttpContext context)
1182 this.context = context;
1185 internal void SetSession (HttpSessionState session)
1187 this.session = session;
1190 IAsyncResult IHttpAsyncHandler.BeginProcessRequest (HttpContext context, AsyncCallback cb, object extraData)
1192 this.context = context;
1195 begin_iar = new AsyncRequestState (done, cb, extraData);
1198 IPortletRenderRequest renderRequest = context.ServletRequest as IPortletRenderRequest;
1199 if (renderRequest != null) {
1200 string actionException = context.ServletRequest.getParameter ("vmw.action.exception");
1201 if (actionException != null && actionException.Length > 0) {
1202 FinalErrorWrite (context.Response, actionException.Replace("\n", "<br>"));
1203 begin_iar.Complete ();
1212 if (Thread.CurrentThread.IsThreadPoolThread)
1216 ThreadPool.QueueUserWorkItem (new WaitCallback (Start), null);
1221 void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result)
1223 if (!result.IsCompleted)
1224 result.AsyncWaitHandle.WaitOne ();
1228 public virtual void Init ()
1232 bool IHttpHandler.IsReusable {
1239 internal void ClearError ()
1241 context.ClearError ();
1244 bool RedirectErrorPage (string error_page)
1246 if (context.Request.QueryString ["aspxerrorpath"] != null)
1249 Response.Redirect (error_page + "?aspxerrorpath=" + Request.Path, false);
1253 bool RedirectCustomError (ref HttpException httpEx)
1256 if (!context.IsCustomErrorEnabledUnsafe)
1260 CustomErrorsSection config = (CustomErrorsSection)WebConfigurationManager.GetSection ("system.web/customErrors");
1262 CustomErrorsConfig config = null;
1264 config = (CustomErrorsConfig) context.GetConfig ("system.web/customErrors");
1268 if (config == null) {
1269 if (context.ErrorPage != null)
1270 return RedirectErrorPage (context.ErrorPage);
1276 CustomError err = config.Errors [context.Response.StatusCode.ToString()];
1277 string redirect = err == null ? null : err.Redirect;
1279 string redirect = config [context.Response.StatusCode];
1281 if (redirect == null) {
1282 redirect = context.ErrorPage;
1283 if (redirect == null)
1284 redirect = config.DefaultRedirect;
1287 if (redirect == null)
1290 return RedirectErrorPage (redirect);
1292 catch (Exception ex) {
1293 httpEx = new HttpException (500, "", ex);
1299 internal static IEnumerable PrivateBinPath
1302 AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
1303 string baseDir = setup.ApplicationBase;
1305 string pbp = setup.PrivateBinPath;
1306 if (pbp == null || pbp.Length == 0)
1308 foreach (string d in pbp.Split (Path.PathSeparator))
1309 yield return Path.Combine (baseDir, d);
1313 internal static bool IsRunningOnWindows {
1315 PlatformID pid = Environment.OSVersion.Platform;
1316 return ((int) pid != 128 && (int) pid != 4);
1320 internal static IEnumerable BinDirectories
1323 AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
1324 string baseDir = setup.ApplicationBase;
1327 if (Environment.GetEnvironmentVariable ("MONO_IOMAP") != null || IsRunningOnWindows)
1328 yield return Path.Combine (baseDir, "bin");
1330 foreach (string dir in BinDirs) {
1331 bindir = Path.Combine (baseDir, dir);
1332 if (!Directory.Exists (bindir))
1334 yield return bindir;
1340 internal static string[] BinDirectoryAssemblies
1343 ArrayList binDlls = null;
1346 foreach (string bindir in BinDirectories) {
1347 if (binDlls == null)
1348 binDlls = new ArrayList ();
1349 dlls = Directory.GetFiles (bindir, "*.dll");
1350 binDlls.AddRange (dlls);
1353 if (binDlls == null)
1354 return new string[] {};
1355 return (string[])binDlls.ToArray (typeof (string));
1359 internal static Type LoadType (string typeName)
1361 return LoadType (typeName, false);
1364 internal static Type LoadType (string typeName, bool throwOnMissing)
1366 Type type = Type.GetType (typeName);
1370 Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
1371 foreach (Assembly ass in assemblies) {
1372 type = ass.GetType (typeName, false);
1378 IList tla = System.Web.Compilation.BuildManager.TopLevelAssemblies;
1379 if (tla != null && tla.Count > 0) {
1380 foreach (Assembly asm in tla) {
1383 type = asm.GetType (typeName, false);
1390 type = LoadTypeFromBin (typeName);
1395 throw new TypeLoadException (String.Format ("Type '{0}' cannot be found", typeName));
1400 internal static Type LoadTypeFromBin (string typeName)
1404 foreach (string s in BinDirectoryAssemblies) {
1405 Assembly binA = Assembly.LoadFrom (s);
1406 type = binA.GetType (typeName, false);
1418 // Based on Fritz' Onion's AsyncRequestState class for asynchronous IHttpAsyncHandlers
1420 class AsyncRequestState : IAsyncResult {
1424 ManualResetEvent complete_event = null;
1426 internal AsyncRequestState (ManualResetEvent complete_event, AsyncCallback cb, object cb_data)
1429 this.cb_data = cb_data;
1430 this.complete_event = complete_event;
1433 internal void Complete ()
1438 // TODO: if this throws an error, we have no way of reporting it
1439 // Not really too bad, since the only failure might be
1440 // `HttpRuntime.request_processed'.
1447 complete_event.Set ();
1450 public object AsyncState {
1456 public bool CompletedSynchronously {
1462 public bool IsCompleted {
1468 public WaitHandle AsyncWaitHandle {
1470 return complete_event;
1475 #region Helper classes
1478 // A wrapper to keep track of begin/end pairs
1480 class AsyncInvoker {
1481 public BeginEventHandler begin;
1482 public EndEventHandler end;
1485 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, object d)
1492 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh)
1498 public void Invoke (object sender, EventArgs e)
1500 throw new Exception ("This is just a dummy");