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
92 static readonly object disposedEvent = new object ();
93 static readonly object errorEvent = new object ();
95 internal static readonly string [] BinDirs = {"Bin", "bin"};
96 object this_lock = new object();
99 HttpSessionState session;
102 // The source, and the exposed API (cache).
103 HttpModuleCollection modcoll;
105 string assemblyLocation;
108 // The factory for the handler currently running.
110 IHttpHandlerFactory factory;
113 // Whether the thread culture is to be auto-set.
114 // Used only in the 2.0 profile, always false for 1.x
120 // Whether the pipeline should be stopped
122 bool stop_processing;
125 // See https://bugzilla.novell.com/show_bug.cgi?id=381971
127 bool in_application_start;
132 IEnumerator pipeline;
134 // To flag when we are done processing a request from BeginProcessRequest.
135 ManualResetEvent done;
137 // The current IAsyncResult for the running async request handler in the pipeline
138 AsyncRequestState begin_iar;
140 // Tracks the current AsyncInvocation being dispatched
141 AsyncInvoker current_ai;
143 EventHandlerList events;
144 EventHandlerList nonApplicationEvents = new EventHandlerList ();
146 // Culture and IPrincipal
147 CultureInfo app_culture;
148 CultureInfo appui_culture;
149 CultureInfo prev_app_culture;
150 CultureInfo prev_appui_culture;
151 IPrincipal prev_user;
153 static string binDirectory;
157 const string initialization_exception_key = "System.Web.HttpApplication.initialization_exception";
158 static Exception initialization_exception {
159 get { return (Exception) AppDomain.CurrentDomain.GetData (initialization_exception_key); }
160 set { AppDomain.CurrentDomain.SetData (initialization_exception_key, value); }
163 static Exception initialization_exception;
165 bool removeConfigurationFromCache;
167 bool fullInitComplete = false;
170 // These are used to detect the case where the EndXXX method is invoked
171 // from within the BeginXXXX delegate, so we detect whether we kick the
172 // pipeline from here, or from the the RunHook routine
177 public virtual event EventHandler Disposed {
178 add { nonApplicationEvents.AddHandler (disposedEvent, value); }
179 remove { nonApplicationEvents.RemoveHandler (disposedEvent, value); }
182 public virtual event EventHandler Error {
183 add { nonApplicationEvents.AddHandler (errorEvent, value); }
184 remove { nonApplicationEvents.RemoveHandler (errorEvent, value); }
187 public HttpApplication ()
189 done = new ManualResetEvent (false);
192 internal void InitOnce (bool full_init)
199 HttpModulesSection modules;
200 modules = (HttpModulesSection) WebConfigurationManager.GetSection ("system.web/httpModules", HttpRuntime.AppDomainAppVirtualPath);
202 ModulesConfiguration modules;
204 modules = (ModulesConfiguration) HttpContext.GetAppConfig ("system.web/httpModules");
207 HttpContext saved = HttpContext.Current;
208 HttpContext.Current = new HttpContext (new System.Web.Hosting.SimpleWorkerRequest ("", "", new StringWriter()));
209 modcoll = modules.LoadModules (this);
210 HttpContext.Current = saved;
213 HttpApplicationFactory.AttachEvents (this);
215 fullInitComplete = true;
220 internal bool InApplicationStart {
221 get { return in_application_start; }
222 set { in_application_start = value; }
225 internal string AssemblyLocation {
227 if (assemblyLocation == null)
228 assemblyLocation = GetType ().Assembly.Location;
229 return assemblyLocation;
234 internal static Exception InitializationException {
235 get { return initialization_exception; }
240 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
241 public HttpApplicationState Application {
243 return HttpApplicationFactory.ApplicationState;
248 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
249 public HttpContext Context {
255 protected EventHandlerList Events {
258 events = new EventHandlerList ();
265 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
266 public HttpModuleCollection Modules {
267 [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
271 modcoll = new HttpModuleCollection ();
279 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
280 public HttpRequest Request {
283 throw new HttpException (Locale.GetText ("No context is available."));
285 if (false == HttpApplicationFactory.ContextAvailable)
286 throw new HttpException (Locale.GetText ("Request is not available in this context."));
288 return context.Request;
293 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
294 public HttpResponse Response {
297 throw new HttpException (Locale.GetText ("No context is available."));
299 if (false == HttpApplicationFactory.ContextAvailable)
300 throw new HttpException (Locale.GetText ("Response is not available in this context."));
302 return context.Response;
307 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
308 public HttpServerUtility Server {
311 return context.Server;
314 // This is so we can get the Server and call a few methods
315 // which are not context sensitive, see HttpServerUtilityTest
317 return new HttpServerUtility ((HttpContext) null);
322 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
323 public HttpSessionState Session {
325 // Only used for Session_End
330 throw new HttpException (Locale.GetText ("No context is available."));
331 return context.Session;
336 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
340 public virtual ISite Site {
352 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
353 public IPrincipal User {
356 throw new HttpException (Locale.GetText ("No context is available."));
357 if (context.User == null)
358 throw new HttpException (Locale.GetText ("No currently authenticated user."));
364 static object PreSendRequestHeadersEvent = new object ();
365 public event EventHandler PreSendRequestHeaders
367 add { AddEventHandler (PreSendRequestHeadersEvent, value); }
368 remove { RemoveEventHandler (PreSendRequestHeadersEvent, value); }
371 internal void TriggerPreSendRequestHeaders ()
373 EventHandler handler = Events [PreSendRequestHeadersEvent] as EventHandler;
375 handler (this, EventArgs.Empty);
378 static object PreSendRequestContentEvent = new object ();
379 public event EventHandler PreSendRequestContent
381 add { AddEventHandler (PreSendRequestContentEvent, value); }
382 remove { RemoveEventHandler (PreSendRequestContentEvent, value); }
385 internal void TriggerPreSendRequestContent ()
387 EventHandler handler = Events [PreSendRequestContentEvent] as EventHandler;
389 handler (this, EventArgs.Empty);
392 static object AcquireRequestStateEvent = new object ();
393 public event EventHandler AcquireRequestState
395 add { AddEventHandler (AcquireRequestStateEvent, value); }
396 remove { RemoveEventHandler (AcquireRequestStateEvent, value); }
399 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
401 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
402 AcquireRequestState += new EventHandler (invoker.Invoke);
405 static object AuthenticateRequestEvent = new object ();
406 public event EventHandler AuthenticateRequest
408 add { AddEventHandler (AuthenticateRequestEvent, value); }
409 remove { RemoveEventHandler (AuthenticateRequestEvent, value); }
412 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
414 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
415 AuthenticateRequest += new EventHandler (invoker.Invoke);
418 static object AuthorizeRequestEvent = new object ();
419 public event EventHandler AuthorizeRequest
421 add { AddEventHandler (AuthorizeRequestEvent, value); }
422 remove { RemoveEventHandler (AuthorizeRequestEvent, value); }
425 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
427 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
428 AuthorizeRequest += new EventHandler (invoker.Invoke);
431 static object BeginRequestEvent = new object ();
432 public event EventHandler BeginRequest
435 // See https://bugzilla.novell.com/show_bug.cgi?id=381971
436 if (InApplicationStart)
438 AddEventHandler (BeginRequestEvent, value);
441 if (InApplicationStart)
443 RemoveEventHandler (BeginRequestEvent, value);
447 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh)
449 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
450 BeginRequest += new EventHandler (invoker.Invoke);
453 static object EndRequestEvent = new object ();
454 public event EventHandler EndRequest
457 // See https://bugzilla.novell.com/show_bug.cgi?id=381971
458 if (InApplicationStart)
460 AddEventHandler (EndRequestEvent, value);
463 if (InApplicationStart)
465 RemoveEventHandler (EndRequestEvent, value);
469 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh)
471 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
472 EndRequest += new EventHandler (invoker.Invoke);
475 static object PostRequestHandlerExecuteEvent = new object ();
476 public event EventHandler PostRequestHandlerExecute
478 add { AddEventHandler (PostRequestHandlerExecuteEvent, value); }
479 remove { RemoveEventHandler (PostRequestHandlerExecuteEvent, value); }
482 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
484 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
485 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
488 static object PreRequestHandlerExecuteEvent = new object ();
489 public event EventHandler PreRequestHandlerExecute
491 add { AddEventHandler (PreRequestHandlerExecuteEvent, value); }
492 remove { RemoveEventHandler (PreRequestHandlerExecuteEvent, value); }
495 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
497 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
498 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
501 static object ReleaseRequestStateEvent = new object ();
502 public event EventHandler ReleaseRequestState
504 add { AddEventHandler (ReleaseRequestStateEvent, value); }
505 remove { RemoveEventHandler (ReleaseRequestStateEvent, value); }
508 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
510 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
511 ReleaseRequestState += new EventHandler (invoker.Invoke);
514 static object ResolveRequestCacheEvent = new object ();
515 public event EventHandler ResolveRequestCache
517 add { AddEventHandler (ResolveRequestCacheEvent, value); }
518 remove { RemoveEventHandler (ResolveRequestCacheEvent, value); }
521 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
523 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
524 ResolveRequestCache += new EventHandler (invoker.Invoke);
527 static object UpdateRequestCacheEvent = new object ();
528 public event EventHandler UpdateRequestCache
530 add { AddEventHandler (UpdateRequestCacheEvent, value); }
531 remove { RemoveEventHandler (UpdateRequestCacheEvent, value); }
534 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
536 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
537 UpdateRequestCache += new EventHandler (invoker.Invoke);
541 static object PostAuthenticateRequestEvent = new object ();
542 public event EventHandler PostAuthenticateRequest
544 add { AddEventHandler (PostAuthenticateRequestEvent, value); }
545 remove { RemoveEventHandler (PostAuthenticateRequestEvent, value); }
548 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
550 AddOnPostAuthenticateRequestAsync (bh, eh, null);
553 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
555 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
556 PostAuthenticateRequest += new EventHandler (invoker.Invoke);
559 static object PostAuthorizeRequestEvent = new object ();
560 public event EventHandler PostAuthorizeRequest
562 add { AddEventHandler (PostAuthorizeRequestEvent, value); }
563 remove { RemoveEventHandler (PostAuthorizeRequestEvent, value); }
566 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
568 AddOnPostAuthorizeRequestAsync (bh, eh, null);
571 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
573 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
574 PostAuthorizeRequest += new EventHandler (invoker.Invoke);
577 static object PostResolveRequestCacheEvent = new object ();
578 public event EventHandler PostResolveRequestCache
580 add { AddEventHandler (PostResolveRequestCacheEvent, value); }
581 remove { RemoveEventHandler (PostResolveRequestCacheEvent, value); }
584 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
586 AddOnPostResolveRequestCacheAsync (bh, eh, null);
589 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
591 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
592 PostResolveRequestCache += new EventHandler (invoker.Invoke);
595 static object PostMapRequestHandlerEvent = new object ();
596 public event EventHandler PostMapRequestHandler
598 add { AddEventHandler (PostMapRequestHandlerEvent, value); }
599 remove { RemoveEventHandler (PostMapRequestHandlerEvent, value); }
602 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
604 AddOnPostMapRequestHandlerAsync (bh, eh, null);
607 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh, object data)
609 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
610 PostMapRequestHandler += new EventHandler (invoker.Invoke);
613 static object PostAcquireRequestStateEvent = new object ();
614 public event EventHandler PostAcquireRequestState
616 add { AddEventHandler (PostAcquireRequestStateEvent, value); }
617 remove { RemoveEventHandler (PostAcquireRequestStateEvent, value); }
620 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
622 AddOnPostAcquireRequestStateAsync (bh, eh, null);
625 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
627 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
628 PostAcquireRequestState += new EventHandler (invoker.Invoke);
631 static object PostReleaseRequestStateEvent = new object ();
632 public event EventHandler PostReleaseRequestState
634 add { AddEventHandler (PostReleaseRequestStateEvent, value); }
635 remove { RemoveEventHandler (PostReleaseRequestStateEvent, value); }
638 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
640 AddOnPostReleaseRequestStateAsync (bh, eh, null);
643 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
645 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
646 PostReleaseRequestState += new EventHandler (invoker.Invoke);
649 static object PostUpdateRequestCacheEvent = new object ();
650 public event EventHandler PostUpdateRequestCache
652 add { AddEventHandler (PostUpdateRequestCacheEvent, value); }
653 remove { RemoveEventHandler (PostUpdateRequestCacheEvent, value); }
656 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
658 AddOnPostUpdateRequestCacheAsync (bh, eh, null);
661 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
663 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
664 PostUpdateRequestCache += new EventHandler (invoker.Invoke);
668 // The new overloads that take a data parameter
670 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
672 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
673 AcquireRequestState += new EventHandler (invoker.Invoke);
676 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
678 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
679 AuthenticateRequest += new EventHandler (invoker.Invoke);
682 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
684 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
685 AuthorizeRequest += new EventHandler (invoker.Invoke);
688 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
690 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
691 BeginRequest += new EventHandler (invoker.Invoke);
694 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
696 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
697 EndRequest += new EventHandler (invoker.Invoke);
700 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
702 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
703 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
706 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
708 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
709 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
712 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
714 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
715 ReleaseRequestState += new EventHandler (invoker.Invoke);
718 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
720 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
721 ResolveRequestCache += new EventHandler (invoker.Invoke);
724 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
726 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
727 UpdateRequestCache += new EventHandler (invoker.Invoke);
731 // They are for use with the IIS7 integrated mode, but have been added for
733 static object LogRequestEvent = new object ();
734 public event EventHandler LogRequest
736 add { AddEventHandler (LogRequestEvent, value); }
737 remove { RemoveEventHandler (LogRequestEvent, value); }
740 public void AddOnLogRequestAsync (BeginEventHandler bh, EndEventHandler eh)
742 AddOnLogRequestAsync (bh, eh, null);
745 public void AddOnLogRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state)
747 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state);
748 LogRequest += new EventHandler (invoker.Invoke);
751 static object MapRequestHandlerEvent = new object ();
752 public event EventHandler MapRequestHandler
754 add { AddEventHandler (MapRequestHandlerEvent, value); }
755 remove { RemoveEventHandler (MapRequestHandlerEvent, value); }
758 public void AddOnMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
760 AddOnMapRequestHandlerAsync (bh, eh, null);
763 public void AddOnMapRequestHandlerAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state)
765 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state);
766 MapRequestHandler += new EventHandler (invoker.Invoke);
769 static object PostLogRequestEvent = new object ();
770 public event EventHandler PostLogRequest
772 add { AddEventHandler (PostLogRequestEvent, value); }
773 remove { RemoveEventHandler (PostLogRequestEvent, value); }
776 public void AddOnPostLogRequestAsync (BeginEventHandler bh, EndEventHandler eh)
778 AddOnPostLogRequestAsync (bh, eh, null);
781 public void AddOnPostLogRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state)
783 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state);
784 PostLogRequest += new EventHandler (invoker.Invoke);
789 internal event EventHandler DefaultAuthentication;
791 void AddEventHandler (object key, EventHandler handler)
793 if (fullInitComplete)
796 Events.AddHandler (key, handler);
799 void RemoveEventHandler (object key, EventHandler handler)
801 if (fullInitComplete)
804 Events.RemoveHandler (key, handler);
808 // Bypass all the event on the Http pipeline and go directly to EndRequest
810 public void CompleteRequest ()
812 stop_processing = true;
815 internal bool RequestCompleted {
816 set { stop_processing = value; }
819 internal void DisposeInternal ()
823 if (modcoll != null) {
824 for (int i = modcoll.Count - 1; i >= 0; i--) {
825 modcoll.Get (i).Dispose ();
831 EventHandler eh = nonApplicationEvents [disposedEvent] as EventHandler;
833 eh (this, EventArgs.Empty);
839 public virtual void Dispose ()
843 public virtual string GetVaryByCustomString (HttpContext context, string custom)
845 if (custom == null) // Sigh
846 throw new NullReferenceException ();
848 if (0 == String.Compare (custom, "browser", true, CultureInfo.InvariantCulture))
849 return context.Request.Browser.Type;
855 // If we catch an error, queue this error
857 void ProcessError (Exception e)
859 bool first = context.Error == null;
860 context.AddError (e);
862 EventHandler eh = nonApplicationEvents [errorEvent] as EventHandler;
865 eh (this, EventArgs.Empty);
866 } catch (ThreadAbortException taex){
867 context.ClearError ();
868 if (FlagEnd.Value == taex.ExceptionState)
869 // This happens on Redirect() or End()
870 Thread.ResetAbort ();
872 // This happens on Thread.Abort()
873 context.AddError (taex);
874 } catch (Exception ee){
875 context.AddError (ee);
879 stop_processing = true;
881 // we want to remove configuration from the cache in case of
882 // invalid resource not exists to prevent DOS attack.
883 HttpException httpEx = e as HttpException;
884 if (httpEx != null && httpEx.GetHttpCode () == 404) {
885 removeConfigurationFromCache = true;
891 // Ticks the clock: next step on the pipeline.
893 internal void Tick ()
897 if (context.Error is UnifyRequestException) {
898 Exception ex = context.Error.InnerException;
899 context.ClearError ();
900 vmw.common.TypeUtils.Throw (ex);
904 if (pipeline.MoveNext ()){
905 if ((bool)pipeline.Current)
910 catch (Exception ex) {
911 if (ex is ThreadAbortException &&
912 ((ThreadAbortException) ex).ExceptionState == FlagEnd.Value)
914 if (context.WorkerRequest is IHttpUnifyWorkerRequest) {
915 context.ClearError ();
916 context.AddError (new UnifyRequestException (ex));
923 } catch (ThreadAbortException taex) {
924 object obj = taex.ExceptionState;
925 Thread.ResetAbort ();
926 stop_processing = true;
927 if (obj is StepTimeout)
928 ProcessError (new HttpException ("The request timed out."));
930 context.ClearError ();
931 if (FlagEnd.Value != obj)
932 context.AddError (taex);
936 } catch (Exception e) {
937 stop_processing = true;
952 // Invoked when our async callback called from RunHooks completes,
953 // we restart the pipeline here.
955 void async_callback_completed_cb (IAsyncResult ar)
957 if (current_ai.end != null){
960 } catch (Exception e) {
968 void async_handler_complete_cb (IAsyncResult ar)
970 IHttpAsyncHandler async_handler = ((IHttpAsyncHandler) ar.AsyncState);
973 async_handler.EndProcessRequest (ar);
974 } catch (Exception e){
982 // This enumerator yields whether processing must be stopped:
983 // true: processing of the pipeline must be stopped
984 // false: processing of the pipeline must not be stopped
986 IEnumerable RunHooks (Delegate list)
988 Delegate [] delegates = list.GetInvocationList ();
990 foreach (EventHandler d in delegates){
991 if (d.Target != null && (d.Target is AsyncInvoker)){
992 current_ai = (AsyncInvoker) d.Target;
997 context.BeginTimeoutPossible ();
998 current_ai.begin (this, EventArgs.Empty, async_callback_completed_cb, current_ai.data);
1001 context.EndTimeoutPossible ();
1005 // If things are still moving forward, yield this
1009 yield return stop_processing;
1010 else if (stop_processing)
1014 context.BeginTimeoutPossible ();
1015 d (this, EventArgs.Empty);
1017 context.EndTimeoutPossible ();
1019 if (stop_processing)
1025 static void FinalErrorWrite (HttpResponse response, string error)
1028 response.Write (error);
1029 response.Flush (true);
1037 if (context.Error == null){
1039 context.Response.Flush (true);
1040 } catch (Exception e){
1041 context.AddError (e);
1045 Exception error = context.Error;
1047 HttpResponse response = context.Response;
1049 if (!response.HeadersSent){
1050 response.ClearHeaders ();
1051 response.ClearContent ();
1053 if (error is HttpException){
1054 response.StatusCode = ((HttpException)error).GetHttpCode ();
1056 error = new HttpException ("", error);
1057 response.StatusCode = 500;
1059 HttpException httpEx = (HttpException) error;
1060 if (!RedirectCustomError (ref httpEx))
1061 FinalErrorWrite (response, httpEx.GetHtmlErrorMessage ());
1063 response.Flush (true);
1065 if (!(error is HttpException))
1066 error = new HttpException ("", error);
1067 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
1074 // Invoked at the end of the pipeline execution
1076 void PipelineDone ()
1079 EventHandler handler = Events [EndRequestEvent] as EventHandler;
1080 if (handler != null)
1081 handler (this, EventArgs.Empty);
1082 } catch (Exception e){
1088 } catch (Exception e) {
1089 Console.WriteLine ("Internal error: OutputPage threw an exception " + e);
1091 context.WorkerRequest.EndOfRequest();
1092 if (factory != null && context.Handler != null){
1093 factory.ReleaseHandler (context.Handler);
1094 context.Handler = null;
1098 context.PopHandler ();
1100 // context = null; -> moved to PostDone
1106 if (begin_iar != null)
1107 begin_iar.Complete ();
1113 // Events fired as described in `Http Runtime Support, HttpModules,
1114 // Handling Public Events'
1116 IEnumerator Pipeline ()
1118 Delegate eventHandler;
1119 if (stop_processing)
1122 eventHandler = Events [BeginRequestEvent];
1123 if (eventHandler != null) {
1124 foreach (bool stop in RunHooks (eventHandler))
1128 eventHandler = Events [AuthenticateRequestEvent];
1129 if (eventHandler != null)
1130 foreach (bool stop in RunHooks (eventHandler))
1133 if (DefaultAuthentication != null)
1134 foreach (bool stop in RunHooks (DefaultAuthentication))
1138 eventHandler = Events [PostAuthenticateRequestEvent];
1139 if (eventHandler != null)
1140 foreach (bool stop in RunHooks (eventHandler))
1143 eventHandler = Events [AuthorizeRequestEvent];
1144 if (eventHandler != null)
1145 foreach (bool stop in RunHooks (eventHandler))
1148 eventHandler = Events [PostAuthorizeRequestEvent];
1149 if (eventHandler != null)
1150 foreach (bool stop in RunHooks (eventHandler))
1154 eventHandler = Events [ResolveRequestCacheEvent];
1155 if (eventHandler != null)
1156 foreach (bool stop in RunHooks (eventHandler))
1160 eventHandler = Events [PostResolveRequestCacheEvent];
1161 if (eventHandler != null)
1162 foreach (bool stop in RunHooks (eventHandler))
1165 // As per http://msdn2.microsoft.com/en-us/library/bb470252(VS.90).aspx
1166 eventHandler = Events [MapRequestHandlerEvent];
1167 if (eventHandler != null)
1168 foreach (bool stop in RunHooks (eventHandler))
1172 // Obtain the handler for the request.
1173 IHttpHandler handler = null;
1175 handler = GetHandler (context, context.Request.CurrentExecutionFilePath);
1176 context.Handler = handler;
1178 context.PushHandler (handler);
1180 } catch (FileNotFoundException fnf){
1182 Console.WriteLine ("$$$$$$$$$$:Sys.Web Pipeline");
1183 Console.WriteLine (fnf.ToString ());
1185 if (context.Request.IsLocal)
1186 ProcessError (new HttpException (404, String.Format ("File not found {0}", fnf.FileName), fnf, context.Request.FilePath));
1188 ProcessError (new HttpException (404, "File not found: " + Path.GetFileName (fnf.FileName), context.Request.FilePath));
1189 } catch (DirectoryNotFoundException dnf){
1190 if (!context.Request.IsLocal)
1191 dnf = null; // Do not "leak" real path information
1192 ProcessError (new HttpException (404, "Directory not found", dnf));
1193 } catch (Exception e) {
1197 if (stop_processing)
1201 eventHandler = Events [PostMapRequestHandlerEvent];
1202 if (eventHandler != null)
1203 foreach (bool stop in RunHooks (eventHandler))
1207 eventHandler = Events [AcquireRequestStateEvent];
1208 if (eventHandler != null){
1209 foreach (bool stop in RunHooks (eventHandler))
1214 eventHandler = Events [PostAcquireRequestStateEvent];
1215 if (eventHandler != null){
1216 foreach (bool stop in RunHooks (eventHandler))
1222 // From this point on, we need to ensure that we call
1223 // ReleaseRequestState, so the code below jumps to
1224 // `release:' to guarantee it rather than yielding.
1226 eventHandler = Events [PreRequestHandlerExecuteEvent];
1227 if (eventHandler != null)
1228 foreach (bool stop in RunHooks (eventHandler))
1235 bool doProcessHandler = false;
1239 IHttpHandler ctxHandler = context.Handler;
1240 if (ctxHandler != null && handler != ctxHandler) {
1241 context.PopHandler ();
1242 handler = ctxHandler;
1243 context.PushHandler (handler);
1248 context.BeginTimeoutPossible ();
1249 if (handler != null){
1250 IHttpAsyncHandler async_handler = handler as IHttpAsyncHandler;
1252 if (async_handler != null){
1255 async_handler.BeginProcessRequest (context, async_handler_complete_cb, handler);
1258 handler.ProcessRequest (context);
1260 IHttpExtendedHandler extHandler=handler as IHttpExtendedHandler;
1261 doProcessHandler = extHandler != null && !extHandler.IsCompleted;
1265 if (context.Error != null)
1266 throw new TargetInvocationException(context.Error);
1269 context.EndTimeoutPossible ();
1272 if (doProcessHandler) {
1274 goto processHandler;
1278 yield return stop_processing;
1279 else if (stop_processing)
1282 // These are executed after the application has returned
1284 eventHandler = Events [PostRequestHandlerExecuteEvent];
1285 if (eventHandler != null)
1286 foreach (bool stop in RunHooks (eventHandler))
1291 eventHandler = Events [ReleaseRequestStateEvent];
1292 if (eventHandler != null){
1293 #pragma warning disable 219
1294 foreach (bool stop in RunHooks (eventHandler)) {
1296 // Ignore the stop signal while release the state
1300 #pragma warning restore 219
1303 if (stop_processing)
1307 eventHandler = Events [PostReleaseRequestStateEvent];
1308 if (eventHandler != null)
1309 foreach (bool stop in RunHooks (eventHandler))
1313 if (context.Error == null)
1314 context.Response.DoFilter (true);
1316 eventHandler = Events [UpdateRequestCacheEvent];
1317 if (eventHandler != null)
1318 foreach (bool stop in RunHooks (eventHandler))
1322 eventHandler = Events [PostUpdateRequestCacheEvent];
1323 if (eventHandler != null)
1324 foreach (bool stop in RunHooks (eventHandler))
1327 eventHandler = Events [LogRequestEvent];
1328 if (eventHandler != null)
1329 foreach (bool stop in RunHooks (eventHandler))
1332 eventHandler = Events [PostLogRequestEvent];
1333 if (eventHandler != null)
1334 foreach (bool stop in RunHooks (eventHandler))
1341 internal CultureInfo GetThreadCulture (HttpRequest request, CultureInfo culture, bool isAuto)
1346 CultureInfo ret = null;
1347 string[] languages = request.UserLanguages;
1349 if (languages != null && languages.Length > 0)
1350 ret = CultureInfo.CreateSpecificCulture (languages[0]);
1367 GlobalizationSection cfg;
1368 cfg = (GlobalizationSection) WebConfigurationManager.GetSection ("system.web/globalization");
1369 app_culture = cfg.GetCulture ();
1370 autoCulture = cfg.IsAutoCulture;
1371 appui_culture = cfg.GetUICulture ();
1372 autoUICulture = cfg.IsAutoUICulture;
1374 GlobalizationConfiguration cfg;
1375 cfg = GlobalizationConfiguration.GetInstance (null);
1377 app_culture = cfg.Culture;
1378 appui_culture = cfg.UICulture;
1383 context.StartTimeoutTimer ();
1385 Thread th = Thread.CurrentThread;
1386 if (app_culture != null) {
1387 prev_app_culture = th.CurrentCulture;
1388 CultureInfo new_app_culture = GetThreadCulture (Request, app_culture, autoCulture);
1389 if (!new_app_culture.Equals (CultureInfo.InvariantCulture))
1390 th.CurrentCulture = new_app_culture;
1393 if (appui_culture != null) {
1394 prev_appui_culture = th.CurrentUICulture;
1395 CultureInfo new_app_culture = GetThreadCulture (Request, appui_culture, autoUICulture);
1396 if (!new_app_culture.Equals (CultureInfo.InvariantCulture))
1397 th.CurrentUICulture = new_app_culture;
1401 prev_user = Thread.CurrentPrincipal;
1408 if (removeConfigurationFromCache) {
1409 WebConfigurationManager.RemoveConfigurationFromCache (context);
1410 removeConfigurationFromCache = false;
1413 Thread th = Thread.CurrentThread;
1415 if (Thread.CurrentPrincipal != prev_user)
1416 Thread.CurrentPrincipal = prev_user;
1418 if (prev_appui_culture != null && prev_appui_culture != th.CurrentUICulture)
1419 th.CurrentUICulture = prev_appui_culture;
1420 if (prev_app_culture != null && prev_app_culture != th.CurrentCulture)
1421 th.CurrentCulture = prev_app_culture;
1424 if (context == null)
1425 context = HttpContext.Current;
1426 context.StopTimeoutTimer ();
1430 HttpContext.Current = null;
1433 void Start (object x)
1435 CultureInfo[] cultures = x as CultureInfo[];
1436 if (cultures != null && cultures.Length == 2) {
1437 Thread ct = Thread.CurrentThread;
1438 ct.CurrentCulture = cultures [0];
1439 ct.CurrentUICulture = cultures [1];
1444 } catch (Exception e) {
1446 initialization_exception = e;
1448 FinalErrorWrite (context.Response, new HttpException ("", e).GetHtmlErrorMessage ());
1453 HttpContext.Current = Context;
1455 pipeline = Pipeline ();
1459 const string HANDLER_CACHE = "@@HttpHandlerCache@@";
1461 internal static Hashtable GetHandlerCache ()
1463 Cache cache = HttpRuntime.InternalCache;
1464 Hashtable ret = cache [HANDLER_CACHE] as Hashtable;
1467 ret = new Hashtable ();
1468 cache.Insert (HANDLER_CACHE, ret);
1474 internal static void ClearHandlerCache ()
1476 Hashtable cache = GetHandlerCache ();
1480 internal object LocateHandler (string verb, string url)
1482 Hashtable cache = GetHandlerCache ();
1483 string id = String.Concat (verb, url);
1484 object ret = cache [id];
1490 HttpHandlersSection httpHandlersSection = (HttpHandlersSection) WebConfigurationManager.GetSection ("system.web/httpHandlers");
1491 ret = httpHandlersSection.LocateHandler (verb, url);
1493 HandlerFactoryConfiguration factory_config = (HandlerFactoryConfiguration) HttpContext.GetAppConfig ("system.web/httpHandlers");
1494 ret = factory_config.LocateHandler (verb, url);
1501 internal IHttpHandler GetHandler (HttpContext context, string url)
1503 return GetHandler (context, url, false);
1506 // Used by HttpServerUtility.Execute
1507 internal IHttpHandler GetHandler (HttpContext context, string url, bool ignoreContextHandler)
1509 if (!ignoreContextHandler && context.Handler != null)
1510 return context.Handler;
1512 HttpRequest request = context.Request;
1513 string verb = request.RequestType;
1515 IHttpHandler handler = null;
1516 object o = LocateHandler (verb, url);
1518 factory = o as IHttpHandlerFactory;
1520 if (factory == null) {
1521 handler = (IHttpHandler) o;
1523 handler = factory.GetHandler (context, verb, url, request.MapPath (url));
1529 void IHttpHandler.ProcessRequest (HttpContext context)
1532 this.context = context;
1540 // This is used by FireOnAppStart, when we init the application
1541 // as the context is required to be set at that point (the user
1542 // might call methods that require it on that hook).
1544 internal void SetContext (HttpContext context)
1546 this.context = context;
1549 internal void SetSession (HttpSessionState session)
1551 this.session = session;
1554 IAsyncResult IHttpAsyncHandler.BeginProcessRequest (HttpContext context, AsyncCallback cb, object extraData)
1556 this.context = context;
1559 begin_iar = new AsyncRequestState (done, cb, extraData);
1561 CultureInfo[] cultures = new CultureInfo [2];
1562 cultures [0] = Thread.CurrentThread.CurrentCulture;
1563 cultures [1] = Thread.CurrentThread.CurrentUICulture;
1568 if (Thread.CurrentThread.IsThreadPoolThread)
1572 ThreadPool.QueueUserWorkItem (new WaitCallback (Start), cultures);
1577 void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result)
1583 if (!result.IsCompleted)
1584 result.AsyncWaitHandle.WaitOne ();
1588 public virtual void Init ()
1592 bool IHttpHandler.IsReusable {
1599 internal void ClearError ()
1601 context.ClearError ();
1604 bool RedirectErrorPage (string error_page)
1606 if (context.Request.QueryString ["aspxerrorpath"] != null)
1609 Response.Redirect (error_page + "?aspxerrorpath=" + Request.Path, false);
1613 bool RedirectCustomError (ref HttpException httpEx)
1616 if (!context.IsCustomErrorEnabledUnsafe)
1620 CustomErrorsSection config = (CustomErrorsSection)WebConfigurationManager.GetSection ("system.web/customErrors");
1622 CustomErrorsConfig config = null;
1624 config = (CustomErrorsConfig) context.GetConfig ("system.web/customErrors");
1628 if (config == null) {
1629 if (context.ErrorPage != null)
1630 return RedirectErrorPage (context.ErrorPage);
1636 CustomError err = config.Errors [context.Response.StatusCode.ToString()];
1637 string redirect = err == null ? null : err.Redirect;
1639 string redirect = config [context.Response.StatusCode];
1641 if (redirect == null) {
1642 redirect = context.ErrorPage;
1643 if (redirect == null)
1644 redirect = config.DefaultRedirect;
1647 if (redirect == null)
1650 return RedirectErrorPage (redirect);
1652 catch (Exception ex) {
1653 httpEx = new HttpException (500, "", ex);
1658 internal static string BinDirectory
1661 if (binDirectory == null) {
1662 AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
1663 string baseDir = setup.ApplicationBase;
1666 foreach (string dir in BinDirs) {
1667 bindir = Path.Combine (baseDir, dir);
1668 if (!Directory.Exists (bindir))
1670 binDirectory = bindir;
1675 return binDirectory;
1679 internal static string[] BinDirectoryAssemblies
1682 ArrayList binDlls = null;
1685 string bindir = BinDirectory;
1686 if (bindir != null) {
1687 binDlls = new ArrayList ();
1688 dlls = Directory.GetFiles (bindir, "*.dll");
1689 binDlls.AddRange (dlls);
1692 if (binDlls == null)
1693 return new string[] {};
1695 return (string[]) binDlls.ToArray (typeof (string));
1699 internal static Type LoadType (string typeName)
1701 return LoadType (typeName, false);
1704 internal static Type LoadType (string typeName, bool throwOnMissing)
1706 Type type = Type.GetType (typeName);
1711 Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
1712 foreach (Assembly ass in assemblies) {
1713 type = ass.GetType (typeName, false);
1719 IList tla = System.Web.Compilation.BuildManager.TopLevelAssemblies;
1720 if (tla != null && tla.Count > 0) {
1721 foreach (Assembly asm in tla) {
1724 type = asm.GetType (typeName, false);
1731 type = LoadTypeFromBin (typeName);
1736 throw new TypeLoadException (String.Format ("Type '{0}' cannot be found", typeName));
1741 internal static Type LoadTypeFromBin (string typeName)
1745 foreach (string s in BinDirectoryAssemblies) {
1746 Assembly binA = Assembly.LoadFrom (s);
1747 type = binA.GetType (typeName, false);
1759 // Based on Fritz' Onion's AsyncRequestState class for asynchronous IHttpAsyncHandlers
1761 class AsyncRequestState : IAsyncResult {
1765 ManualResetEvent complete_event = null;
1767 internal AsyncRequestState (ManualResetEvent complete_event, AsyncCallback cb, object cb_data)
1770 this.cb_data = cb_data;
1771 this.complete_event = complete_event;
1774 internal void Complete ()
1779 // TODO: if this throws an error, we have no way of reporting it
1780 // Not really too bad, since the only failure might be
1781 // `HttpRuntime.request_processed'.
1788 complete_event.Set ();
1791 public object AsyncState {
1797 public bool CompletedSynchronously {
1803 public bool IsCompleted {
1809 public WaitHandle AsyncWaitHandle {
1811 return complete_event;
1816 #region Helper classes
1819 // A wrapper to keep track of begin/end pairs
1821 class AsyncInvoker {
1822 public BeginEventHandler begin;
1823 public EndEventHandler end;
1826 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, object d)
1833 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh)
1839 public void Invoke (object sender, EventArgs e)
1841 throw new Exception ("This is just a dummy");