summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbrowser/base/content/browser.js83
-rw-r--r--browser/base/content/content.js2
-rw-r--r--browser/base/content/nsContextMenu.js5
-rw-r--r--browser/base/content/tabbrowser.xml6
-rw-r--r--browser/base/content/utilityOverlay.js22
-rw-r--r--browser/components/feeds/FeedConverter.js2
-rw-r--r--browser/components/sessionstore/ContentRestore.jsm5
-rw-r--r--browser/components/sessionstore/SessionHistory.jsm5
-rw-r--r--browser/components/sessionstore/SessionMigration.jsm14
-rw-r--r--browser/components/sessionstore/SessionStore.jsm4
-rw-r--r--browser/modules/ContentClick.jsm1
-rw-r--r--devtools/client/responsive.html/browser/web-navigation.js8
-rw-r--r--docshell/base/nsDocShell.cpp78
-rw-r--r--docshell/base/nsDocShell.h6
-rw-r--r--docshell/base/nsILinkHandler.h10
-rw-r--r--docshell/base/nsIWebNavigation.idl23
-rw-r--r--docshell/shistory/nsSHEntry.cpp3
-rw-r--r--docshell/shistory/nsSHistory.cpp3
-rw-r--r--docshell/test/browser/browser.ini3
-rw-r--r--docshell/test/browser/browser_click_link_within_view_source.js60
-rw-r--r--docshell/test/browser/browser_history_triggeringprincipal_viewsource.js50
-rw-r--r--docshell/test/browser/dummy_page.html6
-rw-r--r--docshell/test/browser/file_click_link_within_view_source.html6
-rw-r--r--docshell/test/dummy_page.html6
-rw-r--r--docshell/test/mochitest.ini2
-rw-r--r--docshell/test/test_triggeringprincipal_location_seturi.html102
-rw-r--r--dom/base/nsContentUtils.cpp8
-rw-r--r--dom/base/nsGlobalWindow.cpp9
-rw-r--r--dom/base/test/file_simplecontentpolicy.js1
-rw-r--r--dom/jsurl/nsJSProtocolHandler.cpp49
-rw-r--r--dom/plugins/base/nsPluginInstanceOwner.cpp25
-rw-r--r--dom/plugins/test/mochitest/test_bug813906.html22
-rw-r--r--dom/security/nsContentSecurityManager.cpp74
-rw-r--r--embedding/browser/nsIWebBrowserChrome3.idl9
-rw-r--r--embedding/browser/nsWebBrowser.cpp5
-rw-r--r--netwerk/base/nsNetUtil.cpp14
-rw-r--r--testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/iframe-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini3
-rw-r--r--testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/iframe-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini3
-rw-r--r--testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/iframe-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini3
-rw-r--r--testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/iframe-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini3
-rw-r--r--testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/iframe-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini3
-rw-r--r--testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/iframe-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini3
-rw-r--r--testing/web-platform/tests/service-workers/service-worker/fetch-frame-resource.https.html6
-rw-r--r--toolkit/components/viewsource/content/viewSource-content.js2
-rw-r--r--toolkit/content/widgets/browser.xml6
-rw-r--r--toolkit/modules/sessionstore/Utils.jsm5
-rw-r--r--uriloader/base/nsURILoader.cpp2
-rw-r--r--xpfe/appshell/nsContentTreeOwner.cpp5
-rw-r--r--xpfe/appshell/nsIXULBrowserWindow.idl6
49 files changed, 584 insertions, 197 deletions
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index 696a2871a8..2380f5d21c 100755
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -71,6 +71,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "SafeBrowsing",
["gDNSService", "@mozilla.org/network/dns-service;1", "nsIDNSService"],
].forEach(([name, cc, ci]) => XPCOMUtils.defineLazyServiceGetter(this, name, cc, ci));
+XPCOMUtils.defineLazyServiceGetter(this, "gSerializationHelper",
+ "@mozilla.org/network/serialization-helper;1",
+ "nsISerializationHelper");
+
XPCOMUtils.defineLazyGetter(this, "BrowserToolboxProcess", function() {
let tmp = {};
Cu.import("resource://devtools/client/framework/ToolboxProcess.jsm", tmp);
@@ -807,6 +811,7 @@ function _loadURIWithFlags(browser, uri, params) {
if (!uri) {
uri = "about:blank";
}
+ let triggeringPrincipal = params.triggeringPrincipal || null;
let flags = params.flags || 0;
let referrer = params.referrerURI;
let referrerPolicy = ('referrerPolicy' in params ? params.referrerPolicy :
@@ -831,7 +836,7 @@ function _loadURIWithFlags(browser, uri, params) {
browser.webNavigation.loadURIWithOptions(uri, flags,
referrer, referrerPolicy,
- postData, null, null);
+ postData, null, null, triggeringPrincipal);
} else {
// Check if the current browser is allowed to unload.
let {permitUnload, timedOut} = browser.permitUnload();
@@ -845,6 +850,9 @@ function _loadURIWithFlags(browser, uri, params) {
let loadParams = {
uri: uri,
+ triggeringPrincipal: triggeringPrincipal
+ ? gSerializationHelper.serializeToString(triggeringPrincipal)
+ : null,
flags: flags,
referrer: referrer ? referrer.spec : null,
referrerPolicy: referrerPolicy,
@@ -872,7 +880,7 @@ function _loadURIWithFlags(browser, uri, params) {
}
browser.webNavigation.loadURIWithOptions(uri, flags, referrer, referrerPolicy,
- postData, null, null);
+ postData, null, null, triggeringPrincipal);
} else {
throw e;
}
@@ -1164,6 +1172,7 @@ var gBrowserInit = {
// [5]: referrerPolicy (int)
// [6]: userContextId (int)
// [7]: originPrincipal (nsIPrincipal)
+ // [8]: triggeringPrincipal (nsIPrincipal)
else if (window.arguments.length >= 3) {
let referrerURI = window.arguments[2];
if (typeof(referrerURI) == "string") {
@@ -1181,7 +1190,7 @@ var gBrowserInit = {
window.arguments[4] || false, referrerPolicy, userContextId,
// pass the origin principal (if any) and force its use to create
// an initial about:blank viewer if present:
- window.arguments[7], !!window.arguments[7]);
+ window.arguments[7], !!window.arguments[7], window.arguments[8]);
window.focus();
}
// Note: loadOneOrMoreURIs *must not* be called if window.arguments.length >= 3.
@@ -2067,7 +2076,8 @@ function BrowserTryToCloseWindow()
}
function loadURI(uri, referrer, postData, allowThirdPartyFixup, referrerPolicy,
- userContextId, originPrincipal, forceAboutBlankViewerInCurrent) {
+ userContextId, originPrincipal, forceAboutBlankViewerInCurrent,
+ triggeringPrincipal) {
try {
openLinkIn(uri, "current",
{ referrerURI: referrer,
@@ -2076,6 +2086,7 @@ function loadURI(uri, referrer, postData, allowThirdPartyFixup, referrerPolicy,
allowThirdPartyFixup: allowThirdPartyFixup,
userContextId: userContextId,
originPrincipal,
+ triggeringPrincipal,
forceAboutBlankViewerInCurrent,
});
} catch (e) {}
@@ -2779,24 +2790,6 @@ var BrowserOnClick = {
}
},
- handleEvent: function (event) {
- if (!event.isTrusted || // Don't trust synthetic events
- event.button == 2) {
- return;
- }
-
- let originalTarget = event.originalTarget;
- let ownerDoc = originalTarget.ownerDocument;
- if (!ownerDoc) {
- return;
- }
-
- if (gMultiProcessBrowser &&
- ownerDoc.documentURI.toLowerCase() == "about:newtab") {
- this.onE10sAboutNewTab(event, ownerDoc);
- }
- },
-
receiveMessage: function (msg) {
switch (msg.name) {
case "Browser:CertExceptionError":
@@ -2990,28 +2983,6 @@ var BrowserOnClick = {
}
},
- /**
- * This functions prevents navigation from happening directly through the <a>
- * link in about:newtab (which is loaded in the parent and therefore would load
- * the next page also in the parent) and instructs the browser to open the url
- * in the current tab which will make it update the remoteness of the tab.
- */
- onE10sAboutNewTab: function(event, ownerDoc) {
- let isTopFrame = (ownerDoc.defaultView.parent === ownerDoc.defaultView);
- if (!isTopFrame) {
- return;
- }
-
- let anchorTarget = event.originalTarget.parentNode;
-
- if (anchorTarget instanceof HTMLAnchorElement &&
- anchorTarget.classList.contains("newtab-link")) {
- event.preventDefault();
- let where = whereToOpenLink(event, false, false);
- openLinkIn(anchorTarget.href, where, { charset: ownerDoc.characterSet, referrerURI: ownerDoc.documentURIObject });
- }
- },
-
ignoreWarningButton: function (reason) {
// Allow users to override and continue through to the site,
// but add a notify bar as a reminder, so that they don't lose
@@ -4809,13 +4780,9 @@ var TabsProgressListener = {
}
}
- // Attach a listener to watch for "click" events bubbling up from error
- // pages and other similar pages (like about:newtab). This lets us fix bugs
- // like 401575 which require error page UI to do privileged things, without
- // letting error pages have any privilege themselves.
- // We can't look for this during onLocationChange since at that point the
- // document URI is not yet the about:-uri of the error page.
-
+ // We used to listen for clicks in the browser here, but when that
+ // became unnecessary, removing the code below caused focus issues.
+ // This code should be removed. Tracked in bug 1337794.
let isRemoteBrowser = aBrowser.isRemoteBrowser;
// We check isRemoteBrowser here to avoid requesting the doc CPOW
let doc = isRemoteBrowser ? null : aWebProgress.DOMWindow.document;
@@ -4830,11 +4797,9 @@ var TabsProgressListener = {
// STATE_STOP may be received twice for documents, thus store an
// attribute to ensure handling it just once.
doc.documentElement.setAttribute("hasBrowserHandlers", "true");
- aBrowser.addEventListener("click", BrowserOnClick, true);
aBrowser.addEventListener("pagehide", function onPageHide(event) {
if (event.target.defaultView.frameElement)
return;
- aBrowser.removeEventListener("click", BrowserOnClick, true);
aBrowser.removeEventListener("pagehide", onPageHide, true);
if (event.target.documentElement)
event.target.documentElement.removeAttribute("hasBrowserHandlers");
@@ -4883,7 +4848,7 @@ nsBrowserAccess.prototype = {
_openURIInNewTab: function(aURI, aReferrer, aReferrerPolicy, aIsPrivate,
aIsExternal, aForceNotRemote=false,
aUserContextId=Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID,
- aOpener=null) {
+ aOpener = null, aTriggeringPrincipal = null) {
let win, needToFocusWin;
// try the current window. if we're in a popup, fall back on the most recent browser window
@@ -4908,6 +4873,7 @@ nsBrowserAccess.prototype = {
let loadInBackground = gPrefService.getBoolPref("browser.tabs.loadDivertedInBackground");
let tab = win.gBrowser.loadOneTab(aURI ? aURI.spec : "about:blank", {
+ triggeringPrincipal: aTriggeringPrincipal,
referrerURI: aReferrer,
referrerPolicy: aReferrerPolicy,
userContextId: aUserContextId,
@@ -4956,9 +4922,11 @@ nsBrowserAccess.prototype = {
}
let referrer = aOpener ? makeURI(aOpener.location.href) : null;
+ let triggeringPrincipal = null;
let referrerPolicy = Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT;
if (aOpener && aOpener.document) {
referrerPolicy = aOpener.document.referrerPolicy;
+ triggeringPrincipal = aOpener.document.nodePrincipal;
}
let isPrivate = aOpener
? PrivateBrowsingUtils.isContentWindowPrivate(aOpener)
@@ -4992,7 +4960,7 @@ nsBrowserAccess.prototype = {
let browser = this._openURIInNewTab(aURI, referrer, referrerPolicy,
isPrivate, isExternal,
forceNotRemote, userContextId,
- openerWindow);
+ openerWindow, triggeringPrincipal);
if (browser)
newWindow = browser.contentWindow;
break;
@@ -5003,6 +4971,7 @@ nsBrowserAccess.prototype = {
Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL :
Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
gBrowser.loadURIWithFlags(aURI.spec, {
+ triggeringPrincipal,
flags: loadflags,
referrerURI: referrer,
referrerPolicy: referrerPolicy,
@@ -5031,7 +5000,8 @@ nsBrowserAccess.prototype = {
aParams.referrerPolicy,
aParams.isPrivate,
isExternal, false,
- userContextId);
+ userContextId, null,
+ aParams.triggeringPrincipal);
if (browser)
return browser.QueryInterface(Ci.nsIFrameLoaderOwner);
@@ -5584,6 +5554,7 @@ function handleLinkClick(event, href, linkNode) {
referrerPolicy: referrerPolicy,
noReferrer: BrowserUtils.linkHasNoReferrer(linkNode),
originPrincipal: doc.nodePrincipal,
+ triggeringPrincipal: doc.nodePrincipal,
};
// The new tab/window must use the same userContextId
diff --git a/browser/base/content/content.js b/browser/base/content/content.js
index 8d6f0745e9..46e9b45d69 100644
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -482,6 +482,7 @@ var ClickEventHandler = {
ctrlKey: event.ctrlKey, metaKey: event.metaKey,
altKey: event.altKey, href: null, title: null,
bookmark: false, referrerPolicy: referrerPolicy,
+ triggeringPrincipal: principal,
originAttributes: principal ? principal.originAttributes : {},
isContentWindowPrivate: PrivateBrowsingUtils.isContentWindowPrivate(ownerDoc.defaultView)};
@@ -521,6 +522,7 @@ var ClickEventHandler = {
} catch (e) {}
}
json.originPrincipal = ownerDoc.nodePrincipal;
+ json.triggeringPrincipal = ownerDoc.nodePrincipal;
sendAsyncMessage("Content:Click", json);
return;
diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js
index ddf6952026..955184f647 100644
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -968,6 +968,7 @@ nsContextMenu.prototype = {
_openLinkInParameters : function (extra) {
let params = { charset: gContextMenuContentData.charSet,
originPrincipal: this.principal,
+ triggeringPrincipal: this.principal,
referrerURI: gContextMenuContentData.documentURIObject,
referrerPolicy: gContextMenuContentData.referrerPolicy,
noReferrer: this.linkHasNoReferrer };
@@ -1147,10 +1148,12 @@ nsContextMenu.prototype = {
// Change current window to the URL of the image, video, or audio.
viewMedia: function(e) {
let referrerURI = gContextMenuContentData.documentURIObject;
+ let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
if (this.onCanvas) {
this._canvasToBlobURL(this.target).then(function(blobURL) {
openUILink(blobURL, e, { disallowInheritPrincipal: true,
- referrerURI: referrerURI });
+ referrerURI: referrerURI,
+ triggeringPrincipal: systemPrincipal});
}, Cu.reportError);
}
else {
diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml
index b27846835b..463e74a52a 100644
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1513,6 +1513,7 @@
<parameter name="aAllowThirdPartyFixup"/>
<body>
<![CDATA[
+ var aTriggeringPrincipal;
var aReferrerPolicy;
var aFromExternal;
var aRelatedToCurrent;
@@ -1528,6 +1529,7 @@
typeof arguments[1] == "object" &&
!(arguments[1] instanceof Ci.nsIURI)) {
let params = arguments[1];
+ aTriggeringPrincipal = params.triggeringPrincipal
aReferrerURI = params.referrerURI;
aReferrerPolicy = params.referrerPolicy;
aCharset = params.charset;
@@ -1550,6 +1552,7 @@
Services.prefs.getBoolPref("browser.tabs.loadInBackground");
var owner = bgLoad ? null : this.selectedTab;
var tab = this.addTab(aURI, {
+ triggeringPrincipal: aTriggeringPrincipal,
referrerURI: aReferrerURI,
referrerPolicy: aReferrerPolicy,
charset: aCharset,
@@ -2120,6 +2123,7 @@
"use strict";
const NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+ var aTriggeringPrincipal;
var aReferrerPolicy;
var aFromExternal;
var aRelatedToCurrent;
@@ -2136,6 +2140,7 @@
typeof arguments[1] == "object" &&
!(arguments[1] instanceof Ci.nsIURI)) {
let params = arguments[1];
+ aTriggeringPrincipal = params.triggeringPrincipal;
aReferrerURI = params.referrerURI;
aReferrerPolicy = params.referrerPolicy;
aCharset = params.charset;
@@ -2267,6 +2272,7 @@
try {
b.loadURIWithFlags(aURI, {
flags,
+ triggeringPrincipal: aTriggeringPrincipal,
referrerURI: aNoReferrer ? null: aReferrerURI,
referrerPolicy: aReferrerPolicy,
charset: aCharset,
diff --git a/browser/base/content/utilityOverlay.js b/browser/base/content/utilityOverlay.js
index 6ceaf773ea..b041915a7c 100644
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -225,6 +225,7 @@ function openLinkIn(url, where, params) {
var aUserContextId = params.userContextId;
var aIndicateErrorPageLoad = params.indicateErrorPageLoad;
var aPrincipal = params.originPrincipal;
+ var aTriggeringPrincipal = params.triggeringPrincipal;
var aForceAboutBlankViewerInCurrent =
params.forceAboutBlankViewerInCurrent;
@@ -259,6 +260,24 @@ function openLinkIn(url, where, params) {
return;
}
+ // Teach the principal about the right OA to use, e.g. in case when
+ // opening a link in a new private window, or in a new container tab.
+ // Please note we do not have to do that for SystemPrincipals and we
+ // can not do it for NullPrincipals since NullPrincipals are only
+ // identical if they actually are the same object (See Bug: 1346759)
+ function useOAForPrincipal(principal) {
+ if (principal && principal.isCodebasePrincipal) {
+ let attrs = {
+ userContextId: aUserContextId,
+ privateBrowsingId: aIsPrivate || (w && PrivateBrowsingUtils.isWindowPrivate(w)),
+ };
+ return Services.scriptSecurityManager.createCodebasePrincipal(principal.URI, attrs);
+ }
+ return principal;
+ }
+ aPrincipal = useOAForPrincipal(aPrincipal);
+ aTriggeringPrincipal = useOAForPrincipal(aTriggeringPrincipal);
+
if (!w || where == "window") {
// Strip referrer data when opening a new private window, to prevent
// regular browsing data from leaking into it.
@@ -308,6 +327,7 @@ function openLinkIn(url, where, params) {
sa.appendElement(referrerPolicySupports, /* weak =*/ false);
sa.appendElement(userContextIdSupports, /* weak =*/ false);
sa.appendElement(aPrincipal, /* weak =*/ false);
+ sa.appendElement(aTriggeringPrincipal, /* weak =*/ false);
let features = "chrome,dialog=no,all";
if (aIsPrivate) {
@@ -394,6 +414,7 @@ function openLinkIn(url, where, params) {
}
aCurrentBrowser.loadURIWithFlags(url, {
+ triggeringPrincipal: aTriggeringPrincipal,
flags: flags,
referrerURI: aNoReferrer ? null : aReferrerURI,
referrerPolicy: aReferrerPolicy,
@@ -419,6 +440,7 @@ function openLinkIn(url, where, params) {
noReferrer: aNoReferrer,
userContextId: aUserContextId,
originPrincipal: aPrincipal,
+ triggeringPrincipal: aTriggeringPrincipal,
});
browserUsedForLoad = tabUsedForLoad.linkedBrowser;
break;
diff --git a/browser/components/feeds/FeedConverter.js b/browser/components/feeds/FeedConverter.js
index aa70620d4d..c2c565608b 100644
--- a/browser/components/feeds/FeedConverter.js
+++ b/browser/components/feeds/FeedConverter.js
@@ -264,7 +264,7 @@ FeedConverter.prototype = {
}
chromeChannel.loadGroup = this._request.loadGroup;
- chromeChannel.asyncOpen(this._listener, null);
+ chromeChannel.asyncOpen2(this._listener);
}
finally {
this._releaseHandles();
diff --git a/browser/components/sessionstore/ContentRestore.jsm b/browser/components/sessionstore/ContentRestore.jsm
index 976016770e..d4972bcafe 100644
--- a/browser/components/sessionstore/ContentRestore.jsm
+++ b/browser/components/sessionstore/ContentRestore.jsm
@@ -204,6 +204,9 @@ ContentRestoreInternal.prototype = {
: Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT);
let postData = loadArguments.postData ?
Utils.makeInputStream(loadArguments.postData) : null;
+ let triggeringPrincipal = loadArguments.triggeringPrincipal
+ ? Utils.deserializePrincipal(loadArguments.triggeringPrincipal)
+ : null;
if (loadArguments.userContextId) {
webNavigation.setOriginAttributesBeforeLoading({ userContextId: loadArguments.userContextId });
@@ -211,7 +214,7 @@ ContentRestoreInternal.prototype = {
webNavigation.loadURIWithOptions(loadArguments.uri, loadArguments.flags,
referrer, referrerPolicy, postData,
- null, null);
+ null, null, triggeringPrincipal);
} else if (tabData.userTypedValue && tabData.userTypedClear) {
// If the user typed a URL into the URL bar and hit enter right before
// we crashed, we want to start loading that page again. A non-zero
diff --git a/browser/components/sessionstore/SessionHistory.jsm b/browser/components/sessionstore/SessionHistory.jsm
index aa9c10379c..3d28d87db8 100644
--- a/browser/components/sessionstore/SessionHistory.jsm
+++ b/browser/components/sessionstore/SessionHistory.jsm
@@ -95,7 +95,10 @@ var SessionHistoryInternal = {
// record it. For about:blank we explicitly want an empty array without
// an 'index' property to denote that there are no history entries.
if (uri != "about:blank" || (body && body.hasChildNodes())) {
- data.entries.push({ url: uri });
+ data.entries.push({
+ url: uri,
+ triggeringPrincipal_base64: Utils.SERIALIZED_SYSTEMPRINCIPAL
+ });
data.index = 1;
}
}
diff --git a/browser/components/sessionstore/SessionMigration.jsm b/browser/components/sessionstore/SessionMigration.jsm
index ff339eba9e..1aa22f1a9d 100644
--- a/browser/components/sessionstore/SessionMigration.jsm
+++ b/browser/components/sessionstore/SessionMigration.jsm
@@ -11,6 +11,9 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
Cu.import("resource://gre/modules/Task.jsm", this);
Cu.import("resource://gre/modules/osfile.jsm", this);
+XPCOMUtils.defineLazyModuleGetter(this, "Utils",
+ "resource://gre/modules/sessionstore/Utils.jsm");
+
// An encoder to UTF-8.
XPCOMUtils.defineLazyGetter(this, "gEncoder", function () {
return new TextEncoder();
@@ -27,7 +30,7 @@ var SessionMigrationInternal = {
* only contain:
* - open windows
* - with tabs
- * - with history entries with only title, url
+ * - with history entries with only title, url, triggeringPrincipal
* - with pinned state
* - with tab group info (hidden + group id)
* - with selected tab info
@@ -45,9 +48,11 @@ var SessionMigrationInternal = {
var win = {extData: {}};
win.tabs = oldWin.tabs.map(function(oldTab) {
var tab = {};
- // Keep only titles and urls for history entries
+ // Keep only titles, urls and triggeringPrincipals for history entries
tab.entries = oldTab.entries.map(function(entry) {
- return {url: entry.url, title: entry.title};
+ return { url: entry.url,
+ triggeringPrincipal_base64: entry.triggeringPrincipal_base64,
+ title: entry.title };
});
tab.index = oldTab.index;
tab.hidden = oldTab.hidden;
@@ -60,7 +65,8 @@ var SessionMigrationInternal = {
});
let url = "about:welcomeback";
let formdata = {id: {sessionData: state}, url};
- return {windows: [{tabs: [{entries: [{url}], formdata}]}]};
+ let entry = { url, triggeringPrincipal_base64: Utils.SERIALIZED_SYSTEMPRINCIPAL };
+ return { windows: [{ tabs: [{ entries: [ entry ], formdata}]}]};
},
/**
* Asynchronously read session restore state (JSON) from a path
diff --git a/browser/components/sessionstore/SessionStore.jsm b/browser/components/sessionstore/SessionStore.jsm
index 93e21357f2..6b30943f38 100644
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -603,12 +603,14 @@ var SessionStoreInternal = {
// replace the crashed session with a restore-page-only session
let url = "about:sessionrestore";
let formdata = {id: {sessionData: state}, url};
- state = { windows: [{ tabs: [{ entries: [{url}], formdata }] }] };
+ let entry = {url, triggeringPrincipal_base64: Utils.SERIALIZED_SYSTEMPRINCIPAL };
+ state = { windows: [{ tabs: [{ entries: [entry], formdata }] }] };
} else if (this._hasSingleTabWithURL(state.windows,
"about:welcomeback")) {
// On a single about:welcomeback URL that crashed, replace about:welcomeback
// with about:sessionrestore, to make clear to the user that we crashed.
state.windows[0].tabs[0].entries[0].url = "about:sessionrestore";
+ state.windows[0].tabs[0].entries[0].triggeringPrincipal_base64 = Utils.SERIALIZED_SYSTEMPRINCIPAL;
}
}
diff --git a/browser/modules/ContentClick.jsm b/browser/modules/ContentClick.jsm
index 8abc32525c..40101d5d35 100644
--- a/browser/modules/ContentClick.jsm
+++ b/browser/modules/ContentClick.jsm
@@ -85,6 +85,7 @@ var ContentClick = {
allowMixedContent: json.allowMixedContent,
isContentWindowPrivate: json.isContentWindowPrivate,
originPrincipal: json.originPrincipal,
+ triggeringPrincipal: json.triggeringPrincipal,
};
// The new tab/window must use the same userContextId.
diff --git a/devtools/client/responsive.html/browser/web-navigation.js b/devtools/client/responsive.html/browser/web-navigation.js
index 4519df0bdc..eee24993ac 100644
--- a/devtools/client/responsive.html/browser/web-navigation.js
+++ b/devtools/client/responsive.html/browser/web-navigation.js
@@ -8,6 +8,7 @@ const { Ci, Cu, Cr } = require("chrome");
const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
const Services = require("Services");
const { NetUtil } = require("resource://gre/modules/NetUtil.jsm");
+const { Utils } = require("resource://gre/modules/sessionstore/Utils.jsm");
function readInputStreamToString(stream) {
return NetUtil.readInputStreamToString(stream, stream.available());
@@ -61,11 +62,11 @@ BrowserElementWebNavigation.prototype = {
// No equivalent in the current BrowserElement API
this.loadURIWithOptions(uri, flags, referrer,
Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT,
- postData, headers, null);
+ postData, headers, null, null);
},
loadURIWithOptions(uri, flags, referrer, referrerPolicy, postData, headers,
- baseURI) {
+ baseURI, triggeringPrincipal) {
// No equivalent in the current BrowserElement API
this._sendMessage("WebNavigation:LoadURI", {
uri,
@@ -75,6 +76,9 @@ BrowserElementWebNavigation.prototype = {
postData: postData ? readInputStreamToString(postData) : null,
headers: headers ? readInputStreamToString(headers) : null,
baseURI: baseURI ? baseURI.spec : null,
+ triggeringPrincipal: triggeringPrincipal
+ ? Utils.serializePrincipal(triggeringPrincipal)
+ : null,
});
},
diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
index bd2a8a4338..b3e26da333 100644
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -1644,7 +1644,7 @@ nsDocShell::LoadStream(nsIInputStream* aStream, nsIURI* aURI,
uri,
aStream,
triggeringPrincipal,
- nsILoadInfo::SEC_NORMAL,
+ nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
nsIContentPolicy::TYPE_OTHER,
aContentType,
aContentCharset);
@@ -4732,7 +4732,7 @@ nsDocShell::LoadURI(const char16_t* aURI,
{
return LoadURIWithOptions(aURI, aLoadFlags, aReferringURI,
mozilla::net::RP_Default, aPostStream,
- aHeaderStream, nullptr);
+ aHeaderStream, nullptr, nullptr);
}
NS_IMETHODIMP
@@ -4742,7 +4742,8 @@ nsDocShell::LoadURIWithOptions(const char16_t* aURI,
uint32_t aReferrerPolicy,
nsIInputStream* aPostStream,
nsIInputStream* aHeaderStream,
- nsIURI* aBaseURI)
+ nsIURI* aBaseURI,
+ nsIPrincipal* aTriggeringPrincipal)
{
NS_ASSERTION((aLoadFlags & 0xf) == 0, "Unexpected flags");
@@ -4861,6 +4862,7 @@ nsDocShell::LoadURIWithOptions(const char16_t* aURI,
loadInfo->SetReferrerPolicy(aReferrerPolicy);
loadInfo->SetHeadersStream(aHeaderStream);
loadInfo->SetBaseURI(aBaseURI);
+ loadInfo->SetTriggeringPrincipal(aTriggeringPrincipal);
loadInfo->SetForceAllowDataURI(forceAllowDataURI);
if (fixupInfo) {
@@ -5687,6 +5689,11 @@ nsDocShell::LoadPage(nsISupports* aPageDescriptor, uint32_t aDisplayType)
}
shEntry->SetURI(newUri);
shEntry->SetOriginalURI(nullptr);
+ // shEntry's current triggering principal is whoever loaded that page initially.
+ // But now we're doing another load of the page, via an API that is only exposed
+ // to system code. The triggering principal for this load should be the system
+ // principal.
+ shEntry->SetTriggeringPrincipal(nsContentUtils::GetSystemPrincipal());
}
rv = LoadHistoryEntry(shEntry, LOAD_HISTORY);
@@ -9145,8 +9152,13 @@ nsDocShell::CreateContentViewer(const nsACString& aContentType,
// Make sure we have a URI to set currentURI.
nsCOMPtr<nsIURI> failedURI;
+ nsCOMPtr<nsIPrincipal> triggeringPrincipal;
if (failedChannel) {
NS_GetFinalChannelURI(failedChannel, getter_AddRefs(failedURI));
+ } else {
+ // if there is no failed channel we have to explicitly provide
+ // a triggeringPrincipal for the history entry.
+ triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
}
if (!failedURI) {
@@ -9167,7 +9179,8 @@ nsDocShell::CreateContentViewer(const nsACString& aContentType,
// Create an shistory entry for the old load.
if (failedURI) {
bool errorOnLocationChangeNeeded = OnNewURI(
- failedURI, failedChannel, nullptr, nullptr, mLoadType, false, false, false);
+ failedURI, failedChannel, triggeringPrincipal,
+ nullptr, mLoadType, false, false, false);
if (errorOnLocationChangeNeeded) {
FireOnLocationChange(this, failedChannel, failedURI,
@@ -10394,10 +10407,13 @@ nsDocShell::InternalLoad(nsIURI* aURI,
* call OnNewURI() so that, this traversal will be
* recorded in session and global history.
*/
- nsCOMPtr<nsIPrincipal> triggeringPrincipal, principalToInherit;
+ nsCOMPtr<nsIPrincipal> newURITriggeringPrincipal, newURIPrincipalToInherit;
if (mOSHE) {
- mOSHE->GetTriggeringPrincipal(getter_AddRefs(triggeringPrincipal));
- mOSHE->GetPrincipalToInherit(getter_AddRefs(principalToInherit));
+ mOSHE->GetTriggeringPrincipal(getter_AddRefs(newURITriggeringPrincipal));
+ mOSHE->GetPrincipalToInherit(getter_AddRefs(newURIPrincipalToInherit));
+ } else {
+ newURITriggeringPrincipal = aTriggeringPrincipal;
+ newURIPrincipalToInherit = doc->NodePrincipal();
}
// Pass true for aCloneSHChildren, since we're not
// changing documents here, so all of our subframes are
@@ -10407,7 +10423,7 @@ nsDocShell::InternalLoad(nsIURI* aURI,
// flag on firing onLocationChange(...).
// Anyway, aCloneSHChildren param is simply reflecting
// doShortCircuitedLoad in this scope.
- OnNewURI(aURI, nullptr, triggeringPrincipal, principalToInherit,
+ OnNewURI(aURI, nullptr, newURITriggeringPrincipal, newURIPrincipalToInherit,
mLoadType, true, true, true);
nsCOMPtr<nsIInputStream> postData;
@@ -10606,7 +10622,7 @@ nsDocShell::InternalLoad(nsIURI* aURI,
}
bool shouldLoad;
rv = browserChrome3->ShouldLoadURI(this, uriForShouldLoadCheck, aReferrer,
- &shouldLoad);
+ aTriggeringPrincipal, &shouldLoad);
if (NS_SUCCEEDED(rv) && !shouldLoad) {
return NS_OK;
}
@@ -10961,7 +10977,8 @@ nsDocShell::DoURILoad(nsIURI* aURI,
}
nsLoadFlags loadFlags = mDefaultLoadFlags;
- nsSecurityFlags securityFlags = nsILoadInfo::SEC_NORMAL;
+ nsSecurityFlags securityFlags =
+ nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL;
if (aFirstParty) {
// tag first party URL loads
@@ -12123,7 +12140,9 @@ nsDocShell::AddState(JS::Handle<JS::Value> aData, const nsAString& aTitle,
// Since we're not changing which page we have loaded, pass
// true for aCloneChildren.
- rv = AddToSessionHistory(newURI, nullptr, nullptr, nullptr, true,
+ rv = AddToSessionHistory(newURI, nullptr,
+ document->NodePrincipal(), // triggeringPrincipal
+ nullptr, true,
getter_AddRefs(newSHEntry));
NS_ENSURE_SUCCESS(rv, rv);
@@ -12399,11 +12418,6 @@ nsDocShell::AddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel,
discardLayoutState = ShouldDiscardLayoutState(httpChannel);
}
- // XXX Bug 1286838: Replace channel owner with loadInfo triggeringPrincipal
- nsCOMPtr<nsISupports> owner;
- aChannel->GetOwner(getter_AddRefs(owner));
- triggeringPrincipal = do_QueryInterface(owner);
-
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
if (loadInfo) {
if (!triggeringPrincipal) {
@@ -12649,10 +12663,6 @@ nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry, uint32_t aLoadType)
srcdoc = NullString();
}
- // If there is no triggeringPrincipal we can fall back to using the
- // SystemPrincipal as the triggeringPrincipal for loading the history
- // entry, since the history entry can only end up in history if security
- // checks passed in the initial loading phase.
if (!triggeringPrincipal) {
triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
}
@@ -13917,7 +13927,8 @@ public:
const nsAString& aFileName,
nsIInputStream* aPostDataStream,
nsIInputStream* aHeadersDataStream,
- bool aIsTrusted);
+ bool aIsTrusted,
+ nsIPrincipal* aTriggeringPrincipal);
NS_IMETHOD Run() override
{
@@ -13933,7 +13944,7 @@ public:
mHandler->OnLinkClickSync(mContent, mURI,
mTargetSpec.get(), mFileName,
mPostDataStream, mHeadersDataStream,
- nullptr, nullptr);
+ nullptr, nullptr, mTriggeringPrincipal);
}
return NS_OK;
}
@@ -13948,6 +13959,7 @@ private:
nsCOMPtr<nsIContent> mContent;
PopupControlState mPopupState;
bool mIsTrusted;
+ nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
};
OnLinkClickEvent::OnLinkClickEvent(nsDocShell* aHandler,
@@ -13957,7 +13969,8 @@ OnLinkClickEvent::OnLinkClickEvent(nsDocShell* aHandler,
const nsAString& aFileName,
nsIInputStream* aPostDataStream,
nsIInputStream* aHeadersDataStream,
- bool aIsTrusted)
+ bool aIsTrusted,
+ nsIPrincipal* aTriggeringPrincipal)
: mHandler(aHandler)
, mURI(aURI)
, mTargetSpec(aTargetSpec)
@@ -13967,6 +13980,7 @@ OnLinkClickEvent::OnLinkClickEvent(nsDocShell* aHandler,
, mContent(aContent)
, mPopupState(mHandler->mScriptGlobal->GetPopupControlState())
, mIsTrusted(aIsTrusted)
+ , mTriggeringPrincipal(aTriggeringPrincipal)
{
}
@@ -13977,7 +13991,8 @@ nsDocShell::OnLinkClick(nsIContent* aContent,
const nsAString& aFileName,
nsIInputStream* aPostDataStream,
nsIInputStream* aHeadersDataStream,
- bool aIsTrusted)
+ bool aIsTrusted,
+ nsIPrincipal* aTriggeringPrincipal)
{
NS_ASSERTION(NS_IsMainThread(), "wrong thread");
@@ -14016,7 +14031,8 @@ nsDocShell::OnLinkClick(nsIContent* aContent,
nsCOMPtr<nsIRunnable> ev =
new OnLinkClickEvent(this, aContent, aURI, target.get(), aFileName,
- aPostDataStream, aHeadersDataStream, aIsTrusted);
+ aPostDataStream, aHeadersDataStream,
+ aIsTrusted, aTriggeringPrincipal);
return NS_DispatchToCurrentThread(ev);
}
@@ -14028,7 +14044,8 @@ nsDocShell::OnLinkClickSync(nsIContent* aContent,
nsIInputStream* aPostDataStream,
nsIInputStream* aHeadersDataStream,
nsIDocShell** aDocShell,
- nsIRequest** aRequest)
+ nsIRequest** aRequest,
+ nsIPrincipal* aTriggeringPrincipal)
{
// Initialize the DocShell / Request
if (aDocShell) {
@@ -14151,13 +14168,18 @@ nsDocShell::OnLinkClickSync(nsIContent* aContent,
return NS_ERROR_OUT_OF_MEMORY;
}
+ // if the triggeringPrincipal is not passed explicitly, then we
+ // fall back to using doc->NodePrincipal() as the triggeringPrincipal.
+ nsCOMPtr<nsIPrincipal> triggeringPrincipal =
+ aTriggeringPrincipal ? aTriggeringPrincipal
+ : aContent->NodePrincipal();
+
nsresult rv = InternalLoad(clonedURI, // New URI
nullptr, // Original URI
false, // LoadReplace
referer, // Referer URI
refererPolicy, // Referer policy
- aContent->NodePrincipal(), // Triggering is our node's
- // principal
+ triggeringPrincipal,
aContent->NodePrincipal(),
flags,
target, // Window target
diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h
index 63a4e3358e..f510a15b00 100644
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -201,7 +201,8 @@ public:
const nsAString& aFileName,
nsIInputStream* aPostDataStream,
nsIInputStream* aHeadersDataStream,
- bool aIsTrusted) override;
+ bool aIsTrusted,
+ nsIPrincipal* aTriggeringPrincipal) override;
NS_IMETHOD OnLinkClickSync(nsIContent* aContent,
nsIURI* aURI,
const char16_t* aTargetSpec,
@@ -209,7 +210,8 @@ public:
nsIInputStream* aPostDataStream = 0,
nsIInputStream* aHeadersDataStream = 0,
nsIDocShell** aDocShell = 0,
- nsIRequest** aRequest = 0) override;
+ nsIRequest** aRequest = 0,
+ nsIPrincipal* aTriggeringPrincipal = nullptr) override;
NS_IMETHOD OnOverLink(nsIContent* aContent,
nsIURI* aURI,
const char16_t* aTargetSpec) override;
diff --git a/docshell/base/nsILinkHandler.h b/docshell/base/nsILinkHandler.h
index 7cdcd566df..7069f1f1da 100644
--- a/docshell/base/nsILinkHandler.h
+++ b/docshell/base/nsILinkHandler.h
@@ -37,6 +37,8 @@ public:
* @param aFileName non-null when the link should be downloaded as the given file
* @param aHeadersDataStream ???
* @param aIsTrusted false if the triggerer is an untrusted DOM event.
+ * @param aTriggeringPrincipal, if not passed explicitly we fall back to
+ * the document's principal.
*/
NS_IMETHOD OnLinkClick(nsIContent* aContent,
nsIURI* aURI,
@@ -44,7 +46,8 @@ public:
const nsAString& aFileName,
nsIInputStream* aPostDataStream,
nsIInputStream* aHeadersDataStream,
- bool aIsTrusted) = 0;
+ bool aIsTrusted,
+ nsIPrincipal* aTriggeringPrincipal) = 0;
/**
* Process a click on a link.
@@ -61,6 +64,8 @@ public:
* @param aHeadersDataStream ???
* @param aDocShell (out-param) the DocShell that the request was opened on
* @param aRequest the request that was opened
+ * @param aTriggeringPrincipal, if not passed explicitly we fall back to
+ * the document's principal.
*/
NS_IMETHOD OnLinkClickSync(nsIContent* aContent,
nsIURI* aURI,
@@ -69,7 +74,8 @@ public:
nsIInputStream* aPostDataStream = 0,
nsIInputStream* aHeadersDataStream = 0,
nsIDocShell** aDocShell = 0,
- nsIRequest** aRequest = 0) = 0;
+ nsIRequest** aRequest = 0,
+ nsIPrincipal* aTriggeringPrincipal = nullptr) = 0;
/**
* Process a mouse-over a link.
diff --git a/docshell/base/nsIWebNavigation.idl b/docshell/base/nsIWebNavigation.idl
index 241d0731c1..c3e2fc5503 100644
--- a/docshell/base/nsIWebNavigation.idl
+++ b/docshell/base/nsIWebNavigation.idl
@@ -9,6 +9,7 @@ interface nsIDOMDocument;
interface nsIInputStream;
interface nsISHistory;
interface nsIURI;
+interface nsIPrincipal;
/**
* The nsIWebNavigation interface defines an interface for navigating the web.
@@ -288,14 +289,20 @@ interface nsIWebNavigation : nsISupports
* that at present this argument is only used with view-source aURIs
* and cannot be used to resolve aURI.
* This parameter is optional and may be null.
- */
- void loadURIWithOptions(in wstring aURI,
- in unsigned long aLoadFlags,
- in nsIURI aReferrer,
- in unsigned long aReferrerPolicy,
- in nsIInputStream aPostData,
- in nsIInputStream aHeaders,
- in nsIURI aBaseURI);
+ * @param aTriggeringPrincipal
+ * The principal that initiated the load of aURI. If omitted docShell
+ * tries to create a codeBasePrincipal from aReferrer if not null. If
+ * aReferrer is also null docShell peforms a load using the
+ * SystemPrincipal as the triggeringPrincipal.
+ */
+ void loadURIWithOptions(in wstring aURI,
+ in unsigned long aLoadFlags,
+ in nsIURI aReferrer,
+ in unsigned long aReferrerPolicy,
+ in nsIInputStream aPostData,
+ in nsIInputStream aHeaders,
+ in nsIURI aBaseURI,
+ [optional] in nsIPrincipal aTriggeringPrincipal);
/**
* Tells the Object to reload the current page. There may be cases where the
diff --git a/docshell/shistory/nsSHEntry.cpp b/docshell/shistory/nsSHEntry.cpp
index 9d972136f1..6b0b066d97 100644
--- a/docshell/shistory/nsSHEntry.cpp
+++ b/docshell/shistory/nsSHEntry.cpp
@@ -416,6 +416,9 @@ nsSHEntry::Create(nsIURI* aURI, const nsAString& aTitle,
uint64_t aDocShellID,
bool aDynamicCreation)
{
+ MOZ_ASSERT(aTriggeringPrincipal,
+ "need a valid triggeringPrincipal to create a session history entry");
+
mURI = aURI;
mTitle = aTitle;
mPostData = aInputStream;
diff --git a/docshell/shistory/nsSHistory.cpp b/docshell/shistory/nsSHistory.cpp
index 7c148ffcc7..9443b92bc5 100644
--- a/docshell/shistory/nsSHistory.cpp
+++ b/docshell/shistory/nsSHistory.cpp
@@ -1582,7 +1582,8 @@ nsSHistory::LoadURIWithOptions(const char16_t* aURI,
uint32_t aReferrerPolicy,
nsIInputStream* aPostStream,
nsIInputStream* aExtraHeaderStream,
- nsIURI* aBaseURI)
+ nsIURI* aBaseURI,
+ nsIPrincipal* aTriggeringPrincipal)
{
return NS_OK;
}
diff --git a/docshell/test/browser/browser.ini b/docshell/test/browser/browser.ini
index 9211092a49..300caff1a8 100644
--- a/docshell/test/browser/browser.ini
+++ b/docshell/test/browser/browser.ini
@@ -1,5 +1,6 @@
[DEFAULT]
support-files =
+ dummy_page.html
favicon_bug655270.ico
file_bug234628-1-child.html
file_bug234628-1.html
@@ -45,6 +46,7 @@ support-files =
browser_timelineMarkers-frame-05.js
head.js
frame-head.js
+ file_click_link_within_view_source.html
[browser_bug1206879.js]
[browser_bug1309900_crossProcessHistoryNavigation.js]
@@ -91,3 +93,4 @@ skip-if = true # Bug 1220415
[browser_timelineMarkers-04.js]
[browser_timelineMarkers-05.js]
[browser_ua_emulation.js]
+[browser_click_link_within_view_source.js]
diff --git a/docshell/test/browser/browser_click_link_within_view_source.js b/docshell/test/browser/browser_click_link_within_view_source.js
new file mode 100644
index 0000000000..84cfc1f0f5
--- /dev/null
+++ b/docshell/test/browser/browser_click_link_within_view_source.js
@@ -0,0 +1,60 @@
+"use strict";
+
+/**
+ * Test for Bug 1359204
+ *
+ * Loading a local file, then view-source on that file. Make sure that
+ * clicking a link within that view-source page is not blocked by security checks.
+ */
+
+add_task(function* test_click_link_within_view_source() {
+ let TEST_FILE = "file_click_link_within_view_source.html";
+ let TEST_FILE_URI = getChromeDir(getResolvedURI(gTestPath));
+ TEST_FILE_URI.append(TEST_FILE);
+ TEST_FILE_URI = Services.io.newFileURI(TEST_FILE_URI).spec;
+
+ let DUMMY_FILE = "dummy_page.html";
+ let DUMMY_FILE_URI = getChromeDir(getResolvedURI(gTestPath));
+ DUMMY_FILE_URI.append(DUMMY_FILE);
+ DUMMY_FILE_URI = Services.io.newFileURI(DUMMY_FILE_URI).spec;
+
+ yield BrowserTestUtils.withNewTab(TEST_FILE_URI, function*(aBrowser) {
+ let tabSpec = gBrowser.selectedBrowser.currentURI.spec;
+ info("loading: " + tabSpec);
+ ok(tabSpec.startsWith("file://") && tabSpec.endsWith(TEST_FILE),
+ "sanity check to make sure html loaded");
+
+ info("click view-source of html");
+ let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser);
+ document.getElementById("View:PageSource").doCommand();
+
+ let tab = yield tabPromise;
+ tabSpec = gBrowser.selectedBrowser.currentURI.spec;
+ info("loading: " + tabSpec);
+ ok(tabSpec.startsWith("view-source:file://") && tabSpec.endsWith(TEST_FILE),
+ "loading view-source of html succeeded");
+
+ info("click testlink within view-source page");
+ let loadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, url => url.endsWith("dummy_page.html"));
+ yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function*() {
+ if (content.document.readyState != "complete") {
+ yield ContentTaskUtils.waitForEvent(content.document, "readystatechange", false, () =>
+ content.document.readyState == "complete");
+ }
+ // document.getElementById() does not work on a view-source page, hence we use document.links
+ let linksOnPage = content.document.links;
+ is (linksOnPage.length, 1, "sanity check: make sure only one link is present on page");
+ let myLink = content.document.links[0];
+ myLink.click();
+ });
+
+ yield loadPromise;
+
+ tabSpec = gBrowser.selectedBrowser.currentURI.spec;
+ info("loading: " + tabSpec);
+ ok(tabSpec.startsWith("view-source:file://") && tabSpec.endsWith(DUMMY_FILE),
+ "loading view-source of html succeeded");
+
+ yield BrowserTestUtils.removeTab(tab);
+ });
+});
diff --git a/docshell/test/browser/browser_history_triggeringprincipal_viewsource.js b/docshell/test/browser/browser_history_triggeringprincipal_viewsource.js
new file mode 100644
index 0000000000..96908bbc20
--- /dev/null
+++ b/docshell/test/browser/browser_history_triggeringprincipal_viewsource.js
@@ -0,0 +1,50 @@
+"use strict";
+
+const TEST_PATH = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "http://example.com");
+const HTML_URI = TEST_PATH + "dummy_page.html";
+const VIEW_SRC_URI = "view-source:" + HTML_URI;
+
+add_task(function*() {
+ info("load baseline html in new tab");
+ yield BrowserTestUtils.withNewTab(HTML_URI, function*(aBrowser) {
+ is(gBrowser.selectedBrowser.currentURI.spec, HTML_URI,
+ "sanity check to make sure html loaded");
+
+ info("right-click -> view-source of html");
+ let vSrcCtxtMenu = document.getElementById("contentAreaContextMenu");
+ let popupPromise = BrowserTestUtils.waitForEvent(vSrcCtxtMenu, "popupshown");
+ BrowserTestUtils.synthesizeMouseAtCenter("body", { type: "contextmenu", button: 2 }, aBrowser);
+ yield popupPromise;
+ let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, VIEW_SRC_URI);
+ let vSrcItem = vSrcCtxtMenu.getElementsByAttribute("id", "context-viewsource")[0];
+ vSrcItem.click();
+ vSrcCtxtMenu.hidePopup();
+ let tab = yield tabPromise;
+ is(gBrowser.selectedBrowser.currentURI.spec, VIEW_SRC_URI,
+ "loading view-source of html succeeded");
+
+ info ("load html file again before going .back()");
+ let loadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, HTML_URI);
+ yield ContentTask.spawn(tab.linkedBrowser, HTML_URI, HTML_URI => {
+ content.document.location = HTML_URI;
+ });
+ yield loadPromise;
+ is(gBrowser.selectedBrowser.currentURI.spec, HTML_URI,
+ "loading html another time succeeded");
+
+ info("click .back() to view-source of html again and make sure the history entry has a triggeringPrincipal");
+ let backCtxtMenu = document.getElementById("contentAreaContextMenu");
+ popupPromise = BrowserTestUtils.waitForEvent(backCtxtMenu, "popupshown");
+ BrowserTestUtils.synthesizeMouseAtCenter("body", { type: "contextmenu", button: 2 }, aBrowser);
+ yield popupPromise;
+ loadPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, VIEW_SRC_URI);
+ let backItem = backCtxtMenu.getElementsByAttribute("id", "context-back")[0];
+ backItem.click();
+ backCtxtMenu.hidePopup();
+ yield loadPromise;
+ is(gBrowser.selectedBrowser.currentURI.spec, VIEW_SRC_URI,
+ "clicking .back() to view-source of html succeeded");
+
+ yield BrowserTestUtils.removeTab(tab);
+ });
+});
diff --git a/docshell/test/browser/dummy_page.html b/docshell/test/browser/dummy_page.html
new file mode 100644
index 0000000000..59bf2a5f8f
--- /dev/null
+++ b/docshell/test/browser/dummy_page.html
@@ -0,0 +1,6 @@
+<html>
+<head> <meta charset="utf-8"> </head>
+ <body>
+ just a dummy html file
+ </body>
+</html>
diff --git a/docshell/test/browser/file_click_link_within_view_source.html b/docshell/test/browser/file_click_link_within_view_source.html
new file mode 100644
index 0000000000..d78e4ba0ff
--- /dev/null
+++ b/docshell/test/browser/file_click_link_within_view_source.html
@@ -0,0 +1,6 @@
+<html>
+<head> <meta charset="utf-8"> </head>
+ <body>
+ <a id="testlink" href="dummy_page.html">clickme</a>
+ </body>
+</html>
diff --git a/docshell/test/dummy_page.html b/docshell/test/dummy_page.html
new file mode 100644
index 0000000000..59bf2a5f8f
--- /dev/null
+++ b/docshell/test/dummy_page.html
@@ -0,0 +1,6 @@
+<html>
+<head> <meta charset="utf-8"> </head>
+ <body>
+ just a dummy html file
+ </body>
+</html>
diff --git a/docshell/test/mochitest.ini b/docshell/test/mochitest.ini
index 7b27908fb1..2298bed741 100644
--- a/docshell/test/mochitest.ini
+++ b/docshell/test/mochitest.ini
@@ -11,6 +11,7 @@ support-files =
bug668513_redirect.html
bug668513_redirect.html^headers^
bug691547_frame.html
+ dummy_page.html
file_anchor_scroll_after_document_open.html
file_bug385434_1.html
file_bug385434_2.html
@@ -94,3 +95,4 @@ skip-if = toolkit == 'android' # bug 784321
support-files = file_framedhistoryframes.html
[test_pushState_after_document_open.html]
[test_windowedhistoryframes.html]
+[test_triggeringprincipal_location_seturi.html]
diff --git a/docshell/test/test_triggeringprincipal_location_seturi.html b/docshell/test/test_triggeringprincipal_location_seturi.html
new file mode 100644
index 0000000000..3b0c7bac54
--- /dev/null
+++ b/docshell/test/test_triggeringprincipal_location_seturi.html
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<script type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+const SAME_ORIGIN_URI = "http://mochi.test:8888/tests/docshell/test/dummy_page.html";
+const CROSS_ORIGIN_URI = "http://example.com/tests/docshell/test/dummy_page.html";
+const NUMBER_OF_TESTS = 3;
+let testCounter = 0;
+
+function checkFinish() {
+ testCounter++;
+ if (testCounter < NUMBER_OF_TESTS) {
+ return;
+ }
+ SimpleTest.finish();
+}
+
+// ---- test 1 ----
+
+let myFrame1 = document.createElement("iframe");
+myFrame1.src = SAME_ORIGIN_URI;
+myFrame1.addEventListener("load", checkLoadFrame1);
+document.documentElement.appendChild(myFrame1);
+
+function checkLoadFrame1() {
+ myFrame1.removeEventListener('load', checkLoadFrame1, false);
+ // window.location.href is no longer cross-origin accessible in gecko.
+ is(SpecialPowers.wrap(myFrame1.contentWindow).location.href, SAME_ORIGIN_URI,
+ "initial same origin dummy loaded into frame1");
+
+ SpecialPowers.wrap(myFrame1.contentWindow).location.hash = "#bar";
+ is(SpecialPowers.wrap(myFrame1.contentWindow).location.href, SAME_ORIGIN_URI + "#bar",
+ "initial same origin dummy#bar loaded into iframe1");
+
+ myFrame1.addEventListener("load", checkNavFrame1);
+ myFrame1.src = CROSS_ORIGIN_URI;
+}
+
+function checkNavFrame1() {
+ myFrame1.removeEventListener('load', checkNavFrame1, false);
+ is(SpecialPowers.wrap(myFrame1.contentWindow).location.href, CROSS_ORIGIN_URI,
+ "cross origin dummy loaded into frame1");
+
+ myFrame1.addEventListener("load", checkBackNavFrame1);
+ myFrame1.src = SAME_ORIGIN_URI + "#bar";
+}
+
+function checkBackNavFrame1() {
+ myFrame1.removeEventListener('load', checkBackNavFrame1, false);
+ is(SpecialPowers.wrap(myFrame1.contentWindow).location.href, SAME_ORIGIN_URI + "#bar",
+ "navagiating back to same origin dummy for frame1");
+ checkFinish();
+}
+
+// ---- test 2 ----
+
+let myFrame2 = document.createElement("iframe");
+myFrame2.src = "about:blank";
+myFrame2.addEventListener("load", checkLoadFrame2);
+document.documentElement.appendChild(myFrame2);
+
+function checkLoadFrame2() {
+ myFrame2.removeEventListener('load', checkLoadFrame2, false);
+ is(SpecialPowers.wrap(myFrame2.contentWindow).location.href, "about:blank",
+ "initial about:blank frame loaded");
+
+ myFrame2.contentWindow.location.hash = "#foo";
+ is(SpecialPowers.wrap(myFrame2.contentWindow).location.href, "about:blank#foo",
+ "about:blank#foo frame loaded");
+
+ myFrame2.addEventListener('load', checkHistoryFrame2);
+ myFrame2.src = "about:blank";
+}
+
+function checkHistoryFrame2() {
+ myFrame2.removeEventListener('load', checkHistoryFrame2, false);
+ is(SpecialPowers.wrap(myFrame2.contentWindow).location.href, "about:blank",
+ "about:blank frame loaded again");
+ checkFinish();
+}
+
+// ---- test 3 ----
+
+let myFrame3 = document.createElement("frame");
+document.documentElement.appendChild(myFrame3);
+myFrame3.contentWindow.location.hash = "#foo";
+
+is(myFrame3.contentWindow.location.href, "about:blank#foo",
+ "created history entry with about:blank#foo");
+checkFinish();
+
+</script>
+</body>
+</html>
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index bc8cea35ac..34c7d23b86 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -5104,7 +5104,7 @@ nsContentUtils::TriggerLink(nsIContent *aContent, nsPresContext *aPresContext,
handler->OnLinkClick(aContent, aLinkURI,
fileName.IsVoid() ? aTargetSpec.get() : EmptyString().get(),
- fileName, nullptr, nullptr, aIsTrusted);
+ fileName, nullptr, nullptr, aIsTrusted, aContent->NodePrincipal());
}
}
@@ -9776,9 +9776,13 @@ nsContentUtils::AttemptLargeAllocationLoad(nsIHttpChannel* aChannel)
rv = aChannel->GetReferrer(getter_AddRefs(referrer));
NS_ENSURE_SUCCESS(rv, false);
+ nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
+ nsCOMPtr<nsIPrincipal> triggeringPrincipal = loadInfo->TriggeringPrincipal();
+
// Actually perform the cross process load
bool reloadSucceeded = false;
- rv = wbc3->ReloadInFreshProcess(docShell, uri, referrer, &reloadSucceeded);
+ rv = wbc3->ReloadInFreshProcess(docShell, uri, referrer,
+ triggeringPrincipal, &reloadSucceeded);
NS_ENSURE_SUCCESS(rv, false);
return reloadSucceeded;
diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp
index 738703ef1c..4ffccde9d3 100644
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2521,8 +2521,13 @@ nsGlobalWindow::WouldReuseInnerWindow(nsIDocument* aNewDocument)
return false;
}
- NS_ASSERTION(NS_IsAboutBlank(mDoc->GetDocumentURI()),
- "How'd this happen?");
+#ifdef DEBUG
+{
+ nsCOMPtr<nsIURI> uri;
+ mDoc->GetDocumentURI()->CloneIgnoringRef(getter_AddRefs(uri));
+ NS_ASSERTION(NS_IsAboutBlank(uri), "How'd this happen?");
+}
+#endif
// Great, we're the original document, check for one of the other
// conditions.
diff --git a/dom/base/test/file_simplecontentpolicy.js b/dom/base/test/file_simplecontentpolicy.js
index 1f9606c49d..2727b95306 100644
--- a/dom/base/test/file_simplecontentpolicy.js
+++ b/dom/base/test/file_simplecontentpolicy.js
@@ -39,7 +39,6 @@ var policy = {
{
// Remember last content type seen for the test url
if (contentLocation.spec.endsWith(urlSuffix)) {
- assert.ok(frame === browserElement, "correct <browser> element");
sendAsyncMessage("shouldLoad", {contentType: contentType, isTopLevel: isTopLevel});
return Ci.nsIContentPolicy.REJECT_REQUEST;
}
diff --git a/dom/jsurl/nsJSProtocolHandler.cpp b/dom/jsurl/nsJSProtocolHandler.cpp
index cdb63f890a..90171db102 100644
--- a/dom/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/jsurl/nsJSProtocolHandler.cpp
@@ -36,7 +36,6 @@
#include "nsIContentViewer.h"
#include "nsIXPConnect.h"
#include "nsContentUtils.h"
-#include "nsNullPrincipal.h"
#include "nsJSUtils.h"
#include "nsThreadUtils.h"
#include "nsIScriptChannel.h"
@@ -336,7 +335,7 @@ public:
NS_FORWARD_SAFE_NSIPROPERTYBAG(mPropertyBag)
NS_FORWARD_SAFE_NSIPROPERTYBAG2(mPropertyBag)
- nsresult Init(nsIURI *aURI);
+ nsresult Init(nsIURI *aURI, nsILoadInfo* aLoadInfo);
// Actually evaluate the script.
void EvaluateScript();
@@ -354,17 +353,16 @@ protected:
nsCOMPtr<nsIChannel> mStreamChannel;
nsCOMPtr<nsIPropertyBag2> mPropertyBag;
nsCOMPtr<nsIStreamListener> mListener; // Our final listener
- nsCOMPtr<nsISupports> mContext; // The context passed to AsyncOpen
nsCOMPtr<nsPIDOMWindowInner> mOriginalInnerWindow; // The inner window our load
// started against.
- // If we blocked onload on a document in AsyncOpen, this is the document we
+ // If we blocked onload on a document in AsyncOpen2, this is the document we
// did it on.
nsCOMPtr<nsIDocument> mDocumentOnloadBlockedOn;
nsresult mStatus; // Our status
nsLoadFlags mLoadFlags;
- nsLoadFlags mActualLoadFlags; // See AsyncOpen
+ nsLoadFlags mActualLoadFlags; // See AsyncOpen2
RefPtr<nsJSThunk> mIOThunk;
PopupControlState mPopupState;
@@ -404,7 +402,7 @@ nsresult nsJSChannel::StopAll()
return rv;
}
-nsresult nsJSChannel::Init(nsIURI *aURI)
+nsresult nsJSChannel::Init(nsIURI* aURI, nsILoadInfo* aLoadInfo)
{
RefPtr<nsJSURI> jsURI;
nsresult rv = aURI->QueryInterface(kJSURICID,
@@ -418,21 +416,13 @@ nsresult nsJSChannel::Init(nsIURI *aURI)
// Remember, until AsyncOpen is called, the script will not be evaluated
// and the underlying Input Stream will not be created...
nsCOMPtr<nsIChannel> channel;
-
- nsCOMPtr<nsIPrincipal> nullPrincipal = nsNullPrincipal::Create();
-
- // If the resultant script evaluation actually does return a value, we
- // treat it as html.
- // The following channel is never openend, so it does not matter what
- // securityFlags we pass; let's follow the principle of least privilege.
- rv = NS_NewInputStreamChannel(getter_AddRefs(channel),
- aURI,
- mIOThunk,
- nullPrincipal,
- nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED,
- nsIContentPolicy::TYPE_OTHER,
- NS_LITERAL_CSTRING("text/html"));
- if (NS_FAILED(rv)) return rv;
+ rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel),
+ aURI,
+ mIOThunk,
+ NS_LITERAL_CSTRING("text/html"),
+ EmptyCString(),
+ aLoadInfo);
+ NS_ENSURE_SUCCESS(rv, rv);
rv = mIOThunk->Init(aURI);
if (NS_SUCCEEDED(rv)) {
@@ -563,6 +553,7 @@ nsJSChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext)
"security flags in loadInfo but asyncOpen2() not called");
}
#endif
+ MOZ_RELEASE_ASSERT(!aContext, "please call AsyncOpen2()");
NS_ENSURE_ARG(aListener);
@@ -584,7 +575,6 @@ nsJSChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext)
}
mListener = aListener;
- mContext = aContext;
mIsActive = true;
@@ -655,7 +645,7 @@ nsJSChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext)
return mStatus;
}
- // We're returning success from asyncOpen(), but we didn't open a
+ // We're returning success from asyncOpen2(), but we didn't open a
// stream channel. We'll have to notify ourselves, but make sure to do
// it asynchronously.
method = &nsJSChannel::NotifyListener;
@@ -772,7 +762,7 @@ nsJSChannel::EvaluateScript()
return;
}
- mStatus = mStreamChannel->AsyncOpen(this, mContext);
+ mStatus = mStreamChannel->AsyncOpen2(this);
if (NS_SUCCEEDED(mStatus)) {
// mStreamChannel will call OnStartRequest and OnStopRequest on
// us, so we'll be sure to call them on our listener.
@@ -800,8 +790,8 @@ nsJSChannel::EvaluateScript()
void
nsJSChannel::NotifyListener()
{
- mListener->OnStartRequest(this, mContext);
- mListener->OnStopRequest(this, mContext, mStatus);
+ mListener->OnStartRequest(this, nullptr);
+ mListener->OnStopRequest(this, nullptr, mStatus);
CleanupStrongRefs();
}
@@ -810,7 +800,6 @@ void
nsJSChannel::CleanupStrongRefs()
{
mListener = nullptr;
- mContext = nullptr;
mOriginalInnerWindow = nullptr;
if (mDocumentOnloadBlockedOn) {
mDocumentOnloadBlockedOn->UnblockOnload(false);
@@ -1240,11 +1229,7 @@ nsJSProtocolHandler::NewChannel2(nsIURI* uri,
return NS_ERROR_OUT_OF_MEMORY;
}
- rv = channel->Init(uri);
- NS_ENSURE_SUCCESS(rv, rv);
-
- // set the loadInfo on the new channel
- rv = channel->SetLoadInfo(aLoadInfo);
+ rv = channel->Init(uri, aLoadInfo);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_SUCCEEDED(rv)) {
diff --git a/dom/plugins/base/nsPluginInstanceOwner.cpp b/dom/plugins/base/nsPluginInstanceOwner.cpp
index 291ae576dc..d5b1eb9ead 100644
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -535,16 +535,6 @@ NS_IMETHODIMP nsPluginInstanceOwner::GetURL(const char *aURL,
nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, baseURI);
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
- if (aDoCheckLoadURIChecks) {
- nsCOMPtr<nsIScriptSecurityManager> secMan(
- do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
- NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE);
-
- rv = secMan->CheckLoadURIWithPrincipal(content->NodePrincipal(), uri,
- nsIScriptSecurityManager::STANDARD);
- NS_ENSURE_SUCCESS(rv, rv);
- }
-
nsCOMPtr<nsIInputStream> headersDataStream;
if (aPostStream && aHeadersData) {
if (!aHeadersDataLen)
@@ -563,8 +553,21 @@ NS_IMETHODIMP nsPluginInstanceOwner::GetURL(const char *aURL,
Preferences::GetInt("privacy.popups.disable_from_plugins");
nsAutoPopupStatePusher popupStatePusher((PopupControlState)blockPopups);
+
+ // if security checks (in particular CheckLoadURIWithPrincipal) needs
+ // to be skipped we are creating a codebasePrincipal to make sure
+ // that security check succeeds. Please note that we do not want to
+ // fall back to using the systemPrincipal, because that would also
+ // bypass ContentPolicy checks which should still be enforced.
+ nsCOMPtr<nsIPrincipal> triggeringPrincipal;
+ if (!aDoCheckLoadURIChecks) {
+ mozilla::PrincipalOriginAttributes attrs =
+ BasePrincipal::Cast(content->NodePrincipal())->OriginAttributesRef();
+ triggeringPrincipal = BasePrincipal::CreateCodebasePrincipal(uri, attrs);
+ }
+
rv = lh->OnLinkClick(content, uri, unitarget.get(), NullString(),
- aPostStream, headersDataStream, true);
+ aPostStream, headersDataStream, true, triggeringPrincipal);
return rv;
}
diff --git a/dom/plugins/test/mochitest/test_bug813906.html b/dom/plugins/test/mochitest/test_bug813906.html
index 04c34daafe..d18dbbff2f 100644
--- a/dom/plugins/test/mochitest/test_bug813906.html
+++ b/dom/plugins/test/mochitest/test_bug813906.html
@@ -18,21 +18,35 @@ function f() {
</script>
<script type="application/javascript">
+SimpleTest.requestFlakyTimeout(
+ "Blocking an iframe does not cause the onerror event to be fired");
+
SimpleTest.waitForExplicitFinish();
setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
var frameLoadCount = 0;
+
+function frameNavBlocked() {
+ isnot(SpecialPowers.wrap(window.frame1).location.href.indexOf('chrome://'),
+ 0, 'plugin shouldnt be able to cause navigation to chrome URLs');
+ SimpleTest.finish();
+}
+
function frameLoaded() {
frameLoadCount++;
if (frameLoadCount == 1) {
document.getElementsByTagName("object")[0].type = "application/x-test";
document.getElementsByTagName("use")[0].setAttributeNS("http://www.w3.org/1999/xlink", "href", location.href + "#a");
- } else if (frameLoadCount == 2) {
- isnot(SpecialPowers.wrap(window.frame1).location.href.indexOf('chrome://'),
- 0, 'plugin shouldnt be able to cause navigation to chrome URLs');
- SimpleTest.finish();
+
+ // wait two seconds and verify that frame navigation did not succeed
+ setTimeout(frameNavBlocked, 2000);
+ return;
}
+ // we should never get here, but just in case, make sure the test fails in that case.
+ ok(false, "onload() event should not fire for blocked navigation");
+ SimpleTest.finish();
}
+
</script>
<!-- Note that <svg:use> ends up creating an anonymous subtree, which means that the plugin
diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp
index 0cc4933fe1..c6558fc93a 100644
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -10,6 +10,8 @@
#include "nsIStreamListener.h"
#include "nsIDocument.h"
#include "nsMixedContentBlocker.h"
+#include "nsCDefaultURIFixup.h"
+#include "nsIURIFixup.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/TabChild.h"
@@ -244,10 +246,6 @@ DoCORSChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo,
static nsresult
DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
{
- nsCOMPtr<nsIURI> uri;
- nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
- NS_ENSURE_SUCCESS(rv, rv);
-
nsContentPolicyType contentPolicyType =
aLoadInfo->GetExternalContentPolicyType();
nsContentPolicyType internalContentPolicyType =
@@ -255,12 +253,24 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
nsCString mimeTypeGuess;
nsCOMPtr<nsISupports> requestingContext = nullptr;
-#ifdef DEBUG
- // Don't enforce TYPE_DOCUMENT assertions for loads
- // initiated by javascript tests.
- bool skipContentTypeCheck = false;
- skipContentTypeCheck = Preferences::GetBool("network.loadinfo.skip_type_assertion");
-#endif
+ nsCOMPtr<nsIURI> uri;
+ nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
+ contentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT) {
+ // TYPE_DOCUMENT and TYPE_SUBDOCUMENT loads might potentially
+ // be wyciwyg:// channels. Let's fix up the URI so we can
+ // perform proper security checks.
+ nsCOMPtr<nsIURIFixup> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID, &rv));
+ if (NS_SUCCEEDED(rv) && urifixup) {
+ nsCOMPtr<nsIURI> fixedURI;
+ rv = urifixup->CreateExposableURI(uri, getter_AddRefs(fixedURI));
+ if (NS_SUCCEEDED(rv)) {
+ uri = fixedURI;
+ }
+ }
+ }
switch(contentPolicyType) {
case nsIContentPolicy::TYPE_OTHER: {
@@ -294,16 +304,14 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
}
case nsIContentPolicy::TYPE_DOCUMENT: {
- MOZ_ASSERT(skipContentTypeCheck || false, "contentPolicyType not supported yet");
+ mimeTypeGuess = EmptyCString();
+ requestingContext = aLoadInfo->LoadingNode();
break;
}
case nsIContentPolicy::TYPE_SUBDOCUMENT: {
mimeTypeGuess = NS_LITERAL_CSTRING("text/html");
requestingContext = aLoadInfo->LoadingNode();
- MOZ_ASSERT(!requestingContext ||
- requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE,
- "type_subdocument requires requestingContext of type Document");
break;
}
@@ -470,18 +478,32 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
MOZ_ASSERT(false, "can not perform security check without a valid contentType");
}
+ // For document loads we use the triggeringPrincipal as the originPrincipal.
+ // Note the the loadingPrincipal for loads of TYPE_DOCUMENT is a nullptr.
+ nsCOMPtr<nsIPrincipal> principal =
+ (contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
+ contentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT)
+ ? aLoadInfo->TriggeringPrincipal()
+ : aLoadInfo->LoadingPrincipal();
+
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
rv = NS_CheckContentLoadPolicy(internalContentPolicyType,
uri,
- aLoadInfo->LoadingPrincipal(),
+ principal,
requestingContext,
mimeTypeGuess,
nullptr, //extra,
&shouldLoad,
nsContentUtils::GetContentPolicy(),
nsContentUtils::GetSecurityManager());
- NS_ENSURE_SUCCESS(rv, rv);
- if (NS_CP_REJECTED(shouldLoad)) {
+
+ if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
+ if ((NS_SUCCEEDED(rv) && shouldLoad == nsIContentPolicy::REJECT_TYPE) &&
+ (contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
+ contentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT)) {
+ // for docshell loads we might have to return SHOW_ALT.
+ return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
+ }
return NS_ERROR_CONTENT_BLOCKED;
}
@@ -629,6 +651,24 @@ nsContentSecurityManager::CheckChannel(nsIChannel* aChannel)
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, rv);
+ nsContentPolicyType contentPolicyType =
+ loadInfo->GetExternalContentPolicyType();
+
+ if (contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
+ contentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT) {
+ // TYPE_DOCUMENT and TYPE_SUBDOCUMENT loads might potentially
+ // be wyciwyg:// channels. Let's fix up the URI so we can
+ // perform proper security checks.
+ nsCOMPtr<nsIURIFixup> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID, &rv));
+ if (NS_SUCCEEDED(rv) && urifixup) {
+ nsCOMPtr<nsIURI> fixedURI;
+ rv = urifixup->CreateExposableURI(uri, getter_AddRefs(fixedURI));
+ if (NS_SUCCEEDED(rv)) {
+ uri = fixedURI;
+ }
+ }
+ }
+
// Handle cookie policies
uint32_t cookiePolicy = loadInfo->GetCookiePolicy();
if (cookiePolicy == nsILoadInfo::SEC_COOKIES_SAME_ORIGIN) {
diff --git a/embedding/browser/nsIWebBrowserChrome3.idl b/embedding/browser/nsIWebBrowserChrome3.idl
index a95cab9118..d78a1d63b1 100644
--- a/embedding/browser/nsIWebBrowserChrome3.idl
+++ b/embedding/browser/nsIWebBrowserChrome3.idl
@@ -8,6 +8,7 @@
interface nsIDocShell;
interface nsIInputStream;
+interface nsIPrincipal;
/**
* nsIWebBrowserChrome3 is an extension to nsIWebBrowserChrome2.
@@ -43,10 +44,13 @@ interface nsIWebBrowserChrome3 : nsIWebBrowserChrome2
* The URI being loaded.
* @param aReferrer
* The referrer of the load.
+ * @param aTriggeringPrincipal
+ * The principal that initiated the load of aURI.
*/
bool shouldLoadURI(in nsIDocShell aDocShell,
in nsIURI aURI,
- in nsIURI aReferrer);
+ in nsIURI aReferrer,
+ in nsIPrincipal aTriggeringPrincipal);
/**
* Attempts to load the currently loaded page into a fresh process to increase
@@ -57,5 +61,6 @@ interface nsIWebBrowserChrome3 : nsIWebBrowserChrome2
*/
bool reloadInFreshProcess(in nsIDocShell aDocShell,
in nsIURI aURI,
- in nsIURI aReferrer);
+ in nsIURI aReferrer,
+ in nsIPrincipal aTriggeringPrincipal);
};
diff --git a/embedding/browser/nsWebBrowser.cpp b/embedding/browser/nsWebBrowser.cpp
index 655aa1e432..c034fc03e6 100644
--- a/embedding/browser/nsWebBrowser.cpp
+++ b/embedding/browser/nsWebBrowser.cpp
@@ -654,13 +654,14 @@ nsWebBrowser::LoadURIWithOptions(const char16_t* aURI, uint32_t aLoadFlags,
uint32_t aReferrerPolicy,
nsIInputStream* aPostDataStream,
nsIInputStream* aExtraHeaderStream,
- nsIURI* aBaseURI)
+ nsIURI* aBaseURI,
+ nsIPrincipal* aTriggeringPrincipal)
{
NS_ENSURE_STATE(mDocShell);
return mDocShellAsNav->LoadURIWithOptions(
aURI, aLoadFlags, aReferringURI, aReferrerPolicy, aPostDataStream,
- aExtraHeaderStream, aBaseURI);
+ aExtraHeaderStream, aBaseURI, aTriggeringPrincipal);
}
NS_IMETHODIMP
diff --git a/netwerk/base/nsNetUtil.cpp b/netwerk/base/nsNetUtil.cpp
index 8ff3e788f3..bc9bcf88a5 100644
--- a/netwerk/base/nsNetUtil.cpp
+++ b/netwerk/base/nsNetUtil.cpp
@@ -1285,16 +1285,10 @@ NS_HasBeenCrossOrigin(nsIChannel* aChannel, bool aReport)
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
MOZ_RELEASE_ASSERT(loadInfo, "Origin tracking only works for channels created with a loadinfo");
-#ifdef DEBUG
- // Don't enforce TYPE_DOCUMENT assertions for loads
- // initiated by javascript tests.
- bool skipContentTypeCheck = false;
- skipContentTypeCheck = Preferences::GetBool("network.loadinfo.skip_type_assertion");
-#endif
-
- MOZ_ASSERT(skipContentTypeCheck ||
- loadInfo->GetExternalContentPolicyType() != nsIContentPolicy::TYPE_DOCUMENT,
- "calling NS_HasBeenCrossOrigin on a top level load");
+ // TYPE_DOCUMENT loads have a null LoadingPrincipal and can not be cross origin.
+ if (!loadInfo->LoadingPrincipal()) {
+ return false;
+ }
// Always treat tainted channels as cross-origin.
if (loadInfo->GetTainting() != LoadTainting::Basic) {
diff --git a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/iframe-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini b/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/iframe-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
new file mode 100644
index 0000000000..c65b27a086
--- /dev/null
+++ b/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/iframe-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
@@ -0,0 +1,3 @@
+[no-opt-in-blocks.https.html]
+ type: testharness
+ prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
diff --git a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/iframe-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini b/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/iframe-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
new file mode 100644
index 0000000000..c65b27a086
--- /dev/null
+++ b/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/iframe-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
@@ -0,0 +1,3 @@
+[no-opt-in-blocks.https.html]
+ type: testharness
+ prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
diff --git a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/iframe-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini b/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/iframe-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
new file mode 100644
index 0000000000..c65b27a086
--- /dev/null
+++ b/testing/web-platform/meta/mixed-content/blockable/no-opt-in/cross-origin-http/iframe-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
@@ -0,0 +1,3 @@
+[no-opt-in-blocks.https.html]
+ type: testharness
+ prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
diff --git a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/iframe-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini b/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/iframe-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
new file mode 100644
index 0000000000..c65b27a086
--- /dev/null
+++ b/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/iframe-tag/top-level/keep-scheme-redirect/no-opt-in-blocks.https.html.ini
@@ -0,0 +1,3 @@
+[no-opt-in-blocks.https.html]
+ type: testharness
+ prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
diff --git a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/iframe-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini b/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/iframe-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
new file mode 100644
index 0000000000..c65b27a086
--- /dev/null
+++ b/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/iframe-tag/top-level/no-redirect/no-opt-in-blocks.https.html.ini
@@ -0,0 +1,3 @@
+[no-opt-in-blocks.https.html]
+ type: testharness
+ prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
diff --git a/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/iframe-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini b/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/iframe-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
new file mode 100644
index 0000000000..c65b27a086
--- /dev/null
+++ b/testing/web-platform/meta/mixed-content/blockable/no-opt-in/same-host-http/iframe-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html.ini
@@ -0,0 +1,3 @@
+[no-opt-in-blocks.https.html]
+ type: testharness
+ prefs: [security.mixed_content.send_hsts_priming:false, security.mixed_content.use_hsts:false]
diff --git a/testing/web-platform/tests/service-workers/service-worker/fetch-frame-resource.https.html b/testing/web-platform/tests/service-workers/service-worker/fetch-frame-resource.https.html
index cc1dac472b..fd74198324 100644
--- a/testing/web-platform/tests/service-workers/service-worker/fetch-frame-resource.https.html
+++ b/testing/web-platform/tests/service-workers/service-worker/fetch-frame-resource.https.html
@@ -110,7 +110,8 @@ async_test(function(t) {
frame.src =
scope + '?mode=cors&url=' +
encodeURIComponent(host_info['HTTPS_REMOTE_ORIGIN'] + path +
- '?ACAOrigin=' + host_info['HTTPS_ORIGIN']);
+ '?ACAOrigin=' + host_info['HTTPS_ORIGIN'] +
+ '&ACACredentials=true');
document.body.appendChild(frame);
return getLoadedFrameAsObject(frame);
})
@@ -183,7 +184,8 @@ async_test(function(t) {
var win = window.open(
scope + '?mode=cors&url=' +
encodeURIComponent(host_info['HTTPS_REMOTE_ORIGIN'] + path +
- '?ACAOrigin=' + host_info['HTTPS_ORIGIN']));
+ '?ACAOrigin=' + host_info['HTTPS_ORIGIN'] +
+ '&ACACredentials=true'));
return getLoadedWindowAsObject(win);
})
.then(function(result) {
diff --git a/toolkit/components/viewsource/content/viewSource-content.js b/toolkit/components/viewsource/content/viewSource-content.js
index fa1dd19f1a..70d23eaa46 100644
--- a/toolkit/components/viewsource/content/viewSource-content.js
+++ b/toolkit/components/viewsource/content/viewSource-content.js
@@ -330,6 +330,8 @@ var ViewSourceContent = {
.createInstance(Ci.nsISHEntry);
shEntry.setURI(BrowserUtils.makeURI(viewSrcURL, null, null));
shEntry.setTitle(viewSrcURL);
+ let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
+ shEntry.triggeringPrincipal = systemPrincipal;
shEntry.loadType = Ci.nsIDocShellLoadInfo.loadHistory;
shEntry.cacheKey = shEntrySource.cacheKey;
docShell.QueryInterface(Ci.nsIWebNavigation)
diff --git a/toolkit/content/widgets/browser.xml b/toolkit/content/widgets/browser.xml
index a5f37b62a1..e595c847df 100644
--- a/toolkit/content/widgets/browser.xml
+++ b/toolkit/content/widgets/browser.xml
@@ -135,6 +135,7 @@
aURI = "about:blank";
var aReferrerPolicy = Components.interfaces.nsIHttpChannel.REFERRER_POLICY_DEFAULT;
+ var aTriggeringPrincipal;
// Check for loadURIWithFlags(uri, { ... });
var params = arguments[1];
@@ -144,6 +145,9 @@
if ('referrerPolicy' in params) {
aReferrerPolicy = params.referrerPolicy;
}
+ if ("triggeringPrincipal" in params) {
+ aTriggeringPrincipal = params.triggeringPrincipal;
+ }
aCharset = params.charset;
aPostData = params.postData;
}
@@ -151,7 +155,7 @@
this._wrapURIChangeCall(() =>
this.webNavigation.loadURIWithOptions(
aURI, aFlags, aReferrerURI, aReferrerPolicy,
- aPostData, null, null));
+ aPostData, null, null, aTriggeringPrincipal));
]]>
</body>
</method>
diff --git a/toolkit/modules/sessionstore/Utils.jsm b/toolkit/modules/sessionstore/Utils.jsm
index 863bca6f51..25b75c71b5 100644
--- a/toolkit/modules/sessionstore/Utils.jsm
+++ b/toolkit/modules/sessionstore/Utils.jsm
@@ -16,12 +16,17 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
XPCOMUtils.defineLazyServiceGetter(this, "serializationHelper",
"@mozilla.org/network/serialization-helper;1",
"nsISerializationHelper");
+XPCOMUtils.defineLazyGetter(this, "SERIALIZED_SYSTEMPRINCIPAL", function() {
+ return Utils.serializePrincipal(Services.scriptSecurityManager.getSystemPrincipal());
+});
function debug(msg) {
Services.console.logStringMessage("Utils: " + msg);
}
this.Utils = Object.freeze({
+ get SERIALIZED_SYSTEMPRINCIPAL() { return SERIALIZED_SYSTEMPRINCIPAL; },
+
makeURI: function (url) {
return Services.io.newURI(url, null, null);
},
diff --git a/uriloader/base/nsURILoader.cpp b/uriloader/base/nsURILoader.cpp
index 69475d68fd..ea370aa37c 100644
--- a/uriloader/base/nsURILoader.cpp
+++ b/uriloader/base/nsURILoader.cpp
@@ -834,7 +834,7 @@ NS_IMETHODIMP nsURILoader::OpenURI(nsIChannel *channel,
// the preferred protocol handler.
// But for now, I'm going to let necko do the work for us....
- rv = channel->AsyncOpen(loader, nullptr);
+ rv = channel->AsyncOpen2(loader);
// no content from this load - that's OK.
if (rv == NS_ERROR_NO_CONTENT) {
diff --git a/xpfe/appshell/nsContentTreeOwner.cpp b/xpfe/appshell/nsContentTreeOwner.cpp
index b39b7610fb..f0fcdef9a6 100644
--- a/xpfe/appshell/nsContentTreeOwner.cpp
+++ b/xpfe/appshell/nsContentTreeOwner.cpp
@@ -390,6 +390,7 @@ NS_IMETHODIMP nsContentTreeOwner::OnBeforeLinkTraversal(const nsAString &origina
NS_IMETHODIMP nsContentTreeOwner::ShouldLoadURI(nsIDocShell *aDocShell,
nsIURI *aURI,
nsIURI *aReferrer,
+ nsIPrincipal* aTriggeringPrincipal,
bool *_retval)
{
NS_ENSURE_STATE(mXULWindow);
@@ -398,7 +399,8 @@ NS_IMETHODIMP nsContentTreeOwner::ShouldLoadURI(nsIDocShell *aDocShell,
mXULWindow->GetXULBrowserWindow(getter_AddRefs(xulBrowserWindow));
if (xulBrowserWindow)
- return xulBrowserWindow->ShouldLoadURI(aDocShell, aURI, aReferrer, _retval);
+ return xulBrowserWindow->ShouldLoadURI(aDocShell, aURI, aReferrer,
+ aTriggeringPrincipal, _retval);
*_retval = true;
return NS_OK;
@@ -407,6 +409,7 @@ NS_IMETHODIMP nsContentTreeOwner::ShouldLoadURI(nsIDocShell *aDocShell,
NS_IMETHODIMP nsContentTreeOwner::ReloadInFreshProcess(nsIDocShell* aDocShell,
nsIURI* aURI,
nsIURI* aReferrer,
+ nsIPrincipal* aTriggeringPrincipal,
bool* aRetVal)
{
NS_WARNING("Cannot reload in fresh process from a nsContentTreeOwner!");
diff --git a/xpfe/appshell/nsIXULBrowserWindow.idl b/xpfe/appshell/nsIXULBrowserWindow.idl
index 40f1898c8f..5dbc2d4099 100644
--- a/xpfe/appshell/nsIXULBrowserWindow.idl
+++ b/xpfe/appshell/nsIXULBrowserWindow.idl
@@ -13,6 +13,7 @@ interface nsIDOMElement;
interface nsIInputStream;
interface nsIDocShell;
interface nsITabParent;
+interface nsIPrincipal;
interface mozIDOMWindowProxy;
/**
@@ -60,10 +61,13 @@ interface nsIXULBrowserWindow : nsISupports
* The URI being loaded.
* @param aReferrer
* The referrer of the load.
+ * @param aTriggeringPrincipal
+ * The principal that initiated the load of aURI.
*/
bool shouldLoadURI(in nsIDocShell aDocShell,
in nsIURI aURI,
- in nsIURI aReferrer);
+ in nsIURI aReferrer,
+ in nsIPrincipal aTriggeringPrincipal);
/**
* Show/hide a tooltip (when the user mouses over a link, say).
*/