Mark tests as not working under TARGET_JVM
[mono.git] / mcs / class / System.Web / System.Web / CapabilitiesLoader.cs
1 // 
2 // System.Web.CapabilitiesLoader
3 //
4 // Loads data from browscap.ini file provided by Gary J. Keith from
5 // http://www.GaryKeith.com/browsers. Please don't abuse the
6 // site when updating browscap.ini file. Use the update-browscap.exe tool.
7 //
8 // Authors:
9 //   Gonzalo Paniagua Javier (gonzalo@ximian.com)
10 //
11 // (c) 2003 Novell, Inc. (http://www.novell.com)
12 //
13
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34
35 using System;
36 using System.Collections;
37 using System.Collections.Specialized;
38 using System.Globalization;
39 using System.IO;
40 using System.Text.RegularExpressions;
41 using System.Web.Configuration;
42
43 namespace System.Web
44 {
45         class BrowserData
46         {
47                 static char [] wildchars = new char [] {'*', '?'};
48                 BrowserData parent;
49                 string text;
50                 string pattern;
51                 Regex regex;
52                 ListDictionary data;
53
54                 public BrowserData (string pattern)
55                 {
56                         int norx = pattern.IndexOfAny (wildchars);
57                         if (norx == -1) {
58                                 text = pattern;
59                         } else {
60                                 this.pattern = pattern.Substring (norx);
61                                 text = pattern.Substring (0, norx);
62                                 if (text.Length == 0)
63                                         text = null;
64
65                                 this.pattern = this.pattern.Replace (".", "\\.");
66                                 this.pattern = this.pattern.Replace ("(", "\\(");
67                                 this.pattern = this.pattern.Replace (")", "\\)");
68                                 this.pattern = this.pattern.Replace ("[", "\\[");
69                                 this.pattern = this.pattern.Replace ("]", "\\]");
70                                 this.pattern = this.pattern.Replace ("?", ".");
71                                 this.pattern = this.pattern.Replace ("*", ".*");
72                         }
73                 }
74
75                 public BrowserData Parent {
76                         get { return parent; }
77                         set { parent = value; }
78                 }
79
80                 public void Add (string key, string value)
81                 {
82                         if (data == null)
83                                 data = new ListDictionary ();
84
85                         data.Add (key, value);
86                 }
87
88                 public Hashtable GetProperties (Hashtable tbl)
89                 {
90                         if (parent != null)
91                                 parent.GetProperties (tbl);
92
93                         foreach (string key in data.Keys)
94                                 tbl [key] = data [key];
95
96                         return tbl;
97                 }
98                 
99                 public string GetParentName ()
100                 {
101                         return (string) data ["parent"];
102                 }
103                 
104                 public string GetAlternateBrowser ()
105                 {
106                         return (pattern == null) ? text : null;
107                 }
108
109                 public string GetBrowser ()
110                 {
111                         if (pattern == null)
112                                 return text;
113
114                         return (string) data ["browser"];
115                 }
116                 
117                 public bool IsMatch (string expression)
118                 {
119                         if (expression == null || expression.Length == 0)
120                                 return false;
121
122                         if (text != null) {
123                                 if (text [0] != expression [0] ||
124                                     String.Compare (text, 1, expression, 1,
125                                                     text.Length - 1, false,
126                                                     CultureInfo.InvariantCulture) != 0) {
127                                         return false;
128                                 }
129                                 expression = expression.Substring (text.Length);
130                         }
131                         
132                         if (pattern == null)
133                                 return expression.Length == 0;
134
135                         lock (this) {
136                                 if (regex == null)
137                                         regex = new Regex (pattern);
138                         }
139
140                         return regex.Match (expression).Success;
141                 }
142         }
143         
144         class CapabilitiesLoader : MarshalByRefObject
145         {
146                 const int userAgentsCacheSize = 3000;
147                 static Hashtable defaultCaps;
148                 static readonly object lockobj = new object ();
149
150 #if TARGET_JVM
151                 static bool loaded {
152                         get {
153                                 return alldata != null;
154                         }
155                         set {
156                                 if (alldata == null)
157                                         alldata = new ArrayList ();
158                         }
159                 }
160
161                 const string alldataKey = "System.Web.CapabilitiesLoader.alldata";
162                 static ICollection alldata {
163                         get {
164                                 return (ICollection) AppDomain.CurrentDomain.GetData (alldataKey);
165                         }
166                         set {
167                                 AppDomain.CurrentDomain.SetData (alldataKey, value);
168                         }
169                 }
170
171                 const string userAgentsCacheKey = "System.Web.CapabilitiesLoader.userAgentsCache";
172                 static Hashtable userAgentsCache {
173                         get {
174                                 lock (typeof (CapabilitiesLoader)) {
175                                         Hashtable agentsCache = (Hashtable) AppDomain.CurrentDomain.GetData (userAgentsCacheKey);
176                                         if (agentsCache == null) {
177                                                 agentsCache = Hashtable.Synchronized (new Hashtable (userAgentsCacheSize + 10));
178                                                 AppDomain.CurrentDomain.SetData (userAgentsCacheKey, agentsCache);
179                                         }
180
181                                         return agentsCache;
182                                 }
183                         }
184                 }
185 #else
186                 static volatile bool loaded;
187                 static ICollection alldata;
188                 static Hashtable userAgentsCache = Hashtable.Synchronized(new Hashtable(userAgentsCacheSize+10));
189 #endif
190
191                 private CapabilitiesLoader () {}
192
193                 static CapabilitiesLoader ()
194                 {
195                         defaultCaps = new Hashtable ();
196                         defaultCaps.Add ("frames", "True");
197                         defaultCaps.Add ("tables", "True");
198                 }
199                         
200                 public static Hashtable GetCapabilities (string userAgent)
201                 {
202                         Init ();
203                         if (userAgent != null)
204                                 userAgent = userAgent.Trim ();
205
206                         if (alldata == null || userAgent == null || userAgent == "")
207                                 return defaultCaps;
208
209                         Hashtable userBrowserCaps = (Hashtable) userAgentsCache [userAgent];
210                         if (userBrowserCaps == null) {
211                                 foreach (BrowserData bd in alldata) {
212                                         if (bd.IsMatch (userAgent)) {
213                                                 Hashtable tbl;
214 #if NET_2_0
215                                                 tbl = new Hashtable (StringComparer.InvariantCultureIgnoreCase);
216 #else
217                                                 tbl = new Hashtable (CaseInsensitiveHashCodeProvider.DefaultInvariant,
218                                                         CaseInsensitiveComparer.DefaultInvariant);
219 #endif
220                                                 userBrowserCaps = bd.GetProperties (tbl);
221                                                 break;
222                                         }
223                                 }
224
225                                 if (userBrowserCaps == null)
226                                         userBrowserCaps = defaultCaps;
227
228                                 lock (typeof (CapabilitiesLoader)) {
229                                         if (userAgentsCache.Count >= userAgentsCacheSize) {
230                                                 userAgentsCache.Clear ();
231                                         }
232                                 }
233                                 userAgentsCache [userAgent] = userBrowserCaps;
234                         }
235                         return userBrowserCaps;
236                 }
237
238                 static void Init ()
239                 {
240                         if (loaded)
241                                 return;
242
243                         lock (lockobj) {
244                                 if (loaded)
245                                         return;
246 #if TARGET_J2EE
247                                 string filepath = "browscap.ini";
248 #else
249 #if NET_2_0
250                                 string dir = Path.GetDirectoryName (WebConfigurationManager.OpenMachineConfiguration().FilePath);
251 #else
252                                 string dir = Path.GetDirectoryName (WebConfigurationSettings.MachineConfigPath);
253 #endif
254                                 string filepath = Path.Combine (dir, "browscap.ini");
255                                 if (!File.Exists (filepath)) {
256                                         // try removing the trailing version directory
257                                         dir = Path.GetDirectoryName (dir);
258                                         filepath = Path.Combine (dir, "browscap.ini");
259                                 }
260 #endif
261                                 try {
262                                         LoadFile (filepath);
263                                 } catch (Exception) { }
264
265                                 loaded = true;
266                         }
267                 }
268
269 #if TARGET_J2EE
270                 private static TextReader GetJavaTextReader(string filename)
271                 {
272                         Stream s;
273                         try
274                         {
275                                 java.lang.ClassLoader cl = (java.lang.ClassLoader)
276                                         AppDomain.CurrentDomain.GetData("GH_ContextClassLoader");
277                                 if (cl == null)
278                                         return null;
279
280                                 string custom = String.Concat("browscap/", filename);
281                                 
282                                 java.io.InputStream inputStream = cl.getResourceAsStream(custom);
283                                 if (inputStream == null)
284                                         inputStream = cl.getResourceAsStream(filename);
285
286                                 s = (Stream)vmw.common.IOUtils.getStream(inputStream);
287                         }
288                         catch (Exception e)
289                         {
290                                 return null;
291                         }
292                         return new StreamReader (s);
293                 }
294 #endif
295
296                 static void LoadFile (string filename)
297                 {
298 #if TARGET_J2EE
299                         TextReader input = GetJavaTextReader(filename);
300                         if(input == null)
301                                 return;
302 #else
303                         if (!File.Exists (filename))
304                                 return;
305
306                         TextReader input = new StreamReader (File.OpenRead (filename));
307 #endif
308                         string str;
309                         Hashtable allhash = new Hashtable ();
310                         int aux = 0;
311                         while ((str = input.ReadLine ()) != null) {
312                                 if (str.Length == 0 || str [0] == ';')
313                                         continue;
314
315                                 string userAgent = str.Substring (1, str.Length - 2);
316                                 BrowserData data = new BrowserData (userAgent);
317                                 ReadCapabilities (input, data);
318
319                                 /* Ignore default browser and file version information */
320                                 if (userAgent == "*" || userAgent == "GJK_Browscap_Version")
321                                         continue;
322
323                                 string key = data.GetBrowser ();
324                                 if (key == null || allhash.ContainsKey (key)) {
325                                         allhash.Add (aux++, data);
326                                 } else {
327                                         allhash.Add (key, data);
328                                 }
329                         }
330
331                         alldata = allhash.Values;
332                         foreach (BrowserData data in alldata) {
333                                 if (data.Parent != null)
334                                         continue;
335
336                                 string pname = data.GetParentName ();
337                                 if (pname != null)
338                                         data.Parent = (BrowserData) allhash [pname];
339                         }
340                 }
341
342                 static char [] eq = new char []{'='};
343                 static void ReadCapabilities (TextReader input, BrowserData data)
344                 {
345                         string str;
346                         while ((str = input.ReadLine ()) != null && str.Length != 0) {
347                                 string [] keyvalue = str.Split (eq, 2);
348                                 data.Add (keyvalue [0], keyvalue [1]);
349                         }
350                 }
351         }
352 }
353