Bug 1528939. r=Gijs
authorMarco Bonardo <mbonardo@mozilla.com>
Wed, 13 Mar 2019 10:20:00 +0000
changeset 524690 7417187bdee40dd267586fc334b52c1e4d2743d0
parent 524689 5b06a29334b8f96ab458bea01dcf70645936a9c5
child 524691 53388cbb2a6d8a7e5234f0299c61168d03ae6408
push id2032
push userffxbld-merge
push dateMon, 13 May 2019 09:36:57 +0000
treeherdermozilla-release@455c1065dcbe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersGijs
bugs1528939
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1528939. r=Gijs Differential Revision: https://phabricator.services.mozilla.com/D23195
browser/components/urlbar/UrlbarValueFormatter.jsm
browser/components/urlbar/tests/browser/browser_UrlbarInput_formatValue.js
--- a/browser/components/urlbar/UrlbarValueFormatter.jsm
+++ b/browser/components/urlbar/UrlbarValueFormatter.jsm
@@ -85,17 +85,17 @@ class UrlbarValueFormatter {
       let directionality = this.window.windowUtils.getDirectionFromText(domain);
       if (directionality == this.window.windowUtils.DIRECTION_RTL &&
           url[preDomain.length + domain.length] != "\u200E") {
         this.inputField.scrollLeft = this.inputField.scrollLeftMax;
       }
     });
   }
 
-  _getUrlMetaData() {
+  _getUrlMetaData(allowReplacement = true) {
     if (this.urlbarInput.focused) {
       return null;
     }
 
     let url = this.inputField.value;
 
     // Get the URL from the fixup service:
     let flags = Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS |
@@ -119,22 +119,43 @@ class UrlbarValueFormatter {
     // trimmedLength to ensure we don't count the length of a trimmed protocol
     // when determining which parts of the URL to highlight as "preDomain".
     let trimmedLength = 0;
     if (uriInfo.fixedURI.scheme == "http" && !url.startsWith("http://")) {
       url = "http://" + url;
       trimmedLength = "http://".length;
     }
 
+    // This RegExp is not a perfect match, and for specially crafted URLs it may
+    // get the host wrong; for safety reasons we will later compare the found
+    // host with the one that will actually be loaded.
     let matchedURL = url.match(/^(([a-z]+:\/\/)(?:[^\/#?]+@)?)(\S+?)(?::\d+)?\s*(?:[\/#?]|$)/);
     if (!matchedURL) {
       return null;
     }
+    let [, preDomain, schemeWSlashes, domain] = matchedURL;
 
-    let [, preDomain, schemeWSlashes, domain] = matchedURL;
+    // If the found host differs from the fixed URI one, we can't properly
+    // highlight it. To stay on the safe side, we clobber user's input with
+    // the fixed URI and apply highlight to that one instead.
+    let replaceUrl = false;
+    try {
+      replaceUrl = Services.io.newURI("http://" + domain).displayHost != uriInfo.fixedURI.displayHost;
+    } catch (ex) {
+      return null;
+    }
+    if (replaceUrl) {
+      if (!allowReplacement) {
+        // Protect from infinite recursion.
+        return null;
+      }
+      this.window.URLBarSetURI(uriInfo.fixedURI);
+      return this._getUrlMetaData(false);
+    }
+
     return { preDomain, schemeWSlashes, domain, url, uriInfo, trimmedLength };
   }
 
   _removeURLFormat() {
     this.scheme.value = "";
     if (!this._formattingApplied) {
       return;
     }
--- a/browser/components/urlbar/tests/browser/browser_UrlbarInput_formatValue.js
+++ b/browser/components/urlbar/tests/browser/browser_UrlbarInput_formatValue.js
@@ -1,27 +1,39 @@
 /* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
+ * https://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Checks that the url formatter properly recognizes the host and de-emphasizes
+// the rest of the url.
+
+/**
+ * Tests a given url.
+ * The de-emphasized parts must be wrapped in "<" and ">" chars.
+ * @param {string} aExpected The url to test.
+ * @param {string} aClobbered [optional] Normally the url is de-emphasized
+ *        in-place, thus it's enough to pass aExpected. Though, in some cases
+ *        the formatter may decide to replace the url with a fixed one, because
+ *        it can't properly guess a host. In that case aClobbered is the
+ *        expected de-emphasized value.
  */
-
-function testVal(aExpected) {
+function testVal(aExpected, aClobbered = null) {
   gURLBar.value = aExpected.replace(/[<>]/g, "");
 
   let selectionController = gURLBar.editor.selectionController;
   let selection = selectionController.getSelection(selectionController.SELECTION_URLSECONDARY);
   let value = gURLBar.editor.rootElement.textContent;
   let result = "";
   for (let i = 0; i < selection.rangeCount; i++) {
     let range = selection.getRangeAt(i).toString();
     let pos = value.indexOf(range);
     result += value.substring(0, pos) + "<" + range + ">";
     value = value.substring(pos + range.length);
   }
   result += value;
-  is(result, aExpected,
+  is(result, aClobbered || aExpected,
      "Correct part of the urlbar contents is highlighted");
 }
 
 function test() {
   const prefname = "browser.urlbar.formatting.enabled";
 
   registerCleanupFunction(function() {
     Services.prefs.clearUserPref(prefname);
@@ -77,16 +89,17 @@ function test() {
   testVal("foo.bar<#@x@mozilla.org>");
   testVal("foo.bar<?x@mozilla.org>");
   testVal("foo.bar<?@x@mozilla.org>");
   testVal("<foo.bar@x@>mozilla.org");
   testVal("<foo.bar@:baz@>mozilla.org");
   testVal("<foo.bar:@baz@>mozilla.org");
   testVal("<foo.bar@:ba:z@>mozilla.org");
   testVal("<foo.:bar:@baz@>mozilla.org");
+  testVal("foopy:\\blah@somewhere.com//whatever", "foopy</blah@somewhere.com//whatever>");
 
   testVal("<https://sub.>mozilla.org<:666/file.ext>");
   testVal("<sub.>mozilla.org<:666/file.ext>");
   testVal("localhost<:666/file.ext>");
 
   let IPs = ["192.168.1.1",
              "[::]",
              "[::1]",
@@ -111,24 +124,26 @@ function test() {
   IPs.forEach(function(IP) {
     testVal(IP);
     testVal(IP + "</file.ext>");
     testVal(IP + "<:666/file.ext>");
     testVal("<https://>" + IP);
     testVal("<https://>" + IP + "</file.ext>");
     testVal("<https://user:pass@>" + IP + "<:666/file.ext>");
     testVal("<user:pass@>" + IP + "<:666/file.ext>");
+    testVal("user:\\pass@" + IP, "user</pass@" + IP + ">");
   });
 
   testVal("mailto:admin@mozilla.org");
   testVal("gopher://mozilla.org/");
   testVal("about:config");
   testVal("jar:http://mozilla.org/example.jar!/");
   testVal("view-source:http://mozilla.org/");
   testVal("foo9://mozilla.org/");
   testVal("foo+://mozilla.org/");
   testVal("foo.://mozilla.org/");
   testVal("foo-://mozilla.org/");
 
+  // Disable formatting.
   Services.prefs.setBoolPref(prefname, false);
 
   testVal("https://mozilla.org");
 }