Merge pull request #347 from JamesB7/master
[mono.git] / mcs / class / System.Web / System.Web / BrowserCapabilities.cs
1 // 
2 // System.Web.HttpBrowserCapabilities
3 //
4 // Authors:
5 //   Patrik Torstensson (Patrik.Torstensson@labs2.com)
6 //   Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //
8 // (c) 2003-2009 Novell, Inc. (http://www.novell.com)
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System.Collections;
33 using System.Globalization;
34 using System.Web.Configuration;
35 using System.Web.UI;
36 using System.Security.Permissions;
37 using System.Web.Util;
38
39 namespace System.Web.Configuration
40 {
41         public partial class HttpCapabilitiesBase
42         {
43                 const int HaveActiveXControls = 1; // 1;
44                 const int HaveAdapters = 2;
45                 const int HaveAOL = 3; // 2;
46                 const int HaveBackGroundSounds = 4; // 3;
47                 const int HaveBeta = 5; // 4;
48                 const int HaveBrowser = 6; // 5;
49                 const int HaveBrowsers = 7;
50                 const int HaveCanCombineFormsInDeck = 8;
51                 const int HaveCanInitiateVoiceCall = 9;
52                 const int HaveCanRenderAfterInputOrSelectElement = 10;
53                 const int HaveCanRenderEmptySelects = 11;
54                 const int HaveCanRenderInputAndSelectElementsTogether = 12;
55                 const int HaveCanRenderMixedSelects = 13;
56                 const int HaveCanRenderOneventAndPrevElementsTogether = 14;
57                 const int HaveCanRenderPostBackCards = 15;
58                 const int HaveCanRenderSetvarZeroWithMultiSelectionList = 16;
59                 const int HaveCanSendMail = 17;
60                 const int HaveCDF = 18; // 6;
61                 //const int HaveClrVersion = 19; // 7;
62                 const int HaveCookies = 20; // 8;
63                 const int HaveCrawler = 21; // 9;
64                 const int HaveDefaultSubmitButtonLimit = 22;
65                 const int HaveEcmaScriptVersion = 23;
66                 const int HaveFrames = 24; // 11;
67                 const int HaveGatewayMajorVersion = 25;
68                 const int HaveGatewayMinorVersion = 26;
69                 const int HaveGatewayVersion = 27;
70                 const int HaveHasBackButton = 28;
71                 const int HaveHidesRightAlignedMultiselectScrollbars = 29;
72                 const int HaveHtmlTextWriter = 30;
73                 const int HaveId = 31;
74                 const int HaveInputType = 32;
75                 const int HaveIsColor = 33;
76                 const int HaveIsMobileDevice = 34;
77                 const int HaveJavaApplets = 35; // 12;
78                 const int HaveJavaScript = 36; // 13;
79                 const int HaveJScriptVersion = 37;
80                 const int HaveMajorVersion = 38; // 14;
81                 const int HaveMaximumHrefLength = 39;
82                 const int HaveMaximumRenderedPageSize = 40;
83                 const int HaveMaximumSoftkeyLabelLength = 41;
84                 const int HaveMinorVersion = 42; // 15;
85                 const int HaveMinorVersionString = 43;
86                 const int HaveMobileDeviceManufacturer = 44;
87                 const int HaveMobileDeviceModel = 45;
88                 const int HaveMSDomVersion = 46; // 16;
89                 const int HaveNumberOfSoftkeys = 47;
90                 const int HavePlatform = 48; // 17;
91                 const int HavePreferredImageMime = 49;
92                 const int HavePreferredRenderingMime = 50;
93                 const int HavePreferredRenderingType = 51;
94                 const int HavePreferredRequestEncoding = 52;
95                 const int HavePreferredResponseEncoding = 53;
96                 const int HaveRendersBreakBeforeWmlSelectAndInput = 54;
97                 const int HaveRendersBreaksAfterHtmlLists = 55;
98                 const int HaveRendersBreaksAfterWmlAnchor = 56;
99                 const int HaveRendersBreaksAfterWmlInput = 57;
100                 const int HaveRendersWmlDoAcceptsInline = 58;
101                 const int HaveRendersWmlSelectsAsMenuCards = 59;
102                 const int HaveRequiredMetaTagNameValue = 60;
103                 const int HaveRequiresAttributeColonSubstitution = 61;
104                 const int HaveRequiresContentTypeMetaTag = 62;
105                 const int HaveRequiresControlStateInSession = 63;
106                 const int HaveRequiresDBCSCharacter = 64;
107                 const int HaveRequiresHtmlAdaptiveErrorReporting = 65;
108                 const int HaveRequiresLeadingPageBreak = 66;
109                 const int HaveRequiresNoBreakInFormatting = 67;
110                 const int HaveRequiresOutputOptimization = 68;
111                 const int HaveRequiresPhoneNumbersAsPlainText = 69;
112                 const int HaveRequiresSpecialViewStateEncoding = 70;
113                 const int HaveRequiresUniqueFilePathSuffix = 71;
114                 const int HaveRequiresUniqueHtmlCheckboxNames = 72;
115                 const int HaveRequiresUniqueHtmlInputNames = 73;
116                 const int HaveRequiresUrlEncodedPostfieldValues = 74;
117                 const int HaveScreenBitDepth = 75;
118                 const int HaveScreenCharactersHeight = 76;
119                 const int HaveScreenCharactersWidth = 77;
120                 const int HaveScreenPixelsHeight = 78;
121                 const int HaveScreenPixelsWidth = 79;
122                 const int HaveSupportsAccesskeyAttribute = 80;
123                 const int HaveSupportsBodyColor = 81;
124                 const int HaveSupportsBold = 82;
125                 const int HaveSupportsCacheControlMetaTag = 83;
126                 const int HaveSupportsCallback = 84;
127                 const int HaveSupportsCss = 85;
128                 const int HaveSupportsDivAlign = 86;
129                 const int HaveSupportsDivNoWrap = 87;
130                 const int HaveSupportsEmptyStringInCookieValue = 88;
131                 const int HaveSupportsFontColor = 89;
132                 const int HaveSupportsFontName = 90;
133                 const int HaveSupportsFontSize = 91;
134                 const int HaveSupportsImageSubmit = 92;
135                 const int HaveSupportsIModeSymbols = 93;
136                 const int HaveSupportsInputIStyle = 94;
137                 const int HaveSupportsInputMode = 95;
138                 const int HaveSupportsItalic = 96;
139                 const int HaveSupportsJPhoneMultiMediaAttributes = 97;
140                 const int HaveSupportsJPhoneSymbols = 98;
141                 const int HaveSupportsQueryStringInFormAction = 99;
142                 const int HaveSupportsRedirectWithCookie = 100;
143                 const int HaveSupportsSelectMultiple = 101;
144                 const int HaveSupportsUncheck = 102;
145                 const int HaveSupportsXmlHttp = 103;
146                 const int HaveTables = 104; // 18;
147                 const int HaveTagWriter = 105; // 19;
148                 const int HaveType = 106;
149                 const int HaveUseOptimizedCacheKey = 107;
150                 const int HaveVBScript = 108; // 20;
151                 const int HaveVersion = 109; // 21;
152                 const int HaveW3CDomVersion = 110; // 22;
153                 const int HaveWin16 = 111; // 23;
154                 const int HaveWin32 = 112; // 24;
155                 const int LastHaveFlag = 113;
156
157                 BitArray flags = new BitArray (LastHaveFlag);
158                 bool activeXControls;
159                 bool aol;
160                 bool backgroundSounds;
161                 bool beta;
162                 string browser;
163                 bool cdf;
164                 Version clrVersion;
165                 bool cookies;
166                 bool crawler;
167                 Version ecmaScriptVersion;
168                 bool frames;
169                 bool javaApplets;
170                 bool javaScript;
171                 int majorVersion;
172                 double minorVersion;
173                 Version msDomVersion;
174                 string platform;
175                 bool tables;
176                 Type tagWriter;
177                 bool vbscript;
178                 string version;
179                 Version w3CDomVersion;
180                 bool win16;
181                 bool win32;
182                 Version [] clrVersions;
183                 internal string useragent;
184
185                 public bool ActiveXControls {
186                         get {
187                                 if (!Get (HaveActiveXControls)) {
188                                         activeXControls = ReadBoolean ("activexcontrols");
189                                         Set (HaveActiveXControls);
190                                 }
191
192                                 return activeXControls;
193                         }
194                 }
195
196                 public bool AOL {
197                         get {
198                                 if (!Get (HaveAOL)) {
199                                         aol = ReadBoolean ("aol");
200                                         Set (HaveAOL);
201                                 }
202
203                                 return aol;
204                         }
205                 }
206
207                 public bool BackgroundSounds {
208                         get {
209                                 if (!Get (HaveBackGroundSounds)) {
210                                         backgroundSounds = ReadBoolean ("backgroundsounds");
211                                         Set (HaveBackGroundSounds);
212                                 }
213
214                                 return backgroundSounds;
215                         }
216                 }
217
218                 public bool Beta {
219                         get {
220                                 if (!Get (HaveBeta)) {
221                                         beta = ReadBoolean ("beta");
222                                         Set (HaveBeta);
223                                 }
224
225                                 return beta;
226                         }
227                 }
228
229                 public string Browser {
230                         get {
231                                 if (!Get (HaveBrowser)) {
232                                         browser = this ["browser"];
233                                         if (browser == null || browser.Length == 0)
234                                                 browser = "Unknown";
235                                         Set (HaveBrowser);
236                                 }
237
238                                 return browser;
239                         }
240                 }
241
242                 ArrayList browsers = null;
243                 public ArrayList Browsers {
244                         get {
245                                 if (!Get (HaveBrowsers)) {
246                                         browsers = ReadArrayList ("browsers");
247                                         Set (HaveBrowsers);
248                                 }
249
250                                 return browsers;
251                         }
252                 }
253
254                 public bool IsBrowser (string browserName) 
255                 {
256                         foreach (string browser in Browsers) {
257                                 if (0 == String.Compare (browser, "Unknown", StringComparison.OrdinalIgnoreCase)) {
258                                         continue;
259                                 }
260                                 if (0 == String.Compare (browserName, browser, StringComparison.OrdinalIgnoreCase)) {
261                                         return true;
262                                 }
263                         }
264                         return false;
265                 }
266
267                 public bool CDF {
268                         get {
269                                 if (!Get (HaveCDF)) {
270                                         cdf = ReadBoolean ("cdf");
271                                         Set (HaveCDF);
272                                 }
273
274                                 return cdf;
275                         }
276                 }
277
278                 public Version ClrVersion {
279                         get {
280                                 if (clrVersion == null)
281                                         InternalGetClrVersions ();
282
283                                 return clrVersion;
284                         }
285                 }
286
287                 public bool Cookies {
288                         get {
289                                 if (!Get (HaveCookies)) {
290                                         cookies = ReadBoolean ("cookies");
291                                         Set (HaveCookies);
292                                 }
293
294                                 return cookies;
295                         }
296                 }
297
298                 public bool Crawler {
299                         get {
300                                 if (!Get (HaveCrawler)) {
301                                         crawler = ReadBoolean ("crawler");
302                                         Set (HaveCrawler);
303                                 }
304
305                                 return crawler;
306                         }
307                 }
308
309                 public Version EcmaScriptVersion {
310                         get {
311                                 if (!Get (HaveEcmaScriptVersion)) {
312                                         ecmaScriptVersion = ReadVersion ("ecmascriptversion");
313                                         Set (HaveEcmaScriptVersion);
314                                 }
315
316                                 return ecmaScriptVersion;
317                         }
318                 }
319
320                 public bool Frames {
321                         get {
322                                 if (!Get (HaveFrames)) {
323                                         frames = ReadBoolean ("frames");
324                                         Set (HaveFrames);
325                                 }
326
327                                 return frames;
328                         }
329                 }
330
331                 public bool JavaApplets {
332                         get {
333                                 if (!Get (HaveJavaApplets)) {
334                                         javaApplets = ReadBoolean ("javaapplets");
335                                         Set (HaveJavaApplets);
336                                 }
337
338                                 return javaApplets;
339                         }
340                 }
341
342
343                 [Obsolete ("The recommended alternative is the EcmaScriptVersion property. A Major version value greater than or equal to 1 implies JavaScript support. http://go.microsoft.com/fwlink/?linkid=14202")]
344                 public bool JavaScript {
345                         get {
346                                 if (!Get (HaveJavaScript)) {
347                                         javaScript = ReadBoolean ("javascript");
348                                         Set (HaveJavaScript);
349                                 }
350
351                                 return javaScript;
352                         }
353                 }
354
355                 public int MajorVersion {
356                         get {
357                                 if (!Get (HaveMajorVersion)) {
358                                         // Try with MS.NET's property name.
359                                         // See: https://bugzilla.xamarin.com/show_bug.cgi?id=4108
360                                         if (this["majorversion"] != null)
361                                                 majorVersion = ReadInt32 ("majorversion");
362                                         else 
363                                                 majorVersion = ReadInt32 ("majorver");
364                                         Set (HaveMajorVersion);
365                                 }
366
367                                 return majorVersion;
368                         }
369                 }
370
371                 public double MinorVersion {
372                         get {
373                                 if (!Get (HaveMinorVersion)) {
374                                         // Try with MS.NET's property name.
375                                         // See: https://bugzilla.xamarin.com/show_bug.cgi?id=4108
376                                         if (this["minorversion"] != null)
377                                                 minorVersion = ReadDouble ("minorversion");
378                                         else
379                                                 minorVersion = ReadDouble ("minorver");
380                                         Set (HaveMinorVersion);
381                                 }
382
383                                 return minorVersion;
384                         }
385                 }
386
387                 public Version MSDomVersion {
388                         get {
389                                 if (!Get (HaveMSDomVersion)) {
390                                         msDomVersion = ReadVersion ("msdomversion");
391                                         Set (HaveMSDomVersion);
392                                 }
393
394                                 return msDomVersion;
395                         }
396                 }
397
398                 public string Platform {
399                         get {
400                                 if (!Get (HavePlatform)) {
401                                         platform = ReadString ("platform");
402                                         Set (HavePlatform);
403                                 }
404
405                                 return platform;
406                         }
407                 }
408
409                 public bool Tables {
410                         get {
411                                 if (!Get (HaveTables)) {
412                                         tables = ReadBoolean ("tables");
413                                         Set (HaveTables);
414                                 }
415
416                                 return tables;
417                         }
418                 }
419
420                 public Type TagWriter {
421                         get {
422                                 if (!Get (HaveTagWriter)) {
423                                         tagWriter = GetTagWriter ();
424                                         Set (HaveTagWriter);
425                                 }
426                                 return tagWriter;
427                         }
428                 }
429                 
430                 internal virtual Type GetTagWriter ()
431                 {
432                                 return typeof (HtmlTextWriter);                 
433                 }
434
435                 public string Type {
436                         get {
437                                 return Browser + MajorVersion;
438                         }
439                 }
440
441                 public bool VBScript {
442                         get {
443                                 if (!Get (HaveVBScript)) {
444                                         vbscript = ReadBoolean ("vbscript");
445                                         Set (HaveVBScript);
446                                 }
447
448                                 return vbscript;
449                         }
450                 }
451
452                 public string Version {
453                         get {
454                                 if (!Get (HaveVersion)) {
455                                         version = ReadString ("version");
456                                         Set (HaveVersion);
457                                 }
458
459                                 return version;
460                         }
461                 }
462
463                 public Version W3CDomVersion {
464                         get {
465                                 if (!Get (HaveW3CDomVersion)) {
466                                         w3CDomVersion = ReadVersion ("w3cdomversion");
467                                         Set (HaveW3CDomVersion);
468                                 }
469
470                                 return w3CDomVersion;
471                         }
472                 }
473
474                 public bool Win16 {
475                         get {
476                                 if (!Get (HaveWin16)) {
477                                         win16 = ReadBoolean ("win16");
478                                         Set (HaveWin16);
479                                 }
480
481                                 return win16;
482                         }
483                 }
484
485                 public bool Win32 {
486                         get {
487                                 // This is the list of different windows platforms that browscap.ini has.
488                                 // Win16 Win2000 Win2003 Win32 Win95 Win98 WinME WinNT WinVI WinXP
489                                 if (!Get (HaveWin32)) {
490                                         string platform = Platform;
491                                         win32 = (platform != "Win16" && platform.StartsWith ("Win"));
492                                         Set (HaveWin32);
493                                 }
494                                 return win32;
495                         }
496                 }
497
498                 public Version [] GetClrVersions ()
499                 {
500                         if (clrVersions == null)
501                                 InternalGetClrVersions ();
502
503                         return clrVersions;
504                 }
505
506                 void InternalGetClrVersions ()
507                 {
508                         char [] anychars = new char [] { ';', ')' };
509                         string s = useragent;
510                         ArrayList list = null;
511                         int idx;
512                         while ((s != null) && (idx = s.IndexOf (".NET CLR ")) != -1) {
513                                 int end = s.IndexOfAny (anychars, idx + 9);
514                                 if (end == -1)
515                                         break;
516
517                                 string ver = s.Substring (idx + 9, end - idx - 9);
518                                 Version v = null;
519                                 try {
520                                         v = new Version (ver);
521                                         if (clrVersion == null || v > clrVersion)
522                                                 clrVersion = v;
523
524                                         if (list == null)
525                                                 list = new ArrayList (4);
526
527                                         list.Add (v);
528                                 } catch { }
529                                 s = s.Substring (idx + 9);
530                         }
531                         
532                         if (list == null || list.Count == 0) {
533                                 clrVersion = new Version ();
534                                 clrVersions = null;
535                         } else {
536                                 list.Sort ();
537                                 clrVersions = (Version []) list.ToArray (typeof (Version));
538                         }
539                 }
540
541                 bool ReadBoolean (string key)
542                 {
543                         string v = this [key];
544                         if (v == null) {
545                                 throw CreateCapabilityNotFoundException (key);
546                         }
547
548                         return (String.Compare (v, "True", true, Helpers.InvariantCulture) == 0);
549                 }
550
551                 int ReadInt32 (string key)
552                 {
553                         string v = this [key];
554                         if (v == null) {
555                                 throw CreateCapabilityNotFoundException (key);
556                         }
557
558                         try {
559                                 return Int32.Parse (v);
560                         } catch {
561                                 throw CreateCapabilityNotFoundException (key);
562                         }
563                 }
564
565                 double ReadDouble (string key)
566                 {
567                         string v = this [key];
568                         if (v == null) {
569                                 throw CreateCapabilityNotFoundException (key);
570                         }
571
572                         try {
573                                 return Double.Parse (v);
574                         } catch {
575                                 throw CreateCapabilityNotFoundException (key);
576                         }
577                 }
578
579                 string ReadString (string key) 
580                 {
581                         string v = this [key];
582                         if (v == null) {
583                                 throw CreateCapabilityNotFoundException (key);
584                         }
585
586                         return v;
587                 }
588
589                 Version ReadVersion (string key) 
590                 {
591                         string v = this [key];
592                         if (v == null) {
593                                 throw CreateCapabilityNotFoundException (key);
594                         }
595
596                         try {
597                                 return new Version (v);
598                         }
599                         catch {
600                                 throw CreateCapabilityNotFoundException (key);
601                         }
602                 }
603
604                 ArrayList ReadArrayList (string key) 
605                 {
606                         ArrayList v = (ArrayList)this.capabilities [key];
607                         if (v == null) {
608                                 throw CreateCapabilityNotFoundException (key);
609                         }
610
611                         return v;
612                 }
613
614                 Exception CreateCapabilityNotFoundException (string key) {
615                         return new ArgumentNullException (String.Format ("browscaps.ini does not contain a definition for capability {0} for userAgent {1}", key, Browser));
616                 }
617
618                 bool Get (int idx)
619                 {
620                         return flags.Get (idx);
621                 }
622
623                 void Set (int idx)
624                 {
625                         flags.Set (idx, true);
626                 }
627         }
628 }