Bug 1199430 - Reject hostnames containing @. r=mcmanus, a=al
authorValentin Gosu <valentin.gosu@gmail.com>
Tue, 13 Oct 2015 11:10:26 +0200
changeset 260791 895579563ce015823a95eebfe0247165b116a48d
parent 260790 a6799573f909b3b92e82c7180a0c27b05185e420
child 260792 f0a539ad24798ca5917e5d6ee5883ddb8b17336e
push id184
push usercbook@mozilla.com
push dateTue, 13 Oct 2015 09:10:46 +0000
treeherdermozilla-esr38@895579563ce0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcmanus, al
bugs1199430
milestone38.3.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
--- a/docshell/test/unit/test_nsDefaultURIFixup_info.js
+++ b/docshell/test/unit/test_nsDefaultURIFixup_info.js
@@ -194,22 +194,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,
-    affectedByWhitelist: true,
-    affectedByDNSForSingleHosts: true,
+    protocolChange: true
   }, {
     input: "[::1]]",
     keywordLookup: true,
     protocolChange: true
   }, {
     input: "1234",
     fixedURI: "http://1234/",
     alternateURI: "http://www.1234.com/",
@@ -509,25 +507,25 @@ if (Services.appinfo.OS.toLowerCase().st
     input: "/some/file.txt",
     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,
     affectedByWhitelist: 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
@@ -422,39 +422,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)
@@ -582,16 +585,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;
@@ -1575,32 +1583,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);