Bug 1324243 - Normalize IPv6 r=mcmanus,manishearth draft
authorValentin Gosu <valentin.gosu@gmail.com>
Thu, 09 Mar 2017 00:55:05 +0100
changeset 495853 9a00834599e546d17259ce72c6ce91af8d7bfd3d
parent 495323 800ba54a4bd52628833c4db005ddd182586666c4
child 548478 dbaf76054ae5a0894e98b8d926c81292f0beb672
push id48446
push uservalentin.gosu@gmail.com
push dateThu, 09 Mar 2017 11:10:49 +0000
reviewersmcmanus, manishearth
bugs1324243
milestone55.0a1
Bug 1324243 - Normalize IPv6 r=mcmanus,manishearth MozReview-Commit-ID: 1UFIdeWrz1E
docshell/test/unit/test_nsDefaultURIFixup_info.js
dom/url/tests/test_url.html
netwerk/base/nsStandardURL.cpp
netwerk/base/rust-url-capi/src/lib.rs
netwerk/base/rust-url-capi/src/rust-url-capi.h
netwerk/test/unit/test_URIs.js
netwerk/test/unit/test_standardurl.js
testing/web-platform/meta/url/a-element-origin-xhtml.xhtml.ini
testing/web-platform/meta/url/a-element-origin.html.ini
testing/web-platform/meta/url/a-element-xhtml.xhtml.ini
testing/web-platform/meta/url/a-element.html.ini
testing/web-platform/meta/url/url-constructor.html.ini
testing/web-platform/meta/url/url-origin.html.ini
testing/web-platform/meta/url/url-setters.html.ini
--- a/docshell/test/unit/test_nsDefaultURIFixup_info.js
+++ b/docshell/test/unit/test_nsDefaultURIFixup_info.js
@@ -195,21 +195,23 @@ var testcases = [ {
     protocolChange: true,
   }, {
     input: "[fe80:cd00:0:cde:1257:0:211e:729c]",
     fixedURI: "http://[fe80:cd00:0:cde:1257:0:211e:729c]/",
     alternateURI: "http://[fe80:cd00:0:cde:1257:0:211e:729c]/",
     protocolChange: true,
   }, {
     input: "[64:ff9b::8.8.8.8]",
-    fixedURI: "http://[64:ff9b::8.8.8.8]/",
+    fixedURI: "http://[64:ff9b::808:808]/",
+    alternateURI: "http://[64:ff9b::808:808]/",
     protocolChange: true
   }, {
     input: "[64:ff9b::8.8.8.8]/~moz",
-    fixedURI: "http://[64:ff9b::8.8.8.8]/~moz",
+    fixedURI: "http://[64:ff9b::808:808]/~moz",
+    alternateURI: "http://[64:ff9b::808:808]/~moz",
     protocolChange: true
   }, {
     input: "[::1][::1]",
     keywordLookup: true,
     protocolChange: true
   }, {
     input: "[::1][100",
     fixedURI: null,
--- a/dom/url/tests/test_url.html
+++ b/dom/url/tests/test_url.html
@@ -318,18 +318,18 @@
   <script>
     /** Test for Bug 960014 **/
     var url = new URL("http://localhost/");
     url.hostname = "[2001::1]";
     is(url.hostname, "[2001::1]", "IPv6 hostname");
     is(url.href, "http://[2001::1]/");
 
     url.hostname = "[::192.9.5.5]";
-    is(url.hostname, "[::192.9.5.5]", "IPv6 hostname");
-    is(url.href, "http://[::192.9.5.5]/");
+    is(url.hostname, "[::c009:505]", "IPv6 hostname");
+    is(url.href, "http://[::c009:505]/");
 
     url = new URL("http://localhost/");
     url.hostname = "[::]";
     is(url.hostname, "[::]", "IPv6 hostname");
 
     url = new URL("http://localhost/");
     url.host = "[2001::1]:30";
     is(url.hostname, "[2001::1]", "IPv6 hostname");
--- a/netwerk/base/nsStandardURL.cpp
+++ b/netwerk/base/nsStandardURL.cpp
@@ -768,17 +768,25 @@ nsStandardURL::BuildNormalizedSpec(const
             return NS_ERROR_MALFORMED_URI;  // don't allow spaces in the hostname
         nsresult rv = NormalizeIDN(tempHost, encHost);
         if (NS_FAILED(rv)) {
             return rv;
         }
         if (!SegmentIs(spec, mScheme, "resource") &&
             !SegmentIs(spec, mScheme, "chrome")) {
             nsAutoCString ipString;
-            if (NS_SUCCEEDED(NormalizeIPv4(encHost, ipString))) {
+            if (encHost.Length() > 0 &&
+                encHost.First() == '[' && encHost.Last() == ']' &&
+                ValidIPv6orHostname(encHost.get(), encHost.Length())) {
+                rv = (nsresult) rusturl_parse_ipv6addr(&encHost, &ipString);
+                if (NS_FAILED(rv)) {
+                    return rv;
+                }
+                encHost = ipString;
+            } else if (NS_SUCCEEDED(NormalizeIPv4(encHost, ipString))) {
                 encHost = ipString;
             }
         }
 
         // NormalizeIDN always copies, if the call was successful.
         useEncHost = true;
         approxLen += encHost.Length();
 
@@ -2009,17 +2017,25 @@ nsStandardURL::SetHost(const nsACString 
     nsAutoCString hostBuf;
     nsresult rv = NormalizeIDN(flat, hostBuf);
     if (NS_FAILED(rv)) {
         return rv;
     }
 
     if (!SegmentIs(mScheme, "resource") && !SegmentIs(mScheme, "chrome")) {
         nsAutoCString ipString;
-        if (NS_SUCCEEDED(NormalizeIPv4(hostBuf, ipString))) {
+        if (hostBuf.Length() > 0 &&
+            hostBuf.First() == '[' && hostBuf.Last() == ']' &&
+            ValidIPv6orHostname(hostBuf.get(), hostBuf.Length())) {
+            rv = (nsresult) rusturl_parse_ipv6addr(&hostBuf, &ipString);
+            if (NS_FAILED(rv)) {
+                return rv;
+            }
+            hostBuf = ipString;
+        } else if (NS_SUCCEEDED(NormalizeIPv4(hostBuf, ipString))) {
           hostBuf = ipString;
         }
     }
 
     // NormalizeIDN always copies if the call was successful
     host = hostBuf.get();
     len = hostBuf.Length();
 
--- a/netwerk/base/rust-url-capi/src/lib.rs
+++ b/netwerk/base/rust-url-capi/src/lib.rs
@@ -520,8 +520,24 @@ pub extern "C" fn rusturl_relative_spec(
   cont.assign(&buffer);
   NSError::OK.error_code()
 }
 
 #[no_mangle]
 pub extern "C" fn sizeof_rusturl() -> size_t {
   mem::size_of::<Url>()
 }
+
+#[no_mangle]
+pub extern "C" fn rusturl_parse_ipv6addr(input: &nsACString, cont: &mut nsACString) -> i32 {
+  let ip6 = match str::from_utf8(input) {
+    Ok(content) => content,
+    Err(_) => return ParseError::InvalidDomainCharacter.error_code()
+  };
+
+  let h = match url::Host::parse(ip6) {
+    Ok(host) => host,
+    Err(e) => return e.error_code()
+  };
+
+  cont.assign(&h.to_string());
+  NSError::OK.error_code()
+}
--- a/netwerk/base/rust-url-capi/src/rust-url-capi.h
+++ b/netwerk/base/rust-url-capi/src/rust-url-capi.h
@@ -42,13 +42,15 @@ int32_t rusturl_set_port_no(rusturl* url
 int32_t rusturl_set_path(rusturl* url, const nsACString* path);
 int32_t rusturl_set_query(rusturl* url, const nsACString* query);
 int32_t rusturl_set_fragment(rusturl* url, const nsACString* fragment);
 
 int32_t rusturl_resolve(const rusturl* url, const nsACString* relative, nsACString* cont);
 int32_t rusturl_common_base_spec(const rusturl* url1, const rusturl* url2, nsACString* cont);
 int32_t rusturl_relative_spec(const rusturl* url1, const rusturl* url2, nsACString* cont);
 
+int32_t rusturl_parse_ipv6addr(const nsACString* input, nsACString* cont);
+
 size_t sizeof_rusturl();
 
 }
 
 #endif // __RUST_URL_CAPI
--- a/netwerk/test/unit/test_URIs.js
+++ b/netwerk/test/unit/test_URIs.js
@@ -145,18 +145,18 @@ var gTests = [
     scheme:  "http",
     prePath: "http://10.32.4.239",
     host:    "10.32.4.239",
     path:    "/",
     ref:     "",
     nsIURL:  true, nsINestedURI: false },
   { spec:    "http://[::192.9.5.5]/ipng",
     scheme:  "http",
-    prePath: "http://[::192.9.5.5]",
-    host:    "::192.9.5.5",
+    prePath: "http://[::c009:505]",
+    host:    "::c009:505",
     path:    "/ipng",
     ref:     "",
     nsIURL:  true, nsINestedURI: false },
   { spec:    "http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:8888/index.html",
     scheme:  "http",
     prePath: "http://[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:8888",
     host:    "fedc:ba98:7654:3210:fedc:ba98:7654:3210",
     port:    8888,
--- a/netwerk/test/unit/test_standardurl.js
+++ b/netwerk/test/unit/test_standardurl.js
@@ -456,8 +456,16 @@ add_test(function test_invalidHostChars(
   for (let c of "@[]*<>|:\"") {
     Assert.throws(() => { url.host = "a" + c; }, "Trying to set hostname containing char: " + c);
   }
 
   // It also can't contain /, \, #, ?, but we treat these characters as
   // hostname separators, so there is no way to set them and fail.
   run_next_test();
 });
+
+add_test(function test_normalize_ipv6() {
+  var url = stringToURL("http://example.com");
+  url.host = "[::192.9.5.5]";
+  do_check_eq(url.spec, "http://[::c009:505]/");
+
+  run_next_test();
+});
--- a/testing/web-platform/meta/url/a-element-origin-xhtml.xhtml.ini
+++ b/testing/web-platform/meta/url/a-element-origin-xhtml.xhtml.ini
@@ -1,22 +1,16 @@
 [a-element-origin-xhtml.xhtml]
   type: testharness
   [Parsing origin: <https://:@test> against <about:blank>]
     expected: FAIL
 
   [Parsing origin: <http://::@c@d:2> against <http://example.org/foo/bar>]
     expected: FAIL
 
-  [Parsing origin: <http://[::127.0.0.1\]> against <http://example.org/foo/bar>]
-    expected: FAIL
-
-  [Parsing origin: <http://[0:0:0:0:0:0:13.1.68.3\]> against <http://example.org/foo/bar>]
-    expected: FAIL
-
   [Parsing origin: <gopher:/example.com/> against <http://example.org/foo/bar>]
     expected: FAIL
 
   [Parsing origin: <data:/example.com/> against <http://example.org/foo/bar>]
     expected: FAIL
 
   [Parsing origin: <gopher:example.com/> against <http://example.org/foo/bar>]
     expected: FAIL
@@ -100,14 +94,11 @@
     expected: FAIL
 
   [Parsing origin: <ftp://%e2%98%83> against <about:blank>]
     expected: FAIL
 
   [Parsing origin: <https://%e2%98%83> against <about:blank>]
     expected: FAIL
 
-  [Parsing origin: <http://[1:0::\]> against <http://example.net/>]
-    expected: FAIL
-
   [Parsing origin: <?x> against <sc://ñ>]
     expected: FAIL
 
--- a/testing/web-platform/meta/url/a-element-origin.html.ini
+++ b/testing/web-platform/meta/url/a-element-origin.html.ini
@@ -1,22 +1,16 @@
 [a-element-origin.html]
   type: testharness
   [Parsing origin: <https://:@test> against <about:blank>]
     expected: FAIL
 
   [Parsing origin: <http://::@c@d:2> against <http://example.org/foo/bar>]
     expected: FAIL
 
-  [Parsing origin: <http://[::127.0.0.1\]> against <http://example.org/foo/bar>]
-    expected: FAIL
-
-  [Parsing origin: <http://[0:0:0:0:0:0:13.1.68.3\]> against <http://example.org/foo/bar>]
-    expected: FAIL
-
   [Parsing origin: <gopher:/example.com/> against <http://example.org/foo/bar>]
     expected: FAIL
 
   [Parsing origin: <data:/example.com/> against <http://example.org/foo/bar>]
     expected: FAIL
 
   [Parsing origin: <gopher:example.com/> against <http://example.org/foo/bar>]
     expected: FAIL
@@ -100,14 +94,11 @@
     expected: FAIL
 
   [Parsing origin: <ftp://%e2%98%83> against <about:blank>]
     expected: FAIL
 
   [Parsing origin: <https://%e2%98%83> against <about:blank>]
     expected: FAIL
 
-  [Parsing origin: <http://[1:0::\]> against <http://example.net/>]
-    expected: FAIL
-
   [Parsing origin: <?x> against <sc://ñ>]
     expected: FAIL
 
--- a/testing/web-platform/meta/url/a-element-xhtml.xhtml.ini
+++ b/testing/web-platform/meta/url/a-element-xhtml.xhtml.ini
@@ -409,22 +409,16 @@
     expected: FAIL
 
   [Parsing: <http:> against <https://example.org/foo/bar>]
     expected: FAIL
 
   [Parsing: <tel:1234567890> against <http://example.org/foo/bar>]
     expected: FAIL
 
-  [Parsing: <http://[::127.0.0.1\]> against <http://example.org/foo/bar>]
-    expected: FAIL
-
-  [Parsing: <http://[0:0:0:0:0:0:13.1.68.3\]> against <http://example.org/foo/bar>]
-    expected: FAIL
-
   [Parsing: <https://test:@test> against <about:blank>]
     expected: FAIL
 
   [Parsing: <https://:@test> against <about:blank>]
     expected: FAIL
 
   [Parsing: <non-special://test:@test/x> against <about:blank>]
     expected: FAIL
@@ -546,19 +540,16 @@
       if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL
       if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL
       if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL
       if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL
       if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL
       if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL
       if debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL
 
-  [Parsing: <http://[1:0::\]> against <http://example.net/>]
-    expected: FAIL
-
   [Parsing: <http://?> against <about:blank>]
     expected: FAIL
 
   [Parsing: <http://#> against <about:blank>]
     expected: FAIL
 
   [Parsing: <sc://ñ> against <about:blank>]
     expected: FAIL
--- a/testing/web-platform/meta/url/a-element.html.ini
+++ b/testing/web-platform/meta/url/a-element.html.ini
@@ -418,22 +418,16 @@
     expected: FAIL
 
   [Parsing: <http:> against <https://example.org/foo/bar>]
     expected: FAIL
 
   [Parsing: <tel:1234567890> against <http://example.org/foo/bar>]
     expected: FAIL
 
-  [Parsing: <http://[::127.0.0.1\]> against <http://example.org/foo/bar>]
-    expected: FAIL
-
-  [Parsing: <http://[0:0:0:0:0:0:13.1.68.3\]> against <http://example.org/foo/bar>]
-    expected: FAIL
-
   [Parsing: <https://test:@test> against <about:blank>]
     expected: FAIL
 
   [Parsing: <https://:@test> against <about:blank>]
     expected: FAIL
 
   [Parsing: <non-special://test:@test/x> against <about:blank>]
     expected: FAIL
@@ -555,19 +549,16 @@
       if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL
       if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL
       if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL
       if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL
       if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL
       if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL
       if debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL
 
-  [Parsing: <http://[1:0::\]> against <http://example.net/>]
-    expected: FAIL
-
   [Parsing: <http://?> against <about:blank>]
     expected: FAIL
 
   [Parsing: <http://#> against <about:blank>]
     expected: FAIL
 
   [Parsing: <sc://ñ> against <about:blank>]
     expected: FAIL
--- a/testing/web-platform/meta/url/url-constructor.html.ini
+++ b/testing/web-platform/meta/url/url-constructor.html.ini
@@ -196,22 +196,16 @@
     expected: FAIL
 
   [Parsing: <sc://ñ.test/> against <about:blank>]
     expected: FAIL
 
   [Parsing: <file:..> against <http://www.example.com/test>]
     expected: FAIL
 
-  [Parsing: <http://[::127.0.0.1\]> against <http://example.org/foo/bar>]
-    expected: FAIL
-
-  [Parsing: <http://[0:0:0:0:0:0:13.1.68.3\]> against <http://example.org/foo/bar>]
-    expected: FAIL
-
   [Parsing: <https://test:@test> against <about:blank>]
     expected: FAIL
 
   [Parsing: <https://:@test> against <about:blank>]
     expected: FAIL
 
   [Parsing: <non-special://test:@test/x> against <about:blank>]
     expected: FAIL
@@ -309,19 +303,16 @@
       if debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL
       if not debug and not e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL
       if debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL
       if not debug and e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL
       if not debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL
       if debug and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL
       if debug and not e10s and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): FAIL
 
-  [Parsing: <http://[1:0::\]> against <http://example.net/>]
-    expected: FAIL
-
   [Parsing: <sc://ñ> against <about:blank>]
     expected: FAIL
 
   [Parsing: <sc://ñ?x> against <about:blank>]
     expected: FAIL
 
   [Parsing: <sc://ñ#x> against <about:blank>]
     expected: FAIL
--- a/testing/web-platform/meta/url/url-origin.html.ini
+++ b/testing/web-platform/meta/url/url-origin.html.ini
@@ -1,22 +1,16 @@
 [url-origin.html]
   type: testharness
   [Origin parsing: <https://:@test> against <about:blank>]
     expected: FAIL
 
   [Origin parsing: <http://::@c@d:2> against <http://example.org/foo/bar>]
     expected: FAIL
 
-  [Origin parsing: <http://[::127.0.0.1\]> against <http://example.org/foo/bar>]
-    expected: FAIL
-
-  [Origin parsing: <http://[0:0:0:0:0:0:13.1.68.3\]> against <http://example.org/foo/bar>]
-    expected: FAIL
-
   [Origin parsing: <gopher:/example.com/> against <http://example.org/foo/bar>]
     expected: FAIL
 
   [Origin parsing: <data:/example.com/> against <http://example.org/foo/bar>]
     expected: FAIL
 
   [Origin parsing: <gopher:example.com/> against <http://example.org/foo/bar>]
     expected: FAIL
@@ -100,14 +94,11 @@
     expected: FAIL
 
   [Origin parsing: <ftp://%e2%98%83> against <about:blank>]
     expected: FAIL
 
   [Origin parsing: <https://%e2%98%83> against <about:blank>]
     expected: FAIL
 
-  [Origin parsing: <http://[1:0::\]> against <http://example.net/>]
-    expected: FAIL
-
   [Origin parsing: <?x> against <sc://ñ>]
     expected: FAIL
 
--- a/testing/web-platform/meta/url/url-setters.html.ini
+++ b/testing/web-platform/meta/url/url-setters.html.ini
@@ -223,25 +223,16 @@
     expected: FAIL
 
   [<a>: Setting <a:/foo>.host = 'example.net' Path-only URLs can gain a host]
     expected: FAIL
 
   [<area>: Setting <a:/foo>.host = 'example.net' Path-only URLs can gain a host]
     expected: FAIL
 
-  [URL: Setting <http://example.net>.host = '[::0:01\]:2' IPv6 address syntax is normalized]
-    expected: FAIL
-
-  [<a>: Setting <http://example.net>.host = '[::0:01\]:2' IPv6 address syntax is normalized]
-    expected: FAIL
-
-  [<area>: Setting <http://example.net>.host = '[::0:01\]:2' IPv6 address syntax is normalized]
-    expected: FAIL
-
   [URL: Setting <view-source+http://example.net/path>.host = 'example.com\\stuff' \\ is not a delimiter for non-special schemes, and it’s invalid in a domain]
     expected: FAIL
 
   [<a>: Setting <view-source+http://example.net/path>.host = 'example.com\\stuff' \\ is not a delimiter for non-special schemes, and it’s invalid in a domain]
     expected: FAIL
 
   [<area>: Setting <view-source+http://example.net/path>.host = 'example.com\\stuff' \\ is not a delimiter for non-special schemes, and it’s invalid in a domain]
     expected: FAIL
@@ -268,25 +259,16 @@
     expected: FAIL
 
   [<a>: Setting <a:/foo>.hostname = 'example.net' Path-only URLs can gain a host]
     expected: FAIL
 
   [<area>: Setting <a:/foo>.hostname = 'example.net' Path-only URLs can gain a host]
     expected: FAIL
 
-  [URL: Setting <http://example.net>.hostname = '[::0:01\]' IPv6 address syntax is normalized]
-    expected: FAIL
-
-  [<a>: Setting <http://example.net>.hostname = '[::0:01\]' IPv6 address syntax is normalized]
-    expected: FAIL
-
-  [<area>: Setting <http://example.net>.hostname = '[::0:01\]' IPv6 address syntax is normalized]
-    expected: FAIL
-
   [URL: Setting <http://example.net/path>.hostname = 'example.com:8080' Stuff after a : delimiter is ignored]
     expected: FAIL
 
   [<a>: Setting <http://example.net/path>.hostname = 'example.com:8080' Stuff after a : delimiter is ignored]
     expected: FAIL
 
   [<area>: Setting <http://example.net/path>.hostname = 'example.com:8080' Stuff after a : delimiter is ignored]
     expected: FAIL