From 23e5bd6ffab4b6fa17a92d0bc58fbd185e9a7e6e Mon Sep 17 00:00:00 2001
From: Valentin Gosu <valentin.gosu@gmail.com>
Date: Tue, 13 Oct 2015 11:10:26 +0200
Subject: [PATCH] Bug 1199430 - Reject hostnames containing @. r=mcmanus, a=al

---
 docshell/test/unit/test_nsDefaultURIFixup_info.js | 16 ++++++------
 netwerk/base/nsStandardURL.cpp                    | 30 ++++++++++++++---------
 netwerk/base/nsStandardURL.h                      |  2 +-
 3 files changed, 27 insertions(+), 21 deletions(-)

diff --git a/docshell/test/unit/test_nsDefaultURIFixup_info.js b/docshell/test/unit/test_nsDefaultURIFixup_info.js
index b178ea9..dbb55c6 100644
--- a/docshell/test/unit/test_nsDefaultURIFixup_info.js
+++ b/docshell/test/unit/test_nsDefaultURIFixup_info.js
@@ -199,12 +199,10 @@ let testcases = [ {
     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,
@@ -514,15 +512,15 @@ if (Services.appinfo.OS.toLowerCase().startsWith("win")) {
     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,
   });
 }
 
diff --git a/netwerk/base/nsStandardURL.cpp b/netwerk/base/nsStandardURL.cpp
index f5f516f..cff90fc 100644
--- a/netwerk/base/nsStandardURL.cpp
+++ b/netwerk/base/nsStandardURL.cpp
@@ -427,14 +427,16 @@ nsStandardURL::NormalizeIDN(const nsCSubstring &host, nsCString &result)
 }
 
 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] == ']';
@@ -448,8 +450,9 @@ nsStandardURL::ValidIPv6orHostname(const char *host)
         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;
     }
 
@@ -587,6 +590,11 @@ nsStandardURL::BuildNormalizedSpec(const char *spec)
             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;
+        }
     }
 
     //
@@ -1580,14 +1588,10 @@ nsStandardURL::SetHost(const nsACString &input)
     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();
@@ -1596,6 +1600,10 @@ nsStandardURL::SetHost(const nsACString &input)
     else
         len = flat.Length();
 
+    if (!ValidIPv6orHostname(host, len)) {
+        return NS_ERROR_MALFORMED_URI;
+    }
+
     if (mHost.mLen < 0) {
         int port_length = 0;
         if (mPort != -1) {
diff --git a/netwerk/base/nsStandardURL.h b/netwerk/base/nsStandardURL.h
index 179a618..c56426e 100644
--- a/netwerk/base/nsStandardURL.h
+++ b/netwerk/base/nsStandardURL.h
@@ -173,7 +173,7 @@ private:
     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);
 
-- 
2.5.0