// Authors:
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
//
-// (c) 2003 Novell, Inc. (http://www.novell.com)
+// (c) 2003-2009 Novell, Inc. (http://www.novell.com)
//
//
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;
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 ("*", ".*");
}
}
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 ()
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);
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 ()
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;
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]);
}
}
}
}
-