X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem.Web%2FSystem.Web%2FHttpContext.cs;h=d183afa0f4d31b816f5d2605417568a5e7fa9617;hb=9b87d46bdf11e08d30fe313737bd3822dbc21cbd;hp=603ada3e0cf57ed8ec234f8e4ec82410f8287a1b;hpb=53e266903ec6b2d822cf5b0c566f6374df5307a4;p=mono.git diff --git a/mcs/class/System.Web/System.Web/HttpContext.cs b/mcs/class/System.Web/System.Web/HttpContext.cs index 603ada3e0cf..d183afa0f4d 100644 --- a/mcs/class/System.Web/System.Web/HttpContext.cs +++ b/mcs/class/System.Web/System.Web/HttpContext.cs @@ -4,10 +4,11 @@ // Author: // Miguel de Icaza (miguel@novell.com) // Gonzalo Paniagua Javier (gonzalo@novell.com) +// Marek Habersack // // -// Copyright (C) 2005 Novell, Inc (http://www.novell.com) +// Copyright (C) 2005-2009 Novell, Inc (http://www.novell.com) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -41,18 +42,20 @@ using System.Web.Configuration; using System.Web.SessionState; using System.Web.UI; using System.Web.Util; -#if NET_2_0 using System.Reflection; +using System.Collections.Generic; +using System.IO; using System.Resources; +using System.Web.Compilation; using System.Web.Profile; using CustomErrorMode = System.Web.Configuration.CustomErrorsMode; -#endif -namespace System.Web { - +namespace System.Web +{ // CAS - no InheritanceDemand here as the class is sealed [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] - public sealed class HttpContext : IServiceProvider { + public sealed partial class HttpContext : IServiceProvider + { internal HttpWorkerRequest WorkerRequest; HttpApplication app_instance; HttpRequest request; @@ -69,25 +72,61 @@ namespace System.Web { object config_timeout; int timeout_possible; DateTime time_stamp = DateTime.UtcNow; -#if NET_2_0 - ProfileBase profile = null; -#endif -#if TARGET_JVM // No remoting support (CallContext) yet in Grasshopper - static LocalDataStoreSlot _ContextSlot = Thread.GetNamedDataSlot ("Context"); + Timer timer; + Thread thread; + bool _isProcessingInclude; + + [ThreadStatic] + static ResourceProviderFactory provider_factory; + + [ThreadStatic] + static DefaultResourceProviderFactory default_provider_factory; + + [ThreadStatic] + static Dictionary resource_providers; + +#if TARGET_JVM + const string app_global_res_key = "HttpContext.app_global_res_key"; + internal static Assembly AppGlobalResourcesAssembly { + get { return (Assembly) AppDomain.CurrentDomain.GetData (app_global_res_key); } + set { AppDomain.CurrentDomain.SetData (app_global_res_key, value); } + } +#else + internal static Assembly AppGlobalResourcesAssembly; #endif + ProfileBase profile = null; + LinkedList handlers; + + static DefaultResourceProviderFactory DefaultProviderFactory { + get { + if (default_provider_factory == null) + default_provider_factory = new DefaultResourceProviderFactory (); + return default_provider_factory; + } + } public HttpContext (HttpWorkerRequest wr) { WorkerRequest = wr; request = new HttpRequest (WorkerRequest, this); response = new HttpResponse (WorkerRequest, this); +#if NET_4_0 + SessionStateBehavior = SessionStateBehavior.Default; +#endif } public HttpContext (HttpRequest request, HttpResponse response) { this.request = request; this.response = response; - +#if NET_4_0 + SessionStateBehavior = SessionStateBehavior.Default; +#endif + } + + internal bool IsProcessingInclude { + get { return _isProcessingInclude; } + set { _isProcessingInclude = value; } } public Exception [] AllErrors { @@ -127,18 +166,17 @@ namespace System.Web { } } + internal Cache InternalCache { + get { + return HttpRuntime.InternalCache; + } + } + // // The "Current" property is set just after we have constructed it with // the 'HttpContext (HttpWorkerRequest)' constructor. // -#if TARGET_JVM // No remoting support (CallContext) yet in Grasshopper - [MonoTODO("Context - Use System.Remoting.Messaging.CallContext instead of Thread storage")] - public static HttpContext Current - { - get { return (HttpContext) Thread.GetData (_ContextSlot); } - set { Thread.SetData (_ContextSlot, value); } - } -#else +#if !TARGET_JVM // No remoting CallContext support in Grasshopper public static HttpContext Current { get { return (HttpContext) CallContext.GetData ("c"); @@ -170,42 +208,27 @@ namespace System.Web { public bool IsCustomErrorEnabled { get { -#if NET_2_0 - CustomErrorsSection cfg = (CustomErrorsSection) WebConfigurationManager.GetSection ("system.web/customErrors"); -#else - CustomErrorsConfig cfg = null; try { - cfg = (CustomErrorsConfig) GetConfig ("system.web/customErrors"); - } catch { + return IsCustomErrorEnabledUnsafe; } - - if (cfg == null) + catch { return false; -#endif + } + } + } + internal bool IsCustomErrorEnabledUnsafe { + get { + CustomErrorsSection cfg = (CustomErrorsSection) WebConfigurationManager.GetSection ("system.web/customErrors"); if (cfg.Mode == CustomErrorMode.On) return true; - return (cfg.Mode == CustomErrorMode.RemoteOnly) && - (Request.WorkerRequest.GetLocalAddress () != Request.UserHostAddress); + return (cfg.Mode == CustomErrorMode.RemoteOnly) && !Request.IsLocal; } } -#if TARGET_JVM - public bool IsDebuggingEnabled { get { return false; } } -#else +#if !TARGET_JVM public bool IsDebuggingEnabled { - get { -#if NET_2_0 - CompilationSection section = (CompilationSection) WebConfigurationManager.GetSection ("system.web/compilation"); - return section.Debug; -#else - try { - return CompilationConfiguration.GetInstance (this).Debug; - } catch { - return false; - } -#endif - } + get { return RuntimeHelpers.DebuggingEnabled; } } #endif public IDictionary Items { @@ -278,20 +301,69 @@ namespace System.Web { } } -#if NET_2_0 - [MonoTODO ("Not implemented")] + internal bool MapRequestHandlerDone { + get; + set; + } + + // The two properties below are defined only when the IIS7 integrated mode is used. + // They are useless under Mono + public RequestNotification CurrentNotification { + get { throw new PlatformNotSupportedException ("This property is not supported on Mono."); } + } + + public bool IsPostNotification { + get { throw new PlatformNotSupportedException ("This property is not supported on Mono."); } + } + + internal void PushHandler (IHttpHandler handler) + { + if (handler == null) + return; + if (handlers == null) + handlers = new LinkedList (); + handlers.AddLast (handler); + } + + internal void PopHandler () + { + if (handlers == null || handlers.Count == 0) + return; + handlers.RemoveLast (); + } + + IHttpHandler GetCurrentHandler () + { + if (handlers == null || handlers.Count == 0) + return null; + + return handlers.Last.Value; + } + + IHttpHandler GetPreviousHandler () + { + if (handlers == null || handlers.Count <= 1) + return null; + LinkedListNode previous = handlers.Last.Previous; + if (previous != null) + return previous.Value; + return null; + } + public IHttpHandler CurrentHandler { - get { throw new NotImplementedException (); } + get { return GetCurrentHandler (); } } - [MonoTODO ("Not implemented")] public IHttpHandler PreviousHandler { - get { throw new NotImplementedException (); } + get { return GetPreviousHandler (); } + } + + internal bool ProfileInitialized { + get { return profile != null; } } public ProfileBase Profile { - get - { + get { if (profile == null) { if (Request.IsAuthenticated) profile = ProfileBase.Create (User.Identity.Name); @@ -300,8 +372,11 @@ namespace System.Web { } return profile; } + + internal set { + profile = value; + } } -#endif public void AddError (Exception errorInfo) { @@ -325,14 +400,21 @@ namespace System.Web { errors = null; } + internal bool HasError (Exception e) + { + if (errors == e) + return true; + + return (errors is ArrayList) ? + ((ArrayList) errors).Contains (e) : false; + } + public void ClearError () { errors = null; } -#if NET_2_0 [Obsolete ("use WebConfigurationManager.GetWebApplicationSection")] -#endif public static object GetAppConfig (string name) { object o = ConfigurationSettings.GetConfig (name); @@ -340,104 +422,122 @@ namespace System.Web { return o; } -#if NET_2_0 [Obsolete ("see GetSection")] -#endif public object GetConfig (string name) { -#if NET_2_0 return GetSection (name); -#else - return WebConfigurationSettings.GetConfig (name, this); -#endif } -#if NET_2_0 - internal static Type GetGLResourceType (string typeName) + public static object GetGlobalResourceObject (string classKey, string resourceKey) { - Type type = null; - Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies (); + return GetGlobalResourceObject (classKey, resourceKey, Thread.CurrentThread.CurrentUICulture); + } - foreach (Assembly ass in assemblies) { - type = ass.GetType (typeName); - if (type == null) - continue; + static bool EnsureProviderFactory () + { + if (resource_providers == null) + resource_providers = new Dictionary (); - return type; - } + if (provider_factory != null) + return true; + + GlobalizationSection gs = WebConfigurationManager.GetSection ("system.web/globalization") as GlobalizationSection; - throw new MissingManifestResourceException (String.Format ("Missing resource class {0}", typeName)); - } + if (gs == null) + return false; - internal static object GetGLResourceObject (Type type, string resourceKey) - { - object ret = null; - try { - PropertyInfo pi = type.GetProperty (resourceKey, - BindingFlags.GetProperty | - BindingFlags.Public | - BindingFlags.Static); - if (pi == null) - return null; - ret = pi.GetValue (null, null); - } catch { + String rsfTypeName = gs.ResourceProviderFactoryType; + bool usingDefault = false; + if (String.IsNullOrEmpty (rsfTypeName)) { + usingDefault = true; + rsfTypeName = typeof (DefaultResourceProviderFactory).AssemblyQualifiedName; } - return ret; - } + Type rsfType = HttpApplication.LoadType (rsfTypeName, true); + ResourceProviderFactory rpf = Activator.CreateInstance (rsfType) as ResourceProviderFactory; + + if (rpf == null && usingDefault) + return false; - internal static void SetGLResourceObjectCulture (Type type, CultureInfo ci) - { - try { - PropertyInfo pi = type.GetProperty ("Culture", - BindingFlags.SetProperty | - BindingFlags.Public | - BindingFlags.Static); - if (pi == null) - return; // internal error actually... - pi.SetValue (null, ci, null); - } catch { - } + provider_factory = rpf; + if (usingDefault) + default_provider_factory = rpf as DefaultResourceProviderFactory; + + return true; } - public static object GetGlobalResourceObject (string classKey, string resourceKey) + internal static IResourceProvider GetResourceProvider (string virtualPath, bool isLocal) { - string className = String.Format ("System.Resources.{0}", classKey); - Type type = GetGLResourceType (className); - SetGLResourceObjectCulture (type, null); - return GetGLResourceObject (type, resourceKey); + if (!EnsureProviderFactory ()) + return null; + + // TODO: check if it makes sense to cache the providers and, if yes, maybe + // we should expire the entries (or just store them in InternalCache?) + IResourceProvider rp = null; + if (!resource_providers.TryGetValue (virtualPath, out rp)) { + if (isLocal) + rp = provider_factory.CreateLocalResourceProvider (virtualPath); + else + rp = provider_factory.CreateGlobalResourceProvider (virtualPath); + + if (rp == null) { + if (isLocal) + rp = DefaultProviderFactory.CreateLocalResourceProvider (virtualPath); + else + rp = DefaultProviderFactory.CreateGlobalResourceProvider (virtualPath); + + if (rp == null) + return null; + } + + resource_providers.Add (virtualPath, rp); + } + + return rp; } + static object GetGlobalObjectFromFactory (string classKey, string resourceKey, CultureInfo culture) + { + // FIXME: Retention of data + IResourceProvider rp = GetResourceProvider (classKey, false); + if (rp == null) + return null; + + return rp.GetObject (resourceKey, culture); + } + public static object GetGlobalResourceObject (string classKey, string resourceKey, CultureInfo culture) { - string className = String.Format ("System.Resources.{0}", classKey); - Type type = GetGLResourceType (className); - SetGLResourceObjectCulture (type, culture); - return GetGLResourceObject (type, resourceKey); + return GetGlobalObjectFromFactory ("Resources." + classKey, resourceKey, culture); } - [MonoTODO ("Not implemented")] public static object GetLocalResourceObject (string virtualPath, string resourceKey) { - throw new NotImplementedException (); + return GetLocalResourceObject (virtualPath, resourceKey, Thread.CurrentThread.CurrentUICulture); } - [MonoTODO ("Not implemented")] + static object GetLocalObjectFromFactory (string virtualPath, string resourceKey, CultureInfo culture) + { + IResourceProvider rp = GetResourceProvider (virtualPath, true); + if (rp == null) + return null; + + return rp.GetObject (resourceKey, culture); + } + public static object GetLocalResourceObject (string virtualPath, string resourceKey, CultureInfo culture) { - throw new NotImplementedException (); + if (!VirtualPathUtility.IsAbsolute (virtualPath)) + throw new ArgumentException ("The specified virtualPath was not rooted."); + + return GetLocalObjectFromFactory (virtualPath, resourceKey, culture); } - [MonoTODO ("Only implemented for ASP.NET 2.x applications")] public object GetSection (string name) { -#if NET_2_0 return WebConfigurationManager.GetSection (name); -#else - throw new NotImplementedException (); -#endif } -#endif + object IServiceProvider.GetService (Type service) { if (service == typeof (HttpWorkerRequest)) @@ -483,13 +583,16 @@ namespace System.Web { return null; } + public void RemapHandler (IHttpHandler handler) + { + if (MapRequestHandlerDone) + throw new InvalidOperationException ("The RemapHandler method was called after the MapRequestHandler event occurred."); + Handler = handler; + } + public void RewritePath (string path) { -#if NET_2_0 RewritePath (path, true); -#else - RewritePath (path, false); -#endif } public void RewritePath (string filePath, string pathInfo, string queryString) @@ -497,47 +600,59 @@ namespace System.Web { RewritePath (filePath, pathInfo, queryString, false); } -#if NET_2_0 - public -#else - internal -#endif - void RewritePath (string path, bool rebaseClientPath) + public void RewritePath (string path, bool rebaseClientPath) { int qmark = path.IndexOf ('?'); if (qmark != -1) - RewritePath (path.Substring (0, qmark), "", path.Substring (qmark + 1), rebaseClientPath); + RewritePath (path.Substring (0, qmark), String.Empty, path.Substring (qmark + 1), rebaseClientPath); else RewritePath (path, null, null, rebaseClientPath); } -#if NET_2_0 - public -#else - internal -#endif - void RewritePath (string filePath, string pathInfo, string queryString, bool setClientFilePath) + public void RewritePath (string filePath, string pathInfo, string queryString, bool setClientFilePath) { - filePath = UrlUtils.Combine (Request.BaseVirtualDir, filePath); - if (!filePath.StartsWith (HttpRuntime.AppDomainAppVirtualPath)) - throw new HttpException (404, "The virtual path '" + filePath + - "' maps to another application."); + if (filePath == null) + throw new ArgumentNullException ("filePath"); + if (!VirtualPathUtility.IsValidVirtualPath (filePath)) + throw new HttpException ("'" + HttpUtility.HtmlEncode (filePath) + "' is not a valid virtual path."); + + bool pathRelative = VirtualPathUtility.IsAppRelative (filePath); + bool pathAbsolute = pathRelative ? false : VirtualPathUtility.IsAbsolute (filePath); + HttpRequest req = Request; + if (req == null) + return; + + if (pathRelative || pathAbsolute) { + if (pathRelative) + filePath = VirtualPathUtility.ToAbsolute (filePath); + } else + filePath = VirtualPathUtility.AppendTrailingSlash (req.BaseVirtualDir) + filePath; + + if (!StrUtils.StartsWith (filePath, HttpRuntime.AppDomainAppVirtualPath)) + throw new HttpException (404, "The virtual path '" + HttpUtility.HtmlEncode (filePath) + "' maps to another application.", filePath); - Request.SetCurrentExePath (filePath); + req.SetCurrentExePath (filePath); + req.SetFilePath (filePath); + + if (setClientFilePath) + req.ClientFilePath = filePath; + // A null pathInfo or queryString is ignored and previous values remain untouched if (pathInfo != null) - Request.SetPathInfo (pathInfo); + req.SetPathInfo (pathInfo); if (queryString != null) - Request.QueryStringRaw = queryString; -#if NET_2_0 - if (setClientFilePath) - Request.SetFilePath (filePath); -#endif + req.QueryStringRaw = queryString; } -#region internals +#if NET_4_0 + public void SetSessionStateBehavior (SessionStateBehavior sessionStateBehavior) + { + SessionStateBehavior = sessionStateBehavior; + } +#endif +#region internals internal void SetSession (HttpSessionState state) { session_state = state; @@ -557,14 +672,8 @@ namespace System.Web { internal TimeSpan ConfigTimeout { get { if (config_timeout == null) { -#if NET_2_0 HttpRuntimeSection section = (HttpRuntimeSection)WebConfigurationManager.GetSection ("system.web/httpRuntime"); config_timeout = section.ExecutionTimeout; -#else - HttpRuntimeConfig config = (HttpRuntimeConfig) - GetConfig ("system.web/httpRuntime"); - config_timeout = new TimeSpan (0, 0, config.ExecutionTimeout); -#endif } return (TimeSpan) config_timeout; @@ -572,16 +681,50 @@ namespace System.Web { set { config_timeout = value; +#if !TARGET_J2EE + if (timer != null) { + TimeSpan remaining = value - (DateTime.UtcNow - time_stamp); + long remaining_ms = Math.Max ((long)remaining.TotalMilliseconds, 0); + + // See http://msdn2.microsoft.com/en-us/library/7hs7492w.aspx + if (remaining_ms > 4294967294) + remaining_ms = 4294967294; + + timer.Change (remaining_ms, (long)Timeout.Infinite); + } +#endif } } - internal bool CheckIfTimeout (DateTime t) - { - if (Interlocked.CompareExchange (ref timeout_possible, 0, 0) == 0) - return false; - - TimeSpan ts = t - time_stamp; - return (ts > ConfigTimeout); +#if NET_4_0 + internal SessionStateBehavior SessionStateBehavior { + get; + private set; + } +#endif + +#if !TARGET_J2EE + void TimeoutReached(object state) { + HttpRuntime.QueuePendingRequest (false); + if (Interlocked.CompareExchange (ref timeout_possible, 0, 0) == 0) { + timer.Change(2000, 0); + return; + } + StopTimeoutTimer(); + + thread.Abort (new StepTimeout ()); + } + + internal void StartTimeoutTimer() { + thread = Thread.CurrentThread; + timer = new Timer (TimeoutReached, null, (int)ConfigTimeout.TotalMilliseconds, Timeout.Infinite); + } + + internal void StopTimeoutTimer() { + if(timer != null) { + timer.Dispose (); + timer = null; + } } internal bool TimeoutPossible { @@ -597,20 +740,11 @@ namespace System.Web { { Interlocked.CompareExchange (ref timeout_possible, 0, 1); } -#endregion - -#if NET_2_0 - Page last_page; - - internal Page LastPage { - get { - return last_page; - } - - set { - last_page = value; - } - } #endif +#endregion + } + + class StepTimeout + { } }