2 // System.Web.HttpContext.cs
5 // Miguel de Icaza (miguel@novell.com)
6 // Gonzalo Paniagua Javier (gonzalo@novell.com)
7 // Marek Habersack <mhabersack@novell.com>
11 // Copyright (C) 2005-2009 Novell, Inc (http://www.novell.com)
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.Collections;
34 using System.Configuration;
35 using System.Globalization;
36 using System.Runtime.Remoting.Messaging;
37 using System.Security.Permissions;
38 using System.Security.Principal;
39 using System.Threading;
40 using System.Web.Caching;
41 using System.Web.Configuration;
42 using System.Web.SessionState;
44 using System.Web.Util;
45 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;
55 // CAS - no InheritanceDemand here as the class is sealed
56 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
57 public sealed partial class HttpContext : IServiceProvider
59 internal HttpWorkerRequest WorkerRequest;
60 HttpApplication app_instance;
62 HttpResponse response;
63 HttpSessionState session_state;
64 HttpServerUtility server;
65 TraceContext trace_context;
68 bool skip_authorization = false;
72 object config_timeout;
74 DateTime time_stamp = DateTime.UtcNow;
77 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;
108 public HttpContext (HttpWorkerRequest wr)
111 request = new HttpRequest (WorkerRequest, this);
112 response = new HttpResponse (WorkerRequest, this);
114 SessionStateBehavior = SessionStateBehavior.Default;
118 public HttpContext (HttpRequest request, HttpResponse response)
120 this.request = request;
121 this.response = response;
122 this.request.Context = this;
123 this.response.Context = this;
125 SessionStateBehavior = SessionStateBehavior.Default;
129 internal bool IsProcessingInclude {
130 get { return _isProcessingInclude; }
131 set { _isProcessingInclude = value; }
134 public Exception [] AllErrors {
139 if (errors is Exception){
140 Exception [] all = new Exception [1];
141 all [0] = (Exception) errors;
144 return (Exception []) (((ArrayList) errors).ToArray (typeof (Exception)));
148 public HttpApplicationState Application {
150 return HttpApplicationFactory.ApplicationState;
154 public HttpApplication ApplicationInstance {
160 app_instance = value;
167 return HttpRuntime.Cache;
171 internal Cache InternalCache {
173 return HttpRuntime.InternalCache;
178 // The "Current" property is set just after we have constructed it with
179 // the 'HttpContext (HttpWorkerRequest)' constructor.
181 #if !TARGET_JVM // No remoting CallContext support in Grasshopper
182 public static HttpContext Current {
184 return (HttpContext) CallContext.GetData ("c");
188 CallContext.SetData ("c", value);
193 public Exception Error {
195 if (errors == null || (errors is Exception))
196 return (Exception) errors;
197 return (Exception) (((ArrayList) errors) [0]);
201 public IHttpHandler Handler {
211 public bool IsCustomErrorEnabled {
214 return IsCustomErrorEnabledUnsafe;
222 internal bool IsCustomErrorEnabledUnsafe {
224 CustomErrorsSection cfg = (CustomErrorsSection) WebConfigurationManager.GetSection ("system.web/customErrors");
225 if (cfg.Mode == CustomErrorMode.On)
228 return (cfg.Mode == CustomErrorMode.RemoteOnly) && !Request.IsLocal;
232 public bool IsDebuggingEnabled {
233 get { return RuntimeHelpers.DebuggingEnabled; }
236 public IDictionary Items {
239 items = new Hashtable ();
244 public HttpRequest Request {
250 public HttpResponse Response {
256 public HttpServerUtility Server {
259 server = new HttpServerUtility (this);
264 public HttpSessionState Session {
266 return session_state;
270 public bool SkipAuthorization {
272 return skip_authorization;
275 [SecurityPermission (SecurityAction.Demand, ControlPrincipal = true)]
277 skip_authorization = value;
281 public DateTime Timestamp {
283 return time_stamp.ToLocalTime ();
287 public TraceContext Trace {
289 if (trace_context == null)
290 trace_context = new TraceContext (this);
291 return trace_context;
295 public IPrincipal User {
300 [SecurityPermission (SecurityAction.Demand, ControlPrincipal = true)]
306 internal bool MapRequestHandlerDone {
311 // The two properties below are defined only when the IIS7 integrated mode is used.
312 // They are useless under Mono
313 public RequestNotification CurrentNotification {
314 get { throw new PlatformNotSupportedException ("This property is not supported on Mono."); }
317 public bool IsPostNotification {
318 get { throw new PlatformNotSupportedException ("This property is not supported on Mono."); }
321 internal void PushHandler (IHttpHandler handler)
325 if (handlers == null)
326 handlers = new LinkedList <IHttpHandler> ();
327 handlers.AddLast (handler);
330 internal void PopHandler ()
332 if (handlers == null || handlers.Count == 0)
334 handlers.RemoveLast ();
337 IHttpHandler GetCurrentHandler ()
339 if (handlers == null || handlers.Count == 0)
342 return handlers.Last.Value;
345 IHttpHandler GetPreviousHandler ()
347 if (handlers == null || handlers.Count <= 1)
349 LinkedListNode <IHttpHandler> previous = handlers.Last.Previous;
350 if (previous != null)
351 return previous.Value;
355 public IHttpHandler CurrentHandler {
356 get { return GetCurrentHandler (); }
359 public IHttpHandler PreviousHandler {
360 get { return GetPreviousHandler (); }
363 internal bool ProfileInitialized {
364 get { return profile != null; }
367 public ProfileBase Profile {
369 if (profile == null) {
370 if (Request.IsAuthenticated)
371 profile = ProfileBase.Create (User.Identity.Name);
373 profile = ProfileBase.Create (Request.AnonymousID, false);
383 public void AddError (Exception errorInfo)
390 if (errors is Exception){
391 l = new ArrayList ();
395 l = (ArrayList) errors;
399 internal void ClearError (Exception e)
405 internal bool HasError (Exception e)
410 return (errors is ArrayList) ?
411 ((ArrayList) errors).Contains (e) : false;
414 public void ClearError ()
419 [Obsolete ("The recommended alternative is System.Web.Configuration.WebConfigurationManager.GetWebApplicationSection in System.Web.dll. http://go.microsoft.com/fwlink/?linkid=14202")]
420 public static object GetAppConfig (string name)
422 object o = ConfigurationSettings.GetConfig (name);
427 [Obsolete ("The recommended alternative is System.Web.HttpContext.GetSection in System.Web.dll. http://go.microsoft.com/fwlink/?linkid=14202")]
428 public object GetConfig (string name)
430 return GetSection (name);
433 public static object GetGlobalResourceObject (string classKey, string resourceKey)
435 return GetGlobalResourceObject (classKey, resourceKey, Thread.CurrentThread.CurrentUICulture);
438 static bool EnsureProviderFactory ()
440 if (resource_providers == null)
441 resource_providers = new Dictionary <string, IResourceProvider> ();
443 if (provider_factory != null)
446 GlobalizationSection gs = WebConfigurationManager.GetSection ("system.web/globalization") as GlobalizationSection;
451 String rsfTypeName = gs.ResourceProviderFactoryType;
452 bool usingDefault = false;
453 if (String.IsNullOrEmpty (rsfTypeName)) {
455 rsfTypeName = typeof (DefaultResourceProviderFactory).AssemblyQualifiedName;
458 Type rsfType = HttpApplication.LoadType (rsfTypeName, true);
459 ResourceProviderFactory rpf = Activator.CreateInstance (rsfType) as ResourceProviderFactory;
461 if (rpf == null && usingDefault)
464 provider_factory = rpf;
466 default_provider_factory = rpf as DefaultResourceProviderFactory;
471 internal static IResourceProvider GetResourceProvider (string virtualPath, bool isLocal)
473 if (!EnsureProviderFactory ())
476 // TODO: check if it makes sense to cache the providers and, if yes, maybe
477 // we should expire the entries (or just store them in InternalCache?)
478 IResourceProvider rp = null;
479 if (!resource_providers.TryGetValue (virtualPath, out rp)) {
481 rp = provider_factory.CreateLocalResourceProvider (virtualPath);
483 rp = provider_factory.CreateGlobalResourceProvider (virtualPath);
487 rp = DefaultProviderFactory.CreateLocalResourceProvider (virtualPath);
489 rp = DefaultProviderFactory.CreateGlobalResourceProvider (virtualPath);
495 resource_providers.Add (virtualPath, rp);
501 static object GetGlobalObjectFromFactory (string classKey, string resourceKey, CultureInfo culture)
503 // FIXME: Retention of data
504 IResourceProvider rp = GetResourceProvider (classKey, false);
508 return rp.GetObject (resourceKey, culture);
511 public static object GetGlobalResourceObject (string classKey, string resourceKey, CultureInfo culture)
513 return GetGlobalObjectFromFactory ("Resources." + classKey, resourceKey, culture);
516 public static object GetLocalResourceObject (string virtualPath, string resourceKey)
518 return GetLocalResourceObject (virtualPath, resourceKey, Thread.CurrentThread.CurrentUICulture);
521 static object GetLocalObjectFromFactory (string virtualPath, string resourceKey, CultureInfo culture)
523 IResourceProvider rp = GetResourceProvider (virtualPath, true);
527 return rp.GetObject (resourceKey, culture);
530 public static object GetLocalResourceObject (string virtualPath, string resourceKey, CultureInfo culture)
532 if (!VirtualPathUtility.IsAbsolute (virtualPath))
533 throw new ArgumentException ("The specified virtualPath was not rooted.");
535 return GetLocalObjectFromFactory (virtualPath, resourceKey, culture);
538 public object GetSection (string name)
540 return WebConfigurationManager.GetSection (name);
543 object IServiceProvider.GetService (Type service)
545 if (service == typeof (HttpWorkerRequest))
546 return WorkerRequest;
549 // We return everything out of properties in case
550 // they are dynamically computed in some form in the future.
552 if (service == typeof (HttpApplication))
553 return ApplicationInstance;
555 if (service == typeof (HttpRequest))
558 if (service == typeof (HttpResponse))
561 if (service == typeof (HttpSessionState))
564 if (service == typeof (HttpApplicationState))
567 if (service == typeof (IPrincipal))
570 if (service == typeof (Cache))
573 if (service == typeof (HttpContext))
576 if (service == typeof (IHttpHandler))
579 if (service == typeof (HttpServerUtility))
582 if (service == typeof (TraceContext))
588 public void RemapHandler (IHttpHandler handler)
590 if (MapRequestHandlerDone)
591 throw new InvalidOperationException ("The RemapHandler method was called after the MapRequestHandler event occurred.");
595 public void RewritePath (string path)
597 RewritePath (path, true);
600 public void RewritePath (string filePath, string pathInfo, string queryString)
602 RewritePath (filePath, pathInfo, queryString, false);
605 public void RewritePath (string path, bool rebaseClientPath)
607 int qmark = path.IndexOf ('?');
609 RewritePath (path.Substring (0, qmark), String.Empty, path.Substring (qmark + 1), rebaseClientPath);
611 RewritePath (path, null, null, rebaseClientPath);
614 public void RewritePath (string filePath, string pathInfo, string queryString, bool setClientFilePath)
616 if (filePath == null)
617 throw new ArgumentNullException ("filePath");
618 if (!VirtualPathUtility.IsValidVirtualPath (filePath))
619 throw new HttpException ("'" + HttpUtility.HtmlEncode (filePath) + "' is not a valid virtual path.");
621 filePath = VirtualPathUtility.Canonize (filePath);
622 bool pathRelative = VirtualPathUtility.IsAppRelative (filePath);
623 bool pathAbsolute = pathRelative ? false : VirtualPathUtility.IsAbsolute (filePath);
624 HttpRequest req = Request;
628 if (pathRelative || pathAbsolute) {
630 filePath = VirtualPathUtility.ToAbsolute (filePath);
632 filePath = VirtualPathUtility.AppendTrailingSlash (req.BaseVirtualDir) + filePath;
634 if (!StrUtils.StartsWith (filePath, HttpRuntime.AppDomainAppVirtualPath))
635 throw new HttpException (404, "The virtual path '" + HttpUtility.HtmlEncode (filePath) + "' maps to another application.", filePath);
637 req.SetCurrentExePath (filePath);
638 req.SetFilePath (filePath);
640 if (setClientFilePath)
641 req.ClientFilePath = filePath;
643 // A null pathInfo or queryString is ignored and previous values remain untouched
644 if (pathInfo != null)
645 req.SetPathInfo (pathInfo);
647 if (queryString != null)
648 req.QueryStringRaw = queryString;
652 public void SetSessionStateBehavior (SessionStateBehavior sessionStateBehavior)
654 SessionStateBehavior = sessionStateBehavior;
659 internal void SetSession (HttpSessionState state)
661 session_state = state;
664 // URL of a page used for error redirection.
665 internal string ErrorPage {
675 internal TimeSpan ConfigTimeout {
677 if (config_timeout == null) {
678 HttpRuntimeSection section = (HttpRuntimeSection)WebConfigurationManager.GetSection ("system.web/httpRuntime");
679 config_timeout = section.ExecutionTimeout;
682 return (TimeSpan) config_timeout;
686 config_timeout = value;
689 TimeSpan remaining = value - (DateTime.UtcNow - time_stamp);
690 long remaining_ms = Math.Max ((long)remaining.TotalMilliseconds, 0);
692 // See http://msdn2.microsoft.com/en-us/library/7hs7492w.aspx
693 if (remaining_ms > 4294967294)
694 remaining_ms = 4294967294;
696 timer.Change (remaining_ms, (long)Timeout.Infinite);
703 internal SessionStateBehavior SessionStateBehavior {
710 void TimeoutReached(object state) {
711 HttpRuntime.QueuePendingRequest (false);
712 if (Interlocked.CompareExchange (ref timeout_possible, 0, 0) == 0) {
713 timer.Change(2000, 0);
718 thread.Abort (new StepTimeout ());
721 internal void StartTimeoutTimer() {
722 thread = Thread.CurrentThread;
723 timer = new Timer (TimeoutReached, null, (int)ConfigTimeout.TotalMilliseconds, Timeout.Infinite);
726 internal void StopTimeoutTimer() {
733 internal bool TimeoutPossible {
734 get { return (Interlocked.CompareExchange (ref timeout_possible, 1, 1) == 1); }
737 internal void BeginTimeoutPossible ()
739 timeout_possible = 1;
742 internal void EndTimeoutPossible ()
744 Interlocked.CompareExchange (ref timeout_possible, 0, 1);