2 // System.Web.HttpContext.cs
5 // Miguel de Icaza (miguel@novell.com)
6 // Gonzalo Paniagua Javier (gonzalo@novell.com)
10 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Collections;
33 using System.Configuration;
34 using System.Globalization;
35 using System.Runtime.Remoting.Messaging;
36 using System.Security.Permissions;
37 using System.Security.Principal;
38 using System.Threading;
39 using System.Web.Caching;
40 using System.Web.Configuration;
41 using System.Web.SessionState;
43 using System.Web.Util;
44 using System.Reflection;
46 using System.Collections.Generic;
48 using System.Resources;
49 using System.Web.Compilation;
50 using System.Web.Profile;
51 using CustomErrorMode = System.Web.Configuration.CustomErrorsMode;
54 namespace System.Web {
55 // CAS - no InheritanceDemand here as the class is sealed
56 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
57 public sealed partial class HttpContext : IServiceProvider {
58 internal HttpWorkerRequest WorkerRequest;
59 HttpApplication app_instance;
61 HttpResponse response;
62 HttpSessionState session_state;
63 HttpServerUtility server;
64 TraceContext trace_context;
67 bool skip_authorization = false;
71 object config_timeout;
73 DateTime time_stamp = DateTime.UtcNow;
76 bool _isProcessingInclude;
80 static ResourceProviderFactory provider_factory;
83 static DefaultResourceProviderFactory default_provider_factory;
86 static Dictionary <string, IResourceProvider> resource_providers;
89 const string app_global_res_key = "HttpContext.app_global_res_key";
90 internal static Assembly AppGlobalResourcesAssembly {
91 get { return (Assembly) AppDomain.CurrentDomain.GetData (app_global_res_key); }
92 set { AppDomain.CurrentDomain.SetData (app_global_res_key, value); }
95 internal static Assembly AppGlobalResourcesAssembly;
97 ProfileBase profile = null;
98 LinkedList<IHttpHandler> handlers;
100 static DefaultResourceProviderFactory DefaultProviderFactory {
102 if (default_provider_factory == null)
103 default_provider_factory = new DefaultResourceProviderFactory ();
104 return default_provider_factory;
109 public HttpContext (HttpWorkerRequest wr)
112 request = new HttpRequest (WorkerRequest, this);
113 response = new HttpResponse (WorkerRequest, this);
116 public HttpContext (HttpRequest request, HttpResponse response)
118 this.request = request;
119 this.response = response;
123 internal bool IsProcessingInclude {
124 get { return _isProcessingInclude; }
125 set { _isProcessingInclude = value; }
128 public Exception [] AllErrors {
133 if (errors is Exception){
134 Exception [] all = new Exception [1];
135 all [0] = (Exception) errors;
138 return (Exception []) (((ArrayList) errors).ToArray (typeof (Exception)));
142 public HttpApplicationState Application {
144 return HttpApplicationFactory.ApplicationState;
148 public HttpApplication ApplicationInstance {
154 app_instance = value;
161 return HttpRuntime.Cache;
165 internal Cache InternalCache {
167 return HttpRuntime.InternalCache;
172 // The "Current" property is set just after we have constructed it with
173 // the 'HttpContext (HttpWorkerRequest)' constructor.
175 #if !TARGET_JVM // No remoting CallContext support in Grasshopper
176 public static HttpContext Current {
178 return (HttpContext) CallContext.GetData ("c");
182 CallContext.SetData ("c", value);
187 public Exception Error {
189 if (errors == null || (errors is Exception))
190 return (Exception) errors;
191 return (Exception) (((ArrayList) errors) [0]);
195 public IHttpHandler Handler {
205 public bool IsCustomErrorEnabled {
208 return IsCustomErrorEnabledUnsafe;
216 internal bool IsCustomErrorEnabledUnsafe {
219 CustomErrorsSection cfg = (CustomErrorsSection) WebConfigurationManager.GetSection ("system.web/customErrors");
221 CustomErrorsConfig cfg = null;
223 cfg = (CustomErrorsConfig) GetConfig ("system.web/customErrors");
231 if (cfg.Mode == CustomErrorMode.On)
234 return (cfg.Mode == CustomErrorMode.RemoteOnly) && !Request.IsLocal;
238 public bool IsDebuggingEnabled {
239 get { return HttpRuntime.IsDebuggingEnabled; }
242 public IDictionary Items {
245 items = new Hashtable ();
250 public HttpRequest Request {
256 public HttpResponse Response {
262 public HttpServerUtility Server {
265 server = new HttpServerUtility (this);
270 public HttpSessionState Session {
272 return session_state;
276 public bool SkipAuthorization {
278 return skip_authorization;
281 [SecurityPermission (SecurityAction.Demand, ControlPrincipal = true)]
283 skip_authorization = value;
287 public DateTime Timestamp {
289 return time_stamp.ToLocalTime ();
293 public TraceContext Trace {
295 if (trace_context == null)
296 trace_context = new TraceContext (this);
297 return trace_context;
301 public IPrincipal User {
306 [SecurityPermission (SecurityAction.Demand, ControlPrincipal = true)]
313 internal bool MapRequestHandlerDone {
318 // The two properties below are defined only when the IIS7 integrated mode is used.
319 // They are useless under Mono
320 public RequestNotification CurrentNotification {
321 get { throw new PlatformNotSupportedException ("This property is not supported on Mono."); }
324 public bool IsPostNotification {
325 get { throw new PlatformNotSupportedException ("This property is not supported on Mono."); }
328 internal void PushHandler (IHttpHandler handler)
332 if (handlers == null)
333 handlers = new LinkedList <IHttpHandler> ();
334 handlers.AddLast (handler);
337 internal void PopHandler ()
339 if (handlers == null || handlers.Count == 0)
341 handlers.RemoveLast ();
344 IHttpHandler GetCurrentHandler ()
346 if (handlers == null || handlers.Count == 0)
349 return handlers.Last.Value;
352 IHttpHandler GetPreviousHandler ()
354 if (handlers == null || handlers.Count <= 1)
356 LinkedListNode <IHttpHandler> previous = handlers.Last.Previous;
357 if (previous != null)
358 return previous.Value;
362 public IHttpHandler CurrentHandler {
363 get { return GetCurrentHandler (); }
366 public IHttpHandler PreviousHandler {
367 get { return GetPreviousHandler (); }
370 internal bool ProfileInitialized {
371 get { return profile != null; }
374 public ProfileBase Profile {
376 if (profile == null) {
377 if (Request.IsAuthenticated)
378 profile = ProfileBase.Create (User.Identity.Name);
380 profile = ProfileBase.Create (Request.AnonymousID, false);
391 public void AddError (Exception errorInfo)
398 if (errors is Exception){
399 l = new ArrayList ();
403 l = (ArrayList) errors;
407 internal void ClearError (Exception e)
413 internal bool HasError (Exception e)
418 return (errors is ArrayList) ?
419 ((ArrayList) errors).Contains (e) : false;
422 public void ClearError ()
428 [Obsolete ("use WebConfigurationManager.GetWebApplicationSection")]
430 public static object GetAppConfig (string name)
432 object o = ConfigurationSettings.GetConfig (name);
438 [Obsolete ("see GetSection")]
440 public object GetConfig (string name)
443 return GetSection (name);
445 return WebConfigurationSettings.GetConfig (name, this);
450 public static object GetGlobalResourceObject (string classKey, string resourceKey)
452 return GetGlobalResourceObject (classKey, resourceKey, Thread.CurrentThread.CurrentUICulture);
455 static bool EnsureProviderFactory ()
457 if (resource_providers == null)
458 resource_providers = new Dictionary <string, IResourceProvider> ();
460 if (provider_factory != null)
463 GlobalizationSection gs = WebConfigurationManager.GetSection ("system.web/globalization") as GlobalizationSection;
468 String rsfTypeName = gs.ResourceProviderFactoryType;
469 bool usingDefault = false;
470 if (String.IsNullOrEmpty (rsfTypeName)) {
472 rsfTypeName = typeof (DefaultResourceProviderFactory).AssemblyQualifiedName;
475 Type rsfType = HttpApplication.LoadType (rsfTypeName, true);
476 ResourceProviderFactory rpf = Activator.CreateInstance (rsfType) as ResourceProviderFactory;
478 if (rpf == null && usingDefault)
481 provider_factory = rpf;
483 default_provider_factory = rpf as DefaultResourceProviderFactory;
488 internal static IResourceProvider GetResourceProvider (string virtualPath, bool isLocal)
490 if (!EnsureProviderFactory ())
493 // TODO: check if it makes sense to cache the providers and, if yes, maybe
494 // we should expire the entries (or just store them in InternalCache?)
495 IResourceProvider rp = null;
496 if (!resource_providers.TryGetValue (virtualPath, out rp)) {
498 HttpContext ctx = HttpContext.Current;
499 HttpRequest req = ctx != null ? ctx.Request : null;
500 rp = provider_factory.CreateLocalResourceProvider (virtualPath);
502 rp = provider_factory.CreateGlobalResourceProvider (virtualPath);
506 HttpContext ctx = HttpContext.Current;
507 HttpRequest req = ctx != null ? ctx.Request : null;
508 rp = DefaultProviderFactory.CreateLocalResourceProvider (virtualPath);
510 rp = DefaultProviderFactory.CreateGlobalResourceProvider (virtualPath);
516 resource_providers.Add (virtualPath, rp);
522 static object GetGlobalObjectFromFactory (string classKey, string resourceKey, CultureInfo culture)
524 // FIXME: Retention of data
525 IResourceProvider rp = GetResourceProvider (classKey, false);
529 return rp.GetObject (resourceKey, culture);
532 public static object GetGlobalResourceObject (string classKey, string resourceKey, CultureInfo culture)
534 return GetGlobalObjectFromFactory ("Resources." + classKey, resourceKey, culture);
537 public static object GetLocalResourceObject (string virtualPath, string resourceKey)
539 return GetLocalResourceObject (virtualPath, resourceKey, Thread.CurrentThread.CurrentUICulture);
542 static object GetLocalObjectFromFactory (string virtualPath, string resourceKey, CultureInfo culture)
544 IResourceProvider rp = GetResourceProvider (virtualPath, true);
548 return rp.GetObject (resourceKey, culture);
551 public static object GetLocalResourceObject (string virtualPath, string resourceKey, CultureInfo culture)
553 if (!VirtualPathUtility.IsAbsolute (virtualPath))
554 throw new ArgumentException ("The specified virtualPath was not rooted.");
556 return GetLocalObjectFromFactory (virtualPath, resourceKey, culture);
559 public object GetSection (string name)
561 return WebConfigurationManager.GetSection (name);
564 object IServiceProvider.GetService (Type service)
566 if (service == typeof (HttpWorkerRequest))
567 return WorkerRequest;
570 // We return everything out of properties in case
571 // they are dynamically computed in some form in the future.
573 if (service == typeof (HttpApplication))
574 return ApplicationInstance;
576 if (service == typeof (HttpRequest))
579 if (service == typeof (HttpResponse))
582 if (service == typeof (HttpSessionState))
585 if (service == typeof (HttpApplicationState))
588 if (service == typeof (IPrincipal))
591 if (service == typeof (Cache))
594 if (service == typeof (HttpContext))
597 if (service == typeof (IHttpHandler))
600 if (service == typeof (HttpServerUtility))
603 if (service == typeof (TraceContext))
610 public void RemapHandler (IHttpHandler handler)
612 if (MapRequestHandlerDone)
613 throw new InvalidOperationException ("The RemapHandler method was called after the MapRequestHandler event occurred.");
618 public void RewritePath (string path)
621 RewritePath (path, true);
623 RewritePath (path, false);
627 public void RewritePath (string filePath, string pathInfo, string queryString)
629 RewritePath (filePath, pathInfo, queryString, false);
637 void RewritePath (string path, bool rebaseClientPath)
639 int qmark = path.IndexOf ('?');
641 RewritePath (path.Substring (0, qmark), "", path.Substring (qmark + 1), rebaseClientPath);
643 RewritePath (path, null, null, rebaseClientPath);
651 void RewritePath (string filePath, string pathInfo, string queryString, bool setClientFilePath)
653 if (filePath == null)
654 throw new ArgumentNullException ("filePath");
655 if (!VirtualPathUtility.IsValidVirtualPath (filePath))
656 throw new HttpException ("'" + HttpUtility.HtmlEncode (filePath) + "' is not a valid virtual path.");
658 bool pathRelative = VirtualPathUtility.IsAppRelative (filePath);
659 bool pathAbsolute = pathRelative ? false : VirtualPathUtility.IsAbsolute (filePath);
660 if (pathRelative || pathAbsolute) {
661 bool needSubstring = false;
663 if (pathRelative && filePath.Length > 1)
664 needSubstring = true;
666 string bvd = Request.BaseVirtualDir;
670 string canonizedFilePath = VirtualPathUtility.Canonize (filePath);
671 filePath = VirtualPathUtility.Combine (bvd, needSubstring ? canonizedFilePath.Substring (2) : canonizedFilePath);
673 filePath = VirtualPathUtility.Combine (VirtualPathUtility.GetDirectory (Request.FilePath), filePath);
675 if (!StrUtils.StartsWith (filePath, HttpRuntime.AppDomainAppVirtualPath))
676 throw new HttpException (404, "The virtual path '" + HttpUtility.HtmlEncode (filePath) + "' maps to another application.", filePath);
678 Request.SetCurrentExePath (filePath);
679 if (setClientFilePath)
680 Request.SetFilePath (filePath);
682 // A null pathInfo or queryString is ignored and previous values remain untouched
683 if (pathInfo != null)
684 Request.SetPathInfo (pathInfo);
686 if (queryString != null)
687 Request.QueryStringRaw = queryString;
692 internal void SetSession (HttpSessionState state)
694 session_state = state;
697 // URL of a page used for error redirection.
698 internal string ErrorPage {
708 internal TimeSpan ConfigTimeout {
710 if (config_timeout == null) {
712 HttpRuntimeSection section = (HttpRuntimeSection)WebConfigurationManager.GetSection ("system.web/httpRuntime");
713 config_timeout = section.ExecutionTimeout;
715 HttpRuntimeConfig config = (HttpRuntimeConfig)
716 GetConfig ("system.web/httpRuntime");
717 config_timeout = new TimeSpan (0, 0, config.ExecutionTimeout);
721 return (TimeSpan) config_timeout;
725 config_timeout = value;
728 TimeSpan remaining = value - (DateTime.UtcNow - time_stamp);
729 long remaining_ms = Math.Max ((long)remaining.TotalMilliseconds, 0);
731 // See http://msdn2.microsoft.com/en-us/library/7hs7492w.aspx
732 if (remaining_ms > 4294967294)
733 remaining_ms = 4294967294;
735 timer.Change (remaining_ms, (long)Timeout.Infinite);
742 void TimeoutReached(object state) {
743 HttpRuntime.QueuePendingRequest (false);
744 if (Interlocked.CompareExchange (ref timeout_possible, 0, 0) == 0) {
745 timer.Change(2000, 0);
750 thread.Abort (new StepTimeout ());
753 internal void StartTimeoutTimer() {
754 thread = Thread.CurrentThread;
755 timer = new Timer (TimeoutReached, null, (int)ConfigTimeout.TotalMilliseconds, Timeout.Infinite);
758 internal void StopTimeoutTimer() {
765 internal bool TimeoutPossible {
766 get { return (Interlocked.CompareExchange (ref timeout_possible, 1, 1) == 1); }
769 internal void BeginTimeoutPossible ()
771 timeout_possible = 1;
774 internal void EndTimeoutPossible ()
776 Interlocked.CompareExchange (ref timeout_possible, 0, 1);