2007-07-21 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / System.Web / System.Web / HttpRuntime.cs
index 7ef62e5626ccc8337c8043f90ed3c0b1b997d2a8..b442dd6b9a87f4da6f7c984a5164182753632bd6 100644 (file)
@@ -40,6 +40,7 @@ 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 && !TARGET_JVM
@@ -56,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 ()
                {
@@ -73,29 +76,43 @@ namespace System.Web {
                        _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 ();
@@ -103,13 +120,30 @@ namespace System.Web {
                
                static HttpRuntime ()
                {
+                       firstRun = true;
 #if NET_2_0
-                       WebConfigurationManager.Init ();
+                       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);
                }
 
@@ -118,9 +152,10 @@ namespace System.Web {
 #endif
                public HttpRuntime ()
                {
+
                }
 #endif
-
+               
 #region AppDomain handling
                //
                // http://radio.weblogs.com/0105476/stories/2002/07/12/executingAspxPagesWithoutAWebServer.html
@@ -176,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 ();
                                }
@@ -190,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);
@@ -220,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 ();
                                }
@@ -232,6 +269,7 @@ namespace System.Web {
                        }
                }
 
+               
                [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
                public static void Close ()
                {
@@ -245,38 +283,42 @@ 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 && !TARGET_JVM
-                               //
-                               // Compile the local resources, if any
-                               //
-                               AppResourcesCompiler ac = new AppResourcesCompiler (context, false);
-                               ac.Compile ();
-#endif
                                
                                //
                                // Ask application to service the request
@@ -345,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" +
@@ -402,7 +446,7 @@ namespace System.Web {
                        wr.CloseConnection ();
                }
 
-#if NET_2_0
+#if NET_2_0 && !TARGET_J2EE
                static internal void WritePreservationFile (Assembly asm, string genericNameBase)
                {
                        if (asm == null)