Merge pull request #2087 from joelmartinez/mdoc-membername-fixup
[mono.git] / mcs / class / System.Web / System.Web / HttpRuntime.cs
index 1e184ba3974e5f69908c830447521266e0a5dd54..d2822357434e406f738d294a8269f02c512fea75 100644 (file)
@@ -35,6 +35,7 @@ using System.IO;
 using System.Text;
 using System.Globalization;
 using System.Collections;
+using System.Collections.Concurrent;
 using System.Reflection;
 using System.Security;
 using System.Security.Permissions;
@@ -43,16 +44,10 @@ using System.Web.Configuration;
 using System.Web.Management;
 using System.Web.UI;
 using System.Web.Util;
-#if MONOWEB_DEP
 using Mono.Web.Util;
-#endif
 using System.Threading;
-#if TARGET_J2EE
-using Mainsoft.Web;
-#else
 using System.CodeDom.Compiler;
 using System.Web.Compilation;
-#endif
 
 namespace System.Web
 {      
@@ -61,80 +56,33 @@ namespace System.Web
        public sealed class HttpRuntime
        {
                static bool domainUnloading;
-               
-#if TARGET_J2EE
-               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;
-
-               public HttpRuntime ()
-               {
-                       WebConfigurationManager.Init ();
-                       _queue_manager = new QueueManager ();
-                       _trace_manager = new TraceManager ();
-                       _cache = new Cache ();
-                       _internalCache = new Cache();
-                       _internalCache.DependencyCache = _cache;
-               }
-
-               static HttpRuntime _runtimeInstance {
-                       get {
-                               HttpRuntime runtime = (HttpRuntime) AppDomain.CurrentDomain.GetData ("HttpRuntime");
-                               if (runtime == null)
-                                       lock (typeof (HttpRuntime)) {
-                                               runtime = (HttpRuntime) AppDomain.CurrentDomain.GetData ("HttpRuntime");
-                                               if (runtime == null) {
-                                                       runtime = new HttpRuntime ();
-                                                       AppDomain.CurrentDomain.SetData ("HttpRuntime", runtime);
-                                               }
-                                       }
-                               return runtime;
-                       }
-               }
-               static HttpRuntime _runtime
-               {
-                       get
-                       {
-                               if (HttpContext.Current != null)
-                                       return HttpContext.Current.HttpRuntimeInstance;
-                               else
-                                       return _runtimeInstance;
-                       }
-               }
-#else
+               static SplitOrderedList <string, string> registeredAssemblies;
                static QueueManager queue_manager;
                static TraceManager trace_manager;
                static Cache cache;
                static Cache internalCache;
                static WaitCallback do_RealProcessRequest;
+               static HttpWorkerRequest.EndOfSendNotification end_of_send_cb;
                static Exception initialException;
                static bool firstRun;
                static bool assemblyMappingEnabled;
                static object assemblyMappingLock = new object ();
                static object appOfflineLock = new object ();
+               static HttpRuntimeSection runtime_section;
                
                public HttpRuntime ()
                {
 
                }
-#endif
 
                static HttpRuntime ()
                {
-#if !TARGET_J2EE
                        firstRun = true;
+
                        try {
                                WebConfigurationManager.Init ();
-#if MONOWEB_DEP
                                SettingsMappingManager.Init ();
-#endif
+                               runtime_section = (HttpRuntimeSection) WebConfigurationManager.GetSection ("system.web/httpRuntime");
                        } catch (Exception ex) {
                                initialException = ex;
                        }
@@ -143,18 +91,39 @@ namespace System.Web
                        // 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;
+                       if (queue_manager.HasException) {
+                               if (initialException == null)
+                                       initialException = queue_manager.InitialException;
+                               else {
+                                       Console.Error.WriteLine ("Exception during QueueManager initialization:");
+                                       Console.Error.WriteLine (queue_manager.InitialException);
+                               }
+                       }
 
                        trace_manager = new TraceManager ();
-                       if (trace_manager.HasException)
+                       if (trace_manager.HasException) {
+                               if (initialException == null)
                                        initialException = trace_manager.InitialException;
+                               else {
+                                       Console.Error.WriteLine ("Exception during TraceManager initialization:");
+                                       Console.Error.WriteLine (trace_manager.InitialException);
+                               }
+                       }
 
+                       registeredAssemblies = new SplitOrderedList <string, string> (StringComparer.Ordinal);
                        cache = new Cache ();
                        internalCache = new Cache ();
                        internalCache.DependencyCache = internalCache;
-#endif
-                       do_RealProcessRequest = new WaitCallback (RealProcessRequest);
+                       do_RealProcessRequest = new WaitCallback (state => {
+                               try {
+                                       RealProcessRequest (state);
+                               } catch {}
+                               });
+                       end_of_send_cb = new HttpWorkerRequest.EndOfSendNotification (EndOfSend);
+               }
+
+               internal static SplitOrderedList <string, string> RegisteredAssemblies {
+                       get { return registeredAssemblies; }
                }
                
 #region AppDomain handling
@@ -299,7 +268,22 @@ namespace System.Web
                        }
                }
 
+               internal static HttpRuntimeSection Section { get { return runtime_section; } }
+
                public static bool UsingIntegratedPipeline { get { return false; } }
+
+               public static Version IISVersion {
+                       get {
+                               // Null means not hosted by IIS
+                               return null;
+                       }
+               }
+               
+               public static Version TargetFramework {
+                       get {
+                               return runtime_section.TargetFramework;
+                       }
+               }
                
                [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
                public static void Close ()
@@ -321,7 +305,6 @@ namespace System.Web
                        return next;
                }
 
-#if !TARGET_J2EE
                static readonly string[] app_offline_files = {"app_offline.htm", "App_Offline.htm", "APP_OFFLINE.HTM"};
                static string app_offline_file;
                
@@ -405,7 +388,6 @@ namespace System.Web
                                RenamedEventHandler reh = new RenamedEventHandler (AppOfflineFileRenamed);
 
                                string app_dir = AppDomainAppPath;
-                               ArrayList watchers = new ArrayList ();
                                FileSystemWatcher watcher;
                                string offlineFile = null, tmp;
                                
@@ -419,8 +401,6 @@ namespace System.Web
                                        watcher.Created += seh;
                                        watcher.Renamed += reh;
                                        watcher.EnableRaisingEvents = true;
-                                       
-                                       watchers.Add (watcher);
 
                                        tmp = Path.Combine (app_dir, f);
                                        if (File.Exists (tmp))
@@ -431,10 +411,14 @@ namespace System.Web
                                        SetOfflineMode (true, offlineFile);
                        }
                }
-#endif
                
                static void RealProcessRequest (object o)
                {
+                       if (domainUnloading) {
+                               Console.Error.WriteLine ("Domain is unloading, not processing the request.");
+                               return;
+                       }
+
                        HttpWorkerRequest req = (HttpWorkerRequest) o;
                        bool started_internally = req.StartedInternally;
                        do {
@@ -445,30 +429,19 @@ namespace System.Web
 
                static void Process (HttpWorkerRequest req)
                {
-#if TARGET_J2EE
-                       HttpContext context = HttpContext.Current;
-                       if (context == null)
-                               context = new HttpContext (req);
-                       else
-                               context.SetWorkerRequest (req);
-#else
-                       HttpContext context = new HttpContext (req);
-#endif
-                       HttpContext.Current = context;
                        bool error = false;
-#if !TARGET_J2EE
                        if (firstRun) {
-                               SetupOfflineWatch ();
                                firstRun = false;
                                if (initialException != null) {
                                        FinishWithException (req, HttpException.NewWithCode ("Initial exception", initialException, WebEventCodes.RuntimeErrorRequestAbort));
                                        error = true;
                                }
+                               SetupOfflineWatch ();
                        }
-
+                       HttpContext context = new HttpContext (req);
+                       HttpContext.Current = context;
                        if (AppIsOffline (context))
                                return;
-#endif
                        
                        //
                        // Get application instance (create or reuse an instance of the correct class)
@@ -489,36 +462,25 @@ namespace System.Web
                                HttpContext.Current = null;
                        } else {
                                context.ApplicationInstance = app;
+                               req.SetEndOfSendNotification (end_of_send_cb, context);
 
                                //
                                // Ask application to service the request
                                //
                                
-#if TARGET_J2EE
-                               IHttpAsyncHandler ihah = app;
-                               if (context.Handler == null)
-                                       ihah.BeginProcessRequest (context, new AsyncCallback (request_processed), context);
-                               else
-                                       app.Tick ();
-                               //ihh.ProcessRequest (context);
-                               IHttpExtendedHandler extHandler = context.Handler as IHttpExtendedHandler;
-                               if (extHandler != null && !extHandler.IsCompleted)
-                                       return;
-                               if (context.Error is UnifyRequestException)
-                                       return;
-
-                               ihah.EndProcessRequest (null);
-#else
                                IHttpHandler ihh = app;
 //                             IAsyncResult appiar = ihah.BeginProcessRequest (context, new AsyncCallback (request_processed), context);
 //                             ihah.EndProcessRequest (appiar);
                                ihh.ProcessRequest (context);
-#endif
 
                                HttpApplicationFactory.Recycle (app);
                        }
                }
-               
+
+               static void EndOfSend (HttpWorkerRequest ignored1, object ignored2)
+               {
+               }
+
                //
                // ProcessRequest method is executed in the AppDomain of the application
                //
@@ -542,26 +504,7 @@ namespace System.Web
                        RealProcessRequest (request);
                }
 
-#if TARGET_J2EE
-               //
-               // Callback to be invoked by IHttpAsyncHandler.BeginProcessRequest
-               //
-               static void request_processed (IAsyncResult iar)
-               {
-                       HttpContext context = (HttpContext) iar.AsyncState;
-
-                       context.Request.ReleaseResources ();
-                       context.Response.ReleaseResources ();
-               }
-#endif
                
-#if TARGET_JVM
-               [MonoNotSupported ("UnloadAppDomain is not supported")]
-               public static void UnloadAppDomain ()
-               {
-                       throw new NotImplementedException ("UnloadAppDomain is not supported");
-               }
-#else
                //
                // Called when we are shutting down or we need to reload an application
                // that has been modified (touch global.asax) 
@@ -573,6 +516,7 @@ namespace System.Web
                        // TODO: call ReleaseResources
                        //
                        domainUnloading = true;
+                       HttpApplicationFactory.DisableWatchers ();
                        ThreadPool.QueueUserWorkItem (delegate {
                                try {
                                        ShutdownAppDomain ();
@@ -581,7 +525,6 @@ namespace System.Web
                                }
                        });
                }
-#endif
                //
                // Shuts down the AppDomain
                //
@@ -601,11 +544,7 @@ namespace System.Web
 
                static void DoUnload ()
                {
-#if TARGET_J2EE
-                       // No unload support for appdomains under Grasshopper
-#else
                        AppDomain.Unload (AppDomain.CurrentDomain);
-#endif
                }
 
                static string content503 = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n" +
@@ -655,7 +594,6 @@ namespace System.Web
                        return null;
                }
                
-#if !TARGET_J2EE
                static internal void WritePreservationFile (Assembly asm, string genericNameBase)
                {
                        if (asm == null)
@@ -685,22 +623,29 @@ namespace System.Web
                        AssemblyName an = new AssemblyName (e.Name);
                        string dynamic_base = AppDomain.CurrentDomain.SetupInformation.DynamicBase;
                        string compiled = Path.Combine (dynamic_base, an.Name + ".compiled");
+                       string asmPath;
 
-                       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);
+                       if (!File.Exists (compiled)) {
+                               string fn = an.FullName;
+                               if (!RegisteredAssemblies.Find ((uint)fn.GetHashCode (), fn, out asmPath))
+                                       return null;
+                       } else {
+                               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);
+                               }
+                               asmPath = Path.Combine (dynamic_base, pf.Assembly + ".dll");
                        }
+
+                       if (String.IsNullOrEmpty (asmPath))
+                               return null;
                        
                        Assembly ret = null;
                        try {
-                               string asmPath = Path.Combine (dynamic_base, pf.Assembly + ".dll");
                                ret = Assembly.LoadFrom (asmPath);
                        } catch (Exception) {
                                // ignore
@@ -721,7 +666,6 @@ namespace System.Web
                                assemblyMappingEnabled = enable;
                        }
                }
-#endif // #if !TARGET_J2EE
                
                internal static TraceManager TraceManager {
                        get {