Bug 1199430 - Reject hostnames containing @. r=mcmanus, a=al
authorValentin Gosu <valentin.gosu@gmail.com>
Tue, 13 Oct 2015 11:00:55 +0200
changeset 289537 cdc65a3f9b02
parent 289536 6c9fb21f670b
child 289538 c5ef20f11b44
push id5174
push userphilringnalda@gmail.com
push date2015-10-15 04:34 +0000
treeherdermozilla-beta@c5ef20f11b44 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcmanus, al
bugs1199430
milestone42.0
Bug 1199430 - Reject hostnames containing @. r=mcmanus, a=al
docshell/test/unit/test_nsDefaultURIFixup_info.js
netwerk/base/nsStandardURL.cpp
netwerk/base/nsStandardURL.h
testing/web-platform/meta/content-security-policy/blink-contrib/shared-worker-connect-src-allowed.sub.html.ini
testing/web-platform/meta/content-security-policy/blink-contrib/shared-worker-connect-src-blocked.sub.html.ini
testing/web-platform/meta/url/url-constructor.html.ini
--- a/docshell/test/unit/test_nsDefaultURIFixup_info.js
+++ b/docshell/test/unit/test_nsDefaultURIFixup_info.js
@@ -207,21 +207,20 @@ let testcases = [ {
     fixedURI: "http://[64:ff9b::8.8.8.8]/~moz",
     protocolChange: true
   }, {
     input: "[::1][::1]",
     keywordLookup: true,
     protocolChange: true
   }, {
     input: "[::1][100",
-    fixedURI: "http://[::1][100/",
-    alternateURI: "http://[::1][100/",
+    fixedURI: null,
+    alternateURI: null,
     keywordLookup: true,
-    protocolChange: true,
-    affectedByDNSForSingleHosts: true,
+    protocolChange: true
   }, {
     input: "[::1]]",
     keywordLookup: true,
     protocolChange: true
   }, {
     input: "1234",
     fixedURI: "http://1234/",
     alternateURI: "http://www.1234.com/",
@@ -498,23 +497,24 @@ if (Services.appinfo.OS.toLowerCase().st
     fixedURI: "file:///some/file.txt",
     protocolChange: true,
   });
   testcases.push({
     input: "//mozilla",
     fixedURI: "file:////mozilla",
     protocolChange: true,
   });
+  // \ is an invalid character in the hostname until bug 652186 is implemented
   testcases.push({
     input: "mozilla\\",
-    fixedURI: "http://mozilla\\/",
-    alternateURI: "http://www.mozilla/",
+    // fixedURI: "http://mozilla\\/",
+    // alternateURI: "http://www.mozilla/",
     keywordLookup: true,
     protocolChange: true,
-    affectedByDNSForSingleHosts: true,
+    // affectedByDNSForSingleHosts: true,
   });
 }
 
 function sanitize(input) {
   return input.replace(/\r|\n/g, "").trim();
 }
 
 
--- a/netwerk/base/nsStandardURL.cpp
+++ b/netwerk/base/nsStandardURL.cpp
@@ -417,39 +417,42 @@ nsStandardURL::NormalizeIDN(const nsCSub
         return true;
     }
 
     result.Truncate();
     return false;
 }
 
 bool
-nsStandardURL::ValidIPv6orHostname(const char *host)
+nsStandardURL::ValidIPv6orHostname(const char *host, uint32_t length)
 {
-    if (!host || !*host) {
-        // Should not be NULL or empty string
+    if (!host) {
         return false;
     }
 
-    int32_t length = strlen(host);
+    if (length != strlen(host)) {
+        // Embedded null
+        return false;
+    }
 
     bool openBracket = host[0] == '[';
     bool closeBracket = host[length - 1] == ']';
 
     if (openBracket && closeBracket) {
         return net_IsValidIPv6Addr(host + 1, length - 2);
     }
 
     if (openBracket || closeBracket) {
         // Fail if only one of the brackets is present
         return false;
     }
 
-    if (PL_strchr(host, ':')) {
-        // Hostnames should not contain a colon
+    const char *end = host + length;
+    if (end != net_FindCharInSet(host, end, "\t\n\v\f\r #/:?@[\\]")) {
+        // % is allowed because we don't do hostname percent decoding yet.
         return false;
     }
 
     return true;
 }
 
 void
 nsStandardURL::CoalescePath(netCoalesceFlags coalesceFlag, char *path)
@@ -577,16 +580,21 @@ nsStandardURL::BuildNormalizedSpec(const
         if (tempHost.FindChar('\0') != kNotFound)
             return NS_ERROR_MALFORMED_URI;  // null embedded in hostname
         if (tempHost.FindChar(' ') != kNotFound)
             return NS_ERROR_MALFORMED_URI;  // don't allow spaces in the hostname
         if ((useEncHost = NormalizeIDN(tempHost, encHost)))
             approxLen += encHost.Length();
         else
             approxLen += mHost.mLen;
+
+        if ((useEncHost && !ValidIPv6orHostname(encHost.BeginReading(), encHost.Length())) ||
+            (!useEncHost && !ValidIPv6orHostname(tempHost.BeginReading(), tempHost.Length()))) {
+            return NS_ERROR_MALFORMED_URI;
+        }
     }
 
     //
     // generate the normalized URL string
     //
     // approxLen should be correct or 1 high
     if (!mSpec.SetLength(approxLen+1, mozilla::fallible)) // buf needs a trailing '\0' below
         return NS_ERROR_OUT_OF_MEMORY;
@@ -1577,32 +1585,32 @@ nsStandardURL::SetHost(const nsACString 
     if (strlen(host) < flat.Length())
         return NS_ERROR_MALFORMED_URI; // found embedded null
 
     // For consistency with SetSpec/nsURLParsers, don't allow spaces
     // in the hostname.
     if (strchr(host, ' '))
         return NS_ERROR_MALFORMED_URI;
 
-    if (!ValidIPv6orHostname(host)) {
-        return NS_ERROR_MALFORMED_URI;
-    }
-
     InvalidateCache();
     mHostEncoding = eEncoding_ASCII;
 
-    int32_t len;
+    uint32_t len;
     nsAutoCString hostBuf;
     if (NormalizeIDN(flat, hostBuf)) {
         host = hostBuf.get();
         len = hostBuf.Length();
     }
     else
         len = flat.Length();
 
+    if (!ValidIPv6orHostname(host, len)) {
+        return NS_ERROR_MALFORMED_URI;
+    }
+
     if (mHost.mLen < 0) {
         int port_length = 0;
         if (mPort != -1) {
             nsAutoCString buf;
             buf.Assign(':');
             buf.AppendInt(mPort);
             port_length = buf.Length();
         }
--- a/netwerk/base/nsStandardURL.h
+++ b/netwerk/base/nsStandardURL.h
@@ -168,17 +168,17 @@ protected:
     virtual nsresult EnsureFile();
 
 private:
     int32_t  Port() { return mPort == -1 ? mDefaultPort : mPort; }
 
     void     Clear();
     void     InvalidateCache(bool invalidateCachedFile = true);
 
-    bool     ValidIPv6orHostname(const char *host);
+    bool     ValidIPv6orHostname(const char *host, uint32_t aLen);
     bool     NormalizeIDN(const nsCSubstring &host, nsCString &result);
     void     CoalescePath(netCoalesceFlags coalesceFlag, char *path);
 
     uint32_t AppendSegmentToBuf(char *, uint32_t, const char *, URLSegment &, const nsCString *esc=nullptr, bool useEsc = false);
     uint32_t AppendToBuf(char *, uint32_t, const char *, uint32_t);
 
     nsresult BuildNormalizedSpec(const char *spec);
 
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/content-security-policy/blink-contrib/shared-worker-connect-src-allowed.sub.html.ini
@@ -0,0 +1,4 @@
+[shared-worker-connect-src-allowed.sub.html]
+  type: testharness
+  [Expecting alerts: ["xhr allowed"\]]
+    expected: FAIL
\ No newline at end of file
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/blink-contrib/shared-worker-connect-src-blocked.sub.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[shared-worker-connect-src-blocked.sub.html]
-  type: testharness
-  [Expecting alerts: ["xhr blocked"\]]
-    expected: FAIL
-
--- a/testing/web-platform/meta/url/url-constructor.html.ini
+++ b/testing/web-platform/meta/url/url-constructor.html.ini
@@ -55,22 +55,16 @@
     expected: FAIL
 
   [Parsing: <[61:24:74\]:98> against <http://example.org/foo/bar>]
     expected: FAIL
 
   [Parsing: <http:[61:27\]/:foo> against <http://example.org/foo/bar>]
     expected: FAIL
 
-  [Parsing: <http://2001::1\]> against <http://example.org/foo/bar>]
-    expected: FAIL
-
-  [Parsing: <http://2001::1\]:80> against <http://example.org/foo/bar>]
-    expected: FAIL
-
   [Parsing: <madeupscheme:/example.com/> against <http://example.org/foo/bar>]
     expected: FAIL
 
   [Parsing: <ftps:/example.com/> against <http://example.org/foo/bar>]
     expected: FAIL
 
   [Parsing: <gopher:/example.com/> against <http://example.org/foo/bar>]
     expected: FAIL
@@ -241,25 +235,16 @@
     expected: FAIL
 
   [Parsing: <http://a:b@/www.example.com> against <about:blank>]
     expected: FAIL
 
   [Parsing: <http://www.@pple.com> against <about:blank>]
     expected: FAIL
 
-  [Parsing: <http:@:www.example.com> against <about:blank>]
-    expected: FAIL
-
-  [Parsing: <http:/@:www.example.com> against <about:blank>]
-    expected: FAIL
-
-  [Parsing: <http://@:www.example.com> against <about:blank>]
-    expected: FAIL
-
   [Parsing: <http://:@www.example.com> against <about:blank>]
     expected: FAIL
 
   [Parsing: <http://GOO  goo.com> against <http://other.com/>]
     expected: FAIL
 
   [Parsing: <http://﷐zyx.com> against <http://other.com/>]
     expected: FAIL