Bug 846635 - Use asynchronous getCharsetForURI in getShortcutOrURI

Issue #121
This commit is contained in:
janekptacijarabaci 2018-04-15 09:31:07 +02:00 • committed by Roy Tam
commit d8637395c5
4 changed files with 305 additions and 260 deletions

View file

@ -10,6 +10,9 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/RecentWindow.jsm"); Cu.import("resource:///modules/RecentWindow.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "CharsetMenu", XPCOMUtils.defineLazyModuleGetter(this, "CharsetMenu",
"resource:///modules/CharsetMenu.jsm"); "resource:///modules/CharsetMenu.jsm");
@ -1895,45 +1898,44 @@ function loadURI(uri, referrer, postData, allowThirdPartyFixup) {
} catch (e) {} } catch (e) {}
} }
function getShortcutOrURI(aURL, aPostDataRef, aMayInheritPrincipal) { function getShortcutOrURIAndPostData(aURL) {
// Initialize outparam to false return Task.spawn(function() {
if (aMayInheritPrincipal) let mayInheritPrincipal = false;
aMayInheritPrincipal.value = false; let postData = null;
let shortcutURL = null;
let keyword = aURL;
let param = "";
var shortcutURL = null; let offset = aURL.indexOf(" ");
var keyword = aURL;
var param = "";
var offset = aURL.indexOf(" ");
if (offset > 0) { if (offset > 0) {
keyword = aURL.substr(0, offset); keyword = aURL.substr(0, offset);
param = aURL.substr(offset + 1); param = aURL.substr(offset + 1);
} }
if (!aPostDataRef) let engine = Services.search.getEngineByAlias(keyword);
aPostDataRef = {};
var engine = Services.search.getEngineByAlias(keyword);
if (engine) { if (engine) {
var submission = engine.getSubmission(param); let submission = engine.getSubmission(param);
aPostDataRef.value = submission.postData; postData = submission.postData;
return submission.uri.spec; throw new Task.Result({ postData: submission.postData,
url: submission.uri.spec,
mayInheritPrincipal: mayInheritPrincipal });
} }
[shortcutURL, aPostDataRef.value] = [shortcutURL, postData] =
PlacesUtils.getURLAndPostDataForKeyword(keyword); PlacesUtils.getURLAndPostDataForKeyword(keyword);
if (!shortcutURL) if (!shortcutURL)
return aURL; throw new Task.Result({ postData: postData, url: aURL,
mayInheritPrincipal: mayInheritPrincipal });
var postData = ""; let escapedPostData = "";
if (aPostDataRef.value) if (postData)
postData = unescape(aPostDataRef.value); escapedPostData = unescape(postData);
if (/%s/i.test(shortcutURL) || /%s/i.test(postData)) { if (/%s/i.test(shortcutURL) || /%s/i.test(escapedPostData)) {
var charset = ""; let charset = "";
const re = /^(.*)\&mozcharset=([a-zA-Z][_\-a-zA-Z0-9]+)\s*$/; const re = /^(.*)\&mozcharset=([a-zA-Z][_\-a-zA-Z0-9]+)\s*$/;
var matches = shortcutURL.match(re); let matches = shortcutURL.match(re);
if (matches) if (matches)
[, shortcutURL, charset] = matches; [, shortcutURL, charset] = matches;
else { else {
@ -1941,7 +1943,7 @@ function getShortcutOrURI(aURL, aPostDataRef, aMayInheritPrincipal) {
try { try {
// makeURI throws if URI is invalid. // makeURI throws if URI is invalid.
// Will return an empty string if character-set is not found. // Will return an empty string if character-set is not found.
charset = PlacesUtils.history.getCharsetForURI(makeURI(shortcutURL)); charset = yield PlacesUtils.getCharsetForURI(makeURI(shortcutURL));
} catch (e) {} } catch (e) {}
} }
@ -1950,7 +1952,7 @@ function getShortcutOrURI(aURL, aPostDataRef, aMayInheritPrincipal) {
// Therefore we need to manually replace these ASCII characters by their // Therefore we need to manually replace these ASCII characters by their
// encodeURIComponent result, to match the behavior of nsEscape() with // encodeURIComponent result, to match the behavior of nsEscape() with
// url_XPAlphas // url_XPAlphas
var encodedParam = ""; let encodedParam = "";
if (charset && charset != "UTF-8") if (charset && charset != "UTF-8")
encodedParam = escape(convertFromUnicode(charset, param)). encodedParam = escape(convertFromUnicode(charset, param)).
replace(/[+@\/]+/g, encodeURIComponent); replace(/[+@\/]+/g, encodeURIComponent);
@ -1959,24 +1961,26 @@ function getShortcutOrURI(aURL, aPostDataRef, aMayInheritPrincipal) {
shortcutURL = shortcutURL.replace(/%s/g, encodedParam).replace(/%S/g, param); shortcutURL = shortcutURL.replace(/%s/g, encodedParam).replace(/%S/g, param);
if (/%s/i.test(postData)) // POST keyword if (/%s/i.test(escapedPostData)) // POST keyword
aPostDataRef.value = getPostDataStream(postData, param, encodedParam, postData = getPostDataStream(escapedPostData, param, encodedParam,
"application/x-www-form-urlencoded"); "application/x-www-form-urlencoded");
} }
else if (param) { else if (param) {
// This keyword doesn't take a parameter, but one was provided. Just return // This keyword doesn't take a parameter, but one was provided. Just return
// the original URL. // the original URL.
aPostDataRef.value = null; postData = 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 // This URL came from a bookmark, so it's safe to let it inherit the current
// document's principal. // document's principal.
if (aMayInheritPrincipal) mayInheritPrincipal = true;
aMayInheritPrincipal.value = true;
return shortcutURL; throw new Task.Result({ postData: postData, url: shortcutURL,
mayInheritPrincipal: mayInheritPrincipal });
});
} }
function getPostDataStream(aStringData, aKeyword, aEncKeyword, aType) { function getPostDataStream(aStringData, aKeyword, aEncKeyword, aType) {
@ -2721,12 +2725,13 @@ var newTabButtonObserver = {
onDrop: function (aEvent) onDrop: function (aEvent)
{ {
let url = browserDragAndDrop.drop(aEvent, { }); let url = browserDragAndDrop.drop(aEvent, { });
var postData = {}; Task.spawn(function() {
url = getShortcutOrURI(url, postData); let data = yield getShortcutOrURIAndPostData(url);
if (url) { if (data.url) {
// allow third-party services to fixup this URL // allow third-party services to fixup this URL
openNewTabWith(url, null, postData.value, aEvent, true); openNewTabWith(data.url, null, data.postData, aEvent, true);
} }
});
} }
} }
@ -2741,12 +2746,13 @@ var newWindowButtonObserver = {
onDrop: function (aEvent) onDrop: function (aEvent)
{ {
let url = browserDragAndDrop.drop(aEvent, { }); let url = browserDragAndDrop.drop(aEvent, { });
var postData = {}; Task.spawn(function() {
url = getShortcutOrURI(url, postData); let data = yield getShortcutOrURIAndPostData(url);
if (url) { if (data.url) {
// allow third-party services to fixup this URL // allow third-party services to fixup this URL
openNewWindowWith(url, null, postData.value, true); openNewWindowWith(data.url, null, data.postData, true);
} }
});
} }
} }
@ -5034,36 +5040,52 @@ function middleMousePaste(event) {
// bar's behavior (stripsurroundingwhitespace) // bar's behavior (stripsurroundingwhitespace)
clipboard = clipboard.replace(/\s*\n\s*/g, ""); clipboard = clipboard.replace(/\s*\n\s*/g, "");
let mayInheritPrincipal = { value: false }; // if it's not the current tab, we don't need to do anything because the
let url = getShortcutOrURI(clipboard, mayInheritPrincipal); // browser doesn't exist.
let where = whereToOpenLink(event, true, false);
let lastLocationChange;
if (where == "current") {
lastLocationChange = gBrowser.selectedBrowser.lastLocationChange;
}
Task.spawn(function() {
let data = yield getShortcutOrURIAndPostData(clipboard);
try { try {
makeURI(url); makeURI(data.url);
} catch (ex) { } catch (ex) {
// Not a valid URI. // Not a valid URI.
return; return;
} }
try { try {
addToUrlbarHistory(url); addToUrlbarHistory(data.url);
} catch (ex) { } catch (ex) {
// Things may go wrong when adding url to session history, // Things may go wrong when adding url to session history,
// but don't let that interfere with the loading of the url. // but don't let that interfere with the loading of the url.
Cu.reportError(ex); Cu.reportError(ex);
} }
openUILink(url, event, if (where != "current" ||
lastLocationChange == gBrowser.selectedBrowser.lastLocationChange) {
openUILink(data.url, event,
{ ignoreButton: true, { ignoreButton: true,
disallowInheritPrincipal: !mayInheritPrincipal.value }); disallowInheritPrincipal: !data.mayInheritPrincipal });
}
});
event.stopPropagation(); event.stopPropagation();
} }
function handleDroppedLink(event, url, name) function handleDroppedLink(event, url, name)
{ {
let postData = { }; let lastLocationChange = gBrowser.selectedBrowser.lastLocationChange;
let uri = getShortcutOrURI(url, postData);
if (uri) Task.spawn(function() {
loadURI(uri, null, postData.value, false); 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 // Keep the event from being handled by the dragDrop listeners
// built-in to goanna if they happen to be above us. // built-in to goanna if they happen to be above us.
@ -5178,7 +5200,6 @@ function charsetLoadListener() {
} }
} }
var gPageStyleMenu = { var gPageStyleMenu = {
_getAllStyleSheets: function (frameset) { _getAllStyleSheets: function (frameset) {

View file

@ -16,7 +16,8 @@ try {
} }
Components.utils.import("resource:///modules/openLocationLastURL.jsm", openLocationModule); Components.utils.import("resource:///modules/openLocationLastURL.jsm", openLocationModule);
var gOpenLocationLastURL = new openLocationModule.OpenLocationLastURL(window.opener); Components.utils.import("resource://gre/modules/Task.jsm");
let gOpenLocationLastURL = new openLocationModule.OpenLocationLastURL(window.opener);
function onLoad() function onLoad()
{ {
@ -61,13 +62,19 @@ function doEnabling()
function open() function open()
{ {
var url; Task.spawn(function() {
var postData = {}; let url;
var mayInheritPrincipal = {value: false}; let postData = null;
if (browser) let mayInheritPrincipal = false;
url = browser.getShortcutOrURI(dialog.input.value, postData, mayInheritPrincipal);
else if (browser) {
let data = yield browser.getShortcutOrURIAndPostData(dialog.input.value);
url = data.url;
postData = data.postData;
mayInheritPrincipal = data.mayInheritPrincipal;
} else {
url = dialog.input.value; url = dialog.input.value;
}
try { try {
// Whichever target we use for the load, we allow third-party services to // Whichever target we use for the load, we allow third-party services to
@ -75,18 +82,17 @@ function open()
switch (dialog.openWhereList.value) { switch (dialog.openWhereList.value) {
case "0": case "0":
var webNav = Components.interfaces.nsIWebNavigation; var webNav = Components.interfaces.nsIWebNavigation;
var flags = webNav.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP | var flags = webNav.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
webNav.LOAD_FLAGS_FIXUP_SCHEME_TYPOS; if (!mayInheritPrincipal)
if (!mayInheritPrincipal.value)
flags |= webNav.LOAD_FLAGS_DISALLOW_INHERIT_OWNER; flags |= webNav.LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
browser.gBrowser.loadURIWithFlags(url, flags, null, null, postData.value); browser.gBrowser.loadURIWithFlags(url, flags, null, null, postData);
break; break;
case "1": case "1":
window.opener.delayedOpenWindow(getBrowserURL(), "all,dialog=no", window.opener.delayedOpenWindow(getBrowserURL(), "all,dialog=no",
url, postData.value, null, null, true); url, postData, null, null, true);
break; break;
case "3": case "3":
browser.delayedOpenTab(url, null, null, postData.value, true); browser.delayedOpenTab(url, null, null, postData, true);
break; break;
} }
} }
@ -100,6 +106,8 @@ function open()
// Delay closing slightly to avoid timing bug on Linux. // Delay closing slightly to avoid timing bug on Linux.
window.close(); window.close();
});
return false; return false;
} }

View file

@ -738,8 +738,10 @@
aFlags]); aFlags]);
} }
if (topLevel) if (topLevel) {
this.mBrowser.lastURI = aLocation; this.mBrowser.lastURI = aLocation;
this.mBrowser.lastLocationChange = Date.now();
}
}, },
onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) { onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) {

View file

@ -263,6 +263,9 @@
var postData = null; var postData = null;
var action = this._parseActionUrl(url); var action = this._parseActionUrl(url);
let lastLocationChange = gBrowser.selectedBrowser.lastLocationChange;
Task.spawn(function() {
let matchLastLocationChange = true;
if (action) { if (action) {
url = action.param; url = action.param;
if (this.hasAttribute("actiontype")) { if (this.hasAttribute("actiontype")) {
@ -277,7 +280,9 @@
} }
} }
else { else {
[url, postData, mayInheritPrincipal] = this._canonizeURL(aTriggeringEvent); [url, postData, mayInheritPrincipal] = yield this._canonizeURL(aTriggeringEvent);
matchLastLocationChange = (lastLocationChange ==
gBrowser.selectedBrowser.lastLocationChange);
if (!url) if (!url)
return; return;
} }
@ -293,15 +298,17 @@
} }
function loadCurrent() { function loadCurrent() {
let webnav = Ci.nsIWebNavigation; let flags = Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
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 // Pass LOAD_FLAGS_DISALLOW_INHERIT_OWNER to prevent any loads from
// inheriting the currently loaded document's principal, unless this // inheriting the currently loaded document's principal, unless this
// URL is marked as safe to inherit (e.g. came from a bookmark // URL is marked as safe to inherit (e.g. came from a bookmark
// keyword). // keyword).
if (!mayInheritPrincipal) if (!mayInheritPrincipal)
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER; 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); gBrowser.loadURIWithFlags(url, flags, null, null, postData);
} }
@ -331,26 +338,34 @@
where = whereToOpenLink(aTriggeringEvent, false, false); where = whereToOpenLink(aTriggeringEvent, false, false);
if (where == "current") { if (where == "current") {
if (matchLastLocationChange) {
loadCurrent(); loadCurrent();
}
} else { } else {
this.handleRevert(); this.handleRevert();
let params = { allowThirdPartyFixup: true, let params = { allowThirdPartyFixup: true,
postData: postData, postData: postData,
initiatingDoc: document }; initiatingDoc: document };
if (!this.valueIsTyped)
params.isUTF8 = true;
openUILinkIn(url, where, params); openUILinkIn(url, where, params);
} }
} else { } else {
if (matchLastLocationChange) {
loadCurrent(); loadCurrent();
} }
}
}.bind(this));
]]></body> ]]></body>
</method> </method>
<method name="_canonizeURL"> <method name="_canonizeURL">
<parameter name="aTriggeringEvent"/> <parameter name="aTriggeringEvent"/>
<body><![CDATA[ <body><![CDATA[
return Task.spawn(function() {
var url = this.value; var url = this.value;
if (!url) if (!url)
return ["", null, false]; throw new Task.Result(["", null, false]);
// Only add the suffix when the URL bar value isn't already "URL-like", // Only add the suffix when the URL bar value isn't already "URL-like",
// and only if we get a keyboard event, to match user expectations. // and only if we get a keyboard event, to match user expectations.
@ -403,11 +418,10 @@
} }
} }
var postData = {}; let data = yield getShortcutOrURIAndPostData(url);
var mayInheritPrincipal = { value: false };
url = getShortcutOrURI(url, postData, mayInheritPrincipal);
return [url, postData.value, mayInheritPrincipal.value]; throw new Task.Result([data.url, data.postData, data.mayInheritPrincipal]);
}.bind(this));
]]></body> ]]></body>
</method> </method>