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."));
332 HttpSessionState ret = context.Session;
334 throw new HttpException (Locale.GetText ("Session state is not available in the context."));
341 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
345 public virtual ISite Site {
357 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
358 public IPrincipal User {
361 throw new HttpException (Locale.GetText ("No context is available."));
362 if (context.User == null)
363 throw new HttpException (Locale.GetText ("No currently authenticated user."));
369 static object PreSendRequestHeadersEvent = new object ();
370 public event EventHandler PreSendRequestHeaders
372 add { AddEventHandler (PreSendRequestHeadersEvent, value); }
373 remove { RemoveEventHandler (PreSendRequestHeadersEvent, value); }
376 internal void TriggerPreSendRequestHeaders ()
378 EventHandler handler = Events [PreSendRequestHeadersEvent] as EventHandler;
380 handler (this, EventArgs.Empty);
383 static object PreSendRequestContentEvent = new object ();
384 public event EventHandler PreSendRequestContent
386 add { AddEventHandler (PreSendRequestContentEvent, value); }
387 remove { RemoveEventHandler (PreSendRequestContentEvent, value); }
390 internal void TriggerPreSendRequestContent ()
392 EventHandler handler = Events [PreSendRequestContentEvent] as EventHandler;
394 handler (this, EventArgs.Empty);
397 static object AcquireRequestStateEvent = new object ();
398 public event EventHandler AcquireRequestState
400 add { AddEventHandler (AcquireRequestStateEvent, value); }
401 remove { RemoveEventHandler (AcquireRequestStateEvent, value); }
404 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
406 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
407 AcquireRequestState += new EventHandler (invoker.Invoke);
410 static object AuthenticateRequestEvent = new object ();
411 public event EventHandler AuthenticateRequest
413 add { AddEventHandler (AuthenticateRequestEvent, value); }
414 remove { RemoveEventHandler (AuthenticateRequestEvent, value); }
417 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
419 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
420 AuthenticateRequest += new EventHandler (invoker.Invoke);
423 static object AuthorizeRequestEvent = new object ();
424 public event EventHandler AuthorizeRequest
426 add { AddEventHandler (AuthorizeRequestEvent, value); }
427 remove { RemoveEventHandler (AuthorizeRequestEvent, value); }
430 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
432 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
433 AuthorizeRequest += new EventHandler (invoker.Invoke);
436 static object BeginRequestEvent = new object ();
437 public event EventHandler BeginRequest
440 // See https://bugzilla.novell.com/show_bug.cgi?id=381971
441 if (InApplicationStart)
443 AddEventHandler (BeginRequestEvent, value);
446 if (InApplicationStart)
448 RemoveEventHandler (BeginRequestEvent, value);
452 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh)
454 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
455 BeginRequest += new EventHandler (invoker.Invoke);
458 static object EndRequestEvent = new object ();
459 public event EventHandler EndRequest
462 // See https://bugzilla.novell.com/show_bug.cgi?id=381971
463 if (InApplicationStart)
465 AddEventHandler (EndRequestEvent, value);
468 if (InApplicationStart)
470 RemoveEventHandler (EndRequestEvent, value);
474 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh)
476 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
477 EndRequest += new EventHandler (invoker.Invoke);
480 static object PostRequestHandlerExecuteEvent = new object ();
481 public event EventHandler PostRequestHandlerExecute
483 add { AddEventHandler (PostRequestHandlerExecuteEvent, value); }
484 remove { RemoveEventHandler (PostRequestHandlerExecuteEvent, value); }
487 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
489 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
490 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
493 static object PreRequestHandlerExecuteEvent = new object ();
494 public event EventHandler PreRequestHandlerExecute
496 add { AddEventHandler (PreRequestHandlerExecuteEvent, value); }
497 remove { RemoveEventHandler (PreRequestHandlerExecuteEvent, value); }
500 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
502 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
503 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
506 static object ReleaseRequestStateEvent = new object ();
507 public event EventHandler ReleaseRequestState
509 add { AddEventHandler (ReleaseRequestStateEvent, value); }
510 remove { RemoveEventHandler (ReleaseRequestStateEvent, value); }
513 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
515 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
516 ReleaseRequestState += new EventHandler (invoker.Invoke);
519 static object ResolveRequestCacheEvent = new object ();
520 public event EventHandler ResolveRequestCache
522 add { AddEventHandler (ResolveRequestCacheEvent, value); }
523 remove { RemoveEventHandler (ResolveRequestCacheEvent, value); }
526 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
528 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
529 ResolveRequestCache += new EventHandler (invoker.Invoke);
532 static object UpdateRequestCacheEvent = new object ();
533 public event EventHandler UpdateRequestCache
535 add { AddEventHandler (UpdateRequestCacheEvent, value); }
536 remove { RemoveEventHandler (UpdateRequestCacheEvent, value); }
539 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
541 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
542 UpdateRequestCache += new EventHandler (invoker.Invoke);
546 static object PostAuthenticateRequestEvent = new object ();
547 public event EventHandler PostAuthenticateRequest
549 add { AddEventHandler (PostAuthenticateRequestEvent, value); }
550 remove { RemoveEventHandler (PostAuthenticateRequestEvent, value); }
553 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
555 AddOnPostAuthenticateRequestAsync (bh, eh, null);
558 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
560 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
561 PostAuthenticateRequest += new EventHandler (invoker.Invoke);
564 static object PostAuthorizeRequestEvent = new object ();
565 public event EventHandler PostAuthorizeRequest
567 add { AddEventHandler (PostAuthorizeRequestEvent, value); }
568 remove { RemoveEventHandler (PostAuthorizeRequestEvent, value); }
571 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
573 AddOnPostAuthorizeRequestAsync (bh, eh, null);
576 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
578 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
579 PostAuthorizeRequest += new EventHandler (invoker.Invoke);
582 static object PostResolveRequestCacheEvent = new object ();
583 public event EventHandler PostResolveRequestCache
585 add { AddEventHandler (PostResolveRequestCacheEvent, value); }
586 remove { RemoveEventHandler (PostResolveRequestCacheEvent, value); }
589 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
591 AddOnPostResolveRequestCacheAsync (bh, eh, null);
594 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
596 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
597 PostResolveRequestCache += new EventHandler (invoker.Invoke);
600 static object PostMapRequestHandlerEvent = new object ();
601 public event EventHandler PostMapRequestHandler
603 add { AddEventHandler (PostMapRequestHandlerEvent, value); }
604 remove { RemoveEventHandler (PostMapRequestHandlerEvent, value); }
607 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
609 AddOnPostMapRequestHandlerAsync (bh, eh, null);
612 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh, object data)
614 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
615 PostMapRequestHandler += new EventHandler (invoker.Invoke);
618 static object PostAcquireRequestStateEvent = new object ();
619 public event EventHandler PostAcquireRequestState
621 add { AddEventHandler (PostAcquireRequestStateEvent, value); }
622 remove { RemoveEventHandler (PostAcquireRequestStateEvent, value); }
625 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
627 AddOnPostAcquireRequestStateAsync (bh, eh, null);
630 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
632 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
633 PostAcquireRequestState += new EventHandler (invoker.Invoke);
636 static object PostReleaseRequestStateEvent = new object ();
637 public event EventHandler PostReleaseRequestState
639 add { AddEventHandler (PostReleaseRequestStateEvent, value); }
640 remove { RemoveEventHandler (PostReleaseRequestStateEvent, value); }
643 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
645 AddOnPostReleaseRequestStateAsync (bh, eh, null);
648 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
650 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
651 PostReleaseRequestState += new EventHandler (invoker.Invoke);
654 static object PostUpdateRequestCacheEvent = new object ();
655 public event EventHandler PostUpdateRequestCache
657 add { AddEventHandler (PostUpdateRequestCacheEvent, value); }
658 remove { RemoveEventHandler (PostUpdateRequestCacheEvent, value); }
661 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
663 AddOnPostUpdateRequestCacheAsync (bh, eh, null);
666 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
668 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
669 PostUpdateRequestCache += new EventHandler (invoker.Invoke);
673 // The new overloads that take a data parameter
675 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
677 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
678 AcquireRequestState += new EventHandler (invoker.Invoke);
681 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
683 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
684 AuthenticateRequest += new EventHandler (invoker.Invoke);
687 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
689 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
690 AuthorizeRequest += new EventHandler (invoker.Invoke);
693 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
695 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
696 BeginRequest += new EventHandler (invoker.Invoke);
699 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
701 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
702 EndRequest += new EventHandler (invoker.Invoke);
705 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
707 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
708 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
711 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
713 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
714 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
717 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
719 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
720 ReleaseRequestState += new EventHandler (invoker.Invoke);
723 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
725 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
726 ResolveRequestCache += new EventHandler (invoker.Invoke);
729 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
731 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
732 UpdateRequestCache += new EventHandler (invoker.Invoke);
736 // They are for use with the IIS7 integrated mode, but have been added for
738 static object LogRequestEvent = new object ();
739 public event EventHandler LogRequest
741 add { AddEventHandler (LogRequestEvent, value); }
742 remove { RemoveEventHandler (LogRequestEvent, value); }
745 public void AddOnLogRequestAsync (BeginEventHandler bh, EndEventHandler eh)
747 AddOnLogRequestAsync (bh, eh, null);
750 public void AddOnLogRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state)
752 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state);
753 LogRequest += new EventHandler (invoker.Invoke);
756 static object MapRequestHandlerEvent = new object ();
757 public event EventHandler MapRequestHandler
759 add { AddEventHandler (MapRequestHandlerEvent, value); }
760 remove { RemoveEventHandler (MapRequestHandlerEvent, value); }
763 public void AddOnMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
765 AddOnMapRequestHandlerAsync (bh, eh, null);
768 public void AddOnMapRequestHandlerAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state)
770 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state);
771 MapRequestHandler += new EventHandler (invoker.Invoke);
774 static object PostLogRequestEvent = new object ();
775 public event EventHandler PostLogRequest
777 add { AddEventHandler (PostLogRequestEvent, value); }
778 remove { RemoveEventHandler (PostLogRequestEvent, value); }
781 public void AddOnPostLogRequestAsync (BeginEventHandler bh, EndEventHandler eh)
783 AddOnPostLogRequestAsync (bh, eh, null);
786 public void AddOnPostLogRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state)
788 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state);
789 PostLogRequest += new EventHandler (invoker.Invoke);
794 internal event EventHandler DefaultAuthentication;
796 void AddEventHandler (object key, EventHandler handler)
798 if (fullInitComplete)
801 Events.AddHandler (key, handler);
804 void RemoveEventHandler (object key, EventHandler handler)
806 if (fullInitComplete)
809 Events.RemoveHandler (key, handler);
813 // Bypass all the event on the Http pipeline and go directly to EndRequest
815 public void CompleteRequest ()
817 stop_processing = true;
820 internal bool RequestCompleted {
821 set { stop_processing = value; }
824 internal void DisposeInternal ()
828 if (modcoll != null) {
829 for (int i = modcoll.Count - 1; i >= 0; i--) {
830 modcoll.Get (i).Dispose ();
836 EventHandler eh = nonApplicationEvents [disposedEvent] as EventHandler;
838 eh (this, EventArgs.Empty);
844 public virtual void Dispose ()
848 public virtual string GetVaryByCustomString (HttpContext context, string custom)
850 if (custom == null) // Sigh
851 throw new NullReferenceException ();
853 if (0 == String.Compare (custom, "browser", true, CultureInfo.InvariantCulture))
854 return context.Request.Browser.Type;
860 // If we catch an error, queue this error
862 void ProcessError (Exception e)
864 bool first = context.Error == null;
865 context.AddError (e);
867 EventHandler eh = nonApplicationEvents [errorEvent] as EventHandler;
870 eh (this, EventArgs.Empty);
871 } catch (ThreadAbortException taex){
872 context.ClearError ();
873 if (FlagEnd.Value == taex.ExceptionState)
874 // This happens on Redirect() or End()
875 Thread.ResetAbort ();
877 // This happens on Thread.Abort()
878 context.AddError (taex);
879 } catch (Exception ee){
880 context.AddError (ee);
884 stop_processing = true;
886 // we want to remove configuration from the cache in case of
887 // invalid resource not exists to prevent DOS attack.
888 HttpException httpEx = e as HttpException;
889 if (httpEx != null && httpEx.GetHttpCode () == 404) {
890 removeConfigurationFromCache = true;
896 // Ticks the clock: next step on the pipeline.
898 internal void Tick ()
902 if (context.Error is UnifyRequestException) {
903 Exception ex = context.Error.InnerException;
904 context.ClearError ();
905 vmw.common.TypeUtils.Throw (ex);
909 if (pipeline.MoveNext ()){
910 if ((bool)pipeline.Current)
915 catch (Exception ex) {
916 if (ex is ThreadAbortException &&
917 ((ThreadAbortException) ex).ExceptionState == FlagEnd.Value)
919 if (context.WorkerRequest is IHttpUnifyWorkerRequest) {
920 context.ClearError ();
921 context.AddError (new UnifyRequestException (ex));
928 } catch (ThreadAbortException taex) {
929 object obj = taex.ExceptionState;
930 Thread.ResetAbort ();
931 stop_processing = true;
932 if (obj is StepTimeout)
933 ProcessError (new HttpException ("The request timed out."));
935 context.ClearError ();
936 if (FlagEnd.Value != obj)
937 context.AddError (taex);
941 } catch (Exception e) {
942 stop_processing = true;
957 // Invoked when our async callback called from RunHooks completes,
958 // we restart the pipeline here.
960 void async_callback_completed_cb (IAsyncResult ar)
962 if (current_ai.end != null){
965 } catch (Exception e) {
973 void async_handler_complete_cb (IAsyncResult ar)
975 IHttpAsyncHandler async_handler = ar != null ? ar.AsyncState as IHttpAsyncHandler : null;
978 if (async_handler != null)
979 async_handler.EndProcessRequest (ar);
980 } catch (Exception e){
988 // This enumerator yields whether processing must be stopped:
989 // true: processing of the pipeline must be stopped
990 // false: processing of the pipeline must not be stopped
992 IEnumerable RunHooks (Delegate list)
994 Delegate [] delegates = list.GetInvocationList ();
996 foreach (EventHandler d in delegates){
997 if (d.Target != null && (d.Target is AsyncInvoker)){
998 current_ai = (AsyncInvoker) d.Target;
1003 context.BeginTimeoutPossible ();
1004 current_ai.begin (this, EventArgs.Empty, async_callback_completed_cb, current_ai.data);
1007 context.EndTimeoutPossible ();
1011 // If things are still moving forward, yield this
1015 yield return stop_processing;
1016 else if (stop_processing)
1020 context.BeginTimeoutPossible ();
1021 d (this, EventArgs.Empty);
1023 context.EndTimeoutPossible ();
1025 if (stop_processing)
1031 static void FinalErrorWrite (HttpResponse response, string error)
1034 response.Write (error);
1035 response.Flush (true);
1043 if (context.Error == null){
1045 context.Response.Flush (true);
1046 } catch (Exception e){
1047 context.AddError (e);
1051 Exception error = context.Error;
1053 HttpResponse response = context.Response;
1055 if (!response.HeadersSent){
1056 response.ClearHeaders ();
1057 response.ClearContent ();
1059 if (error is HttpException){
1060 response.StatusCode = ((HttpException)error).GetHttpCode ();
1062 error = new HttpException ("", error);
1063 response.StatusCode = 500;
1065 HttpException httpEx = (HttpException) error;
1066 if (!RedirectCustomError (ref httpEx))
1067 FinalErrorWrite (response, httpEx.GetHtmlErrorMessage ());
1069 response.Flush (true);
1071 if (!(error is HttpException))
1072 error = new HttpException ("", error);
1073 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
1080 // Invoked at the end of the pipeline execution
1082 void PipelineDone ()
1085 EventHandler handler = Events [EndRequestEvent] as EventHandler;
1086 if (handler != null)
1087 handler (this, EventArgs.Empty);
1088 } catch (Exception e){
1094 } catch (Exception e) {
1095 Console.WriteLine ("Internal error: OutputPage threw an exception " + e);
1097 context.WorkerRequest.EndOfRequest();
1098 if (factory != null && context.Handler != null){
1099 factory.ReleaseHandler (context.Handler);
1100 context.Handler = null;
1104 context.PopHandler ();
1106 // context = null; -> moved to PostDone
1112 if (begin_iar != null)
1113 begin_iar.Complete ();
1119 // Events fired as described in `Http Runtime Support, HttpModules,
1120 // Handling Public Events'
1122 IEnumerator Pipeline ()
1124 Delegate eventHandler;
1125 if (stop_processing)
1128 eventHandler = Events [BeginRequestEvent];
1129 if (eventHandler != null) {
1130 foreach (bool stop in RunHooks (eventHandler))
1134 eventHandler = Events [AuthenticateRequestEvent];
1135 if (eventHandler != null)
1136 foreach (bool stop in RunHooks (eventHandler))
1139 if (DefaultAuthentication != null)
1140 foreach (bool stop in RunHooks (DefaultAuthentication))
1144 eventHandler = Events [PostAuthenticateRequestEvent];
1145 if (eventHandler != null)
1146 foreach (bool stop in RunHooks (eventHandler))
1149 eventHandler = Events [AuthorizeRequestEvent];
1150 if (eventHandler != null)
1151 foreach (bool stop in RunHooks (eventHandler))
1154 eventHandler = Events [PostAuthorizeRequestEvent];
1155 if (eventHandler != null)
1156 foreach (bool stop in RunHooks (eventHandler))
1160 eventHandler = Events [ResolveRequestCacheEvent];
1161 if (eventHandler != null)
1162 foreach (bool stop in RunHooks (eventHandler))
1166 eventHandler = Events [PostResolveRequestCacheEvent];
1167 if (eventHandler != null)
1168 foreach (bool stop in RunHooks (eventHandler))
1171 // As per http://msdn2.microsoft.com/en-us/library/bb470252(VS.90).aspx
1172 eventHandler = Events [MapRequestHandlerEvent];
1173 if (eventHandler != null)
1174 foreach (bool stop in RunHooks (eventHandler))
1178 // Obtain the handler for the request.
1179 IHttpHandler handler = null;
1181 handler = GetHandler (context, context.Request.CurrentExecutionFilePath);
1182 context.Handler = handler;
1184 context.PushHandler (handler);
1186 } catch (FileNotFoundException fnf){
1188 Console.WriteLine ("$$$$$$$$$$:Sys.Web Pipeline");
1189 Console.WriteLine (fnf.ToString ());
1191 if (context.Request.IsLocal)
1192 ProcessError (new HttpException (404, String.Format ("File not found {0}", fnf.FileName), fnf, context.Request.FilePath));
1194 ProcessError (new HttpException (404, "File not found: " + Path.GetFileName (fnf.FileName), context.Request.FilePath));
1195 } catch (DirectoryNotFoundException dnf){
1196 if (!context.Request.IsLocal)
1197 dnf = null; // Do not "leak" real path information
1198 ProcessError (new HttpException (404, "Directory not found", dnf));
1199 } catch (Exception e) {
1203 if (stop_processing)
1207 eventHandler = Events [PostMapRequestHandlerEvent];
1208 if (eventHandler != null)
1209 foreach (bool stop in RunHooks (eventHandler))
1213 eventHandler = Events [AcquireRequestStateEvent];
1214 if (eventHandler != null){
1215 foreach (bool stop in RunHooks (eventHandler))
1220 eventHandler = Events [PostAcquireRequestStateEvent];
1221 if (eventHandler != null){
1222 foreach (bool stop in RunHooks (eventHandler))
1228 // From this point on, we need to ensure that we call
1229 // ReleaseRequestState, so the code below jumps to
1230 // `release:' to guarantee it rather than yielding.
1232 eventHandler = Events [PreRequestHandlerExecuteEvent];
1233 if (eventHandler != null)
1234 foreach (bool stop in RunHooks (eventHandler))
1241 bool doProcessHandler = false;
1245 IHttpHandler ctxHandler = context.Handler;
1246 if (ctxHandler != null && handler != ctxHandler) {
1247 context.PopHandler ();
1248 handler = ctxHandler;
1249 context.PushHandler (handler);
1254 context.BeginTimeoutPossible ();
1255 if (handler != null){
1256 IHttpAsyncHandler async_handler = handler as IHttpAsyncHandler;
1258 if (async_handler != null){
1261 async_handler.BeginProcessRequest (context, async_handler_complete_cb, handler);
1264 handler.ProcessRequest (context);
1266 IHttpExtendedHandler extHandler=handler as IHttpExtendedHandler;
1267 doProcessHandler = extHandler != null && !extHandler.IsCompleted;
1271 if (context.Error != null)
1272 throw new TargetInvocationException(context.Error);
1275 context.EndTimeoutPossible ();
1278 if (doProcessHandler) {
1280 goto processHandler;
1284 yield return stop_processing;
1285 else if (stop_processing)
1288 // These are executed after the application has returned
1290 eventHandler = Events [PostRequestHandlerExecuteEvent];
1291 if (eventHandler != null)
1292 foreach (bool stop in RunHooks (eventHandler))
1297 eventHandler = Events [ReleaseRequestStateEvent];
1298 if (eventHandler != null){
1299 #pragma warning disable 219
1300 foreach (bool stop in RunHooks (eventHandler)) {
1302 // Ignore the stop signal while release the state
1306 #pragma warning restore 219
1309 if (stop_processing)
1313 eventHandler = Events [PostReleaseRequestStateEvent];
1314 if (eventHandler != null)
1315 foreach (bool stop in RunHooks (eventHandler))
1319 if (context.Error == null)
1320 context.Response.DoFilter (true);
1322 eventHandler = Events [UpdateRequestCacheEvent];
1323 if (eventHandler != null)
1324 foreach (bool stop in RunHooks (eventHandler))
1328 eventHandler = Events [PostUpdateRequestCacheEvent];
1329 if (eventHandler != null)
1330 foreach (bool stop in RunHooks (eventHandler))
1333 eventHandler = Events [LogRequestEvent];
1334 if (eventHandler != null)
1335 foreach (bool stop in RunHooks (eventHandler))
1338 eventHandler = Events [PostLogRequestEvent];
1339 if (eventHandler != null)
1340 foreach (bool stop in RunHooks (eventHandler))
1347 internal CultureInfo GetThreadCulture (HttpRequest request, CultureInfo culture, bool isAuto)
1352 CultureInfo ret = null;
1353 string[] languages = request.UserLanguages;
1355 if (languages != null && languages.Length > 0)
1356 ret = CultureInfo.CreateSpecificCulture (languages[0]);
1373 GlobalizationSection cfg;
1374 cfg = (GlobalizationSection) WebConfigurationManager.GetSection ("system.web/globalization");
1375 app_culture = cfg.GetCulture ();
1376 autoCulture = cfg.IsAutoCulture;
1377 appui_culture = cfg.GetUICulture ();
1378 autoUICulture = cfg.IsAutoUICulture;
1380 GlobalizationConfiguration cfg;
1381 cfg = GlobalizationConfiguration.GetInstance (null);
1383 app_culture = cfg.Culture;
1384 appui_culture = cfg.UICulture;
1389 context.StartTimeoutTimer ();
1391 Thread th = Thread.CurrentThread;
1392 if (app_culture != null) {
1393 prev_app_culture = th.CurrentCulture;
1394 CultureInfo new_app_culture = GetThreadCulture (Request, app_culture, autoCulture);
1395 if (!new_app_culture.Equals (CultureInfo.InvariantCulture))
1396 th.CurrentCulture = new_app_culture;
1399 if (appui_culture != null) {
1400 prev_appui_culture = th.CurrentUICulture;
1401 CultureInfo new_app_culture = GetThreadCulture (Request, appui_culture, autoUICulture);
1402 if (!new_app_culture.Equals (CultureInfo.InvariantCulture))
1403 th.CurrentUICulture = new_app_culture;
1407 prev_user = Thread.CurrentPrincipal;
1414 if (removeConfigurationFromCache) {
1415 WebConfigurationManager.RemoveConfigurationFromCache (context);
1416 removeConfigurationFromCache = false;
1419 Thread th = Thread.CurrentThread;
1421 if (Thread.CurrentPrincipal != prev_user)
1422 Thread.CurrentPrincipal = prev_user;
1424 if (prev_appui_culture != null && prev_appui_culture != th.CurrentUICulture)
1425 th.CurrentUICulture = prev_appui_culture;
1426 if (prev_app_culture != null && prev_app_culture != th.CurrentCulture)
1427 th.CurrentCulture = prev_app_culture;
1430 if (context == null)
1431 context = HttpContext.Current;
1432 context.StopTimeoutTimer ();
1434 context.Request.ReleaseResources ();
1435 context.Response.ReleaseResources ();
1438 HttpContext.Current = null;
1441 void Start (object x)
1443 CultureInfo[] cultures = x as CultureInfo[];
1444 if (cultures != null && cultures.Length == 2) {
1445 Thread ct = Thread.CurrentThread;
1446 ct.CurrentCulture = cultures [0];
1447 ct.CurrentUICulture = cultures [1];
1452 } catch (Exception e) {
1454 initialization_exception = e;
1456 FinalErrorWrite (context.Response, new HttpException ("", e).GetHtmlErrorMessage ());
1461 HttpContext.Current = Context;
1463 pipeline = Pipeline ();
1467 const string HANDLER_CACHE = "@@HttpHandlerCache@@";
1469 internal static Hashtable GetHandlerCache ()
1471 Cache cache = HttpRuntime.InternalCache;
1472 Hashtable ret = cache [HANDLER_CACHE] as Hashtable;
1475 ret = new Hashtable ();
1476 cache.Insert (HANDLER_CACHE, ret);
1482 internal static void ClearHandlerCache ()
1484 Hashtable cache = GetHandlerCache ();
1488 object LocateHandler (string verb, string url)
1490 Hashtable cache = GetHandlerCache ();
1491 string id = String.Concat (verb, url);
1492 object ret = cache [id];
1498 HttpHandlersSection httpHandlersSection = (HttpHandlersSection) WebConfigurationManager.GetSection ("system.web/httpHandlers");
1499 ret = httpHandlersSection.LocateHandler (verb, url);
1501 HandlerFactoryConfiguration factory_config = (HandlerFactoryConfiguration) HttpContext.GetAppConfig ("system.web/httpHandlers");
1502 ret = factory_config.LocateHandler (verb, url);
1505 IHttpHandler handler = ret as IHttpHandler;
1506 if (handler != null && handler.IsReusable)
1512 internal IHttpHandler GetHandler (HttpContext context, string url)
1514 return GetHandler (context, url, false);
1517 // Used by HttpServerUtility.Execute
1518 internal IHttpHandler GetHandler (HttpContext context, string url, bool ignoreContextHandler)
1520 if (!ignoreContextHandler && context.Handler != null)
1521 return context.Handler;
1523 HttpRequest request = context.Request;
1524 string verb = request.RequestType;
1526 IHttpHandler handler = null;
1527 object o = LocateHandler (verb, url);
1529 factory = o as IHttpHandlerFactory;
1531 if (factory == null) {
1532 handler = (IHttpHandler) o;
1534 handler = factory.GetHandler (context, verb, url, request.MapPath (url));
1540 void IHttpHandler.ProcessRequest (HttpContext context)
1543 this.context = context;
1551 // This is used by FireOnAppStart, when we init the application
1552 // as the context is required to be set at that point (the user
1553 // might call methods that require it on that hook).
1555 internal void SetContext (HttpContext context)
1557 this.context = context;
1560 internal void SetSession (HttpSessionState session)
1562 this.session = session;
1565 IAsyncResult IHttpAsyncHandler.BeginProcessRequest (HttpContext context, AsyncCallback cb, object extraData)
1567 this.context = context;
1570 begin_iar = new AsyncRequestState (done, cb, extraData);
1572 CultureInfo[] cultures = new CultureInfo [2];
1573 cultures [0] = Thread.CurrentThread.CurrentCulture;
1574 cultures [1] = Thread.CurrentThread.CurrentUICulture;
1579 if (Thread.CurrentThread.IsThreadPoolThread)
1583 ThreadPool.QueueUserWorkItem (new WaitCallback (Start), cultures);
1588 void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result)
1594 if (!result.IsCompleted)
1595 result.AsyncWaitHandle.WaitOne ();
1599 public virtual void Init ()
1603 bool IHttpHandler.IsReusable {
1610 internal void ClearError ()
1612 context.ClearError ();
1615 bool RedirectErrorPage (string error_page)
1617 if (context.Request.QueryString ["aspxerrorpath"] != null)
1620 Response.Redirect (error_page + "?aspxerrorpath=" + Request.Path, false);
1624 bool RedirectCustomError (ref HttpException httpEx)
1627 if (!context.IsCustomErrorEnabledUnsafe)
1631 CustomErrorsSection config = (CustomErrorsSection)WebConfigurationManager.GetSection ("system.web/customErrors");
1633 CustomErrorsConfig config = null;
1635 config = (CustomErrorsConfig) context.GetConfig ("system.web/customErrors");
1639 if (config == null) {
1640 if (context.ErrorPage != null)
1641 return RedirectErrorPage (context.ErrorPage);
1647 CustomError err = config.Errors [context.Response.StatusCode.ToString()];
1648 string redirect = err == null ? null : err.Redirect;
1650 string redirect = config [context.Response.StatusCode];
1652 if (redirect == null) {
1653 redirect = context.ErrorPage;
1654 if (redirect == null)
1655 redirect = config.DefaultRedirect;
1658 if (redirect == null)
1661 return RedirectErrorPage (redirect);
1663 catch (Exception ex) {
1664 httpEx = new HttpException (500, "", ex);
1669 internal static string BinDirectory
1672 if (binDirectory == null) {
1673 AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
1674 string baseDir = setup.ApplicationBase;
1677 foreach (string dir in BinDirs) {
1678 bindir = Path.Combine (baseDir, dir);
1679 if (!Directory.Exists (bindir))
1681 binDirectory = bindir;
1686 return binDirectory;
1690 internal static string[] BinDirectoryAssemblies
1693 ArrayList binDlls = null;
1696 string bindir = BinDirectory;
1697 if (bindir != null) {
1698 binDlls = new ArrayList ();
1699 dlls = Directory.GetFiles (bindir, "*.dll");
1700 binDlls.AddRange (dlls);
1703 if (binDlls == null)
1704 return new string[] {};
1706 return (string[]) binDlls.ToArray (typeof (string));
1710 internal static Type LoadType (string typeName)
1712 return LoadType (typeName, false);
1715 internal static Type LoadType (string typeName, bool throwOnMissing)
1717 Type type = Type.GetType (typeName);
1722 Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
1723 foreach (Assembly ass in assemblies) {
1724 type = ass.GetType (typeName, false);
1730 IList tla = System.Web.Compilation.BuildManager.TopLevelAssemblies;
1731 if (tla != null && tla.Count > 0) {
1732 foreach (Assembly asm in tla) {
1735 type = asm.GetType (typeName, false);
1742 type = LoadTypeFromBin (typeName);
1747 throw new TypeLoadException (String.Format ("Type '{0}' cannot be found", typeName));
1752 internal static Type LoadTypeFromBin (string typeName)
1756 foreach (string s in BinDirectoryAssemblies) {
1757 Assembly binA = Assembly.LoadFrom (s);
1758 type = binA.GetType (typeName, false);
1770 // Based on Fritz' Onion's AsyncRequestState class for asynchronous IHttpAsyncHandlers
1772 class AsyncRequestState : IAsyncResult {
1776 ManualResetEvent complete_event = null;
1778 internal AsyncRequestState (ManualResetEvent complete_event, AsyncCallback cb, object cb_data)
1781 this.cb_data = cb_data;
1782 this.complete_event = complete_event;
1785 internal void Complete ()
1790 // TODO: if this throws an error, we have no way of reporting it
1791 // Not really too bad, since the only failure might be
1792 // `HttpRuntime.request_processed'.
1799 complete_event.Set ();
1802 public object AsyncState {
1808 public bool CompletedSynchronously {
1814 public bool IsCompleted {
1820 public WaitHandle AsyncWaitHandle {
1822 return complete_event;
1827 #region Helper classes
1830 // A wrapper to keep track of begin/end pairs
1832 class AsyncInvoker {
1833 public BeginEventHandler begin;
1834 public EndEventHandler end;
1837 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, object d)
1844 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh)
1850 public void Invoke (object sender, EventArgs e)
1852 throw new Exception ("This is just a dummy");