2 // System.Web.HttpApplication.cs
5 // Miguel de Icaza (miguel@novell.com)
6 // Gonzalo Paniagua (gonzalo@ximian.com)
9 // Copyright (C) 2005-2009 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.Diagnostics;
70 using System.Globalization;
71 using System.Reflection;
72 using System.Security.Permissions;
73 using System.Security.Principal;
74 using System.Threading;
75 using System.Web.Caching;
76 using System.Web.Configuration;
77 using System.Web.SessionState;
79 using System.Web.Util;
88 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
89 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
92 public class HttpApplication : IHttpAsyncHandler, IHttpHandler, IComponent, IDisposable
94 static readonly object disposedEvent = new object ();
95 static readonly object errorEvent = new object ();
97 // we do this static rather than per HttpApplication because
98 // mono's perfcounters use the counter instance parameter for
99 // the process to access shared memory.
100 internal static PerformanceCounter requests_total_counter = new PerformanceCounter ("ASP.NET", "Requests Total");
102 internal static readonly string [] BinDirs = {"Bin", "bin"};
103 object this_lock = new object();
106 HttpSessionState session;
109 // The source, and the exposed API (cache).
110 HttpModuleCollection modcoll;
112 string assemblyLocation;
115 // The factory for the handler currently running.
117 IHttpHandlerFactory factory;
120 // Whether the thread culture is to be auto-set.
121 // Used only in the 2.0 profile, always false for 1.x
127 // Whether the pipeline should be stopped
129 bool stop_processing;
132 // See https://bugzilla.novell.com/show_bug.cgi?id=381971
134 bool in_application_start;
139 IEnumerator pipeline;
141 // To flag when we are done processing a request from BeginProcessRequest.
142 ManualResetEvent done;
144 // The current IAsyncResult for the running async request handler in the pipeline
145 AsyncRequestState begin_iar;
147 // Tracks the current AsyncInvocation being dispatched
148 AsyncInvoker current_ai;
150 EventHandlerList events;
151 EventHandlerList nonApplicationEvents = new EventHandlerList ();
153 // Culture and IPrincipal
154 CultureInfo app_culture;
155 CultureInfo appui_culture;
156 CultureInfo prev_app_culture;
157 CultureInfo prev_appui_culture;
158 IPrincipal prev_user;
160 static string binDirectory;
163 const string initialization_exception_key = "System.Web.HttpApplication.initialization_exception";
164 static Exception initialization_exception {
165 get { return (Exception) AppDomain.CurrentDomain.GetData (initialization_exception_key); }
166 set { AppDomain.CurrentDomain.SetData (initialization_exception_key, value); }
169 static Exception initialization_exception;
171 bool removeConfigurationFromCache;
172 bool fullInitComplete = false;
175 // These are used to detect the case where the EndXXX method is invoked
176 // from within the BeginXXXX delegate, so we detect whether we kick the
177 // pipeline from here, or from the the RunHook routine
182 public virtual event EventHandler Disposed {
183 add { nonApplicationEvents.AddHandler (disposedEvent, value); }
184 remove { nonApplicationEvents.RemoveHandler (disposedEvent, value); }
187 public virtual event EventHandler Error {
188 add { nonApplicationEvents.AddHandler (errorEvent, value); }
189 remove { nonApplicationEvents.RemoveHandler (errorEvent, value); }
192 public HttpApplication ()
194 done = new ManualResetEvent (false);
197 internal void InitOnce (bool full_init)
203 HttpModulesSection modules;
204 modules = (HttpModulesSection) WebConfigurationManager.GetWebApplicationSection ("system.web/httpModules");
205 HttpContext saved = HttpContext.Current;
206 HttpContext.Current = new HttpContext (new System.Web.Hosting.SimpleWorkerRequest (String.Empty, String.Empty, new StringWriter()));
207 modcoll = modules.LoadModules (this);
208 HttpContext.Current = saved;
211 HttpApplicationFactory.AttachEvents (this);
213 fullInitComplete = true;
218 internal bool InApplicationStart {
219 get { return in_application_start; }
220 set { in_application_start = value; }
223 internal string AssemblyLocation {
225 if (assemblyLocation == null)
226 assemblyLocation = GetType ().Assembly.Location;
227 return assemblyLocation;
231 internal static Exception InitializationException {
232 get { return initialization_exception; }
236 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
237 public HttpApplicationState Application {
239 return HttpApplicationFactory.ApplicationState;
244 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
245 public HttpContext Context {
251 protected EventHandlerList Events {
254 events = new EventHandlerList ();
261 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
262 public HttpModuleCollection Modules {
263 [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
267 modcoll = new HttpModuleCollection ();
275 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
276 public HttpRequest Request {
279 throw new HttpException (Locale.GetText ("No context is available."));
281 if (false == HttpApplicationFactory.ContextAvailable)
282 throw new HttpException (Locale.GetText ("Request is not available in this context."));
284 return context.Request;
289 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
290 public HttpResponse Response {
293 throw new HttpException (Locale.GetText ("No context is available."));
295 if (false == HttpApplicationFactory.ContextAvailable)
296 throw new HttpException (Locale.GetText ("Response is not available in this context."));
298 return context.Response;
303 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
304 public HttpServerUtility Server {
307 return context.Server;
310 // This is so we can get the Server and call a few methods
311 // which are not context sensitive, see HttpServerUtilityTest
313 return new HttpServerUtility ((HttpContext) null);
318 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
319 public HttpSessionState Session {
321 // Only used for Session_End
326 throw new HttpException (Locale.GetText ("No context is available."));
328 HttpSessionState ret = context.Session;
330 throw new HttpException (Locale.GetText ("Session state is not available in the context."));
337 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
339 get { return isite; }
341 set { isite = value; }
345 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
346 public IPrincipal User {
349 throw new HttpException (Locale.GetText ("No context is available."));
350 if (context.User == null)
351 throw new HttpException (Locale.GetText ("No currently authenticated user."));
357 static object PreSendRequestHeadersEvent = new object ();
358 public event EventHandler PreSendRequestHeaders
360 add { AddEventHandler (PreSendRequestHeadersEvent, value); }
361 remove { RemoveEventHandler (PreSendRequestHeadersEvent, value); }
364 internal void TriggerPreSendRequestHeaders ()
366 EventHandler handler = Events [PreSendRequestHeadersEvent] as EventHandler;
368 handler (this, EventArgs.Empty);
371 static object PreSendRequestContentEvent = new object ();
372 public event EventHandler PreSendRequestContent
374 add { AddEventHandler (PreSendRequestContentEvent, value); }
375 remove { RemoveEventHandler (PreSendRequestContentEvent, value); }
378 internal void TriggerPreSendRequestContent ()
380 EventHandler handler = Events [PreSendRequestContentEvent] as EventHandler;
382 handler (this, EventArgs.Empty);
385 static object AcquireRequestStateEvent = new object ();
386 public event EventHandler AcquireRequestState
388 add { AddEventHandler (AcquireRequestStateEvent, value); }
389 remove { RemoveEventHandler (AcquireRequestStateEvent, value); }
392 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
394 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
395 AcquireRequestState += new EventHandler (invoker.Invoke);
398 static object AuthenticateRequestEvent = new object ();
399 public event EventHandler AuthenticateRequest
401 add { AddEventHandler (AuthenticateRequestEvent, value); }
402 remove { RemoveEventHandler (AuthenticateRequestEvent, value); }
405 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
407 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
408 AuthenticateRequest += new EventHandler (invoker.Invoke);
411 static object AuthorizeRequestEvent = new object ();
412 public event EventHandler AuthorizeRequest
414 add { AddEventHandler (AuthorizeRequestEvent, value); }
415 remove { RemoveEventHandler (AuthorizeRequestEvent, value); }
418 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
420 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
421 AuthorizeRequest += new EventHandler (invoker.Invoke);
424 static object BeginRequestEvent = new object ();
425 public event EventHandler BeginRequest
428 // See https://bugzilla.novell.com/show_bug.cgi?id=381971
429 if (InApplicationStart)
431 AddEventHandler (BeginRequestEvent, value);
434 if (InApplicationStart)
436 RemoveEventHandler (BeginRequestEvent, value);
440 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh)
442 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
443 BeginRequest += new EventHandler (invoker.Invoke);
446 static object EndRequestEvent = new object ();
447 public event EventHandler EndRequest
450 // See https://bugzilla.novell.com/show_bug.cgi?id=381971
451 if (InApplicationStart)
453 AddEventHandler (EndRequestEvent, value);
456 if (InApplicationStart)
458 RemoveEventHandler (EndRequestEvent, value);
462 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh)
464 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
465 EndRequest += new EventHandler (invoker.Invoke);
468 static object PostRequestHandlerExecuteEvent = new object ();
469 public event EventHandler PostRequestHandlerExecute
471 add { AddEventHandler (PostRequestHandlerExecuteEvent, value); }
472 remove { RemoveEventHandler (PostRequestHandlerExecuteEvent, value); }
475 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
477 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
478 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
481 static object PreRequestHandlerExecuteEvent = new object ();
482 public event EventHandler PreRequestHandlerExecute
484 add { AddEventHandler (PreRequestHandlerExecuteEvent, value); }
485 remove { RemoveEventHandler (PreRequestHandlerExecuteEvent, value); }
488 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
490 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
491 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
494 static object ReleaseRequestStateEvent = new object ();
495 public event EventHandler ReleaseRequestState
497 add { AddEventHandler (ReleaseRequestStateEvent, value); }
498 remove { RemoveEventHandler (ReleaseRequestStateEvent, value); }
501 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
503 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
504 ReleaseRequestState += new EventHandler (invoker.Invoke);
507 static object ResolveRequestCacheEvent = new object ();
508 public event EventHandler ResolveRequestCache
510 add { AddEventHandler (ResolveRequestCacheEvent, value); }
511 remove { RemoveEventHandler (ResolveRequestCacheEvent, value); }
514 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
516 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
517 ResolveRequestCache += new EventHandler (invoker.Invoke);
520 static object UpdateRequestCacheEvent = new object ();
521 public event EventHandler UpdateRequestCache
523 add { AddEventHandler (UpdateRequestCacheEvent, value); }
524 remove { RemoveEventHandler (UpdateRequestCacheEvent, value); }
527 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
529 AsyncInvoker invoker = new AsyncInvoker (bh, eh);
530 UpdateRequestCache += new EventHandler (invoker.Invoke);
533 static object PostAuthenticateRequestEvent = new object ();
534 public event EventHandler PostAuthenticateRequest
536 add { AddEventHandler (PostAuthenticateRequestEvent, value); }
537 remove { RemoveEventHandler (PostAuthenticateRequestEvent, value); }
540 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
542 AddOnPostAuthenticateRequestAsync (bh, eh, null);
545 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
547 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
548 PostAuthenticateRequest += new EventHandler (invoker.Invoke);
551 static object PostAuthorizeRequestEvent = new object ();
552 public event EventHandler PostAuthorizeRequest
554 add { AddEventHandler (PostAuthorizeRequestEvent, value); }
555 remove { RemoveEventHandler (PostAuthorizeRequestEvent, value); }
558 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
560 AddOnPostAuthorizeRequestAsync (bh, eh, null);
563 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
565 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
566 PostAuthorizeRequest += new EventHandler (invoker.Invoke);
569 static object PostResolveRequestCacheEvent = new object ();
570 public event EventHandler PostResolveRequestCache
572 add { AddEventHandler (PostResolveRequestCacheEvent, value); }
573 remove { RemoveEventHandler (PostResolveRequestCacheEvent, value); }
576 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
578 AddOnPostResolveRequestCacheAsync (bh, eh, null);
581 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
583 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
584 PostResolveRequestCache += new EventHandler (invoker.Invoke);
587 static object PostMapRequestHandlerEvent = new object ();
588 public event EventHandler PostMapRequestHandler
590 add { AddEventHandler (PostMapRequestHandlerEvent, value); }
591 remove { RemoveEventHandler (PostMapRequestHandlerEvent, value); }
594 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
596 AddOnPostMapRequestHandlerAsync (bh, eh, null);
599 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh, object data)
601 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
602 PostMapRequestHandler += new EventHandler (invoker.Invoke);
605 static object PostAcquireRequestStateEvent = new object ();
606 public event EventHandler PostAcquireRequestState
608 add { AddEventHandler (PostAcquireRequestStateEvent, value); }
609 remove { RemoveEventHandler (PostAcquireRequestStateEvent, value); }
612 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
614 AddOnPostAcquireRequestStateAsync (bh, eh, null);
617 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
619 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
620 PostAcquireRequestState += new EventHandler (invoker.Invoke);
623 static object PostReleaseRequestStateEvent = new object ();
624 public event EventHandler PostReleaseRequestState
626 add { AddEventHandler (PostReleaseRequestStateEvent, value); }
627 remove { RemoveEventHandler (PostReleaseRequestStateEvent, value); }
630 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
632 AddOnPostReleaseRequestStateAsync (bh, eh, null);
635 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
637 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
638 PostReleaseRequestState += new EventHandler (invoker.Invoke);
641 static object PostUpdateRequestCacheEvent = new object ();
642 public event EventHandler PostUpdateRequestCache
644 add { AddEventHandler (PostUpdateRequestCacheEvent, value); }
645 remove { RemoveEventHandler (PostUpdateRequestCacheEvent, value); }
648 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
650 AddOnPostUpdateRequestCacheAsync (bh, eh, null);
653 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
655 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
656 PostUpdateRequestCache += new EventHandler (invoker.Invoke);
660 // The new overloads that take a data parameter
662 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
664 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
665 AcquireRequestState += new EventHandler (invoker.Invoke);
668 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
670 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
671 AuthenticateRequest += new EventHandler (invoker.Invoke);
674 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
676 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
677 AuthorizeRequest += new EventHandler (invoker.Invoke);
680 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
682 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
683 BeginRequest += new EventHandler (invoker.Invoke);
686 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh, object data)
688 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
689 EndRequest += new EventHandler (invoker.Invoke);
692 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
694 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
695 PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
698 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh, object data)
700 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
701 PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
704 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh, object data)
706 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
707 ReleaseRequestState += new EventHandler (invoker.Invoke);
710 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
712 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
713 ResolveRequestCache += new EventHandler (invoker.Invoke);
716 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh, object data)
718 AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
719 UpdateRequestCache += new EventHandler (invoker.Invoke);
723 // They are for use with the IIS7 integrated mode, but have been added for
725 static object LogRequestEvent = new object ();
726 public event EventHandler LogRequest
728 add { AddEventHandler (LogRequestEvent, value); }
729 remove { RemoveEventHandler (LogRequestEvent, value); }
732 public void AddOnLogRequestAsync (BeginEventHandler bh, EndEventHandler eh)
734 AddOnLogRequestAsync (bh, eh, null);
737 public void AddOnLogRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state)
739 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state);
740 LogRequest += new EventHandler (invoker.Invoke);
743 static object MapRequestHandlerEvent = new object ();
744 public event EventHandler MapRequestHandler
746 add { AddEventHandler (MapRequestHandlerEvent, value); }
747 remove { RemoveEventHandler (MapRequestHandlerEvent, value); }
750 public void AddOnMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
752 AddOnMapRequestHandlerAsync (bh, eh, null);
755 public void AddOnMapRequestHandlerAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state)
757 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state);
758 MapRequestHandler += new EventHandler (invoker.Invoke);
761 static object PostLogRequestEvent = new object ();
762 public event EventHandler PostLogRequest
764 add { AddEventHandler (PostLogRequestEvent, value); }
765 remove { RemoveEventHandler (PostLogRequestEvent, value); }
768 public void AddOnPostLogRequestAsync (BeginEventHandler bh, EndEventHandler eh)
770 AddOnPostLogRequestAsync (bh, eh, null);
773 public void AddOnPostLogRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state)
775 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state);
776 PostLogRequest += new EventHandler (invoker.Invoke);
779 internal event EventHandler DefaultAuthentication;
781 void AddEventHandler (object key, EventHandler handler)
783 if (fullInitComplete)
786 Events.AddHandler (key, handler);
789 void RemoveEventHandler (object key, EventHandler handler)
791 if (fullInitComplete)
794 Events.RemoveHandler (key, handler);
798 // Bypass all the event on the Http pipeline and go directly to EndRequest
800 public void CompleteRequest ()
802 stop_processing = true;
805 internal bool RequestCompleted {
806 set { stop_processing = value; }
809 internal void DisposeInternal ()
813 if (modcoll != null) {
814 for (int i = modcoll.Count - 1; i >= 0; i--) {
815 modcoll.Get (i).Dispose ();
821 EventHandler eh = nonApplicationEvents [disposedEvent] as EventHandler;
823 eh (this, EventArgs.Empty);
829 public virtual void Dispose ()
833 public virtual string GetVaryByCustomString (HttpContext context, string custom)
835 if (custom == null) // Sigh
836 throw new NullReferenceException ();
838 if (0 == String.Compare (custom, "browser", true, Helpers.InvariantCulture))
839 return context.Request.Browser.Type;
845 // If we catch an error, queue this error
847 void ProcessError (Exception e)
849 bool first = context.Error == null;
850 context.AddError (e);
852 EventHandler eh = nonApplicationEvents [errorEvent] as EventHandler;
855 eh (this, EventArgs.Empty);
856 } catch (ThreadAbortException taex){
857 context.ClearError ();
858 if (FlagEnd.Value == taex.ExceptionState)
859 // This happens on Redirect() or End()
860 Thread.ResetAbort ();
862 // This happens on Thread.Abort()
863 context.AddError (taex);
864 } catch (Exception ee){
865 context.AddError (ee);
869 stop_processing = true;
871 // we want to remove configuration from the cache in case of
872 // invalid resource not exists to prevent DOS attack.
873 HttpException httpEx = e as HttpException;
874 if (httpEx != null && httpEx.GetHttpCode () == 404) {
875 removeConfigurationFromCache = true;
880 // Ticks the clock: next step on the pipeline.
882 internal void Tick ()
886 if (context.Error is UnifyRequestException) {
887 Exception ex = context.Error.InnerException;
888 context.ClearError ();
889 vmw.common.TypeUtils.Throw (ex);
893 if (pipeline.MoveNext ()){
894 if ((bool)pipeline.Current)
899 catch (Exception ex) {
900 if (ex is ThreadAbortException &&
901 ((ThreadAbortException) ex).ExceptionState == FlagEnd.Value)
903 if (context.WorkerRequest is IHttpUnifyWorkerRequest) {
904 context.ClearError ();
905 context.AddError (new UnifyRequestException (ex));
912 } catch (ThreadAbortException taex) {
913 object obj = taex.ExceptionState;
914 Thread.ResetAbort ();
915 stop_processing = true;
916 if (obj is StepTimeout)
917 ProcessError (new HttpException ("The request timed out."));
919 context.ClearError ();
920 if (FlagEnd.Value != obj)
921 context.AddError (taex);
925 } catch (Exception e) {
926 stop_processing = true;
941 // Invoked when our async callback called from RunHooks completes,
942 // we restart the pipeline here.
944 void async_callback_completed_cb (IAsyncResult ar)
946 if (current_ai.end != null){
949 } catch (Exception e) {
957 void async_handler_complete_cb (IAsyncResult ar)
959 IHttpAsyncHandler async_handler = ar != null ? ar.AsyncState as IHttpAsyncHandler : null;
962 if (async_handler != null)
963 async_handler.EndProcessRequest (ar);
964 } catch (Exception e){
972 // This enumerator yields whether processing must be stopped:
973 // true: processing of the pipeline must be stopped
974 // false: processing of the pipeline must not be stopped
976 IEnumerable RunHooks (Delegate list)
978 Delegate [] delegates = list.GetInvocationList ();
980 foreach (EventHandler d in delegates){
981 if (d.Target != null && (d.Target is AsyncInvoker)){
982 current_ai = (AsyncInvoker) d.Target;
987 context.BeginTimeoutPossible ();
988 current_ai.begin (this, EventArgs.Empty, async_callback_completed_cb, current_ai.data);
991 context.EndTimeoutPossible ();
995 // If things are still moving forward, yield this
999 yield return stop_processing;
1000 else if (stop_processing)
1004 context.BeginTimeoutPossible ();
1005 d (this, EventArgs.Empty);
1007 context.EndTimeoutPossible ();
1009 if (stop_processing)
1015 static void FinalErrorWrite (HttpResponse response, string error)
1018 response.Write (error);
1019 response.Flush (true);
1027 if (context.Error == null){
1029 context.Response.Flush (true);
1030 } catch (Exception e){
1031 context.AddError (e);
1035 Exception error = context.Error;
1037 HttpResponse response = context.Response;
1039 if (!response.HeadersSent){
1040 response.ClearHeaders ();
1041 response.ClearContent ();
1043 if (error is HttpException){
1044 response.StatusCode = ((HttpException)error).GetHttpCode ();
1046 error = new HttpException ("", error);
1047 response.StatusCode = 500;
1049 HttpException httpEx = (HttpException) error;
1050 if (!RedirectCustomError (ref httpEx))
1051 FinalErrorWrite (response, httpEx.GetHtmlErrorMessage ());
1053 response.Flush (true);
1055 if (!(error is HttpException))
1056 error = new HttpException ("", error);
1057 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
1064 // Invoked at the end of the pipeline execution
1066 void PipelineDone ()
1069 EventHandler handler = Events [EndRequestEvent] as EventHandler;
1070 if (handler != null)
1071 handler (this, EventArgs.Empty);
1072 } catch (Exception e){
1078 } catch (ThreadAbortException taex) {
1079 ProcessError (taex);
1080 Thread.ResetAbort ();
1081 } catch (Exception e) {
1082 Console.WriteLine ("Internal error: OutputPage threw an exception " + e);
1084 context.WorkerRequest.EndOfRequest();
1085 if (factory != null && context.Handler != null){
1086 factory.ReleaseHandler (context.Handler);
1087 context.Handler = null;
1090 context.PopHandler ();
1092 // context = null; -> moved to PostDone
1098 if (begin_iar != null)
1099 begin_iar.Complete ();
1103 requests_total_counter.Increment ();
1113 public Tim (string name) {
1117 public string Name {
1118 get { return name; }
1119 set { name = value; }
1122 public void Start () {
1123 start = DateTime.UtcNow;
1126 public void Stop () {
1127 Console.WriteLine ("{0}: {1}ms", name, (DateTime.UtcNow - start).TotalMilliseconds);
1132 [Conditional ("PIPELINE_TIMER")]
1133 void StartTimer (string name)
1141 [Conditional ("PIPELINE_TIMER")]
1148 // Events fired as described in `Http Runtime Support, HttpModules,
1149 // Handling Public Events'
1151 IEnumerator Pipeline ()
1153 Delegate eventHandler;
1154 if (stop_processing)
1157 context.MapRequestHandlerDone = false;
1158 StartTimer ("BeginRequest");
1159 eventHandler = Events [BeginRequestEvent];
1160 if (eventHandler != null) {
1161 foreach (bool stop in RunHooks (eventHandler))
1166 StartTimer ("AuthenticateRequest");
1167 eventHandler = Events [AuthenticateRequestEvent];
1168 if (eventHandler != null)
1169 foreach (bool stop in RunHooks (eventHandler))
1173 StartTimer ("DefaultAuthentication");
1174 if (DefaultAuthentication != null)
1175 foreach (bool stop in RunHooks (DefaultAuthentication))
1179 StartTimer ("PostAuthenticateRequest");
1180 eventHandler = Events [PostAuthenticateRequestEvent];
1181 if (eventHandler != null)
1182 foreach (bool stop in RunHooks (eventHandler))
1186 StartTimer ("AuthorizeRequest");
1187 eventHandler = Events [AuthorizeRequestEvent];
1188 if (eventHandler != null)
1189 foreach (bool stop in RunHooks (eventHandler))
1193 StartTimer ("PostAuthorizeRequest");
1194 eventHandler = Events [PostAuthorizeRequestEvent];
1195 if (eventHandler != null)
1196 foreach (bool stop in RunHooks (eventHandler))
1200 StartTimer ("ResolveRequestCache");
1201 eventHandler = Events [ResolveRequestCacheEvent];
1202 if (eventHandler != null)
1203 foreach (bool stop in RunHooks (eventHandler))
1207 StartTimer ("PostResolveRequestCache");
1208 eventHandler = Events [PostResolveRequestCacheEvent];
1209 if (eventHandler != null)
1210 foreach (bool stop in RunHooks (eventHandler))
1214 StartTimer ("MapRequestHandler");
1215 // As per http://msdn2.microsoft.com/en-us/library/bb470252(VS.90).aspx
1216 eventHandler = Events [MapRequestHandlerEvent];
1217 if (eventHandler != null)
1218 foreach (bool stop in RunHooks (eventHandler))
1221 context.MapRequestHandlerDone = true;
1223 StartTimer ("GetHandler");
1224 // Obtain the handler for the request.
1225 IHttpHandler handler = null;
1227 handler = GetHandler (context, context.Request.CurrentExecutionFilePath);
1228 context.Handler = handler;
1229 context.PushHandler (handler);
1230 } catch (FileNotFoundException fnf){
1232 Console.WriteLine ("$$$$$$$$$$:Sys.Web Pipeline");
1233 Console.WriteLine (fnf.ToString ());
1235 if (context.Request.IsLocal)
1236 ProcessError (new HttpException (404, String.Format ("File not found {0}", fnf.FileName), fnf, context.Request.FilePath));
1238 ProcessError (new HttpException (404, "File not found: " + Path.GetFileName (fnf.FileName), context.Request.FilePath));
1239 } catch (DirectoryNotFoundException dnf){
1240 if (!context.Request.IsLocal)
1241 dnf = null; // Do not "leak" real path information
1242 ProcessError (new HttpException (404, "Directory not found", dnf));
1243 } catch (Exception e) {
1248 if (stop_processing)
1251 StartTimer ("PostMapRequestHandler");
1252 eventHandler = Events [PostMapRequestHandlerEvent];
1253 if (eventHandler != null)
1254 foreach (bool stop in RunHooks (eventHandler))
1258 StartTimer ("AcquireRequestState");
1259 eventHandler = Events [AcquireRequestStateEvent];
1260 if (eventHandler != null){
1261 foreach (bool stop in RunHooks (eventHandler))
1266 StartTimer ("PostAcquireRequestState");
1267 eventHandler = Events [PostAcquireRequestStateEvent];
1268 if (eventHandler != null){
1269 foreach (bool stop in RunHooks (eventHandler))
1275 // From this point on, we need to ensure that we call
1276 // ReleaseRequestState, so the code below jumps to
1277 // `release:' to guarantee it rather than yielding.
1279 StartTimer ("PreRequestHandlerExecute");
1280 eventHandler = Events [PreRequestHandlerExecuteEvent];
1281 if (eventHandler != null)
1282 foreach (bool stop in RunHooks (eventHandler))
1290 bool doProcessHandler = false;
1293 IHttpHandler ctxHandler = context.Handler;
1294 if (ctxHandler != null && handler != ctxHandler) {
1295 context.PopHandler ();
1296 handler = ctxHandler;
1297 context.PushHandler (handler);
1300 StartTimer ("ProcessRequest");
1302 context.BeginTimeoutPossible ();
1303 if (handler != null){
1304 IHttpAsyncHandler async_handler = handler as IHttpAsyncHandler;
1306 if (async_handler != null){
1309 async_handler.BeginProcessRequest (context, async_handler_complete_cb, handler);
1312 handler.ProcessRequest (context);
1314 IHttpExtendedHandler extHandler=handler as IHttpExtendedHandler;
1315 doProcessHandler = extHandler != null && !extHandler.IsCompleted;
1319 if (context.Error != null)
1320 throw new TargetInvocationException(context.Error);
1323 context.EndTimeoutPossible ();
1327 if (doProcessHandler) {
1329 goto processHandler;
1333 yield return stop_processing;
1334 else if (stop_processing)
1337 // These are executed after the application has returned
1339 StartTimer ("PostRequestHandlerExecute");
1340 eventHandler = Events [PostRequestHandlerExecuteEvent];
1341 if (eventHandler != null)
1342 foreach (bool stop in RunHooks (eventHandler))
1348 StartTimer ("ReleaseRequestState");
1349 eventHandler = Events [ReleaseRequestStateEvent];
1350 if (eventHandler != null){
1351 #pragma warning disable 219
1352 foreach (bool stop in RunHooks (eventHandler)) {
1354 // Ignore the stop signal while release the state
1358 #pragma warning restore 219
1362 if (stop_processing)
1365 StartTimer ("PostReleaseRequestState");
1366 eventHandler = Events [PostReleaseRequestStateEvent];
1367 if (eventHandler != null)
1368 foreach (bool stop in RunHooks (eventHandler))
1372 StartTimer ("Filter");
1373 if (context.Error == null)
1374 context.Response.DoFilter (true);
1377 StartTimer ("UpdateRequestCache");
1378 eventHandler = Events [UpdateRequestCacheEvent];
1379 if (eventHandler != null)
1380 foreach (bool stop in RunHooks (eventHandler))
1384 StartTimer ("PostUpdateRequestCache");
1385 eventHandler = Events [PostUpdateRequestCacheEvent];
1386 if (eventHandler != null)
1387 foreach (bool stop in RunHooks (eventHandler))
1391 StartTimer ("LogRequest");
1392 eventHandler = Events [LogRequestEvent];
1393 if (eventHandler != null)
1394 foreach (bool stop in RunHooks (eventHandler))
1398 StartTimer ("PostLogRequest");
1399 eventHandler = Events [PostLogRequestEvent];
1400 if (eventHandler != null)
1401 foreach (bool stop in RunHooks (eventHandler))
1405 StartTimer ("PipelineDone");
1411 internal CultureInfo GetThreadCulture (HttpRequest request, CultureInfo culture, bool isAuto)
1415 CultureInfo ret = null;
1416 string[] languages = request.UserLanguages;
1418 if (languages != null && languages.Length > 0)
1419 ret = CultureInfo.CreateSpecificCulture (languages[0]);
1432 GlobalizationSection cfg;
1433 cfg = (GlobalizationSection) WebConfigurationManager.GetSection ("system.web/globalization");
1434 app_culture = cfg.GetCulture ();
1435 autoCulture = cfg.IsAutoCulture;
1436 appui_culture = cfg.GetUICulture ();
1437 autoUICulture = cfg.IsAutoUICulture;
1439 context.StartTimeoutTimer ();
1441 Thread th = Thread.CurrentThread;
1442 if (app_culture != null) {
1443 prev_app_culture = th.CurrentCulture;
1444 CultureInfo new_app_culture = GetThreadCulture (Request, app_culture, autoCulture);
1445 if (!new_app_culture.Equals (Helpers.InvariantCulture))
1446 th.CurrentCulture = new_app_culture;
1449 if (appui_culture != null) {
1450 prev_appui_culture = th.CurrentUICulture;
1451 CultureInfo new_app_culture = GetThreadCulture (Request, appui_culture, autoUICulture);
1452 if (!new_app_culture.Equals (Helpers.InvariantCulture))
1453 th.CurrentUICulture = new_app_culture;
1457 prev_user = Thread.CurrentPrincipal;
1463 if (removeConfigurationFromCache) {
1464 WebConfigurationManager.RemoveConfigurationFromCache (context);
1465 removeConfigurationFromCache = false;
1468 Thread th = Thread.CurrentThread;
1470 if (Thread.CurrentPrincipal != prev_user)
1471 Thread.CurrentPrincipal = prev_user;
1473 if (prev_appui_culture != null && prev_appui_culture != th.CurrentUICulture)
1474 th.CurrentUICulture = prev_appui_culture;
1475 if (prev_app_culture != null && prev_app_culture != th.CurrentCulture)
1476 th.CurrentCulture = prev_app_culture;
1479 if (context == null)
1480 context = HttpContext.Current;
1481 context.StopTimeoutTimer ();
1483 context.Request.ReleaseResources ();
1484 context.Response.ReleaseResources ();
1487 HttpContext.Current = null;
1490 void Start (object x)
1492 CultureInfo[] cultures = x as CultureInfo[];
1493 if (cultures != null && cultures.Length == 2) {
1494 Thread ct = Thread.CurrentThread;
1495 ct.CurrentCulture = cultures [0];
1496 ct.CurrentUICulture = cultures [1];
1501 } catch (Exception e) {
1502 initialization_exception = e;
1503 FinalErrorWrite (context.Response, new HttpException ("", e).GetHtmlErrorMessage ());
1508 HttpContext.Current = Context;
1510 pipeline = Pipeline ();
1514 const string HANDLER_CACHE = "@@HttpHandlerCache@@";
1516 internal static Hashtable GetHandlerCache ()
1518 Cache cache = HttpRuntime.InternalCache;
1519 Hashtable ret = cache [HANDLER_CACHE] as Hashtable;
1522 ret = new Hashtable ();
1523 cache.Insert (HANDLER_CACHE, ret);
1529 internal static void ClearHandlerCache ()
1531 Hashtable cache = GetHandlerCache ();
1535 object LocateHandler (HttpRequest req, string verb, string url)
1537 Hashtable cache = GetHandlerCache ();
1538 string id = String.Concat (verb, url);
1539 object ret = cache [id];
1545 HttpHandlersSection httpHandlersSection = WebConfigurationManager.GetSection ("system.web/httpHandlers", req.Path, req.Context) as HttpHandlersSection;
1546 ret = httpHandlersSection.LocateHandler (verb, url, out allowCache);
1548 IHttpHandler handler = ret as IHttpHandler;
1549 if (allowCache && handler != null && handler.IsReusable)
1555 internal IHttpHandler GetHandler (HttpContext context, string url)
1557 return GetHandler (context, url, false);
1560 // Used by HttpServerUtility.Execute
1561 internal IHttpHandler GetHandler (HttpContext context, string url, bool ignoreContextHandler)
1563 if (!ignoreContextHandler && context.Handler != null)
1564 return context.Handler;
1566 HttpRequest request = context.Request;
1567 string verb = request.RequestType;
1569 IHttpHandler handler = null;
1570 object o = LocateHandler (request, verb, url);
1572 factory = o as IHttpHandlerFactory;
1573 if (factory == null) {
1574 handler = (IHttpHandler) o;
1576 handler = factory.GetHandler (context, verb, url, request.MapPath (url));
1582 void IHttpHandler.ProcessRequest (HttpContext context)
1585 this.context = context;
1593 // This is used by FireOnAppStart, when we init the application
1594 // as the context is required to be set at that point (the user
1595 // might call methods that require it on that hook).
1597 internal void SetContext (HttpContext context)
1599 this.context = context;
1602 internal void SetSession (HttpSessionState session)
1604 this.session = session;
1607 IAsyncResult IHttpAsyncHandler.BeginProcessRequest (HttpContext context, AsyncCallback cb, object extraData)
1609 this.context = context;
1612 begin_iar = new AsyncRequestState (done, cb, extraData);
1614 CultureInfo[] cultures = new CultureInfo [2];
1615 cultures [0] = Thread.CurrentThread.CurrentCulture;
1616 cultures [1] = Thread.CurrentThread.CurrentUICulture;
1621 if (Thread.CurrentThread.IsThreadPoolThread)
1625 ThreadPool.QueueUserWorkItem (new WaitCallback (Start), cultures);
1630 void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result)
1636 if (!result.IsCompleted)
1637 result.AsyncWaitHandle.WaitOne ();
1641 public virtual void Init ()
1645 bool IHttpHandler.IsReusable {
1652 internal void ClearError ()
1654 context.ClearError ();
1657 bool RedirectErrorPage (string error_page)
1659 if (context.Request.QueryString ["aspxerrorpath"] != null)
1662 Response.Redirect (error_page + "?aspxerrorpath=" + Request.Path, false);
1666 bool RedirectCustomError (ref HttpException httpEx)
1669 if (!context.IsCustomErrorEnabledUnsafe)
1672 CustomErrorsSection config = (CustomErrorsSection)WebConfigurationManager.GetSection ("system.web/customErrors");
1673 if (config == null) {
1674 if (context.ErrorPage != null)
1675 return RedirectErrorPage (context.ErrorPage);
1680 CustomError err = config.Errors [context.Response.StatusCode.ToString()];
1681 string redirect = err == null ? null : err.Redirect;
1682 if (redirect == null) {
1683 redirect = context.ErrorPage;
1684 if (redirect == null)
1685 redirect = config.DefaultRedirect;
1688 if (redirect == null)
1691 return RedirectErrorPage (redirect);
1693 catch (Exception ex) {
1694 httpEx = new HttpException (500, "", ex);
1699 internal static string BinDirectory
1702 if (binDirectory == null) {
1703 AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
1704 string baseDir = setup.ApplicationBase;
1707 foreach (string dir in BinDirs) {
1708 bindir = Path.Combine (baseDir, dir);
1709 if (!Directory.Exists (bindir))
1711 binDirectory = bindir;
1716 return binDirectory;
1720 internal static string[] BinDirectoryAssemblies
1723 ArrayList binDlls = null;
1726 string bindir = BinDirectory;
1727 if (bindir != null) {
1728 binDlls = new ArrayList ();
1729 dlls = Directory.GetFiles (bindir, "*.dll");
1730 binDlls.AddRange (dlls);
1733 if (binDlls == null)
1734 return new string[] {};
1736 return (string[]) binDlls.ToArray (typeof (string));
1740 internal static Type LoadType (string typeName)
1742 return LoadType (typeName, false);
1745 internal static Type LoadType (string typeName, bool throwOnMissing)
1747 Type type = Type.GetType (typeName);
1752 Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
1753 foreach (Assembly ass in assemblies) {
1754 type = ass.GetType (typeName, false);
1759 IList tla = System.Web.Compilation.BuildManager.TopLevelAssemblies;
1760 if (tla != null && tla.Count > 0) {
1761 foreach (Assembly asm in tla) {
1764 type = asm.GetType (typeName, false);
1770 Exception loadException = null;
1773 type = LoadTypeFromBin (typeName);
1774 } catch (Exception ex) {
1782 throw new TypeLoadException (String.Format ("Type '{0}' cannot be found", typeName), loadException);
1787 internal static Type LoadTypeFromBin (string typeName)
1791 foreach (string s in BinDirectoryAssemblies) {
1792 Assembly binA = null;
1795 binA = Assembly.LoadFrom (s);
1796 } catch (FileLoadException) {
1799 } catch (BadImageFormatException) {
1804 type = binA.GetType (typeName, false);
1816 // Based on Fritz' Onion's AsyncRequestState class for asynchronous IHttpAsyncHandlers
1818 class AsyncRequestState : IAsyncResult {
1822 ManualResetEvent complete_event = null;
1824 internal AsyncRequestState (ManualResetEvent complete_event, AsyncCallback cb, object cb_data)
1827 this.cb_data = cb_data;
1828 this.complete_event = complete_event;
1831 internal void Complete ()
1836 // TODO: if this throws an error, we have no way of reporting it
1837 // Not really too bad, since the only failure might be
1838 // `HttpRuntime.request_processed'.
1845 complete_event.Set ();
1848 public object AsyncState {
1854 public bool CompletedSynchronously {
1860 public bool IsCompleted {
1866 public WaitHandle AsyncWaitHandle {
1868 return complete_event;
1873 #region Helper classes
1876 // A wrapper to keep track of begin/end pairs
1878 class AsyncInvoker {
1879 public BeginEventHandler begin;
1880 public EndEventHandler end;
1883 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, object d)
1890 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh)
1896 public void Invoke (object sender, EventArgs e)
1898 throw new Exception ("This is just a dummy");