2007-07-21 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / System.Web / System.Web / HttpRuntime.cs
index acc36775988f5bc2f75cd8464f6395ad2ec4aa74..b442dd6b9a87f4da6f7c984a5164182753632bd6 100644 (file)
@@ -34,14 +34,16 @@ using System.IO;
 using System.Text;
 using System.Globalization;
 using System.Collections;
+using System.Reflection;
 using System.Security;
 using System.Security.Permissions;
 using System.Web.Caching;
 using System.Web.Configuration;
 using System.Web.UI;
+using System.Web.Util;
 using System.Threading;
 
-#if NET_2_0
+#if NET_2_0 && !TARGET_JVM
 using System.CodeDom.Compiler;
 using System.Web.Compilation;
 #endif
@@ -55,11 +57,13 @@ namespace System.Web {
                static QueueManager queue_manager { get { return _runtime._queue_manager; } }
                static TraceManager trace_manager { get { return _runtime._trace_manager; } }
                static Cache cache { get { return _runtime._cache; } }
+               static Cache internalCache { get { return _runtime._internalCache; } }
                static WaitCallback do_RealProcessRequest;
-
+               
                QueueManager _queue_manager;
                TraceManager _trace_manager;
                Cache _cache;
+               Cache _internalCache;
 
                static HttpRuntime ()
                {
@@ -68,38 +72,78 @@ namespace System.Web {
 
                public HttpRuntime ()
                {
+                       WebConfigurationManager.Init ();
                        _queue_manager = new QueueManager ();
                        _trace_manager = new TraceManager ();
                        _cache = new Cache ();
+                       _internalCache = new Cache();
                }
 
-               static private HttpRuntime _runtime {
+               static private HttpRuntime _runtimeInstance {
                        get {
-                               HttpRuntime runtime = (HttpRuntime)AppDomain.CurrentDomain.GetData("HttpRuntime");
+                               HttpRuntime runtime = (HttpRuntime) AppDomain.CurrentDomain.GetData ("HttpRuntime");
                                if (runtime == null)
-                                       lock (typeof(HttpRuntime)) {
-                                               runtime = (HttpRuntime)AppDomain.CurrentDomain.GetData("HttpRuntime");
+                                       lock (typeof (HttpRuntime)) {
+                                               runtime = (HttpRuntime) AppDomain.CurrentDomain.GetData ("HttpRuntime");
                                                if (runtime == null) {
-                                                       runtime = new HttpRuntime();
-                                                       AppDomain.CurrentDomain.SetData("HttpRuntime", runtime);
+                                                       runtime = new HttpRuntime ();
+                                                       AppDomain.CurrentDomain.SetData ("HttpRuntime", runtime);
                                                }
                                        }
                                return runtime;
                        }
                }
+               static private HttpRuntime _runtime
+               {
+                       get
+                       {
+                               if (HttpContext.Current != null)
+                                       return HttpContext.Current.HttpRuntimeInstance;
+                               else
+                                       return _runtimeInstance;
+                       }
+               }
 #else
                static QueueManager queue_manager;
                static TraceManager trace_manager;
                static TimeoutManager timeout_manager;
                static Cache cache;
+               static Cache internalCache;
                static WaitCallback do_RealProcessRequest;
-
+               static Exception initialException;
+               static bool firstRun;
+               
+#if NET_2_0
+               static bool assemblyMappingEnabled;
+               static object assemblyMappingLock = new object ();
+#endif
+               
                static HttpRuntime ()
                {
+                       firstRun = true;
+#if NET_2_0
+                       try {
+                               WebConfigurationManager.Init ();
+                       } catch (Exception ex) {
+                               initialException = ex;
+                       }
+                       
+#endif
+
+                       // The classes in whose constructors exceptions may be thrown, should be handled the same way QueueManager
+                       // and TraceManager are below. The constructors themselves MUST NOT throw any exceptions - we MUST be sure
+                       // the objects are created here. The exceptions will be dealt with below, in RealProcessRequest.
                        queue_manager = new QueueManager ();
+                       if (queue_manager.HasException)
+                               initialException = queue_manager.InitialException;
+
                        trace_manager = new TraceManager ();
+                       if (trace_manager.HasException)
+                                       initialException = trace_manager.InitialException;
+
                        timeout_manager = new TimeoutManager ();
                        cache = new Cache ();
+                       internalCache = new Cache ();
                        do_RealProcessRequest = new WaitCallback (RealProcessRequest);
                }
 
@@ -108,9 +152,10 @@ namespace System.Web {
 #endif
                public HttpRuntime ()
                {
+
                }
 #endif
-
+               
 #region AppDomain handling
                //
                // http://radio.weblogs.com/0105476/stories/2002/07/12/executingAspxPagesWithoutAWebServer.html
@@ -166,7 +211,7 @@ namespace System.Web {
                
                public static string BinDirectory {
                        get {
-                               string dirname = Path.Combine (AppDomainAppPath, "bin");
+                               string dirname = AppDomain.CurrentDomain.SetupInformation.PrivateBinPath;
                                if (SecurityManager.SecurityEnabled) {
                                        new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dirname).Demand ();
                                }
@@ -180,6 +225,12 @@ namespace System.Web {
                        }
                }
 
+               internal static Cache InternalCache {
+                       get {
+                               return internalCache;
+                       }
+               }
+               
                public static string ClrInstallDirectory {
                        get {
                                string dirname = Path.GetDirectoryName (typeof (Object).Assembly.Location);
@@ -210,11 +261,7 @@ namespace System.Web {
 
                public static string MachineConfigurationDirectory {
                        get {
-#if NET_2_0
-                               string dirname = Path.GetDirectoryName (WebConfigurationManager.OpenMachineConfiguration().FilePath);
-#else
-                               string dirname = Path.GetDirectoryName (WebConfigurationSettings.MachineConfigPath);
-#endif
+                               string dirname = Path.GetDirectoryName (ICalls.GetMachineConfigPath ());
                                if ((dirname != null) && (dirname.Length > 0) && SecurityManager.SecurityEnabled) {
                                        new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dirname).Demand ();
                                }
@@ -222,6 +269,7 @@ namespace System.Web {
                        }
                }
 
+               
                [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
                public static void Close ()
                {
@@ -235,40 +283,43 @@ namespace System.Web {
                                return;
                        ThreadPool.QueueUserWorkItem (do_RealProcessRequest, request);
                }
-
+               
                static void RealProcessRequest (object o)
                {
                        HttpContext context = new HttpContext ((HttpWorkerRequest) o);
                        HttpContext.Current = context;
 
+                       bool error = false;
+#if !TARGET_J2EE
+                       if (firstRun) {
+                               firstRun = false;
+                               if (initialException != null) {
+                                       FinishWithException ((HttpWorkerRequest) o, new HttpException ("Initial exception", initialException));
+                                       error = true;
+                               }
+                       }
+#endif
+
                        //
                        // Get application instance (create or reuse an instance of the correct class)
                        //
                        HttpApplication app = null;
-                       bool error = false;
-                       try {
-                               app = HttpApplicationFactory.GetApplication (context);
-                       } catch (Exception e) {
-                               FinishWithException ((HttpWorkerRequest) o, new HttpException ("", e));
-                               error = true;
+                       if (!error) {
+                               try {
+                                       app = HttpApplicationFactory.GetApplication (context);
+                               } catch (Exception e) {
+                                       FinishWithException ((HttpWorkerRequest) o, new HttpException ("", e));
+                                       error = true;
+                               }
                        }
-
+                       
                        if (error) {
                                context.Request.ReleaseResources ();
                                context.Response.ReleaseResources ();
                                HttpContext.Current = null;
                        } else {
                                context.ApplicationInstance = app;
-                       
-#if NET_2_0
-                               //
-                               // Compile the local resources, if any
-                               //
-                               AppLocalResourcesCompiler alrc = new AppLocalResourcesCompiler();
-                               CompilerResults cr = alrc.Compile();
-                               if (cr != null && cr.CompiledAssembly != null)
-                                       WebConfigurationManager.ExtraAssemblies.Add(cr.PathToAssembly);
-#endif                 
+                               
                                //
                                // Ask application to service the request
                                //
@@ -336,22 +387,24 @@ namespace System.Web {
                {
                        queue_manager.Dispose ();
                        // This will call Session_End if needed.
-                       Cache.InvokePrivateCallbacks ();
+                       InternalCache.InvokePrivateCallbacks ();
                        // Kill our application.
                        HttpApplicationFactory.Dispose ();
                        ThreadPool.QueueUserWorkItem (new WaitCallback (DoUnload), null);
                }
 
-#if TARGET_J2EE // No unload support for appdomains under Grasshopper
                static void DoUnload (object state)
                {
-               }
+                       if (Environment.GetEnvironmentVariable ("MONO_ASPNET_NODELETE") == null)
+                               System.Web.Hosting.ApplicationHost.ClearDynamicBaseDirectory (
+                                       AppDomain.CurrentDomain.SetupInformation.DynamicBase
+                               );
+#if TARGET_J2EE
+                       // No unload support for appdomains under Grasshopper
 #else
-               static void DoUnload (object state)
-               {
                        AppDomain.Unload (AppDomain.CurrentDomain);
-               }
 #endif
+               }
 
                 static string content503 = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n" +
                        "<html><head>\n<title>503 Server Unavailable</title>\n</head><body>\n" +
@@ -393,6 +446,73 @@ namespace System.Web {
                        wr.CloseConnection ();
                }
 
+#if NET_2_0 && !TARGET_J2EE
+               static internal void WritePreservationFile (Assembly asm, string genericNameBase)
+               {
+                       if (asm == null)
+                               throw new ArgumentNullException ("asm");
+                       if (String.IsNullOrEmpty (genericNameBase))
+                               throw new ArgumentNullException ("genericNameBase");
+
+                       string compiled = Path.Combine (AppDomain.CurrentDomain.SetupInformation.DynamicBase,
+                                                       genericNameBase + ".compiled");
+                       PreservationFile pf = new PreservationFile ();
+                       try {
+                               pf.VirtualPath = String.Format ("/{0}/", genericNameBase);
+
+                               AssemblyName an = asm.GetName ();
+                               pf.Assembly = an.Name;
+                               pf.ResultType = BuildResultTypeCode.TopLevelAssembly;
+                               pf.Save (compiled);
+                       } catch (Exception ex) {
+                               throw new HttpException (
+                                       String.Format ("Failed to write preservation file {0}", genericNameBase + ".compiled"),
+                                       ex);
+                       }
+               }
+               
+               static Assembly ResolveAssemblyHandler(object sender, ResolveEventArgs e)
+               {
+                       AssemblyName an = new AssemblyName (e.Name);
+                       string dynamic_base = AppDomain.CurrentDomain.SetupInformation.DynamicBase;
+                       string compiled = Path.Combine (dynamic_base, an.Name + ".compiled");
+
+                       if (!File.Exists (compiled))
+                               return null;
+
+                       PreservationFile pf;
+                       try {
+                               pf = new PreservationFile (compiled);
+                       } catch (Exception ex) {
+                               throw new HttpException (
+                                       String.Format ("Failed to read preservation file {0}", an.Name + ".compiled"),
+                                       ex);
+                       }
+                       
+                       Assembly ret = null;
+                       try {
+                               string asmPath = Path.Combine (dynamic_base, pf.Assembly + ".dll");
+                               ret = Assembly.LoadFrom (asmPath);
+                       } catch (Exception) {
+                               // ignore
+                       }
+                       
+                       return ret;
+               }
+               
+               internal static void EnableAssemblyMapping (bool enable)
+               {
+                       lock (assemblyMappingLock) {
+                               if (assemblyMappingEnabled == enable)
+                                       return;
+                               if (enable)
+                                       AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler (ResolveAssemblyHandler);
+                               else
+                                       AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler (ResolveAssemblyHandler);
+                       }
+               }
+#endif
+               
                internal static TraceManager TraceManager {
                        get {
                                return trace_manager;