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;
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;
145 static bool _runningOnWindows;
149 const string initialization_exception_key = "System.Web.HttpApplication.initialization_exception";
150 static Exception initialization_exception {
151 get { return (Exception) AppDomain.CurrentDomain.GetData (initialization_exception_key); }
152 set { AppDomain.CurrentDomain.SetData (initialization_exception_key, value); }
155 static Exception initialization_exception;
157 bool removeConfigurationFromCache;
161 // These are used to detect the case where the EndXXX method is invoked
162 // from within the BeginXXXX delegate, so we detect whether we kick the
163 // pipeline from here, or from the the RunHook routine
168 static HttpApplication ()
170 PlatformID pid = Environment.OSVersion.Platform;
171 _runningOnWindows = ((int) pid != 128 && (int) pid != 4);
174 public HttpApplication ()
176 done = new ManualResetEvent (false);
179 internal void InitOnce (bool full_init)
186 HttpModulesSection modules;
187 modules = (HttpModulesSection) WebConfigurationManager.GetSection ("system.web/httpModules", HttpRuntime.AppDomainAppVirtualPath);
189 ModulesConfiguration modules;
191 modules = (ModulesConfiguration) HttpContext.GetAppConfig ("system.web/httpModules");
194 modcoll = modules.LoadModules (this);
197 HttpApplicationFactory.AttachEvents (this);
203 internal string AssemblyLocation {
205 if (assemblyLocation == null)
206 assemblyLocation = GetType ().Assembly.Location;
207 return assemblyLocation;
212 internal static Exception InitializationException {
213 get { return initialization_exception; }
218 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
219 public HttpApplicationState Application {
221 return HttpApplicationFactory.ApplicationState;
226 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
227 public HttpContext Context {
233 protected EventHandlerList Events {
236 events = new EventHandlerList ();
243 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
244 public HttpModuleCollection Modules {
245 [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
248 modcoll = new HttpModuleCollection ();
255 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
256 public HttpRequest Request {
259 throw new HttpException (Locale.GetText ("No context is available."));
261 if (false == HttpApplicationFactory.ContextAvailable)
262 throw new HttpException (Locale.GetText ("Request is not available in this context."));
264 return context.Request;
269 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
270 public HttpResponse Response {
273 throw new HttpException (Locale.GetText ("No context is available."));
275 if (false == HttpApplicationFactory.ContextAvailable)
276 throw new HttpException (Locale.GetText ("Response is not available in this context."));
278 return context.Response;
283 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
284 public HttpServerUtility Server {
287 return context.Server;
290 // This is so we can get the Server and call a few methods
291 // which are not context sensitive, see HttpServerUtilityTest
293 return new HttpServerUtility ((HttpContext) null);
298 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
299 public HttpSessionState Session {
301 // Only used for Session_End
306 throw new HttpException (Locale.GetText ("No context is available."));
307 return context.Session;
312 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
316 public virtual ISite Site {
328 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
329 public IPrincipal User {
332 throw new HttpException (Locale.GetText ("No context is available."));
333 if (context.User == null)
334 throw new HttpException (Locale.GetText ("No currently authenticated user."));
340 public virtual event EventHandler Disposed;
341 public virtual event EventHandler Error;
343 public event EventHandler PreSendRequestHeaders;
344 internal void TriggerPreSendRequestHeaders ()
346 if (PreSendRequestHeaders != null)
347 PreSendRequestHeaders (this, EventArgs.Empty);
350 public event EventHandler PreSendRequestContent;
351 internal void TriggerPreSendRequestContent ()
353 if (PreSendRequestContent != null)
354 PreSendRequestContent (this, EventArgs.Empty);
357 public event EventHandler AcquireRequestState;
358 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
360 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
361 AcquireRequestState += new EventHandler (invoker.Invoke);
364 public event EventHandler AuthenticateRequest;
365 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
367 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
368 AuthenticateRequest += new EventHandler (invoker.Invoke);
371 public event EventHandler AuthorizeRequest;
372 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
374 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
375 AuthorizeRequest += new EventHandler (invoker.Invoke);
378 public event EventHandler BeginRequest;
379 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh)
381 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
382 BeginRequest += new EventHandler (invoker.Invoke);
385 public event EventHandler EndRequest;
386 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh)
388 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
389 EndRequest += new EventHandler (invoker.Invoke);
392 public event EventHandler PostRequestHandlerExecute;
393 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
395 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
396 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
399 public event EventHandler PreRequestHandlerExecute;
400 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
402 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
403 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
406 public event EventHandler ReleaseRequestState;
407 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
409 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
410 ReleaseRequestState += new EventHandler (invoker.Invoke);
413 public event EventHandler ResolveRequestCache;
414 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
416 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
417 ResolveRequestCache += new EventHandler (invoker.Invoke);
420 public event EventHandler UpdateRequestCache;
421 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
423 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
424 UpdateRequestCache += new EventHandler (invoker.Invoke);
428 public event EventHandler PostAuthenticateRequest;
429 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
431 AddOnPostAuthenticateRequestAsync (bh, eh, null);
434 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
436 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
437 PostAuthenticateRequest += new EventHandler (invoker.Invoke);
440 public event EventHandler PostAuthorizeRequest;
441 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
443 AddOnPostAuthorizeRequestAsync (bh, eh, null);
446 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
448 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
449 PostAuthorizeRequest += new EventHandler (invoker.Invoke);
452 public event EventHandler PostResolveRequestCache;
453 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
455 AddOnPostResolveRequestCacheAsync (bh, eh, null);
458 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
460 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
461 PostResolveRequestCache += new EventHandler (invoker.Invoke);
464 public event EventHandler PostMapRequestHandler;
465 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
467 AddOnPostMapRequestHandlerAsync (bh, eh, null);
470 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh, object data)
472 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
473 PostMapRequestHandler += new EventHandler (invoker.Invoke);
476 public event EventHandler PostAcquireRequestState;
477 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
479 AddOnPostAcquireRequestStateAsync (bh, eh, null);
482 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
484 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
485 PostAcquireRequestState += new EventHandler (invoker.Invoke);
488 public event EventHandler PostReleaseRequestState;
489 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
491 AddOnPostReleaseRequestStateAsync (bh, eh, null);
494 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
496 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
497 PostReleaseRequestState += new EventHandler (invoker.Invoke);
500 public event EventHandler PostUpdateRequestCache;
501 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
503 AddOnPostUpdateRequestCacheAsync (bh, eh, null);
506 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
508 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
509 PostUpdateRequestCache += new EventHandler (invoker.Invoke);
513 // The new overloads that take a data parameter
515 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
517 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
518 AcquireRequestState += new EventHandler (invoker.Invoke);
521 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
523 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
524 AuthenticateRequest += new EventHandler (invoker.Invoke);
527 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
529 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
530 AuthorizeRequest += new EventHandler (invoker.Invoke);
533 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
535 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
536 BeginRequest += new EventHandler (invoker.Invoke);
539 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
541 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
542 EndRequest += new EventHandler (invoker.Invoke);
545 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
547 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
548 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
551 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
553 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
554 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
557 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
559 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
560 ReleaseRequestState += new EventHandler (invoker.Invoke);
563 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
565 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
566 ResolveRequestCache += new EventHandler (invoker.Invoke);
569 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
571 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
572 UpdateRequestCache += new EventHandler (invoker.Invoke);
576 // They are for use with the IIS7 integrated mode, but have been added for compatibility
577 public event EventHandler LogRequest;
578 public void AddOnLogRequestAsync (BeginEventHandler bh, EndEventHandler eh)
580 AddOnLogRequestAsync (bh, eh, null);
583 public void AddOnLogRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state)
585 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state);
586 LogRequest += new EventHandler (invoker.Invoke);
589 public event EventHandler MapRequestHandler;
590 public void AddOnMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
592 AddOnMapRequestHandlerAsync (bh, eh, null);
595 public void AddOnMapRequestHandlerAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state)
597 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state);
598 MapRequestHandler += new EventHandler (invoker.Invoke);
601 public event EventHandler PostLogRequest;
602 public void AddOnPostLogRequestAsync (BeginEventHandler bh, EndEventHandler eh)
604 AddOnPostLogRequestAsync (bh, eh, null);
607 public void AddOnPostLogRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state)
609 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state);
610 PostLogRequest += new EventHandler (invoker.Invoke);
615 internal event EventHandler DefaultAuthentication;
618 // Bypass all the event on the Http pipeline and go directly to EndRequest
620 public void CompleteRequest ()
622 stop_processing = true;
625 internal bool RequestCompleted {
626 set { stop_processing = value; }
629 public virtual void Dispose ()
631 if (modcoll != null) {
632 for (int i = modcoll.Count - 1; i >= 0; i--) {
633 modcoll.Get (i).Dispose ();
638 if (Disposed != null)
639 Disposed (this, EventArgs.Empty);
645 public virtual string GetVaryByCustomString (HttpContext context, string custom)
647 if (custom == null) // Sigh
648 throw new NullReferenceException ();
650 if (0 == String.Compare (custom, "browser", true, CultureInfo.InvariantCulture))
651 return context.Request.Browser.Type;
657 // If we catch an error, queue this error
659 void ProcessError (Exception e)
661 bool first = context.Error == null;
662 context.AddError (e);
666 Error (this, EventArgs.Empty);
667 } catch (ThreadAbortException taex){
668 context.ClearError ();
669 if (FlagEnd.Value == taex.ExceptionState)
670 // This happens on Redirect() or End()
671 Thread.ResetAbort ();
673 // This happens on Thread.Abort()
674 context.AddError (taex);
675 } catch (Exception ee){
676 context.AddError (ee);
680 stop_processing = true;
682 // we want to remove configuration from the cache in case of
683 // invalid resource not exists to prevent DOS attack.
684 HttpException httpEx = e as HttpException;
685 if (httpEx != null && httpEx.GetHttpCode () == 404) {
686 removeConfigurationFromCache = true;
692 // Ticks the clock: next step on the pipeline.
694 internal void Tick ()
697 if (pipeline.MoveNext ()){
698 if ((bool)pipeline.Current)
701 } catch (ThreadAbortException taex) {
702 object obj = taex.ExceptionState;
703 Thread.ResetAbort ();
704 stop_processing = true;
705 if (obj is StepTimeout)
706 ProcessError (new HttpException ("The request timed out."));
708 context.ClearError ();
709 if (FlagEnd.Value != obj)
710 context.AddError (taex);
714 } catch (Exception e) {
715 stop_processing = true;
730 // Invoked when our async callback called from RunHooks completes,
731 // we restart the pipeline here.
733 void async_callback_completed_cb (IAsyncResult ar)
735 if (current_ai.end != null){
738 } catch (Exception e) {
746 void async_handler_complete_cb (IAsyncResult ar)
748 IHttpAsyncHandler async_handler = ((IHttpAsyncHandler) ar.AsyncState);
751 async_handler.EndProcessRequest (ar);
752 } catch (Exception e){
760 // This enumerator yields whether processing must be stopped:
761 // true: processing of the pipeline must be stopped
762 // false: processing of the pipeline must not be stopped
764 IEnumerable RunHooks (Delegate list)
766 Delegate [] delegates = list.GetInvocationList ();
768 foreach (EventHandler d in delegates){
769 if (d.Target != null && (d.Target is AsyncInvoker)){
770 current_ai = (AsyncInvoker) d.Target;
775 context.BeginTimeoutPossible ();
776 current_ai.begin (this, EventArgs.Empty, async_callback_completed_cb, current_ai.data);
779 context.EndTimeoutPossible ();
783 // If things are still moving forward, yield this
787 yield return stop_processing;
788 else if (stop_processing)
792 context.BeginTimeoutPossible ();
793 d (this, EventArgs.Empty);
795 context.EndTimeoutPossible ();
803 static void FinalErrorWrite (HttpResponse response, string error)
806 response.Write (error);
807 response.Flush (true);
815 if (context.Error == null){
817 context.Response.Flush (true);
818 } catch (Exception e){
819 context.AddError (e);
823 Exception error = context.Error;
826 Console.WriteLine (error.ToString ());
828 HttpResponse response = context.Response;
830 if (!response.HeadersSent){
831 response.ClearHeaders ();
832 response.ClearContent ();
834 if (error is HttpException){
835 response.StatusCode = ((HttpException)error).GetHttpCode ();
837 error = new HttpException ("", error);
838 response.StatusCode = 500;
840 HttpException httpEx = (HttpException) error;
841 if (!RedirectCustomError (ref httpEx))
842 FinalErrorWrite (response, httpEx.GetHtmlErrorMessage ());
844 response.Flush (true);
846 if (!(error is HttpException))
847 error = new HttpException ("", error);
848 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
855 // Invoked at the end of the pipeline execution
860 if (EndRequest != null)
861 EndRequest (this, EventArgs.Empty);
862 } catch (Exception e){
868 } catch (Exception e) {
869 Console.WriteLine ("Internal error: OutputPage threw an exception " + e);
871 context.WorkerRequest.EndOfRequest();
872 if (factory != null && context.Handler != null){
873 factory.ReleaseHandler (context.Handler);
874 context.Handler = null;
878 context.PopHandler ();
880 // context = null; -> moved to PostDone
886 if (begin_iar != null)
887 begin_iar.Complete ();
893 // Events fired as described in `Http Runtime Support, HttpModules,
894 // Handling Public Events'
896 IEnumerator Pipeline ()
901 if (BeginRequest != null)
902 foreach (bool stop in RunHooks (BeginRequest))
905 if (AuthenticateRequest != null)
906 foreach (bool stop in RunHooks (AuthenticateRequest))
909 if (DefaultAuthentication != null)
910 foreach (bool stop in RunHooks (DefaultAuthentication))
914 if (PostAuthenticateRequest != null)
915 foreach (bool stop in RunHooks (PostAuthenticateRequest))
918 if (AuthorizeRequest != null)
919 foreach (bool stop in RunHooks (AuthorizeRequest))
922 if (PostAuthorizeRequest != null)
923 foreach (bool stop in RunHooks (PostAuthorizeRequest))
927 if (ResolveRequestCache != null)
928 foreach (bool stop in RunHooks (ResolveRequestCache))
932 if (PostResolveRequestCache != null)
933 foreach (bool stop in RunHooks (PostResolveRequestCache))
936 // As per http://msdn2.microsoft.com/en-us/library/bb470252(VS.90).aspx
937 if (MapRequestHandler != null)
938 foreach (bool stop in RunHooks (MapRequestHandler))
942 // Obtain the handler for the request.
943 IHttpHandler handler = null;
945 handler = GetHandler (context, context.Request.FilePath);
946 context.Handler = handler;
948 context.PushHandler (handler);
950 } catch (FileNotFoundException fnf){
951 if (context.Request.IsLocal)
952 ProcessError (new HttpException (404, String.Format ("File not found {0}", fnf.FileName), fnf));
954 ProcessError (new HttpException (404, "File not found: " + Path.GetFileName (fnf.FileName)));
955 } catch (DirectoryNotFoundException dnf){
956 if (!context.Request.IsLocal)
957 dnf = null; // Do not "leak" real path information
958 ProcessError (new HttpException (404, "Directory not found", dnf));
959 } catch (Exception e) {
967 if (PostMapRequestHandler != null)
968 foreach (bool stop in RunHooks (PostMapRequestHandler))
972 if (AcquireRequestState != null){
973 foreach (bool stop in RunHooks (AcquireRequestState))
978 if (PostAcquireRequestState != null){
979 foreach (bool stop in RunHooks (PostAcquireRequestState))
985 // From this point on, we need to ensure that we call
986 // ReleaseRequestState, so the code below jumps to
987 // `release:' to guarantee it rather than yielding.
989 if (PreRequestHandlerExecute != null)
990 foreach (bool stop in RunHooks (PreRequestHandlerExecute))
996 bool doProcessHandler = false;
999 context.BeginTimeoutPossible ();
1000 if (handler != null){
1001 IHttpAsyncHandler async_handler = handler as IHttpAsyncHandler;
1003 if (async_handler != null){
1006 async_handler.BeginProcessRequest (context, async_handler_complete_cb, handler);
1009 handler.ProcessRequest (context);
1011 IHttpExtendedHandler extHandler=handler as IHttpExtendedHandler;
1012 doProcessHandler = extHandler != null && !extHandler.IsCompleted;
1016 if (context.Error != null)
1017 throw new TargetInvocationException(context.Error);
1020 context.EndTimeoutPossible ();
1023 if (doProcessHandler) {
1025 goto processHandler;
1029 yield return stop_processing;
1030 else if (stop_processing)
1033 // These are executed after the application has returned
1035 if (PostRequestHandlerExecute != null)
1036 foreach (bool stop in RunHooks (PostRequestHandlerExecute))
1041 if (ReleaseRequestState != null){
1042 #pragma warning disable 168
1043 foreach (bool stop in RunHooks (ReleaseRequestState)){
1045 // Ignore the stop signal while release the state
1049 #pragma warning restore 168
1052 if (stop_processing)
1056 if (PostReleaseRequestState != null)
1057 foreach (bool stop in RunHooks (PostReleaseRequestState))
1061 if (context.Error == null)
1062 context.Response.DoFilter (true);
1064 if (UpdateRequestCache != null)
1065 foreach (bool stop in RunHooks (UpdateRequestCache))
1069 if (PostUpdateRequestCache != null)
1070 foreach (bool stop in RunHooks (PostUpdateRequestCache))
1073 if (LogRequest != null)
1074 foreach (bool stop in RunHooks (LogRequest))
1077 if (PostLogRequest != null)
1078 foreach (bool stop in RunHooks (PostLogRequest))
1085 internal CultureInfo GetThreadCulture (HttpRequest request, CultureInfo culture, bool isAuto)
1090 CultureInfo ret = null;
1091 string[] languages = request.UserLanguages;
1093 if (languages != null && languages.Length > 0)
1094 ret = CultureInfo.CreateSpecificCulture (languages[0]);
1111 GlobalizationSection cfg;
1112 cfg = (GlobalizationSection) WebConfigurationManager.GetSection ("system.web/globalization");
1113 app_culture = cfg.GetCulture ();
1114 autoCulture = cfg.IsAutoCulture;
1115 appui_culture = cfg.GetUICulture ();
1116 autoUICulture = cfg.IsAutoUICulture;
1118 GlobalizationConfiguration cfg;
1119 cfg = GlobalizationConfiguration.GetInstance (null);
1121 app_culture = cfg.Culture;
1122 appui_culture = cfg.UICulture;
1127 context.StartTimeoutTimer ();
1129 Thread th = Thread.CurrentThread;
1130 if (app_culture != null) {
1131 prev_app_culture = th.CurrentCulture;
1132 CultureInfo new_app_culture = GetThreadCulture (Request, app_culture, autoCulture);
1133 if (!new_app_culture.Equals (CultureInfo.InvariantCulture))
1134 th.CurrentCulture = new_app_culture;
1137 if (appui_culture != null) {
1138 prev_appui_culture = th.CurrentUICulture;
1139 CultureInfo new_app_culture = GetThreadCulture (Request, appui_culture, autoUICulture);
1140 if (!new_app_culture.Equals (CultureInfo.InvariantCulture))
1141 th.CurrentUICulture = new_app_culture;
1145 prev_user = Thread.CurrentPrincipal;
1152 if (removeConfigurationFromCache) {
1153 WebConfigurationManager.RemoveConfigurationFromCache (context);
1154 removeConfigurationFromCache = false;
1157 Thread th = Thread.CurrentThread;
1159 if (Thread.CurrentPrincipal != prev_user)
1160 Thread.CurrentPrincipal = prev_user;
1162 if (prev_appui_culture != null && prev_appui_culture != th.CurrentUICulture)
1163 th.CurrentUICulture = prev_appui_culture;
1164 if (prev_app_culture != null && prev_app_culture != th.CurrentCulture)
1165 th.CurrentCulture = prev_app_culture;
1168 if (context == null)
1169 context = HttpContext.Current;
1170 context.StopTimeoutTimer ();
1174 HttpContext.Current = null;
1177 void Start (object x)
1181 } catch (Exception e) {
1183 initialization_exception = e;
1185 FinalErrorWrite (context.Response, new HttpException ("", e).GetHtmlErrorMessage ());
1190 HttpContext.Current = Context;
1192 pipeline = Pipeline ();
1196 const string HANDLER_CACHE = "@@HttpHandlerCache@@";
1198 internal static Hashtable GetHandlerCache ()
1200 Cache cache = HttpRuntime.InternalCache;
1201 Hashtable ret = cache [HANDLER_CACHE] as Hashtable;
1204 ret = new Hashtable ();
1205 cache.Insert (HANDLER_CACHE, ret);
1211 internal static void ClearHandlerCache ()
1213 Hashtable cache = GetHandlerCache ();
1217 internal object LocateHandler (string verb, string url)
1219 Hashtable cache = GetHandlerCache ();
1220 string id = String.Concat (verb, url);
1221 object ret = cache [id];
1227 HttpHandlersSection httpHandlersSection = (HttpHandlersSection) WebConfigurationManager.GetSection ("system.web/httpHandlers");
1228 ret = httpHandlersSection.LocateHandler (verb, url);
1230 HandlerFactoryConfiguration factory_config = (HandlerFactoryConfiguration) HttpContext.GetAppConfig ("system.web/httpHandlers");
1231 ret = factory_config.LocateHandler (verb, url);
1238 // Used by HttpServerUtility.Execute
1239 internal IHttpHandler GetHandler (HttpContext context,string url)
1241 HttpRequest request = context.Request;
1242 string verb = request.RequestType;
1244 IHttpHandler handler = null;
1245 object o = LocateHandler (verb, url);
1247 factory = o as IHttpHandlerFactory;
1249 if (factory == null) {
1250 handler = (IHttpHandler) o;
1252 handler = factory.GetHandler (context, verb, url, request.MapPath (url));
1258 void IHttpHandler.ProcessRequest (HttpContext context)
1261 this.context = context;
1269 // This is used by FireOnAppStart, when we init the application
1270 // as the context is required to be set at that point (the user
1271 // might call methods that require it on that hook).
1273 internal void SetContext (HttpContext context)
1275 this.context = context;
1278 internal void SetSession (HttpSessionState session)
1280 this.session = session;
1283 IAsyncResult IHttpAsyncHandler.BeginProcessRequest (HttpContext context, AsyncCallback cb, object extraData)
1285 this.context = context;
1288 begin_iar = new AsyncRequestState (done, cb, extraData);
1293 if (Thread.CurrentThread.IsThreadPoolThread)
1297 ThreadPool.QueueUserWorkItem (new WaitCallback (Start), null);
1302 void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result)
1308 if (!result.IsCompleted)
1309 result.AsyncWaitHandle.WaitOne ();
1313 public virtual void Init ()
1317 bool IHttpHandler.IsReusable {
1324 internal void ClearError ()
1326 context.ClearError ();
1329 bool RedirectErrorPage (string error_page)
1331 if (context.Request.QueryString ["aspxerrorpath"] != null)
1334 Response.Redirect (error_page + "?aspxerrorpath=" + Request.Path, false);
1338 bool RedirectCustomError (ref HttpException httpEx)
1341 if (!context.IsCustomErrorEnabledUnsafe)
1345 CustomErrorsSection config = (CustomErrorsSection)WebConfigurationManager.GetSection ("system.web/customErrors");
1347 CustomErrorsConfig config = null;
1349 config = (CustomErrorsConfig) context.GetConfig ("system.web/customErrors");
1353 if (config == null) {
1354 if (context.ErrorPage != null)
1355 return RedirectErrorPage (context.ErrorPage);
1361 CustomError err = config.Errors [context.Response.StatusCode.ToString()];
1362 string redirect = err == null ? null : err.Redirect;
1364 string redirect = config [context.Response.StatusCode];
1366 if (redirect == null) {
1367 redirect = context.ErrorPage;
1368 if (redirect == null)
1369 redirect = config.DefaultRedirect;
1372 if (redirect == null)
1375 return RedirectErrorPage (redirect);
1377 catch (Exception ex) {
1378 httpEx = new HttpException (500, "", ex);
1383 internal static bool IsRunningOnWindows {
1384 get { return _runningOnWindows; }
1387 internal static IEnumerable BinDirectories
1390 AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
1391 string baseDir = setup.ApplicationBase;
1394 if (Environment.GetEnvironmentVariable ("MONO_IOMAP") != null || IsRunningOnWindows) {
1395 bindir = Path.Combine (baseDir, "bin");
1396 if (Directory.Exists (bindir))
1397 yield return bindir;
1399 foreach (string dir in BinDirs) {
1400 bindir = Path.Combine (baseDir, dir);
1401 if (!Directory.Exists (bindir))
1403 yield return bindir;
1409 internal static string[] BinDirectoryAssemblies
1412 ArrayList binDlls = null;
1415 foreach (string bindir in BinDirectories) {
1416 if (binDlls == null)
1417 binDlls = new ArrayList ();
1418 dlls = Directory.GetFiles (bindir, "*.dll");
1419 binDlls.AddRange (dlls);
1422 if (binDlls == null)
1423 return new string[] {};
1424 return (string[])binDlls.ToArray (typeof (string));
1428 internal static Type LoadType (string typeName)
1430 return LoadType (typeName, false);
1433 internal static Type LoadType (string typeName, bool throwOnMissing)
1435 Type type = Type.GetType (typeName);
1440 Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
1441 foreach (Assembly ass in assemblies) {
1442 type = ass.GetType (typeName, false);
1448 IList tla = System.Web.Compilation.BuildManager.TopLevelAssemblies;
1449 if (tla != null && tla.Count > 0) {
1450 foreach (Assembly asm in tla) {
1453 type = asm.GetType (typeName, false);
1460 type = LoadTypeFromBin (typeName);
1465 throw new TypeLoadException (String.Format ("Type '{0}' cannot be found", typeName));
1470 internal static Type LoadTypeFromBin (string typeName)
1474 foreach (string s in BinDirectoryAssemblies) {
1475 Assembly binA = Assembly.LoadFrom (s);
1476 type = binA.GetType (typeName, false);
1488 // Based on Fritz' Onion's AsyncRequestState class for asynchronous IHttpAsyncHandlers
1490 class AsyncRequestState : IAsyncResult {
1494 ManualResetEvent complete_event = null;
1496 internal AsyncRequestState (ManualResetEvent complete_event, AsyncCallback cb, object cb_data)
1499 this.cb_data = cb_data;
1500 this.complete_event = complete_event;
1503 internal void Complete ()
1508 // TODO: if this throws an error, we have no way of reporting it
1509 // Not really too bad, since the only failure might be
1510 // `HttpRuntime.request_processed'.
1517 complete_event.Set ();
1520 public object AsyncState {
1526 public bool CompletedSynchronously {
1532 public bool IsCompleted {
1538 public WaitHandle AsyncWaitHandle {
1540 return complete_event;
1545 #region Helper classes
1548 // A wrapper to keep track of begin/end pairs
1550 class AsyncInvoker {
1551 public BeginEventHandler begin;
1552 public EndEventHandler end;
1555 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, object d)
1562 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh)
1568 public void Invoke (object sender, EventArgs e)
1570 throw new Exception ("This is just a dummy");