2010-04-21 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / System.Web / System.Web / HttpContext.cs
index fffd779b321c5deadce5b129a36b5608b5457667..d183afa0f4d31b816f5d2605417568a5e7fa9617 100644 (file)
@@ -4,10 +4,11 @@
 // Author:
 //     Miguel de Icaza (miguel@novell.com)
 //     Gonzalo Paniagua Javier (gonzalo@novell.com)
+//      Marek Habersack <mhabersack@novell.com>
 //
 
 //
-// 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,20 +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.Reflection;
 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 partial class HttpContext : IServiceProvider {
+       public sealed partial class HttpContext : IServiceProvider
+       {
                internal HttpWorkerRequest WorkerRequest;
                HttpApplication app_instance;
                HttpRequest request;
@@ -74,10 +75,13 @@ namespace System.Web {
                Timer timer;
                Thread thread;
                bool _isProcessingInclude;
-
-#if NET_2_0
+               
                [ThreadStatic]
                static ResourceProviderFactory provider_factory;
+
+               [ThreadStatic]
+               static DefaultResourceProviderFactory default_provider_factory;
+               
                [ThreadStatic]
                static Dictionary <string, IResourceProvider> resource_providers;
                
@@ -88,26 +92,36 @@ namespace System.Web {
                        set { AppDomain.CurrentDomain.SetData (app_global_res_key, value); }
                }
 #else
-               [ThreadStatic]
-               static Dictionary <ResourceManagerCacheKey, ResourceManager> resourceManagerCache;
                internal static Assembly AppGlobalResourcesAssembly;
 #endif
                ProfileBase profile = null;
                LinkedList<IHttpHandler> handlers;
-#endif
+
+               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 {
@@ -205,19 +219,7 @@ namespace System.Web {
 
                internal bool IsCustomErrorEnabledUnsafe {
                        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 {
-                               }
-
-                               if (cfg == null)
-                                       return false;
-#endif
-
                                if (cfg.Mode == CustomErrorMode.On)
                                        return true;
 
@@ -226,18 +228,7 @@ namespace System.Web {
                }
 #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 {
@@ -310,7 +301,11 @@ namespace System.Web {
                        }
                }
 
-#if NET_2_0
+               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 {
@@ -382,7 +377,6 @@ namespace System.Web {
                                profile = value;
                        }
                }
-#endif
 
                public void AddError (Exception errorInfo)
                {
@@ -420,9 +414,7 @@ namespace System.Web {
                        errors = null;
                }
 
-#if NET_2_0
                [Obsolete ("use WebConfigurationManager.GetWebApplicationSection")]
-#endif
                public static object GetAppConfig (string name)
                {
                        object o = ConfigurationSettings.GetConfig (name);
@@ -430,93 +422,93 @@ 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
-               static object GetResourceObject (string classKey, string resourceKey, CultureInfo culture, Assembly assembly)
-               {
-                       ResourceManager rm;
-                       try {
-                               if (resourceManagerCache == null)
-                                       resourceManagerCache = new Dictionary <ResourceManagerCacheKey, ResourceManager> ();
-                               
-                               ResourceManagerCacheKey key = new ResourceManagerCacheKey (classKey, assembly);
-                               if (!resourceManagerCache.TryGetValue (key, out rm)) {
-                                       rm = new ResourceManager (classKey, assembly);
-                                       rm.IgnoreCase = true;
-                                       resourceManagerCache.Add (key, rm);
-                               }
-                               
-                               return rm.GetObject (resourceKey, culture);
-                       } catch (MissingManifestResourceException) {
-                               throw;
-                       } catch (Exception ex) {
-                               throw new HttpException ("Failed to retrieve the specified global resource object.", ex);
-                       }
-               }
-               
                public static object GetGlobalResourceObject (string classKey, string resourceKey)
                {
                        return GetGlobalResourceObject (classKey, resourceKey, Thread.CurrentThread.CurrentUICulture);
                }
 
-               static object GetGlobalObjectFromFactory (string classKey, string resourceKey, CultureInfo culture)
+               static bool EnsureProviderFactory ()
                {
-                       // FIXME: Retention of data
+                       if (resource_providers == null)
+                               resource_providers = new Dictionary <string, IResourceProvider> ();
 
-                       if (provider_factory == null) {
-                               GlobalizationSection gs = WebConfigurationManager.GetSection ("system.web/globalization") as GlobalizationSection;
+                       if (provider_factory != null)
+                               return true;
+                       
+                       GlobalizationSection gs = WebConfigurationManager.GetSection ("system.web/globalization") as GlobalizationSection;
 
-                               if (gs == null)
-                                       return null;
+                       if (gs == null)
+                               return false;
 
-                               String rsfTypeName = gs.ResourceProviderFactoryType;
-                               if (String.IsNullOrEmpty (rsfTypeName))
-                                       return null;
+                       String rsfTypeName = gs.ResourceProviderFactoryType;
+                       bool usingDefault = false;
+                       if (String.IsNullOrEmpty (rsfTypeName)) {
+                               usingDefault = true;
+                               rsfTypeName = typeof (DefaultResourceProviderFactory).AssemblyQualifiedName;
+                       }
                        
-                               Type rsfType = Type.GetType (rsfTypeName, true);
-                               ResourceProviderFactory rpf = Activator.CreateInstance (rsfType) as ResourceProviderFactory;
+                       Type rsfType = HttpApplication.LoadType (rsfTypeName, true);
+                       ResourceProviderFactory rpf = Activator.CreateInstance (rsfType) as ResourceProviderFactory;
                        
-                               if (rpf == null)
-                                       return null;
+                       if (rpf == null && usingDefault)
+                               return false;
 
-                               provider_factory = rpf;
-                       }
+                       provider_factory = rpf;
+                       if (usingDefault)
+                               default_provider_factory = rpf as DefaultResourceProviderFactory;
+                       
+                       return true;
+               }
+               
+               internal static IResourceProvider GetResourceProvider (string virtualPath, bool isLocal)
+               {
+                       if (!EnsureProviderFactory ())
+                               return null;
 
-                       if (resource_providers == null)
-                               resource_providers = new Dictionary <string, IResourceProvider> ();
+                       // 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);
 
-                       IResourceProvider rp;
-                       if (!resource_providers.TryGetValue (classKey, out rp)) {
-                               rp = provider_factory.CreateGlobalResourceProvider (classKey);
-                               if (rp == null)
-                                       return null;
-                               resource_providers.Add (classKey, rp);
+                                       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)
                {
-                       object ret = GetGlobalObjectFromFactory (classKey, resourceKey, culture);
-                       if (ret != null)
-                               return ret;
-                       
-                       if (AppGlobalResourcesAssembly == null)
-                               return null;
-
-                       return GetResourceObject ("Resources." + classKey, resourceKey, culture, AppGlobalResourcesAssembly);
+                       return GetGlobalObjectFromFactory ("Resources." + classKey, resourceKey, culture);
                }
 
                public static object GetLocalResourceObject (string virtualPath, string resourceKey)
@@ -524,22 +516,21 @@ namespace System.Web {
                        return GetLocalResourceObject (virtualPath, resourceKey, Thread.CurrentThread.CurrentUICulture);
                }
 
+               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)
                {
                        if (!VirtualPathUtility.IsAbsolute (virtualPath))
                                throw new ArgumentException ("The specified virtualPath was not rooted.");
-                       
-                       string path = Path.GetDirectoryName (virtualPath);
-                       Assembly asm = AppResourcesCompiler.GetCachedLocalResourcesAssembly (path);
-                       if (asm == null) {
-                               AppResourcesCompiler ac = new AppResourcesCompiler (path);
-                               asm = ac.Compile ();
-                               if (asm == null)
-                                       throw new MissingManifestResourceException ("A resource object was not found at the specified virtualPath.");
-                       }
-                       
-                       path = Path.GetFileName (virtualPath);
-                       return GetResourceObject (path, resourceKey, culture, asm);
+
+                       return GetLocalObjectFromFactory (virtualPath, resourceKey, culture);
                }
 
                public object GetSection (string name)
@@ -547,31 +538,6 @@ namespace System.Web {
                        return WebConfigurationManager.GetSection (name);
                }
 
-               sealed class ResourceManagerCacheKey
-               {
-                       readonly string _name;
-                       readonly Assembly _asm;
-
-                       public ResourceManagerCacheKey (string name, Assembly asm)
-                       {
-                               _name = name;
-                               _asm = asm;
-                       }
-
-                       public override bool Equals (object obj)
-                       {
-                               if (!(obj is ResourceManagerCacheKey))
-                                       return false;
-                               ResourceManagerCacheKey key = (ResourceManagerCacheKey) obj;
-                               return key._asm == _asm && _name.Equals (key._name, StringComparison.Ordinal);
-                       }
-
-                       public override int GetHashCode ()
-                       {
-                               return _name.GetHashCode () + _asm.GetHashCode ();
-                       }
-               }
-#endif
                object IServiceProvider.GetService (Type service)
                {
                        if (service == typeof (HttpWorkerRequest))
@@ -617,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)
@@ -631,54 +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)
                {
                        if (filePath == null)
                                throw new ArgumentNullException ("filePath");
                        if (!VirtualPathUtility.IsValidVirtualPath (filePath))
                                throw new HttpException ("'" + HttpUtility.HtmlEncode (filePath) + "' is not a valid virtual path.");
 
-                       if (VirtualPathUtility.IsRooted (filePath))
-                               filePath = VirtualPathUtility.Combine (Request.BaseVirtualDir, VirtualPathUtility.Canonize (filePath).Substring (1));
-                       else
-                               filePath = VirtualPathUtility.Combine (VirtualPathUtility.GetDirectory (Request.FilePath), filePath);
-
+                       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)
-                               Request.SetFilePath (filePath);
+                               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;
+                               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;
@@ -698,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;
@@ -728,8 +696,16 @@ namespace System.Web {
                        }
                }
 
+#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;