2008-11-21 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / System.Web / System.Web / HttpApplicationFactory.cs
index 1151cb1caee6909110a1944e760c9c3dd384f7fd..d9260af0cf209b75aa05515358e92de6dafa8253 100644 (file)
@@ -45,6 +45,8 @@ using System.CodeDom.Compiler;
 
 namespace System.Web {
        class HttpApplicationFactory {
+               object this_lock = new object ();
+               
                // Initialized in InitType
 #if TARGET_J2EE
                static HttpApplicationFactory theFactory {
@@ -67,8 +69,6 @@ namespace System.Web {
 #else
                static HttpApplicationFactory theFactory = new HttpApplicationFactory();
 #endif
-        
-
                MethodInfo session_end;
                bool needs_init = true;
                bool app_start_needed = true;
@@ -77,6 +77,11 @@ namespace System.Web {
                Hashtable app_event_handlers;
                static ArrayList watchers = new ArrayList();
                static object watchers_lock = new object();
+               static bool app_shutdown = false;
+#if NET_2_0
+               static bool app_disabled = false;
+               static string[] app_browsers_files = new string[0];
+#endif
                Stack available = new Stack ();
                Stack available_for_end = new Stack ();
                
@@ -123,22 +128,48 @@ namespace System.Web {
 
                        list.Add (method);
                }
+
+               ArrayList GetMethodsDeep (Type type)
+               {
+                       ArrayList al = new ArrayList ();
+                       MethodInfo[] methods = type.GetMethods (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance  | BindingFlags.Static | BindingFlags.FlattenHierarchy);
+                       al.AddRange (methods);
+
+                       Type t = type.BaseType;
+                       while (t != null) {
+                               methods = t.GetMethods (BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
+                               al.AddRange (methods);
+                               t = t.BaseType;
+                       }
+
+                       return al;
+               }
                
                Hashtable GetApplicationTypeEvents (Type type)
                {
-                       lock (this) {
+                       lock (this_lock) {
                                if (app_event_handlers != null)
                                        return app_event_handlers;
 
                                app_event_handlers = new Hashtable ();
-                               BindingFlags flags = BindingFlags.Public    | BindingFlags.NonPublic | 
-                                       BindingFlags.Instance  | BindingFlags.Static;
-
-                               MethodInfo [] methods = type.GetMethods (flags);
-                               foreach (MethodInfo m in methods) {
-                                       if (m.DeclaringType != typeof (HttpApplication) && IsEventHandler (m))
+                               ArrayList methods = GetMethodsDeep (type);
+                               Hashtable used = null;
+                               MethodInfo m;
+                               string mname;
+                               
+                               foreach (object o in methods) {
+                                       m = o as MethodInfo;
+                                       if (m.DeclaringType != typeof (HttpApplication) && IsEventHandler (m)) {
+                                               mname = m.ToString ();
+                                               if (used == null)
+                                                       used = new Hashtable ();
+                                               else if (used.ContainsKey (mname))
+                                                       continue;
+                                               used.Add (mname, m);
                                                AddEvent (m, app_event_handlers);
+                                       }
                                }
+                               used = null;
                        }
 
                        return app_event_handlers;
@@ -146,7 +177,7 @@ namespace System.Web {
 
                Hashtable GetApplicationTypeEvents (HttpApplication app)
                {
-                       lock (this) {
+                       lock (this_lock) {
                                if (app_event_handlers != null)
                                        return app_event_handlers;
 
@@ -175,7 +206,9 @@ namespace System.Web {
                        context.ApplicationInstance = app;
                        app.SetContext (context);
                        object [] args = new object [] {app, EventArgs.Empty};
+                       app.InApplicationStart = true;
                        FireEvent ("Application_Start", app, args);
+                       app.InApplicationStart = false;
                        return app;
                }
 
@@ -186,7 +219,8 @@ namespace System.Web {
 
                        HttpApplication app = (HttpApplication) Activator.CreateInstance (app_type, true);
                        FireEvent ("Application_End", app, new object [] {new object (), EventArgs.Empty});
-                       app.Dispose ();
+                       app.DisposeInternal ();
+                       app_type = null;
                }
 
                //
@@ -204,7 +238,10 @@ namespace System.Web {
 
                        watcher.Path = Path.GetFullPath (Path.GetDirectoryName (file));
                        watcher.Filter = Path.GetFileName (file);
-
+                       
+                       // This will enable the Modify flag for Linux/inotify
+                       watcher.NotifyFilter |= NotifyFilters.Size;
+                       
                        watcher.Changed += hnd;
                        watcher.Created += hnd;
                        watcher.Deleted += hnd;
@@ -265,12 +302,19 @@ namespace System.Web {
                        int length = method.GetParameters ().Length;
 
                        if (length == 0) {
-                               NoParamsInvoker npi = new NoParamsInvoker (app, method.Name);
+                               NoParamsInvoker npi = new NoParamsInvoker (app, method);
                                evt.AddEventHandler (target, npi.FakeDelegate);
                        } else {
                                evt.AddEventHandler (target, Delegate.CreateDelegate (
-                                                            evt.EventHandlerType, app, method.Name));
+                                                            evt.EventHandlerType, app,
+#if NET_2_0
+                                                            method
+#else
+                                                            method.Name
+#endif
+                                                    ));
                        }
+                       
                }
 
                internal static void InvokeSessionEnd (object state)
@@ -342,14 +386,14 @@ namespace System.Web {
                
                void InitType (HttpContext context)
                {
-                       lock (this) {
+                       lock (this_lock) {
                                if (!needs_init)
                                        return;
 
 #if NET_2_0
                                try {
 #endif
-                                       string physical_app_path = context.Request.PhysicalApplicationPath;
+                                       string physical_app_path = HttpRuntime.AppDomainAppPath;
                                        string app_file = null;
                                        
                                        app_file = Path.Combine (physical_app_path, "Global.asax");
@@ -366,40 +410,51 @@ namespace System.Web {
 #if NET_2_0 && !TARGET_J2EE
                                        AppResourcesCompiler ac = new AppResourcesCompiler (context);
                                        ac.Compile ();
-                               
-                                       // Todo: Process App_WebResources here
-                               
+
+#if WEBSERVICES_DEP
+                                       AppWebReferencesCompiler awrc = new AppWebReferencesCompiler ();
+                                       awrc.Compile ();
+#endif
+                                       
                                        // Todo: Generate profile properties assembly from Web.config here
                                
-                                       // Todo: Compile code from App_Code here
                                        AppCodeCompiler acc = new AppCodeCompiler ();
                                        acc.Compile ();
+
+                                       // Note whether there are any App_Browsers/*.browser files.  If there
+                                       // are we will be using *.browser files for sniffing in addition to browscap.ini
+                                       string app_browsers_path = Path.Combine (physical_app_path, "App_Browsers");
+                                       app_browsers_files = new string[0];
+                                       if (Directory.Exists (app_browsers_path)) {
+                                               app_browsers_files = Directory.GetFiles (app_browsers_path, "*.browser");
+                                       }
 #endif
 
                                        if (app_file != null) {
 #if TARGET_J2EE
-                                               app_type = System.Web.J2EE.PageMapper.GetObjectType(app_file);
+                                               app_file = System.Web.Util.UrlUtils.ResolveVirtualPathFromAppAbsolute("~/" + Path.GetFileName(app_file));
+                                               app_type = System.Web.J2EE.PageMapper.GetObjectType(context, app_file);
+#else
+#if NET_2_0
+                                               app_type = BuildManager.GetCompiledType ("~/" + Path.GetFileName (app_file));
 #else
                                                app_type = ApplicationFileParser.GetCompiledApplicationType (app_file, context);
+#endif
+#endif
                                                if (app_type == null) {
                                                        string msg = String.Format ("Error compiling application file ({0}).", app_file);
                                                        throw new ApplicationException (msg);
                                                }
-#endif
                                        } else {
                                                app_type = typeof (System.Web.HttpApplication);
                                                app_state = new HttpApplicationState ();
                                        }
 
-                                       if (app_file != null)
-                                               WatchLocationForRestart(app_file);
-                                           
-                                       if (File.Exists(Path.Combine(physical_app_path, "Web.config")))
-                                               WatchLocationForRestart("Web.config");
-                                       else if (File.Exists(Path.Combine(physical_app_path, "web.config")))
-                                               WatchLocationForRestart("web.config");
-                                       else if (File.Exists(Path.Combine(physical_app_path, "Web.Config")))
-                                               WatchLocationForRestart("Web.Config");
+                                       WatchLocationForRestart("Global.asax");
+                                       WatchLocationForRestart("global.asax");
+                                       WatchLocationForRestart("Web.config");
+                                       WatchLocationForRestart("web.config");
+                                       WatchLocationForRestart("Web.Config");
                                        needs_init = false;
 #if NET_2_0
                                } catch (Exception) {
@@ -426,6 +481,10 @@ namespace System.Web {
                //
                internal static HttpApplication GetApplication (HttpContext context)
                {
+#if TARGET_J2EE
+                       if (context.ApplicationInstance!=null)
+                               return context.ApplicationInstance;
+#endif
                        HttpApplicationFactory factory = theFactory;
                        HttpApplication app = null;
                        if (factory.app_start_needed){
@@ -435,12 +494,17 @@ namespace System.Web {
                                factory.InitType (context);
                                lock (factory) {
                                        if (factory.app_start_needed) {
-                                               WatchLocationForRestart (AppDomain.CurrentDomain.SetupInformation.PrivateBinPath,
-                                                                        "*.dll");
+                                               foreach (string dir in HttpApplication.BinDirs)
+                                                       WatchLocationForRestart (dir, "*.dll");
 #if NET_2_0
-                                               WatchLocationForRestart ("App_Code", "");
-                                               WatchLocationForRestart ("App_Browsers", "");
-                                               WatchLocationForRestart ("App_GlobalResources", "");
+                                                                       // Restart if the App_* directories are created...
+                                               WatchLocationForRestart (".", "App_Code");
+                                               WatchLocationForRestart (".", "App_Browsers");
+                                               WatchLocationForRestart (".", "App_GlobalResources");
+                                               // ...or their contents is changed.
+                                               WatchLocationForRestart ("App_Code", "*", true);
+                                               WatchLocationForRestart ("App_Browsers", "*");
+                                               WatchLocationForRestart ("App_GlobalResources", "*");
 #endif
                                                app = factory.FireOnAppStart (context);
                                                factory.app_start_needed = false;
@@ -498,26 +562,34 @@ namespace System.Web {
                internal static bool ContextAvailable {
                        get { return theFactory != null && !theFactory.app_start_needed; }
                }
-               
-               internal static bool WatchLocationForRestart(string filter)
+
+
+                internal static bool WatchLocationForRestart (string filter)
                {
-                       return WatchLocationForRestart("", filter);
+                       return WatchLocationForRestart ("", filter, false);
                }
-        
-               internal static bool WatchLocationForRestart(string virtualPath, string filter)
+
+               internal static bool WatchLocationForRestart (string virtualPath, string filter)
+               {
+                       return WatchLocationForRestart (virtualPath, filter, false);
+               }
+               
+                internal static bool WatchLocationForRestart(string virtualPath, string filter, bool watchSubdirs)
                {
                        // map the path to the physical one
                        string physicalPath = HttpRuntime.AppDomainAppPath;
                        physicalPath = Path.Combine(physicalPath, virtualPath);
-
-                       if (Directory.Exists(physicalPath) || File.Exists(physicalPath)) {
-                               physicalPath = Path.Combine(physicalPath, filter);
-
+                       bool isDir = Directory.Exists(physicalPath);
+                       bool isFile = isDir ? false : File.Exists(physicalPath);
+                       
+                       if (isDir || isFile) {
                                // create the watcher
                                FileSystemEventHandler fseh = new FileSystemEventHandler(OnFileChanged);
                                RenamedEventHandler reh = new RenamedEventHandler(OnFileRenamed);
-                               FileSystemWatcher watcher = CreateWatcher(physicalPath, fseh, reh);
-                       
+                               FileSystemWatcher watcher = CreateWatcher(Path.Combine(physicalPath, filter), fseh, reh);
+                               if (isDir)
+                                       watcher.IncludeSubdirectories = watchSubdirs;
+                               
                                lock (watchers_lock) {
                                        watchers.Add(watcher);
                                }
@@ -527,6 +599,57 @@ namespace System.Web {
                        }
                }
 
+#if NET_2_0
+               internal static bool ApplicationDisabled {
+                       get { return app_disabled; }
+                       set { app_disabled = value; }
+               }
+
+               internal static string[] AppBrowsersFiles {
+                       get { return app_browsers_files; }
+               }
+               
+               static System.Web.Configuration.nBrowser.Build capabilities_processor = null;
+               static object capabilities_processor_lock = new object();
+               internal static System.Web.Configuration.ICapabilitiesProcess CapabilitiesProcessor {
+                       get {
+                               lock (capabilities_processor_lock) {
+                                       if (capabilities_processor == null) {
+                                               capabilities_processor = new System.Web.Configuration.nBrowser.Build();
+                                               string machine_browsers_path = Path.Combine (HttpRuntime.MachineConfigurationDirectory, "Browsers");
+                                               if (Directory.Exists (machine_browsers_path)) {
+                                                       string[] machine_browsers_files 
+                                                               = Directory.GetFiles (machine_browsers_path, "*.browser");
+                                                       foreach (string f in machine_browsers_files) {
+                                                               capabilities_processor.AddBrowserFile(f);
+                                                       }
+                                               }
+                                               foreach (string f in app_browsers_files) {
+                                                       capabilities_processor.AddBrowserFile(f);
+                                               }
+                                       }
+                               }
+                               return capabilities_processor;
+                       }
+               }
+#endif
+               
+               internal static void DisableWatchers ()
+               {
+                       lock (watchers_lock) {
+                               foreach (FileSystemWatcher watcher in watchers)
+                                       watcher.EnableRaisingEvents = false;
+                       }
+               }
+
+               internal static void EnableWatchers ()
+               {
+                       lock (watchers_lock) {
+                               foreach (FileSystemWatcher watcher in watchers)
+                                       watcher.EnableRaisingEvents = true;
+                       }
+               }
+               
                static void OnFileRenamed(object sender, RenamedEventArgs args)
                {
                        OnFileChanged(sender, args);
@@ -535,10 +658,13 @@ namespace System.Web {
                static void OnFileChanged(object sender, FileSystemEventArgs args)
                {
                        lock (watchers_lock) {
+                               if(app_shutdown)
+                                       return;
+                               app_shutdown = true;
+
                                // Disable event raising to avoid concurrent restarts
-                               foreach (FileSystemWatcher watcher in watchers) {
-                                       watcher.EnableRaisingEvents = false;
-                               }
+                               DisableWatchers ();
+                               
                                // Restart application
                                HttpRuntime.UnloadAppDomain();
                        }