Merge pull request #3622 from rolfbjarne/remove-stray-file
[mono.git] / mcs / class / System.Web / System.Web / CapabilitiesLoader.cs
index c21cac8dfb8761cef1e87bc84fc890980b192fe9..4f82dfe0ae02a1bb6fa65a7cd208a7d1302e6951 100644 (file)
@@ -8,7 +8,7 @@
 // Authors:
 //   Gonzalo Paniagua Javier (gonzalo@ximian.com)
 //
-// (c) 2003 Novell, Inc. (http://www.novell.com)
+// (c) 2003-2009 Novell, Inc. (http://www.novell.com)
 //
 
 //
@@ -39,12 +39,15 @@ using System.Globalization;
 using System.IO;
 using System.Text.RegularExpressions;
 using System.Web.Configuration;
+using System.Web.Util;
 
 namespace System.Web
 {
-       class BrowserData
+       sealed class BrowserData
        {
                static char [] wildchars = new char [] {'*', '?'};
+
+               object this_lock = new object ();
                BrowserData parent;
                string text;
                string pattern;
@@ -67,7 +70,7 @@ namespace System.Web
                                this.pattern = this.pattern.Replace (")", "\\)");
                                this.pattern = this.pattern.Replace ("[", "\\[");
                                this.pattern = this.pattern.Replace ("]", "\\]");
-                               this.pattern = this.pattern.Replace ("?", ".");
+                               this.pattern = this.pattern.Replace ('?', '.');
                                this.pattern = this.pattern.Replace ("*", ".*");
                        }
                }
@@ -90,15 +93,27 @@ namespace System.Web
                        if (parent != null)
                                parent.GetProperties (tbl);
 
-                       foreach (string key in data.Keys)
-                               tbl [key] = data [key];
+                       if (data ["browser"] != null) { // Last one (most derived) will win.
+                               tbl ["browser"] = data ["browser"];
+                       } else if (tbl ["browser"] == null) { // If none so far defined value set to *
+                               tbl ["browser"] = "*";
+                       }
+
+                       if (!tbl.ContainsKey ("browsers")) {
+                               tbl ["browsers"] = new ArrayList ();
+                       }
 
+                       ((ArrayList) tbl ["browsers"]).Add (tbl["browser"]);
+
+                       foreach (string key in data.Keys)
+                               tbl [key.ToLower (Helpers.InvariantCulture).Trim ()] = data [key];
+                       
                        return tbl;
                }
                
                public string GetParentName ()
                {
-                       return (string) data ["parent"];
+                       return (string)(data.Contains("parent")? data ["parent"] : null);
                }
                
                public string GetAlternateBrowser ()
@@ -123,7 +138,7 @@ namespace System.Web
                                if (text [0] != expression [0] ||
                                    String.Compare (text, 1, expression, 1,
                                                    text.Length - 1, false,
-                                                   CultureInfo.InvariantCulture) != 0) {
+                                                   Helpers.InvariantCulture) != 0) {
                                        return false;
                                }
                                expression = expression.Substring (text.Length);
@@ -132,45 +147,181 @@ namespace System.Web
                        if (pattern == null)
                                return expression.Length == 0;
 
-                       lock (this) {
+                       lock (this_lock) {
                                if (regex == null)
-                                       regex = new Regex (pattern);
+                               regex = new Regex (pattern);
                        }
-
                        return regex.Match (expression).Success;
                }
        }
        
-       class CapabilitiesLoader : MarshalByRefObject
+       sealed class CapabilitiesLoader : MarshalByRefObject
        {
-               static volatile bool loaded;
-               static ICollection alldata;
+               const int userAgentsCacheSize = 3000;
                static Hashtable defaultCaps;
                static readonly object lockobj = new object ();
-               private CapabilitiesLoader () {}
+
+               static volatile bool loaded;
+               static ICollection alldata;
+               static Hashtable userAgentsCache = Hashtable.Synchronized(new Hashtable(userAgentsCacheSize+10));
+
+               CapabilitiesLoader () {}
 
                static CapabilitiesLoader ()
                {
-                       defaultCaps = new Hashtable ();
-                       defaultCaps.Add ("frames", "True");
-                       defaultCaps.Add ("tables", "True");
+                       defaultCaps = new Hashtable (StringComparer.OrdinalIgnoreCase);
+                       defaultCaps.Add ("activexcontrols", "False");
+                       defaultCaps.Add ("alpha", "False");
+                       defaultCaps.Add ("aol", "False");
+                       defaultCaps.Add ("aolversion", "0");
+                       defaultCaps.Add ("authenticodeupdate", "");
+                       defaultCaps.Add ("backgroundsounds", "False");
+                       defaultCaps.Add ("beta", "False");
+                       defaultCaps.Add ("browser", "*");
+                       defaultCaps.Add ("browsers", new ArrayList ());
+                       defaultCaps.Add ("cdf", "False");
+                       defaultCaps.Add ("clrversion", "0");
+                       defaultCaps.Add ("cookies", "False");
+                       defaultCaps.Add ("crawler", "False");
+                       defaultCaps.Add ("css", "0");
+                       defaultCaps.Add ("cssversion", "0");
+                       defaultCaps.Add ("ecmascriptversion", "0.0");
+                       defaultCaps.Add ("frames", "False");
+                       defaultCaps.Add ("iframes", "False");
+                       defaultCaps.Add ("isbanned", "False");
+                       defaultCaps.Add ("ismobiledevice", "False");
+                       defaultCaps.Add ("issyndicationreader", "False");
+                       defaultCaps.Add ("javaapplets", "False");
+                       defaultCaps.Add ("javascript", "False");
+                       defaultCaps.Add ("majorver", "0");
+                       defaultCaps.Add ("minorver", "0");
+                       defaultCaps.Add ("msdomversion", "0.0");
+                       defaultCaps.Add ("netclr", "False");
+                       defaultCaps.Add ("platform", "unknown");
+                       defaultCaps.Add ("stripper", "False");
+                       defaultCaps.Add ("supportscss", "False");
+                       defaultCaps.Add ("tables", "False");
+                       defaultCaps.Add ("vbscript", "False");
+                       defaultCaps.Add ("version", "0");
+                       defaultCaps.Add ("w3cdomversion", "0.0");
+                       defaultCaps.Add ("wap", "False");
+                       defaultCaps.Add ("win16", "False");
+                       defaultCaps.Add ("win32", "False");
+                       defaultCaps.Add ("win64", "False");
+                       defaultCaps.Add ("adapters", new Hashtable ());
+                       defaultCaps.Add ("cancombineformsindeck", "False");
+                       defaultCaps.Add ("caninitiatevoicecall", "False");
+                       defaultCaps.Add ("canrenderafterinputorselectelement", "False");
+                       defaultCaps.Add ("canrenderemptyselects", "False");
+                       defaultCaps.Add ("canrenderinputandselectelementstogether", "False");
+                       defaultCaps.Add ("canrendermixedselects", "False");
+                       defaultCaps.Add ("canrenderoneventandprevelementstogether", "False");
+                       defaultCaps.Add ("canrenderpostbackcards", "False");
+                       defaultCaps.Add ("canrendersetvarzerowithmultiselectionlist", "False");
+                       defaultCaps.Add ("cansendmail", "False");
+                       defaultCaps.Add ("defaultsubmitbuttonlimit", "0");
+                       defaultCaps.Add ("gatewayminorversion", "0");
+                       defaultCaps.Add ("gatewaymajorversion", "0");
+                       defaultCaps.Add ("gatewayversion", "None");
+                       defaultCaps.Add ("hasbackbutton", "True");
+                       defaultCaps.Add ("hidesrightalignedmultiselectscrollbars", "False");
+                       defaultCaps.Add ("inputtype", "telephoneKeypad");
+                       defaultCaps.Add ("iscolor", "False");
+                       defaultCaps.Add ("jscriptversion", "0.0");
+                       defaultCaps.Add ("maximumhreflength", "0");
+                       defaultCaps.Add ("maximumrenderedpagesize", "2000");
+                       defaultCaps.Add ("maximumsoftkeylabellength", "5");
+                       defaultCaps.Add ("minorversionstring", "0.0");
+                       defaultCaps.Add ("mobiledevicemanufacturer", "Unknown");
+                       defaultCaps.Add ("mobiledevicemodel", "Unknown");
+                       defaultCaps.Add ("numberofsoftkeys", "0");
+                       defaultCaps.Add ("preferredimagemime", "image/gif");
+                       defaultCaps.Add ("preferredrenderingmime", "text/html");
+                       defaultCaps.Add ("preferredrenderingtype", "html32");
+                       defaultCaps.Add ("preferredrequestencoding", "");
+                       defaultCaps.Add ("preferredresponseencoding", "");
+                       defaultCaps.Add ("rendersbreakbeforewmlselectandinput", "False");
+                       defaultCaps.Add ("rendersbreaksafterhtmllists", "True");
+                       defaultCaps.Add ("rendersbreaksafterwmlanchor", "False");
+                       defaultCaps.Add ("rendersbreaksafterwmlinput", "False");
+                       defaultCaps.Add ("renderswmldoacceptsinline", "True");
+                       defaultCaps.Add ("renderswmlselectsasmenucards", "False");
+                       defaultCaps.Add ("requiredmetatagnamevalue", "");
+                       defaultCaps.Add ("requiresattributecolonsubstitution", "False");
+                       defaultCaps.Add ("requirescontenttypemetatag", "False");
+                       defaultCaps.Add ("requirescontrolstateinsession", "False");
+                       defaultCaps.Add ("requiresdbcscharacter", "False");
+                       defaultCaps.Add ("requireshtmladaptiveerrorreporting", "False");
+                       defaultCaps.Add ("requiresleadingpagebreak", "False");
+                       defaultCaps.Add ("requiresnobreakinformatting", "False");
+                       defaultCaps.Add ("requiresoutputoptimization", "False");
+                       defaultCaps.Add ("requiresphonenumbersasplaintext", "False");
+                       defaultCaps.Add ("requiresspecialviewstateencoding", "False");
+                       defaultCaps.Add ("requiresuniquefilepathsuffix", "False");
+                       defaultCaps.Add ("requiresuniquehtmlcheckboxnames", "False");
+                       defaultCaps.Add ("requiresuniquehtmlinputnames", "False");
+                       defaultCaps.Add ("requiresurlencodedpostfieldvalues", "False");
+                       defaultCaps.Add ("screenbitdepth", "1");
+                       defaultCaps.Add ("screencharactersheight", "6");
+                       defaultCaps.Add ("screencharacterswidth", "12");
+                       defaultCaps.Add ("screenpixelsheight", "72");
+                       defaultCaps.Add ("screenpixelswidth", "96");
+                       defaultCaps.Add ("supportsaccesskeyattribute", "False");
+                       defaultCaps.Add ("supportsbodycolor", "True");
+                       defaultCaps.Add ("supportsbold", "False");
+                       defaultCaps.Add ("supportscachecontrolmetatag", "True");
+                       defaultCaps.Add ("supportscallback", "False");
+                       defaultCaps.Add ("supportsdivalign", "True");
+                       defaultCaps.Add ("supportsdivnowrap", "False");
+                       defaultCaps.Add ("supportsemptystringincookievalue", "False");
+                       defaultCaps.Add ("supportsfontcolor", "True");
+                       defaultCaps.Add ("supportsfontname", "False");
+                       defaultCaps.Add ("supportsfontsize", "False");
+                       defaultCaps.Add ("supportsimagesubmit", "False");
+                       defaultCaps.Add ("supportsimodesymbols", "False");
+                       defaultCaps.Add ("supportsinputistyle", "False");
+                       defaultCaps.Add ("supportsinputmode", "False");
+                       defaultCaps.Add ("supportsitalic", "False");
+                       defaultCaps.Add ("supportsjphonemultimediaattributes", "False");
+                       defaultCaps.Add ("supportsjphonesymbols", "False");
+                       defaultCaps.Add ("supportsquerystringinformaction", "True");
+                       defaultCaps.Add ("supportsredirectwithcookie", "True");
+                       defaultCaps.Add ("supportsselectmultiple", "True");
+                       defaultCaps.Add ("supportsuncheck", "True");
+                       defaultCaps.Add ("supportsxmlhttp", "False");
+                       defaultCaps.Add ("type", "Unknown");
                }
-                       
+               
                public static Hashtable GetCapabilities (string userAgent)
                {
                        Init ();
                        if (userAgent != null)
                                userAgent = userAgent.Trim ();
 
-                       if (alldata == null || userAgent == null || userAgent == "")
+                       if (alldata == null || userAgent == null || userAgent.Length == 0)
                                return defaultCaps;
 
-                       foreach (BrowserData bd in alldata) {
-                               if (bd.IsMatch (userAgent))
-                                       return bd.GetProperties (new Hashtable ());
+                       Hashtable userBrowserCaps = (Hashtable) (userAgentsCache.Contains(userAgent)? userAgentsCache [userAgent] : null);
+                       if (userBrowserCaps == null) {
+                               foreach (BrowserData bd in alldata) {
+                                       if (bd.IsMatch (userAgent)) {
+                                               Hashtable tbl;
+                                               tbl = new Hashtable (defaultCaps, StringComparer.OrdinalIgnoreCase);
+                                               userBrowserCaps = bd.GetProperties (tbl);
+                                               break;
+                                       }
+                               }
+
+                               if (userBrowserCaps == null)
+                                       userBrowserCaps = defaultCaps;
+
+                               lock (lockobj) {
+                                       if (userAgentsCache.Count >= userAgentsCacheSize)
+                                               userAgentsCache.Clear ();
+                               }
+                               userAgentsCache [userAgent] = userBrowserCaps;
                        }
-                       
-                       return defaultCaps;
+                       return userBrowserCaps;
                }
 
                static void Init ()
@@ -181,71 +332,33 @@ namespace System.Web
                        lock (lockobj) {
                                if (loaded)
                                        return;
-#if TARGET_J2EE
-                               string filepath = "browscap.ini";
-#else
-#if NET_2_0
-                               string dir = Path.GetDirectoryName (WebConfigurationManager.OpenMachineConfiguration().FilePath);
-#else
-                               string dir = Path.GetDirectoryName (WebConfigurationSettings.MachineConfigPath);
-#endif
+                               string dir = HttpRuntime.MachineConfigurationDirectory;
                                string filepath = Path.Combine (dir, "browscap.ini");
                                if (!File.Exists (filepath)) {
                                        // try removing the trailing version directory
                                        dir = Path.GetDirectoryName (dir);
                                        filepath = Path.Combine (dir, "browscap.ini");
                                }
-#endif
                                try {
                                        LoadFile (filepath);
-                               } catch (Exception) { }
+                               } catch (Exception) {}
 
                                loaded = true;
                        }
                }
 
-#if TARGET_J2EE
-               private static TextReader GetJavaTextReader(string filename)
-               {
-                       Stream s;
-                       try
-                       {
-                               java.lang.ClassLoader cl = (java.lang.ClassLoader)
-                                       AppDomain.CurrentDomain.GetData("GH_ContextClassLoader");
-                               if (cl == null)
-                                       return null;
-
-                               string custom = String.Concat("browscap/", filename);
-                               
-                               java.io.InputStream inputStream = cl.getResourceAsStream(custom);
-                               if (inputStream == null)
-                                       inputStream = cl.getResourceAsStream(filename);
-
-                               s = (Stream)vmw.common.IOUtils.getStream(inputStream);
-                       }
-                       catch (Exception e)
-                       {
-                               return null;
-                       }
-                       return new StreamReader (s);
-               }
-#endif
 
                static void LoadFile (string filename)
                {
-#if TARGET_J2EE
-                       TextReader input = GetJavaTextReader(filename);
-                       if(input == null)
-                               return;
-#else
                        if (!File.Exists (filename))
                                return;
 
                        TextReader input = new StreamReader (File.OpenRead (filename));
-#endif
+                       using (input) {
                        string str;
-                       Hashtable allhash = new Hashtable ();
+                       Hashtable allhash = new Hashtable (StringComparer.OrdinalIgnoreCase);
                        int aux = 0;
+                       ArrayList browserData = new ArrayList ();
                        while ((str = input.ReadLine ()) != null) {
                                if (str.Length == 0 || str [0] == ';')
                                        continue;
@@ -261,31 +374,37 @@ namespace System.Web
                                string key = data.GetBrowser ();
                                if (key == null || allhash.ContainsKey (key)) {
                                        allhash.Add (aux++, data);
+                                       browserData.Add (data);
                                } else {
                                        allhash.Add (key, data);
+                                       browserData.Add (data);
                                }
-                       }
+                       }                       
 
-                       alldata = allhash.Values;
+                       alldata = browserData;
                        foreach (BrowserData data in alldata) {
-                               if (data.Parent != null)
+                               string pname = data.GetParentName ();
+                               if (pname == null)
                                        continue;
 
-                               string pname = data.GetParentName ();
-                               if (pname != null)
-                                       data.Parent = (BrowserData) allhash [pname];
+                               data.Parent = (BrowserData) allhash [pname];
+                       }
                        }
                }
 
                static char [] eq = new char []{'='};
                static void ReadCapabilities (TextReader input, BrowserData data)
                {
-                       string str;
+                       string str, key;
+                       string [] keyvalue;
+                       
                        while ((str = input.ReadLine ()) != null && str.Length != 0) {
-                               string [] keyvalue = str.Split (eq, 2);
-                               data.Add (keyvalue [0], keyvalue [1]);
+                               keyvalue = str.Split (eq, 2);
+                               key = keyvalue [0].ToLower (Helpers.InvariantCulture).Trim ();
+                               if (key.Length == 0)
+                                       continue;
+                               data.Add (key, keyvalue [1]);
                        }
                }
        }
 }
-