Multiple fixes for URI using 'news:' scheme
authorSebastien Pouliot <sebastien@ximian.com>
Wed, 15 Sep 2010 18:12:49 +0000 (14:12 -0400)
committerSebastien Pouliot <sebastien@ximian.com>
Wed, 15 Sep 2010 21:31:20 +0000 (17:31 -0400)
* System/Uri.cs: Make it easier to reuse EscapeString without adding new
boolean parameters. Shortcut parsing for 'news' since it's simpler (no
query, host, authority...) Avoid creating StringBuilder instance when
[un]escape-ing empty strings
* System/UriBuilder.cs: Adjust for EscapeString API change
* System/UriParser.cs: Fix default news port and adjust for EscapeString
API change

* Test/System/UriTest2.cs: Add test case for 'news:' showing the lack
of Query and Port (but support for Fragment) and the escape-ing
differences.

mcs/class/System/System/Uri.cs
mcs/class/System/System/UriBuilder.cs
mcs/class/System/System/UriParser.cs
mcs/class/System/Test/System/UriTest2.cs

index c0d179620409c3614ea8d81adb7fa9c4b8c5457f..6f9aebb8a05ed74f6baa39f34d4af8e5936fbc7d 100644 (file)
@@ -536,19 +536,15 @@ namespace System {
                                EnsureAbsoluteUri ();
                                if (cachedLocalPath != null)
                                        return cachedLocalPath;
-                               if (!IsFile && IsWellFormedOriginalString ())
+                               if (!IsFile && (scheme != Uri.UriSchemeNews) && IsWellFormedOriginalString ())
                                        return AbsolutePath;
 
-                               bool windows = (path.Length > 3 && path [1] == ':' &&
-                                               (path [2] == '\\' || path [2] == '/'));
-
                                if (!IsUnc) {
                                        string p = Unescape (path);
-                                       bool replace = windows;
-#if ONLY_1_1
-                                       replace |= (System.IO.Path.DirectorySeparatorChar == '\\');
-#endif
-                                       if (replace)
+                                       bool windows = (path.Length > 3 && path [1] == ':' &&
+                                               (path [2] == '\\' || path [2] == '/'));
+
+                                       if (windows)
                                                cachedLocalPath = p.Replace ('/', '\\');
                                        else
                                                cachedLocalPath = p;
@@ -1091,12 +1087,22 @@ namespace System {
                protected static string EscapeString (string str) 
 #endif
                {
-                       return EscapeString (str, false, true, true);
+                       return EscapeString (str, Uri.EscapeCommonHexBrackets);
                }
-               
-               internal static string EscapeString (string str, bool escapeReserved, bool escapeHex, bool escapeBrackets) 
+
+               private const string EscapeCommon = "<>%\"{}|\\^`";
+               private const string EscapeReserved = ";/?:@&=+$,";
+               private const string EscapeHex = "#";
+               private const string EscapeBrackets = "[]";
+
+               private const string EscapeNews = EscapeCommon + EscapeBrackets + "?";
+               private const string EscapeCommonHex = EscapeCommon + EscapeHex;
+               private const string EscapeCommonBrackets = EscapeCommon + EscapeBrackets;
+               internal const string EscapeCommonHexBrackets = EscapeCommon + EscapeHex + EscapeBrackets;
+
+               internal static string EscapeString (string str, string escape) 
                {
-                       if (str == null)
+                       if (String.IsNullOrEmpty (str))
                                return String.Empty;
                        
                        StringBuilder s = new StringBuilder ();
@@ -1124,15 +1130,10 @@ namespace System {
                                int length = data.Length;
                                for (int j = 0; j < length; j++) {
                                        char c = (char) data [j];
-                                       if ((c <= 0x20) || (c >= 0x7f) || 
-                                           ("<>%\"{}|\\^`".IndexOf (c) != -1) ||
-                                           (escapeHex && (c == '#')) ||
-                                           (escapeBrackets && (c == '[' || c == ']')) ||
-                                           (escapeReserved && (";/?:@&=+$,".IndexOf (c) != -1))) {
+                                       if ((c <= 0x20) || (c >= 0x7f) || (escape.IndexOf (c) != -1))
                                                s.Append (HexEscape (c));
-                                               continue;
-                                       }       
-                                       s.Append (c);
+                                       else
+                                               s.Append (c);
                                }
                        }
                        
@@ -1154,7 +1155,7 @@ namespace System {
                        if (userEscaped)
                                return;
 
-                       host = EscapeString (host, false, true, false);
+                       host = EscapeString (host, EscapeCommonHex);
                        if (host.Length > 1 && host [0] != '[' && host [host.Length - 1] != ']') {
                                // host name present (but not an IPv6 address)
                                host = host.ToLower (CultureInfo.InvariantCulture);
@@ -1177,8 +1178,9 @@ namespace System {
                
                internal static string Unescape (string str, bool excludeSpecial) 
                {
-                       if (str == null)
+                       if (String.IsNullOrEmpty (str))
                                return String.Empty;
+
                        StringBuilder s = new StringBuilder ();
                        int len = str.Length;
                        for (int i = 0; i < len; i++) {
@@ -1391,6 +1393,13 @@ namespace System {
                                endpos = pos;
                        }
 
+                       // special case: there is no query part for 'news'
+                       if (scheme == Uri.UriSchemeNews) {
+                               pos = scheme.Length + 1;
+                               path = EscapeString (uriString.Substring (pos, endpos - pos), EscapeNews);
+                               return null;
+                       }
+
                        // 6 query
                        pos = uriString.IndexOf ('?', startpos, endpos-startpos);
                        if (pos != -1) {
@@ -1914,7 +1923,7 @@ namespace System {
                {
                        // funny, but it does not use the Parser's IsWellFormedOriginalString().
                        // Also, it seems we need to *not* escape hex.
-                       return EscapeString (OriginalString, false, false, true) == OriginalString;
+                       return EscapeString (OriginalString, EscapeCommonBrackets) == OriginalString;
                }
 
                // static methods
index 15a7846b962874e385dee40fca76e04c95eff06c..c4c66017fb99d3482f03b45ad746e3c3af682ede 100644 (file)
@@ -164,7 +164,7 @@ namespace System
                                if (value == null || value.Length == 0) {\r
                                        path = "/";\r
                                } else {\r
-                                       path = Uri.EscapeString (value.Replace ('\\', '/'), false, true, true);\r
+                                       path = Uri.EscapeString (value.Replace ('\\', '/'), Uri.EscapeCommonHexBrackets);\r
                                }\r
                                modified = true;\r
                        }\r
index 7a948b464f107e27448bd44c9f7dd9db9fa01699..33bfbda5387be247027d6a876b27feacff267825 100644 (file)
@@ -233,7 +233,7 @@ namespace System {
 
                        switch (format) {
                        case UriFormat.UriEscaped:
-                               return Uri.EscapeString (s, false, true, true);
+                               return Uri.EscapeString (s, Uri.EscapeCommonHexBrackets);
                        case UriFormat.SafeUnescaped:
                                // TODO subset of escape rules
                                s = Uri.Unescape (s, false);
@@ -259,11 +259,9 @@ namespace System {
                        InternalRegister (newtable, new DefaultUriParser (), Uri.UriSchemeHttp, 80);
                        InternalRegister (newtable, new DefaultUriParser (), Uri.UriSchemeHttps, 443);
                        InternalRegister (newtable, new DefaultUriParser (), Uri.UriSchemeMailto, 25);
-#if NET_2_0
                        InternalRegister (newtable, new DefaultUriParser (), Uri.UriSchemeNetPipe, -1);
                        InternalRegister (newtable, new DefaultUriParser (), Uri.UriSchemeNetTcp, -1);
-#endif
-                       InternalRegister (newtable, new DefaultUriParser (), Uri.UriSchemeNews, 119);
+                       InternalRegister (newtable, new DefaultUriParser (), Uri.UriSchemeNews, -1);
                        InternalRegister (newtable, new DefaultUriParser (), Uri.UriSchemeNntp, 119);
                        // not defined in Uri.UriScheme* but a parser class exists
                        InternalRegister (newtable, new DefaultUriParser (), "ldap", 389);
index 2e480b8997339f92d48f28d2da929b939cd19151..1c4a23619eba1ae9a2dd24350f04cfcc4f2d3c4b 100644 (file)
@@ -738,5 +738,39 @@ TextWriter sw = Console.Out;
                        Assert.AreEqual ("subdir/", segments [2].Replace ("%5C", "/"), "s[2]");
                        Assert.AreEqual ("file", segments [3], "s[3]");
                }
+
+               [Test]
+               public void NewsScheme ()
+               {
+                       Uri uri = new Uri ("news:novell.mono.moonlight/uri?query");
+
+                       Assert.AreEqual ("novell.mono.moonlight/uri%3Fquery", uri.AbsolutePath, "AbsolutePath");
+                       Assert.AreEqual ("news:novell.mono.moonlight/uri%3Fquery", uri.AbsoluteUri, "AbsoluteUri");
+                       Assert.AreEqual (String.Empty, uri.Authority, "Authority");
+                       Assert.AreEqual (String.Empty, uri.DnsSafeHost, "DnsSafeHost");
+                       Assert.AreEqual (String.Empty, uri.Fragment, "Fragment");
+                       Assert.AreEqual (String.Empty, uri.Host, "Host");
+                       Assert.AreEqual (UriHostNameType.Unknown, uri.HostNameType, "HostNameType");
+                       Assert.IsTrue (uri.IsAbsoluteUri, "IsAbsoluteUri");
+                       Assert.IsTrue (uri.IsDefaultPort, "IsDefaultPort");
+                       Assert.IsFalse (uri.IsFile, "IsFile");
+                       Assert.IsFalse (uri.IsLoopback, "IsLoopback");
+                       Assert.IsFalse (uri.IsUnc, "IsUnc");
+                       Assert.AreEqual ("novell.mono.moonlight/uri?query", uri.LocalPath, "LocalPath");
+                       Assert.AreEqual ("news:novell.mono.moonlight/uri?query", uri.OriginalString, "OriginalString");
+                       Assert.AreEqual ("novell.mono.moonlight/uri%3Fquery", uri.PathAndQuery, "PathAndQuery");
+                       Assert.AreEqual (-1, uri.Port, "Port");
+                       Assert.AreEqual (String.Empty, uri.Query, "Query");
+                       Assert.AreEqual ("news", uri.Scheme, "Scheme");
+                       Assert.AreEqual ("novell.mono.moonlight/", uri.Segments [0], "Segments [0]");
+                       Assert.AreEqual ("uri%3Fquery", uri.Segments [1], "Segments [1]");
+                       Assert.IsFalse (uri.UserEscaped, "UserEscaped");
+                       Assert.AreEqual (String.Empty, uri.UserInfo, "UserInfo");
+
+                       // special escaped characters - they differs a bit from other URI
+                       uri = new Uri ("news:novell.mono.moonlight/<>%\"{}|\\^`;/?:@&=+$,[]#abc");
+                       Assert.AreEqual ("novell.mono.moonlight/%3C%3E%25%22%7B%7D%7C%5C%5E%60;/%3F:@&=+$,%5B%5D", uri.AbsolutePath, "Special");
+                       Assert.AreEqual ("#abc", uri.Fragment, "Special/Fragment");
+               }
        }\r
 }\r