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;
45 using System.Collections.Generic;
47 using System.Reflection;
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;
82 static Dictionary <string, IResourceProvider> resource_providers;
85 const string app_global_res_key = "HttpContext.app_global_res_key";
86 internal static Assembly AppGlobalResourcesAssembly {
87 get { return (Assembly) AppDomain.CurrentDomain.GetData (app_global_res_key); }
88 set { AppDomain.CurrentDomain.SetData (app_global_res_key, value); }
92 static Dictionary <ResourceManagerCacheKey, ResourceManager> resourceManagerCache;
93 internal static Assembly AppGlobalResourcesAssembly;
95 ProfileBase profile = null;
96 LinkedList<IHttpHandler> handlers;
99 public HttpContext (HttpWorkerRequest wr)
102 request = new HttpRequest (WorkerRequest, this);
103 response = new HttpResponse (WorkerRequest, this);
106 public HttpContext (HttpRequest request, HttpResponse response)
108 this.request = request;
109 this.response = response;
113 internal bool IsProcessingInclude {
114 get { return _isProcessingInclude; }
115 set { _isProcessingInclude = value; }
118 public Exception [] AllErrors {
123 if (errors is Exception){
124 Exception [] all = new Exception [1];
125 all [0] = (Exception) errors;
128 return (Exception []) (((ArrayList) errors).ToArray (typeof (Exception)));
132 public HttpApplicationState Application {
134 return HttpApplicationFactory.ApplicationState;
138 public HttpApplication ApplicationInstance {
144 app_instance = value;
151 return HttpRuntime.Cache;
155 internal Cache InternalCache {
157 return HttpRuntime.InternalCache;
162 // The "Current" property is set just after we have constructed it with
163 // the 'HttpContext (HttpWorkerRequest)' constructor.
165 #if !TARGET_JVM // No remoting CallContext support in Grasshopper
166 public static HttpContext Current {
168 return (HttpContext) CallContext.GetData ("c");
172 CallContext.SetData ("c", value);
177 public Exception Error {
179 if (errors == null || (errors is Exception))
180 return (Exception) errors;
181 return (Exception) (((ArrayList) errors) [0]);
185 public IHttpHandler Handler {
195 public bool IsCustomErrorEnabled {
198 return IsCustomErrorEnabledUnsafe;
206 internal bool IsCustomErrorEnabledUnsafe {
209 CustomErrorsSection cfg = (CustomErrorsSection) WebConfigurationManager.GetSection ("system.web/customErrors");
211 CustomErrorsConfig cfg = null;
213 cfg = (CustomErrorsConfig) GetConfig ("system.web/customErrors");
221 if (cfg.Mode == CustomErrorMode.On)
224 return (cfg.Mode == CustomErrorMode.RemoteOnly) && !Request.IsLocal;
228 public bool IsDebuggingEnabled {
229 get { return HttpRuntime.IsDebuggingEnabled; }
232 public IDictionary Items {
235 items = new Hashtable ();
240 public HttpRequest Request {
246 public HttpResponse Response {
252 public HttpServerUtility Server {
255 server = new HttpServerUtility (this);
260 public HttpSessionState Session {
262 return session_state;
266 public bool SkipAuthorization {
268 return skip_authorization;
271 [SecurityPermission (SecurityAction.Demand, ControlPrincipal = true)]
273 skip_authorization = value;
277 public DateTime Timestamp {
279 return time_stamp.ToLocalTime ();
283 public TraceContext Trace {
285 if (trace_context == null)
286 trace_context = new TraceContext (this);
287 return trace_context;
291 public IPrincipal User {
296 [SecurityPermission (SecurityAction.Demand, ControlPrincipal = true)]
303 internal bool MapRequestHandlerDone {
308 // The two properties below are defined only when the IIS7 integrated mode is used.
309 // They are useless under Mono
310 public RequestNotification CurrentNotification {
311 get { throw new PlatformNotSupportedException ("This property is not supported on Mono."); }
314 public bool IsPostNotification {
315 get { throw new PlatformNotSupportedException ("This property is not supported on Mono."); }
318 internal void PushHandler (IHttpHandler handler)
322 if (handlers == null)
323 handlers = new LinkedList <IHttpHandler> ();
324 handlers.AddLast (handler);
327 internal void PopHandler ()
329 if (handlers == null || handlers.Count == 0)
331 handlers.RemoveLast ();
334 IHttpHandler GetCurrentHandler ()
336 if (handlers == null || handlers.Count == 0)
339 return handlers.Last.Value;
342 IHttpHandler GetPreviousHandler ()
344 if (handlers == null || handlers.Count <= 1)
346 LinkedListNode <IHttpHandler> previous = handlers.Last.Previous;
347 if (previous != null)
348 return previous.Value;
352 public IHttpHandler CurrentHandler {
353 get { return GetCurrentHandler (); }
356 public IHttpHandler PreviousHandler {
357 get { return GetPreviousHandler (); }
360 internal bool ProfileInitialized {
361 get { return profile != null; }
364 public ProfileBase Profile {
366 if (profile == null) {
367 if (Request.IsAuthenticated)
368 profile = ProfileBase.Create (User.Identity.Name);
370 profile = ProfileBase.Create (Request.AnonymousID, false);
381 public void AddError (Exception errorInfo)
388 if (errors is Exception){
389 l = new ArrayList ();
393 l = (ArrayList) errors;
397 internal void ClearError (Exception e)
403 internal bool HasError (Exception e)
408 return (errors is ArrayList) ?
409 ((ArrayList) errors).Contains (e) : false;
412 public void ClearError ()
418 [Obsolete ("use WebConfigurationManager.GetWebApplicationSection")]
420 public static object GetAppConfig (string name)
422 object o = ConfigurationSettings.GetConfig (name);
428 [Obsolete ("see GetSection")]
430 public object GetConfig (string name)
433 return GetSection (name);
435 return WebConfigurationSettings.GetConfig (name, this);
440 static object GetResourceObject (string classKey, string resourceKey, CultureInfo culture, Assembly assembly)
444 if (resourceManagerCache == null)
445 resourceManagerCache = new Dictionary <ResourceManagerCacheKey, ResourceManager> ();
447 ResourceManagerCacheKey key = new ResourceManagerCacheKey (classKey, assembly);
448 if (!resourceManagerCache.TryGetValue (key, out rm)) {
449 rm = new ResourceManager (classKey, assembly);
450 rm.IgnoreCase = true;
451 resourceManagerCache.Add (key, rm);
454 return rm.GetObject (resourceKey, culture);
455 } catch (MissingManifestResourceException) {
457 } catch (Exception ex) {
458 throw new HttpException ("Failed to retrieve the specified global resource object.", ex);
462 public static object GetGlobalResourceObject (string classKey, string resourceKey)
464 return GetGlobalResourceObject (classKey, resourceKey, Thread.CurrentThread.CurrentUICulture);
467 static bool EnsureProviderFactory ()
469 if (resource_providers == null)
470 resource_providers = new Dictionary <string, IResourceProvider> ();
472 if (provider_factory != null)
475 GlobalizationSection gs = WebConfigurationManager.GetSection ("system.web/globalization") as GlobalizationSection;
480 String rsfTypeName = gs.ResourceProviderFactoryType;
481 if (String.IsNullOrEmpty (rsfTypeName))
484 Type rsfType = HttpApplication.LoadType (rsfTypeName, true);
485 ResourceProviderFactory rpf = Activator.CreateInstance (rsfType) as ResourceProviderFactory;
490 provider_factory = rpf;
494 internal static IResourceProvider GetResourceProvider (string key, bool isLocal)
496 if (!EnsureProviderFactory ())
499 IResourceProvider rp = null;
500 if (!resource_providers.TryGetValue (key, out rp)) {
502 rp = provider_factory.CreateLocalResourceProvider (key);
504 rp = provider_factory.CreateGlobalResourceProvider (key);
507 resource_providers.Add (key, rp);
513 static object GetGlobalObjectFromFactory (string classKey, string resourceKey, CultureInfo culture)
515 // FIXME: Retention of data
516 IResourceProvider rp = GetResourceProvider (classKey, false);
520 return rp.GetObject (resourceKey, culture);
523 public static object GetGlobalResourceObject (string classKey, string resourceKey, CultureInfo culture)
525 object ret = GetGlobalObjectFromFactory (classKey, resourceKey, culture);
529 if (AppGlobalResourcesAssembly == null)
532 return GetResourceObject ("Resources." + classKey, resourceKey, culture, AppGlobalResourcesAssembly);
535 public static object GetLocalResourceObject (string virtualPath, string resourceKey)
537 return GetLocalResourceObject (virtualPath, resourceKey, Thread.CurrentThread.CurrentUICulture);
540 static object GetLocalObjectFromFactory (string virtualPath, string resourceKey, CultureInfo culture)
542 IResourceProvider rp = GetResourceProvider (virtualPath, true);
546 return rp.GetObject (resourceKey, culture);
549 public static object GetLocalResourceObject (string virtualPath, string resourceKey, CultureInfo culture)
551 if (!VirtualPathUtility.IsAbsolute (virtualPath))
552 throw new ArgumentException ("The specified virtualPath was not rooted.");
554 object ret = GetLocalObjectFromFactory (virtualPath, resourceKey, culture);
558 string path = VirtualPathUtility.GetDirectory (virtualPath);
559 Assembly asm = AppResourcesCompiler.GetCachedLocalResourcesAssembly (path);
561 AppResourcesCompiler ac = new AppResourcesCompiler (path);
564 throw new MissingManifestResourceException ("A resource object was not found at the specified virtualPath.");
567 path = Path.GetFileName (virtualPath);
568 return GetResourceObject (path, resourceKey, culture, asm);
571 public object GetSection (string name)
573 return WebConfigurationManager.GetSection (name);
576 sealed class ResourceManagerCacheKey
578 readonly string _name;
579 readonly Assembly _asm;
581 public ResourceManagerCacheKey (string name, Assembly asm)
587 public override bool Equals (object obj)
589 if (!(obj is ResourceManagerCacheKey))
591 ResourceManagerCacheKey key = (ResourceManagerCacheKey) obj;
592 return key._asm == _asm && _name.Equals (key._name, StringComparison.Ordinal);
595 public override int GetHashCode ()
597 return _name.GetHashCode () + _asm.GetHashCode ();
601 object IServiceProvider.GetService (Type service)
603 if (service == typeof (HttpWorkerRequest))
604 return WorkerRequest;
607 // We return everything out of properties in case
608 // they are dynamically computed in some form in the future.
610 if (service == typeof (HttpApplication))
611 return ApplicationInstance;
613 if (service == typeof (HttpRequest))
616 if (service == typeof (HttpResponse))
619 if (service == typeof (HttpSessionState))
622 if (service == typeof (HttpApplicationState))
625 if (service == typeof (IPrincipal))
628 if (service == typeof (Cache))
631 if (service == typeof (HttpContext))
634 if (service == typeof (IHttpHandler))
637 if (service == typeof (HttpServerUtility))
640 if (service == typeof (TraceContext))
647 public void RemapHandler (IHttpHandler handler)
649 if (MapRequestHandlerDone)
650 throw new InvalidOperationException ("The RemapHandler method was called after the MapRequestHandler event occurred.");
655 public void RewritePath (string path)
658 RewritePath (path, true);
660 RewritePath (path, false);
664 public void RewritePath (string filePath, string pathInfo, string queryString)
666 RewritePath (filePath, pathInfo, queryString, false);
674 void RewritePath (string path, bool rebaseClientPath)
676 int qmark = path.IndexOf ('?');
678 RewritePath (path.Substring (0, qmark), "", path.Substring (qmark + 1), rebaseClientPath);
680 RewritePath (path, null, null, rebaseClientPath);
688 void RewritePath (string filePath, string pathInfo, string queryString, bool setClientFilePath)
690 if (filePath == null)
691 throw new ArgumentNullException ("filePath");
692 if (!VirtualPathUtility.IsValidVirtualPath (filePath))
693 throw new HttpException ("'" + HttpUtility.HtmlEncode (filePath) + "' is not a valid virtual path.");
695 bool pathRelative = VirtualPathUtility.IsAppRelative (filePath);
696 bool pathAbsolute = pathRelative ? false : VirtualPathUtility.IsAbsolute (filePath);
697 if (pathRelative || pathAbsolute) {
698 bool needSubstring = false;
700 if (pathRelative && filePath.Length > 1)
701 needSubstring = true;
703 string bvd = Request.BaseVirtualDir;
707 string canonizedFilePath = VirtualPathUtility.Canonize (filePath);
708 filePath = VirtualPathUtility.Combine (bvd, needSubstring ? canonizedFilePath.Substring (2) : canonizedFilePath);
710 filePath = VirtualPathUtility.Combine (VirtualPathUtility.GetDirectory (Request.FilePath), filePath);
712 if (!StrUtils.StartsWith (filePath, HttpRuntime.AppDomainAppVirtualPath))
713 throw new HttpException (404, "The virtual path '" + HttpUtility.HtmlEncode (filePath) + "' maps to another application.", filePath);
715 Request.SetCurrentExePath (filePath);
716 if (setClientFilePath)
717 Request.SetFilePath (filePath);
719 // A null pathInfo or queryString is ignored and previous values remain untouched
720 if (pathInfo != null)
721 Request.SetPathInfo (pathInfo);
723 if (queryString != null)
724 Request.QueryStringRaw = queryString;
729 internal void SetSession (HttpSessionState state)
731 session_state = state;
734 // URL of a page used for error redirection.
735 internal string ErrorPage {
745 internal TimeSpan ConfigTimeout {
747 if (config_timeout == null) {
749 HttpRuntimeSection section = (HttpRuntimeSection)WebConfigurationManager.GetSection ("system.web/httpRuntime");
750 config_timeout = section.ExecutionTimeout;
752 HttpRuntimeConfig config = (HttpRuntimeConfig)
753 GetConfig ("system.web/httpRuntime");
754 config_timeout = new TimeSpan (0, 0, config.ExecutionTimeout);
758 return (TimeSpan) config_timeout;
762 config_timeout = value;
765 TimeSpan remaining = value - (DateTime.UtcNow - time_stamp);
766 long remaining_ms = Math.Max ((long)remaining.TotalMilliseconds, 0);
768 // See http://msdn2.microsoft.com/en-us/library/7hs7492w.aspx
769 if (remaining_ms > 4294967294)
770 remaining_ms = 4294967294;
772 timer.Change (remaining_ms, (long)Timeout.Infinite);
779 void TimeoutReached(object state) {
780 HttpRuntime.QueuePendingRequest (false);
781 if (Interlocked.CompareExchange (ref timeout_possible, 0, 0) == 0) {
782 timer.Change(2000, 0);
787 thread.Abort (new StepTimeout ());
790 internal void StartTimeoutTimer() {
791 thread = Thread.CurrentThread;
792 timer = new Timer (TimeoutReached, null, (int)ConfigTimeout.TotalMilliseconds, Timeout.Infinite);
795 internal void StopTimeoutTimer() {
802 internal bool TimeoutPossible {
803 get { return (Interlocked.CompareExchange (ref timeout_possible, 1, 1) == 1); }
806 internal void BeginTimeoutPossible ()
808 timeout_possible = 1;
811 internal void EndTimeoutPossible ()
813 Interlocked.CompareExchange (ref timeout_possible, 0, 1);