From 0c6c32a0e6243040360d9dce05af377e95a71a5f Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Sun, 15 Apr 2018 09:31:07 +0200 Subject: Bug 846635 - Use asynchronous getCharsetForURI in getShortcutOrURI Issue #121 --- application/palemoon/base/content/browser.js | 239 ++++++++++---------- application/palemoon/base/content/openLocation.js | 78 ++++--- application/palemoon/base/content/tabbrowser.xml | 4 +- .../palemoon/base/content/urlbarBindings.xml | 242 +++++++++++---------- 4 files changed, 304 insertions(+), 259 deletions(-) (limited to 'application') diff --git a/application/palemoon/base/content/browser.js b/application/palemoon/base/content/browser.js index b2d260101..73661a8c9 100644 --- a/application/palemoon/base/content/browser.js +++ b/application/palemoon/base/content/browser.js @@ -9,6 +9,9 @@ var Cu = Components.utils; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource:///modules/RecentWindow.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Task", + "resource://gre/modules/Task.jsm"); + XPCOMUtils.defineLazyModuleGetter(this, "CharsetMenu", "resource:///modules/CharsetMenu.jsm"); @@ -1896,88 +1899,89 @@ function loadURI(uri, referrer, postData, allowThirdPartyFixup) { } catch (e) {} } -function getShortcutOrURI(aURL, aPostDataRef, aMayInheritPrincipal) { - // Initialize outparam to false - if (aMayInheritPrincipal) - aMayInheritPrincipal.value = false; - - var shortcutURL = null; - var keyword = aURL; - var param = ""; - - var offset = aURL.indexOf(" "); - if (offset > 0) { - keyword = aURL.substr(0, offset); - param = aURL.substr(offset + 1); - } - - if (!aPostDataRef) - aPostDataRef = {}; - - var engine = Services.search.getEngineByAlias(keyword); - if (engine) { - var submission = engine.getSubmission(param); - aPostDataRef.value = submission.postData; - return submission.uri.spec; - } - - [shortcutURL, aPostDataRef.value] = - PlacesUtils.getURLAndPostDataForKeyword(keyword); +function getShortcutOrURIAndPostData(aURL) { + return Task.spawn(function() { + let mayInheritPrincipal = false; + let postData = null; + let shortcutURL = null; + let keyword = aURL; + let param = ""; + + let offset = aURL.indexOf(" "); + if (offset > 0) { + keyword = aURL.substr(0, offset); + param = aURL.substr(offset + 1); + } + + let engine = Services.search.getEngineByAlias(keyword); + if (engine) { + let submission = engine.getSubmission(param); + postData = submission.postData; + throw new Task.Result({ postData: submission.postData, + url: submission.uri.spec, + mayInheritPrincipal: mayInheritPrincipal }); + } + + [shortcutURL, postData] = + PlacesUtils.getURLAndPostDataForKeyword(keyword); + + if (!shortcutURL) + throw new Task.Result({ postData: postData, url: aURL, + mayInheritPrincipal: mayInheritPrincipal }); + + let escapedPostData = ""; + if (postData) + escapedPostData = unescape(postData); + + if (/%s/i.test(shortcutURL) || /%s/i.test(escapedPostData)) { + let charset = ""; + const re = /^(.*)\&mozcharset=([a-zA-Z][_\-a-zA-Z0-9]+)\s*$/; + let matches = shortcutURL.match(re); + if (matches) + [, shortcutURL, charset] = matches; + 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 = yield PlacesUtils.getCharsetForURI(makeURI(shortcutURL)); + } catch (e) {} + } - if (!shortcutURL) - return aURL; + // 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 behavior of nsEscape() with + // url_XPAlphas + let encodedParam = ""; + if (charset && charset != "UTF-8") + encodedParam = escape(convertFromUnicode(charset, param)). + replace(/[+@\/]+/g, encodeURIComponent); + else // Default charset is UTF-8 + encodedParam = encodeURIComponent(param); - var postData = ""; - if (aPostDataRef.value) - postData = unescape(aPostDataRef.value); + shortcutURL = shortcutURL.replace(/%s/g, encodedParam).replace(/%S/g, param); - 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, charset] = matches; - 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.history.getCharsetForURI(makeURI(shortcutURL)); - } catch (e) {} + if (/%s/i.test(escapedPostData)) // POST keyword + postData = getPostDataStream(escapedPostData, param, encodedParam, + "application/x-www-form-urlencoded"); } + else if (param) { + // This keyword doesn't take a parameter, but one was provided. Just return + // the original URL. + postData = null; - // 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 behavior 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 - aPostDataRef.value = getPostDataStream(postData, param, encodedParam, - "application/x-www-form-urlencoded"); - } - else if (param) { - // This keyword doesn't take a parameter, but one was provided. Just return - // the original URL. - aPostDataRef.value = null; - - return aURL; - } + throw new Task.Result({ postData: postData, url: aURL, + mayInheritPrincipal: mayInheritPrincipal }); + } - // This URL came from a bookmark, so it's safe to let it inherit the current - // document's principal. - if (aMayInheritPrincipal) - aMayInheritPrincipal.value = true; + // This URL came from a bookmark, so it's safe to let it inherit the current + // document's principal. + mayInheritPrincipal = true; - return shortcutURL; + throw new Task.Result({ postData: postData, url: shortcutURL, + mayInheritPrincipal: mayInheritPrincipal }); + }); } function getPostDataStream(aStringData, aKeyword, aEncKeyword, aType) { @@ -2722,12 +2726,13 @@ var newTabButtonObserver = { onDrop: function (aEvent) { let url = browserDragAndDrop.drop(aEvent, { }); - var postData = {}; - url = getShortcutOrURI(url, postData); - if (url) { - // allow third-party services to fixup this URL - openNewTabWith(url, null, postData.value, aEvent, true); - } + Task.spawn(function() { + let data = yield getShortcutOrURIAndPostData(url); + if (data.url) { + // allow third-party services to fixup this URL + openNewTabWith(data.url, null, data.postData, aEvent, true); + } + }); } } @@ -2742,12 +2747,13 @@ var newWindowButtonObserver = { onDrop: function (aEvent) { let url = browserDragAndDrop.drop(aEvent, { }); - var postData = {}; - url = getShortcutOrURI(url, postData); - if (url) { - // allow third-party services to fixup this URL - openNewWindowWith(url, null, postData.value, true); - } + Task.spawn(function() { + let data = yield getShortcutOrURIAndPostData(url); + if (data.url) { + // allow third-party services to fixup this URL + openNewWindowWith(data.url, null, data.postData, true); + } + }); } } @@ -5035,36 +5041,52 @@ function middleMousePaste(event) { // bar's behavior (stripsurroundingwhitespace) clipboard = clipboard.replace(/\s*\n\s*/g, ""); - let mayInheritPrincipal = { value: false }; - let url = getShortcutOrURI(clipboard, mayInheritPrincipal); - try { - makeURI(url); - } catch (ex) { - // Not a valid URI. - return; + // if it's 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; } - try { - addToUrlbarHistory(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. - Cu.reportError(ex); - } + Task.spawn(function() { + let data = yield getShortcutOrURIAndPostData(clipboard); + try { + makeURI(data.url); + } catch (ex) { + // Not a valid URI. + return; + } + + 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. + Cu.reportError(ex); + } - openUILink(url, event, - { ignoreButton: true, - disallowInheritPrincipal: !mayInheritPrincipal.value }); + if (where != "current" || + lastLocationChange == gBrowser.selectedBrowser.lastLocationChange) { + openUILink(data.url, event, + { ignoreButton: true, + disallowInheritPrincipal: !data.mayInheritPrincipal }); + } + }); event.stopPropagation(); } function handleDroppedLink(event, url, name) { - let postData = { }; - let uri = getShortcutOrURI(url, postData); - if (uri) - loadURI(uri, null, postData.value, false); + let lastLocationChange = gBrowser.selectedBrowser.lastLocationChange; + + Task.spawn(function() { + let data = yield getShortcutOrURIAndPostData(url); + if (data.url && + lastLocationChange == gBrowser.selectedBrowser.lastLocationChange) + loadURI(data.url, null, data.postData, false); + }); // Keep the event from being handled by the dragDrop listeners // built-in to goanna if they happen to be above us. @@ -5179,7 +5201,6 @@ function charsetLoadListener() { } } - var gPageStyleMenu = { _getAllStyleSheets: function (frameset) { diff --git a/application/palemoon/base/content/openLocation.js b/application/palemoon/base/content/openLocation.js index 5b731c7e8..b00dbc571 100644 --- a/application/palemoon/base/content/openLocation.js +++ b/application/palemoon/base/content/openLocation.js @@ -16,6 +16,7 @@ try { } Components.utils.import("resource:///modules/openLocationLastURL.jsm", openLocationModule); +Components.utils.import("resource://gre/modules/Task.jsm"); let gOpenLocationLastURL = new openLocationModule.OpenLocationLastURL(window.opener); function onLoad() @@ -61,45 +62,52 @@ function doEnabling() function open() { - var url; - var postData = {}; - var mayInheritPrincipal = {value: false}; - if (browser) - url = browser.getShortcutOrURI(dialog.input.value, postData, mayInheritPrincipal); - else - url = dialog.input.value; + Task.spawn(function() { + let url; + let postData = null; + let mayInheritPrincipal = false; + + if (browser) { + let data = yield browser.getShortcutOrURIAndPostData(dialog.input.value); + url = data.url; + postData = data.postData; + mayInheritPrincipal = data.mayInheritPrincipal; + } else { + url = dialog.input.value; + } - try { - // Whichever target we use for the load, we allow third-party services to - // fixup the URI - switch (dialog.openWhereList.value) { - case "0": - var webNav = Components.interfaces.nsIWebNavigation; - var flags = webNav.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP | - webNav.LOAD_FLAGS_FIXUP_SCHEME_TYPOS; - if (!mayInheritPrincipal.value) - flags |= webNav.LOAD_FLAGS_DISALLOW_INHERIT_OWNER; - browser.gBrowser.loadURIWithFlags(url, flags, null, null, postData.value); - break; - case "1": - window.opener.delayedOpenWindow(getBrowserURL(), "all,dialog=no", - url, postData.value, null, null, true); - break; - case "3": - browser.delayedOpenTab(url, null, null, postData.value, true); - break; + try { + // Whichever target we use for the load, we allow third-party services to + // fixup the URI + switch (dialog.openWhereList.value) { + case "0": + var webNav = Components.interfaces.nsIWebNavigation; + var flags = webNav.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP; + if (!mayInheritPrincipal) + flags |= webNav.LOAD_FLAGS_DISALLOW_INHERIT_OWNER; + browser.gBrowser.loadURIWithFlags(url, flags, null, null, postData); + break; + case "1": + window.opener.delayedOpenWindow(getBrowserURL(), "all,dialog=no", + url, postData, null, null, true); + break; + case "3": + browser.delayedOpenTab(url, null, null, postData, true); + break; + } + } + catch(exception) { } - } - catch(exception) { - } - if (pref) { - gOpenLocationLastURL.value = dialog.input.value; - pref.setIntPref("general.open_location.last_window_choice", dialog.openWhereList.value); - } + if (pref) { + gOpenLocationLastURL.value = dialog.input.value; + pref.setIntPref("general.open_location.last_window_choice", dialog.openWhereList.value); + } + + // Delay closing slightly to avoid timing bug on Linux. + window.close(); + }); - // Delay closing slightly to avoid timing bug on Linux. - window.close(); return false; } diff --git a/application/palemoon/base/content/tabbrowser.xml b/application/palemoon/base/content/tabbrowser.xml index 4b10855a7..4f713d76f 100644 --- a/application/palemoon/base/content/tabbrowser.xml +++ b/application/palemoon/base/content/tabbrowser.xml @@ -738,8 +738,10 @@ aFlags]); } - if (topLevel) + if (topLevel) { this.mBrowser.lastURI = aLocation; + this.mBrowser.lastLocationChange = Date.now(); + } }, onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) { diff --git a/application/palemoon/base/content/urlbarBindings.xml b/application/palemoon/base/content/urlbarBindings.xml index c99819f0d..e0bb40d64 100644 --- a/application/palemoon/base/content/urlbarBindings.xml +++ b/application/palemoon/base/content/urlbarBindings.xml @@ -263,151 +263,165 @@ var postData = null; var action = this._parseActionUrl(url); - if (action) { - url = action.param; - if (this.hasAttribute("actiontype")) { - if (action.type == "switchtab") { - this.handleRevert(); - let prevTab = gBrowser.selectedTab; - if (switchToTabHavingURI(url) && - isTabEmpty(prevTab)) - gBrowser.removeTab(prevTab); + let lastLocationChange = gBrowser.selectedBrowser.lastLocationChange; + Task.spawn(function() { + let matchLastLocationChange = true; + if (action) { + url = action.param; + if (this.hasAttribute("actiontype")) { + if (action.type == "switchtab") { + this.handleRevert(); + let prevTab = gBrowser.selectedTab; + if (switchToTabHavingURI(url) && + isTabEmpty(prevTab)) + gBrowser.removeTab(prevTab); + } + return; } - return; } - } - else { - [url, postData, mayInheritPrincipal] = this._canonizeURL(aTriggeringEvent); - if (!url) - return; - } + else { + [url, postData, mayInheritPrincipal] = yield this._canonizeURL(aTriggeringEvent); + matchLastLocationChange = (lastLocationChange == + gBrowser.selectedBrowser.lastLocationChange); + if (!url) + return; + } - this.value = url; - gBrowser.userTypedValue = url; - try { - addToUrlbarHistory(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. - Cu.reportError(ex); - } + this.value = url; + gBrowser.userTypedValue = url; + try { + addToUrlbarHistory(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. + Cu.reportError(ex); + } - function loadCurrent() { - let webnav = Ci.nsIWebNavigation; - let flags = webnav.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP | - webnav.LOAD_FLAGS_FIXUP_SCHEME_TYPOS; - // Pass LOAD_FLAGS_DISALLOW_INHERIT_OWNER to prevent any loads from - // inheriting the currently loaded document's principal, unless this - // URL is marked as safe to inherit (e.g. came from a bookmark - // keyword). - if (!mayInheritPrincipal) - flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER; - gBrowser.loadURIWithFlags(url, flags, null, null, postData); - } + function loadCurrent() { + let flags = Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP; + // Pass LOAD_FLAGS_DISALLOW_INHERIT_OWNER to prevent any loads from + // inheriting the currently loaded document's principal, unless this + // URL is marked as safe to inherit (e.g. came from a bookmark + // keyword). + if (!mayInheritPrincipal) + flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER; + // If the value wasn't typed, we know that we decoded the value as + // UTF-8 (see losslessDecodeURI) + if (!this.valueIsTyped) + flags |= Ci.nsIWebNavigation.LOAD_FLAGS_URI_IS_UTF8; + gBrowser.loadURIWithFlags(url, flags, null, null, postData); + } - // Focus the content area before triggering loads, since if the load - // occurs in a new tab, we want focus to be restored to the content - // area when the current tab is re-selected. - gBrowser.selectedBrowser.focus(); + // Focus the content area before triggering loads, since if the load + // occurs in a new tab, we want focus to be restored to the content + // area when the current tab is re-selected. + gBrowser.selectedBrowser.focus(); - let isMouseEvent = aTriggeringEvent instanceof MouseEvent; - let altEnter = !isMouseEvent && aTriggeringEvent && aTriggeringEvent.altKey; + let isMouseEvent = aTriggeringEvent instanceof MouseEvent; + let altEnter = !isMouseEvent && aTriggeringEvent && aTriggeringEvent.altKey; - if (altEnter) { - // XXX This was added a long time ago, and I'm not sure why it is - // necessary. Alt+Enter's default action might cause a system beep, - // or something like that? - aTriggeringEvent.preventDefault(); - aTriggeringEvent.stopPropagation(); - } + if (altEnter) { + // XXX This was added a long time ago, and I'm not sure why it is + // necessary. Alt+Enter's default action might cause a system beep, + // or something like that? + aTriggeringEvent.preventDefault(); + aTriggeringEvent.stopPropagation(); + } - // If the current tab is empty, ignore Alt+Enter (just reuse this tab) - altEnter = altEnter && !isTabEmpty(gBrowser.selectedTab); + // If the current tab is empty, ignore Alt+Enter (just reuse this tab) + altEnter = altEnter && !isTabEmpty(gBrowser.selectedTab); - if (isMouseEvent || altEnter) { - // Use the standard UI link behaviors for clicks or Alt+Enter - let where = "tab"; - if (isMouseEvent) - where = whereToOpenLink(aTriggeringEvent, false, false); + if (isMouseEvent || altEnter) { + // Use the standard UI link behaviors for clicks or Alt+Enter + let where = "tab"; + if (isMouseEvent) + where = whereToOpenLink(aTriggeringEvent, false, false); - if (where == "current") { - loadCurrent(); + if (where == "current") { + if (matchLastLocationChange) { + loadCurrent(); + } + } else { + this.handleRevert(); + let params = { allowThirdPartyFixup: true, + postData: postData, + initiatingDoc: document }; + if (!this.valueIsTyped) + params.isUTF8 = true; + openUILinkIn(url, where, params); + } } else { - this.handleRevert(); - let params = { allowThirdPartyFixup: true, - postData: postData, - initiatingDoc: document }; - openUILinkIn(url, where, params); + if (matchLastLocationChange) { + loadCurrent(); + } } - } else { - loadCurrent(); - } + }.bind(this)); ]]> = 0) { + url = url.substring(0, firstSlash) + suffix + + url.substring(firstSlash + 1); + } else { + url = url + suffix; + } - if (firstSlash >= 0) { - url = url.substring(0, firstSlash) + suffix + - url.substring(firstSlash + 1); - } else { - url = url + suffix; + url = "http://www." + url; } - - url = "http://www." + url; } - } - var postData = {}; - var mayInheritPrincipal = { value: false }; - url = getShortcutOrURI(url, postData, mayInheritPrincipal); + let data = yield getShortcutOrURIAndPostData(url); - return [url, postData.value, mayInheritPrincipal.value]; + throw new Task.Result([data.url, data.postData, data.mayInheritPrincipal]); + }.bind(this)); ]]> -- cgit v1.2.3