Bug 1319212 - Make drag and drop into the tabbrowser work again. r=IanN
authorFrank-Rainer Grahl <frgrahl@gmx.net>
Sat, 25 Feb 2017 12:58:42 +0100
changeset 24353 a23c9cbe5de187e5fdcdc2c2bb7822ccf916b7ec
parent 24352 4b1fc11b94209e7cf767f4805a0b774b209f7a98
child 24354 303fc1060ea8baa6ec931edb12f9a09c5a48cce1
push id2022
push userclokep@gmail.com
push dateTue, 07 Mar 2017 14:36:55 +0000
treeherdercomm-aurora@ecedf2f0d1b4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersIanN
bugs1319212, 1150678, 92737
Bug 1319212 - Make drag and drop into the tabbrowser work again. r=IanN Replace promiseShortcutOrURI with getShortcutOrURIAndPostData and clean up surrounding code. See Bug 1150678 [Autocomplete produces incorrect results for modified bookmark keyword searches] Also ports tabbrowser part of Bug 92737 [DnD of multiple shortcuts from desktop only opens one]
suite/browser/navigator.js
suite/browser/navigatorDD.js
suite/browser/tabbrowser.xml
suite/common/contentAreaClick.js
--- a/suite/browser/navigator.js
+++ b/suite/browser/navigator.js
@@ -1376,31 +1376,35 @@ function QualifySearchTerm()
     return gURLBar.value;
   return "";
 }
 
 function BrowserOpenWindow()
 {
   //opens a window where users can select a web location to open
   var params = { action: gPrivate ? "4" : "0", url: "" };
-  openDialog("chrome://communicator/content/openLocation.xul", "_blank", "chrome,modal,titlebar", params);
-  promiseShortcutOrURI(params.url).then(([url, postData]) => {
+  openDialog("chrome://communicator/content/openLocation.xul", "_blank",
+             "chrome,modal,titlebar", params);
+
+  getShortcutOrURIAndPostData(params.url).then(data => {
     switch (params.action) {
       case "0": // current window
-        loadURI(url, null, postData, true);
+        loadURI(data.url, null, data.postData, true);
         break;
       case "1": // new window
-        openDialog(getBrowserURL(), "_blank", "all,dialog=no", url, null, null,
-                   postData, true);
+        openDialog(getBrowserURL(), "_blank", "all,dialog=no", data.url, null, null,
+                   data.postData, true);
         break;
       case "2": // edit
-        editPage(url);
+        editPage(data.url);
         break;
       case "3": // new tab
-        gBrowser.selectedTab = gBrowser.addTab(url, {allowThirdPartyFixup: true, postData: postData});
+        gBrowser.selectedTab = gBrowser.addTab(data.url,
+                                               {allowThirdPartyFixup: true,
+                                                postData: data.postData});
         break;
       case "4": // private
         openNewPrivateWith(params.url);
         break;
     }
   });
 }
 
@@ -1685,17 +1689,17 @@ function handleURLBarCommand(aUserAction
     // but don't let that interfere with the loading of the url.
   }
 
   if (url.match(/^view-source:/)) {
     gViewSourceUtils.viewSource(url.replace(/^view-source:/, ""), null, null);
     return;
   }
 
-  promiseShortcutOrURI(url).then(([url, postData]) => {
+  getShortcutOrURIAndPostData(url).then(data => {
     // Check the pressed modifiers: (also see bug 97123)
     // Modifier Mac | Modifier PC | Action
     // -------------+-------------+-----------
     // Command      | Control     | New Window/Tab
     // Shift+Cmd    | Shift+Ctrl  | New Window/Tab behind current one
     // Option       | Shift       | Save URL (show Filepicker)
 
     // If false, the save modifier is Alt, which is Option on Mac.
@@ -1717,29 +1721,29 @@ function handleURLBarCommand(aUserAction
         (('ctrlKey' in aTriggeringEvent && aTriggeringEvent.ctrlKey) ||
          ('metaKey' in aTriggeringEvent && aTriggeringEvent.metaKey) ||
          ('button'  in aTriggeringEvent && aTriggeringEvent.button == 1))) {
       // Check if user requests Tabs instead of windows
       if (GetBoolPref("browser.tabs.opentabfor.urlbar", false)) {
         // Reset url in the urlbar
         URLBarSetURI();
         // Open link in new tab
-        var t = browser.addTab(url, {
-                  postData: postData,
+        var t = browser.addTab(data.url, {
+                  postData: data.postData,
                   allowThirdPartyFixup: true,
                   isUTF8: isUTF8
                 });
 
         // Focus new tab unless shift is pressed
         if (!shiftPressed)
           browser.selectedTab = t;
       } else {
         // Open a new window with the URL
-        var newWin = openDialog(getBrowserURL(), "_blank", "all,dialog=no", url,
-            null, null, postData, true, isUTF8);
+        var newWin = openDialog(getBrowserURL(), "_blank", "all,dialog=no", data.url,
+                                null, null, data.postData, true, isUTF8);
         // Reset url in the urlbar
         URLBarSetURI();
 
         // Focus old window if shift was pressed, as there's no
         // way to open a new window in the background
         // XXX this doesn't seem to work
         if (shiftPressed) {
           //newWin.blur();
@@ -1748,109 +1752,95 @@ function handleURLBarCommand(aUserAction
       }
     } else if (saveModifier) {
       try {
         // Firstly, fixup the url so that (e.g.) "www.foo.com" works
         const nsIURIFixup = Components.interfaces.nsIURIFixup;
         if (!gURIFixup)
           gURIFixup = Components.classes["@mozilla.org/docshell/urifixup;1"]
                                 .getService(nsIURIFixup);
-        url = gURIFixup.createFixupURI(url, nsIURIFixup.FIXUP_FLAGS_MAKE_ALTERNATE_URI).spec;
+        url = gURIFixup.createFixupURI(data.url, nsIURIFixup.FIXUP_FLAGS_MAKE_ALTERNATE_URI).spec;
         // Open filepicker to save the url
         saveURL(url, null, null, false, true, null, document);
       }
       catch(ex) {
         // XXX Do nothing for now.
         // Do we want to put up an alert in the future?  Mmm, l10n...
       }
     } else {
       // No modifier was pressed, load the URL normally and
       // focus the content area
-      loadURI(url, null, postData, true, isUTF8);
+      loadURI(data.url, null, data.postData, true, isUTF8);
       content.focus();
     }
   });
 }
 
-function promiseShortcutOrURI(aURL)
-{
-  var keyword = aURL;
-  var param = "";
-
-  var offset = aURL.indexOf(" ");
-  if (offset > 0) {
-    keyword = aURL.substr(0, offset);
-    param = aURL.substr(offset + 1);
-  }
-
-  var engine = Services.search.getEngineByAlias(keyword);
-  if (engine) {
-    var submission = engine.getSubmission(param);
-    return Promise.resolve([submission.uri.spec, submission.postData]);
-  }
-
-  return PlacesUtils.keywords.fetch(keyword).then(entry => {
-    if (!entry)
-      return [aURL];
-
-    var shortcutURL = entry.url.href;
-    var postData = entry.postData;
-    if (postData)
-      postData = unescape(postData);
-
-    if (/%s/i.test(shortcutURL) || /%s/i.test(postData)) {
-      var charset;
-      const re = /^(.*)\&mozcharset=([a-zA-Z][_\-a-zA-Z0-9]+)\s*$/;
-      var matches = shortcutURL.match(re);
-      if (matches) {
-        shortcutURL = matches[1];
-        charset = Promise.resolve(matches[2]);
-      } else {
-        // Try to get the saved character-set.
-        try {
-          // makeURI throws if URI is invalid.
-          // Will return an empty string if character-set is not found.
-          charset = PlacesUtils.getCharsetForURI(makeURI(shortcutURL));
-        } catch (e) {
-          charset = Promise.resolve();
-        }
+/**
+ * Given a string, will generate a more appropriate urlbar value if a Places
+ * keyword or a search alias is found at the beginning of it.
+ *
+ * @param url
+ *        A string that may begin with a keyword or an alias.
+ *
+ * @return {Promise}
+ * @resolves { url, postData, mayInheritPrincipal }. If it's not possible
+ *           to discern a keyword or an alias, url will be the input string.
+ */
+function getShortcutOrURIAndPostData(url) {
+  return Task.spawn(function* () {
+    let mayInheritPrincipal = false;
+    let postData = null;
+    // Split on the first whitespace.
+    let [keyword, param = ""] = url.trim().split(/\s(.+)/, 2);
+
+    if (!keyword) {
+      return { url, postData, mayInheritPrincipal };
+    }
+
+    let engine = Services.search.getEngineByAlias(keyword);
+    if (engine) {
+      let submission = engine.getSubmission(param, null, "keyword");
+      return { url: submission.uri.spec,
+               postData: submission.postData,
+               mayInheritPrincipal };
+    }
+
+    // A corrupt Places database could make this throw, breaking navigation
+    // from the location bar.
+    let entry = null;
+    try {
+      entry = yield PlacesUtils.keywords.fetch(keyword);
+    } catch (ex) {
+      Components.utils.reportError(`Unable to fetch Places keyword "${keyword}": ${ex}`);
+    }
+    if (!entry || !entry.url) {
+      // This is not a Places keyword.
+      return { url, postData, mayInheritPrincipal };
+    }
+
+    try {
+      [url, postData] =
+        yield BrowserUtils.parseUrlAndPostData(entry.url.href,
+                                               entry.postData,
+                                               param);
+      if (postData) {
+        postData = getPostDataStream(postData);
       }
 
-      return charset.then(charset => {
-        // encodeURIComponent produces UTF-8, and cannot be used for other
-        // charsets. escape() works in those cases, but it doesn't uri-encode
-        // +, @, and /. Therefore we need to manually replace these ASCII
-        // characters by their encodeURIComponent result, to match the
-        // behaviour of nsEscape() with url_XPAlphas.
-        var encodedParam = "";
-        if (charset && charset != "UTF-8")
-          encodedParam = escape(convertFromUnicode(charset, param)).
-                         replace(/[+@\/]+/g, encodeURIComponent);
-        else // Default charset is UTF-8
-          encodedParam = encodeURIComponent(param);
-
-        shortcutURL = shortcutURL.replace(/%s/g, encodedParam).replace(/%S/g, param);
-
-        if (/%s/i.test(postData)) { // POST keyword
-          var postDataStream = getPostDataStream(postData, param, encodedParam,
-                                                 "application/x-www-form-urlencoded");
-          return [shortcutURL, postDataStream];
-        }
-
-        return [shortcutURL];
-      });
+      // Since this URL came from a bookmark, it's safe to let it inherit the
+      // current document's principal.
+      mayInheritPrincipal = true;
+    } catch (ex) {
+      // It was not possible to bind the param, just use the original url value.
     }
 
-    if (param) {
-      // This keyword doesn't take a parameter, but one was provided. Just return
-      // the original URL.
-      return [aURL];
-    }
-
-    return [shortcutURL];
+    return { url, postData, mayInheritPrincipal };
+  }).then(data => {
+    return data;
   });
 }
 
 function getPostDataStream(aStringData, aKeyword, aEncKeyword, aType)
 {
   var dataStream = Components.classes["@mozilla.org/io/string-input-stream;1"]
                              .createInstance(Components.interfaces.nsIStringInputStream);
   aStringData = aStringData.replace(/%s/g, aEncKeyword).replace(/%S/g, aKeyword);
@@ -1859,26 +1849,68 @@ function getPostDataStream(aStringData, 
   var mimeStream = Components.classes["@mozilla.org/network/mime-input-stream;1"]
                              .createInstance(Components.interfaces.nsIMIMEInputStream);
   mimeStream.addHeader("Content-Type", aType);
   mimeStream.addContentLength = true;
   mimeStream.setData(dataStream);
   return mimeStream.QueryInterface(Components.interfaces.nsIInputStream);
 }
 
-function handleDroppedLink(event, url, name)
+// handleDroppedLink has the following 2 overloads:
+//   handleDroppedLink(event, url, name)
+//   handleDroppedLink(event, links)
+function handleDroppedLink(event, urlOrLinks, name)
 {
-  promiseShortcutOrURI(url).then(([uri, postData]) => {
-    if (uri)
-      loadURI(uri, null, postData, false);
+  let links;
+  if (Array.isArray(urlOrLinks)) {
+    links = urlOrLinks;
+  } else {
+    links = [{ url: urlOrLinks, name, type: "" }];
+  }
+
+  let lastLocationChange = gBrowser.selectedBrowser.lastLocationChange;
+
+  // Usually blank for SeaMonkey.
+  let userContextId = gBrowser.selectedBrowser.getAttribute("usercontextid");
+
+  // event is null if links are dropped in content process.
+  // inBackground should be false, as it's loading into current browser.
+  let inBackground = false;
+  if (event) {
+    inBackground = Services.prefs.getBoolPref("browser.tabs.loadInBackground");
+    if (event.shiftKey)
+      inBackground = !inBackground;
+  }
+
+  Task.spawn(function*() {
+    let urls = [];
+    let postDatas = [];
+    for (let link of links) {
+      let data = yield getShortcutOrURIAndPostData(link.url);
+      urls.push(data.url);
+      postDatas.push(data.postData);
+    }
+    if (lastLocationChange == gBrowser.selectedBrowser.lastLocationChange) {
+      gBrowser.loadTabs(urls, {
+        inBackground,
+        replace: true,
+        allowThirdPartyFixup: false,
+        postDatas,
+        userContextId,
+      });
+    }
   });
 
-  // Keep the event from being handled by the dragDrop listeners
-  // built-in to gecko if they happen to be above us.
-  event.preventDefault();
+  // If links are dropped in content process, event.preventDefault() should be
+  // called in content process.
+  if (event) {
+    // Keep the event from being handled by the dragDrop listeners
+    // built-in to gecko if they happen to be above us.
+    event.preventDefault();
+  }
 }
 
 function readFromClipboard()
 {
   var url;
 
   try {
     // Get the clipboard.
--- a/suite/browser/navigatorDD.js
+++ b/suite/browser/navigatorDD.js
@@ -132,19 +132,20 @@ function openHomeDialog(aURL)
 }
 
 var goButtonObserver = {
   onDragOver: DragLinkOver,
 
   onDrop: function (aEvent)
   {
     var url = Services.droppedLinkHandler.dropLink(aEvent, {});
-    promiseShortcutOrURI(url).then(([url, postData]) => {
-      if (url)
-        loadURI(url, null, postData, false);
+
+    getShortcutOrURIAndPostData(url).then(data => {
+      if (data.url)
+        loadURI(data.url, null, data.postData, false);
     });
   }
 };
 
 var searchButtonObserver = {
   onDragOver: DragLinkOver,
 
   onDrop: function (aEvent)
--- a/suite/browser/tabbrowser.xml
+++ b/suite/browser/tabbrowser.xml
@@ -1465,55 +1465,96 @@
         </body>
       </method>
 
       <method name="loadTabs">
         <parameter name="aURIs"/>
         <parameter name="aLoadInBackground"/>
         <parameter name="aReplace"/>
         <body><![CDATA[
+          let aAllowThirdPartyFixup;
+          let aPostDatas = [];
+          let aUserContextId;
+
+          // Additional parameters are in a params object.
+          // Firefox uses additional parameters not supported here.
+          if (arguments.length == 2 &&
+              typeof arguments[1] == "object") {
+            let params = arguments[1];
+            aLoadInBackground     = params.inBackground;
+            aReplace              = params.replace;
+            aAllowThirdPartyFixup = params.allowThirdPartyFixup;
+            aPostDatas            = params.postDatas || aPostDatas;
+            aUserContextId        = params.userContextId;
+          }
+
           if (!aURIs.length)
             return;
 
           // The tab selected after this new tab is closed (i.e. the new tab's
           // "owner") is the next adjacent tab (i.e. not the previously viewed tab)
           // when several urls are opened here (i.e. closing the first should select
           // the next of many URLs opened) or if the pref to have UI links opened in
           // the background is set (i.e. the link is not being opened modally)
           //
           // i.e.
           //    Number of URLs    Load UI Links in BG       Focus Last Viewed?
           //    == 1              false                     YES
           //    == 1              true                      NO
           //    > 1               false/true                NO
+          var multiple = aURIs.length > 1;
+          var owner = multiple || aLoadInBackground ? null : this.selectedTab;
           var firstTabAdded = null;
+          var targetTabIndex = -1;
 
           if (aReplace) {
+            let browser;
+            browser = this.mCurrentBrowser;
+            targetTabIndex = this.tabContainer.selectedIndex;
+
+            let flags = Components.interfaces.nsIWebNavigation.LOAD_FLAGS_NONE;
+            if (aAllowThirdPartyFixup) {
+              flags |= Components.interfaces.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
+                       Components.interfaces.nsIWebNavigation.LOAD_FLAGS_FIXUP_SCHEME_TYPOS;
+            }
             try {
-              this.loadURI(aURIs[0]);
+              browser.loadURIWithFlags(aURIs[0], {
+                flags, postData: aPostDatas[0]
+              });
             } catch (e) {
               // Ignore failure in case a URI is wrong, so we can continue
               // opening the next ones.
             }
-          }
-          else {
+          } else {
             firstTabAdded = this.addTab(aURIs[0], {
-              focusNewTab: !aLoadInBackground && aURIs.length == 1
+              ownerTab: owner,
+              allowThirdPartyFixup: aAllowThirdPartyFixup,
+              postData: aPostDatas[0],
+              userContextId: aUserContextId
             });
           }
 
-          var tabNum = this.tabContainer.selectedIndex;
+          let tabNum = targetTabIndex;
           for (let i = 1; i < aURIs.length; ++i) {
-            let tab = this.addTab(aURIs[i]);
-            if (aReplace)
+            let tab = this.addTab(aURIs[i], {
+              allowThirdPartyFixup: aAllowThirdPartyFixup,
+              postData: aPostDatas[i],
+              userContextId: aUserContextId
+            });
+            if (targetTabIndex !== -1)
               this.moveTabTo(tab, ++tabNum);
           }
 
-          if (!aLoadInBackground && aReplace)
-            window.content.focus();
+          if (!aLoadInBackground) {
+            if (firstTabAdded) {
+              // .selectedTab setter focuses the content area
+              this.selectedTab = firstTabAdded;
+            } else
+              this.selectedBrowser.focus();
+          }
         ]]></body>
       </method>
 
       <method name="addTab">
         <parameter name="aURI"/>
         <parameter name="aReferrerURI"/>
         <parameter name="aCharset"/>
         <parameter name="aPostData"/>
@@ -2362,40 +2403,40 @@
               url = linkHandler.dropLink(aEvent, {}, true);
             } catch (ex) {}
 
             // Valid urls don't contain spaces ' '; if we have a space
             // it isn't a valid url.
             if (!url || url.indexOf(" ") != -1)
               return;
 
-            promiseShortcutOrURI(url).then(([url]) => {
+            getShortcutOrURIAndPostData(url).then(data => {
               var bgLoad = this.mPrefs.getBoolPref("browser.tabs.loadInBackground");
               if (aEvent.shiftKey)
                 bgLoad = !bgLoad;
 
               var tab = null;
               tabIndex = this.getDropOnIndex(aEvent);
               if (tabIndex != -1) {
                 // Load in an existing tab.
                 tab = this.tabs[tabIndex];
-                tab.linkedBrowser.loadURI(url);
+                tab.linkedBrowser.loadURI(data.url);
                 if (this.mCurrentTab != tab && !bgLoad)
                   this.selectedTab = tab;
               }
               else if (dt.mozSourceDocument &&
                        dt.mozSourceDocument.defaultView.top == content) {
                 // We're adding a new tab, and we may want parent-tab tracking.
-                tab = this.loadOneTab(url, {inBackground: bgLoad});
+                tab = this.loadOneTab(data.url, {inBackground: bgLoad});
                 if (newIndex != this.tabs.length - 1)
                   this.moveTabTo(this.tabs.length - 1, newIndex);
               }
               else {
                 // We're adding a new tab, but do not want parent-tab tracking.
-                tab = this.addTab(url);
+                tab = this.addTab(data.url);
                 if (newIndex != this.tabs.length - 1)
                   this.moveTabTo(this.tabs.length - 1, newIndex);
                 if (this.mCurrentTab != tab && !bgLoad)
                   this.selectedTab = tab;
               }
             });
           ]]>
         </body>
--- a/suite/common/contentAreaClick.js
+++ b/suite/common/contentAreaClick.js
@@ -139,88 +139,98 @@
           return true;
         break;
     }
     return false;
   }
 
   var gURIFixup = null;
 
-  function middleMousePaste(event)
-  {
-    var url = readFromClipboard();
-    if (!url)
+  function middleMousePaste(event) {
+
+    let clipboard = readFromClipboard();
+
+    if (!clipboard)
       return;
-    addToUrlbarHistory(url);
-    promiseShortcutOrURI(url).then(([url]) => {
-      // On ctrl-middleclick, open in new window or tab.  Do not send referrer.
-      if (event.ctrlKey) {
-        // fix up our pasted URI in case it is malformed.
-        const nsIURIFixup = Components.interfaces.nsIURIFixup;
-        if (!gURIFixup)
-          gURIFixup = Components.classes["@mozilla.org/docshell/urifixup;1"]
-                                .getService(nsIURIFixup);
+
+    // Strip embedded newlines and surrounding whitespace, to match the URL
+    // bar's behavior (stripsurroundingwhitespace).
+    clipboard = clipboard.replace(/\s*\n\s*/g, "");
+
+    clipboard = stripUnsafeProtocolOnPaste(clipboard);
 
-        url = gURIFixup.createFixupURI(url, nsIURIFixup.FIXUP_FLAGS_MAKE_ALTERNATE_URI).spec;
+    // If its not the current tab, we don't need to do anything because the
+    // browser doesn't exist.
+    let where = whereToOpenLink(event, true, false);
+    let lastLocationChange;
+    if (where == "current") {
+        lastLocationChange = gBrowser.selectedBrowser.lastLocationChange;
+    }
 
-        if (openNewTabOrWindow(event, url, null))
-          event.stopPropagation();
+    getShortcutOrURIAndPostData(clipboard).then(data => {
+      try {
+        makeURI(data.url);
+      } catch (ex) {
+        // Not a valid URI.
         return;
       }
 
-      // If ctrl wasn't down, then just load the url in the targeted win/tab.
-      var browser = getBrowser();
-      var tab = event.originalTarget;
-      if (tab.localName == "tab" &&
-          tab.parentNode == browser.tabContainer) {
-        tab.linkedBrowser.userTypedValue = url;
-        if (tab == browser.mCurrentTab && url != "about:blank") {
-            gURLBar.value = url;
-        }
-        tab.linkedBrowser.loadURI(url);
-        if (event.shiftKey != (Services.prefs.getBoolPref("browser.tabs.loadInBackground")))
-          browser.selectedTab = tab;
+      try {
+        addToUrlbarHistory(data.url);
+      } catch (ex) {
+        // Things may go wrong when adding url to session history,
+        // but don't let that interfere with the loading of the url.
+        Components.utils.reportError(ex);
       }
-      else if (event.target == browser) {
-        tab = browser.addTab(url);
-        if (event.shiftKey != (Services.prefs.getBoolPref("browser.tabs.loadInBackground")))
-          browser.selectedTab = tab;
-      }
-      else {
-        if (url != "about:blank") {
-          gURLBar.value = url;
-        }
-        loadURI(url);
+
+      if (where != "current" ||
+          lastLocationChange == gBrowser.selectedBrowser.lastLocationChange) {
+        openUILink(data.url, event,
+                   { ignoreButton: true,
+                       disallowInheritPrincipal: !data.mayInheritPrincipal });
       }
     });
+
     event.stopPropagation();
   }
 
+  function stripUnsafeProtocolOnPaste(pasteData) {
+    // Don't allow pasting javascript URIs since we don't support
+    // LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL for those.
+    let changed = false;
+    let pasteDataNoJS = pasteData.replace(/\r?\n/g, "")
+                                 .replace(/^(?:\s*javascript:)+/i,
+                                          () => { changed = true;
+                                                  return ""; });
+    return changed ? pasteDataNoJS : pasteData;
+  }
+
   function addToUrlbarHistory(aUrlToAdd)
   {
     if (gPrivate)
       return;
 
     if (!Services.prefs.getBoolPref("browser.urlbar.historyEnabled"))
       return;
 
-    // Remove leading and trailing spaces first
+    // Remove leading and trailing spaces first.
     aUrlToAdd = aUrlToAdd.trim();
 
     if (!aUrlToAdd)
       return;
-    if (aUrlToAdd.search(/[\x00-\x1F]/) != -1) // don't store bad URLs
+    // Don't store bad URLs.
+    if (aUrlToAdd.search(/[\x00-\x1F]/) != -1) 
       return;
 
     if (!gURIFixup)
       gURIFixup = Components.classes["@mozilla.org/docshell/urifixup;1"]
                             .getService(Components.interfaces.nsIURIFixup);
 
-    promiseShortcutOrURI(aUrlToAdd).then(([url]) => {
-      var fixedUpURI = gURIFixup.createFixupURI(url, 0);
+    getShortcutOrURIAndPostData(aUrlToAdd).then(data => {
+      var fixedUpURI = gURIFixup.createFixupURI(data.url, 0);
       if (!fixedUpURI.schemeIs("data"))
         PlacesUtils.history.markPageAsTyped(fixedUpURI);
     }).catch(() => {});
 
     // Open or create the urlbar history database.
     var file = GetUrlbarHistoryFile();
     var connection = Services.storage.openDatabase(file);
     connection.beginTransaction();
@@ -230,17 +240,17 @@
     // If the URL is already present in the database then remove it from
     // its current position. It is then reinserted at the top of the list.
     var statement = connection.createStatement(
         "DELETE FROM urlbarhistory WHERE LOWER(url) = LOWER(?1)");
     statement.bindByIndex(0, aUrlToAdd);
     statement.execute();
     statement.finalize();
 
-    // Put the value as it was typed by the user in to urlbar history
+    // Put the value as it was typed by the user in to urlbar history.
     statement = connection.createStatement(
         "INSERT INTO urlbarhistory (url) VALUES (?1)");
     statement.bindByIndex(0, aUrlToAdd);
     statement.execute();
     statement.finalize();
 
     // Remove any expired history items so that we don't let
     // this grow without bound.