зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1646560: Part 2 - Move allowJavascript and friends from DocShell to BrowsingContext and WindowContext. r=jdescottes,nika,geckoview-reviewers,devtools-backward-compat-reviewers,agi
This is slightly complicated by the fact that the editor code wants to be able to set this from the content process, so we really need separate BrowsingContext and WindowContext flags, the latter of which can be set by the owning process. Differential Revision: https://phabricator.services.mozilla.com/D114899
This commit is contained in:
Родитель
b3c34d273e
Коммит
ae436f55ec
|
@ -11,7 +11,7 @@
|
|||
add_task(async function docshell_capabilities() {
|
||||
let tab = await createTab();
|
||||
let browser = tab.linkedBrowser;
|
||||
let docShell = browser.docShell;
|
||||
let { browsingContext, docShell } = browser;
|
||||
|
||||
// Get the list of capabilities for docShells.
|
||||
let flags = Object.keys(docShell).filter(k => k.startsWith("allow"));
|
||||
|
@ -27,7 +27,7 @@ add_task(async function docshell_capabilities() {
|
|||
// Flip a couple of allow* flags.
|
||||
docShell.allowImages = false;
|
||||
docShell.allowMetaRedirects = false;
|
||||
docShell.allowJavascript = false;
|
||||
browsingContext.allowJavascript = false;
|
||||
|
||||
// Now reload the document to ensure that these capabilities
|
||||
// are taken into account.
|
||||
|
@ -68,7 +68,7 @@ add_task(async function docshell_capabilities() {
|
|||
ok(!docShell.allowMetaRedirects, "meta redirects not allowed");
|
||||
|
||||
// Check that docShell allowJavascript flag is not set.
|
||||
ok(docShell.allowJavascript, "Javascript still allowed");
|
||||
ok(browsingContext.allowJavascript, "Javascript still allowed");
|
||||
|
||||
// Check that we correctly restored features as disabled.
|
||||
state = JSON.parse(ss.getTabState(tab));
|
||||
|
|
|
@ -85,8 +85,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=840488
|
|||
is(win.wrappedJSObject.gFiredOnclick, expectEnabled, "Checking script-enabled for " + win.name + " (" + win.location + ")");
|
||||
}
|
||||
|
||||
function setScriptEnabledForDocShell(win, enabled) {
|
||||
win.docShell.allowJavascript = enabled;
|
||||
function setScriptEnabled(win, enabled) {
|
||||
win.browsingContext.allowJavascript = enabled;
|
||||
}
|
||||
|
||||
function testList(expectEnabled, win, list, idx) {
|
||||
|
@ -138,16 +138,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=840488
|
|||
|
||||
// Test simple docshell enable/disable.
|
||||
checkScriptEnabled(rootWin, true);
|
||||
setScriptEnabledForDocShell(rootWin, false);
|
||||
setScriptEnabled(rootWin, false);
|
||||
checkScriptEnabled(rootWin, false);
|
||||
setScriptEnabledForDocShell(rootWin, true);
|
||||
setScriptEnabled(rootWin, true);
|
||||
checkScriptEnabled(rootWin, true);
|
||||
|
||||
// Privileged frames are immune to docshell flags.
|
||||
ok(chromeWin.document.nodePrincipal.isSystemPrincipal, "Sanity check for System Principal");
|
||||
setScriptEnabledForDocShell(chromeWin, false);
|
||||
setScriptEnabled(chromeWin, false);
|
||||
checkScriptEnabled(chromeWin, true);
|
||||
setScriptEnabledForDocShell(chromeWin, true);
|
||||
setScriptEnabled(chromeWin, true);
|
||||
|
||||
// Play around with the docshell tree and make sure everything works as
|
||||
// we expect.
|
||||
|
@ -156,32 +156,32 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=840488
|
|||
return addFrame(rootWin[0], 'childA', true);
|
||||
}).then(function() {
|
||||
checkScriptEnabled(rootWin[0][0], true);
|
||||
setScriptEnabledForDocShell(rootWin[0], false);
|
||||
setScriptEnabled(rootWin[0], false);
|
||||
checkScriptEnabled(rootWin, true);
|
||||
checkScriptEnabled(rootWin[0], false);
|
||||
checkScriptEnabled(rootWin[0][0], false);
|
||||
return addFrame(rootWin[0], 'childB', false);
|
||||
}).then(function() {
|
||||
checkScriptEnabled(rootWin[0][1], false);
|
||||
setScriptEnabledForDocShell(rootWin[0][0], false);
|
||||
setScriptEnabledForDocShell(rootWin[0], true);
|
||||
setScriptEnabled(rootWin[0][0], false);
|
||||
setScriptEnabled(rootWin[0], true);
|
||||
checkScriptEnabled(rootWin[0], true);
|
||||
checkScriptEnabled(rootWin[0][0], false);
|
||||
setScriptEnabledForDocShell(rootWin[0][0], true);
|
||||
setScriptEnabled(rootWin[0][0], true);
|
||||
|
||||
// Flags are inherited from the parent docshell at attach time. Note that
|
||||
// the flag itself is inherited, regardless of whether or not scripts are
|
||||
// currently allowed on the parent (which could depend on the parent's
|
||||
// parent). Check that.
|
||||
checkScriptEnabled(rootWin[0][1], false);
|
||||
setScriptEnabledForDocShell(rootWin[0], false);
|
||||
setScriptEnabledForDocShell(rootWin[0][1], true);
|
||||
setScriptEnabled(rootWin[0], false);
|
||||
setScriptEnabled(rootWin[0][1], true);
|
||||
return addFrame(rootWin[0][1], 'grandchild', false);
|
||||
}).then(function() {
|
||||
checkScriptEnabled(rootWin[0], false);
|
||||
checkScriptEnabled(rootWin[0][1], false);
|
||||
checkScriptEnabled(rootWin[0][1][0], false);
|
||||
setScriptEnabledForDocShell(rootWin[0], true);
|
||||
setScriptEnabled(rootWin[0], true);
|
||||
checkScriptEnabled(rootWin[0], true);
|
||||
checkScriptEnabled(rootWin[0][1], true);
|
||||
checkScriptEnabled(rootWin[0][1][0], true);
|
||||
|
@ -195,8 +195,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=840488
|
|||
.then(function() {
|
||||
checkScriptEnabled(rootWin[0][0], true);
|
||||
checkScriptEnabled(rootWin[0][1][0], true);
|
||||
setScriptEnabledForDocShell(rootWin[0][0], false);
|
||||
setScriptEnabledForDocShell(rootWin[0][1], false);
|
||||
setScriptEnabled(rootWin[0][0], false);
|
||||
setScriptEnabled(rootWin[0][1], false);
|
||||
checkScriptEnabled(rootWin[0][0], false);
|
||||
checkScriptEnabled(rootWin[0][1][0], false);
|
||||
return navigateBack(rootWin[0][0].frameElement);
|
||||
|
|
|
@ -34,8 +34,8 @@ add_task(async function() {
|
|||
async function testJSEnabled() {
|
||||
info("Testing that JS is enabled");
|
||||
|
||||
// We use waitForTick here because switching docShell.allowJavascript to true
|
||||
// takes a while to become live.
|
||||
// We use waitForTick here because switching browsingContext.allowJavascript
|
||||
// to true takes a while to become live.
|
||||
await waitForTick();
|
||||
|
||||
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function() {
|
||||
|
|
|
@ -605,10 +605,10 @@ OptionsPanel.prototype = {
|
|||
|
||||
/**
|
||||
* Disables JavaScript for the currently loaded tab. We force a page refresh
|
||||
* here because setting docShell.allowJavascript to true fails to block JS
|
||||
* execution from event listeners added using addEventListener(), AJAX calls
|
||||
* and timers. The page refresh prevents these things from being added in the
|
||||
* first place.
|
||||
* here because setting browsingContext.allowJavascript to true fails to block
|
||||
* JS execution from event listeners added using addEventListener(), AJAX
|
||||
* calls and timers. The page refresh prevents these things from being added
|
||||
* in the first place.
|
||||
*
|
||||
* @param {Event} event
|
||||
* The event sent by checking / unchecking the disable JS checkbox.
|
||||
|
|
|
@ -2115,14 +2115,18 @@ Toolbox.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Read the initial javascriptEnabled configuration from the current target
|
||||
* and forward it to the configuration actor.
|
||||
* If we have an older version of the server which handles `javascriptEnabled`
|
||||
* in the browsing-context target, read the initial javascriptEnabled
|
||||
* configuration from the current target and forward it to the configuration
|
||||
* actor.
|
||||
*/
|
||||
_applyJavascriptEnabledSettings: function() {
|
||||
const javascriptEnabled = this.target._javascriptEnabled;
|
||||
this.commands.targetConfigurationCommand.updateConfiguration({
|
||||
javascriptEnabled,
|
||||
});
|
||||
if (this.target.traits.javascriptEnabled) {
|
||||
const javascriptEnabled = this.target._javascriptEnabled;
|
||||
this.commands.targetConfigurationCommand.updateConfiguration({
|
||||
javascriptEnabled,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,9 +20,8 @@ class BrowsingContextTargetFront extends TargetMixin(
|
|||
|
||||
// For targets which support the Watcher and configuration actor, the status
|
||||
// for the `javascriptEnabled` setting will be available on the configuration
|
||||
// front, and the target will only be used to read the initial value.
|
||||
// For other targets, _javascriptEnabled will be updated everytime
|
||||
// `reconfigure` is called.
|
||||
// front, and the target will only be used to read the initial value from older
|
||||
// servers.
|
||||
// Note: this property is marked as private but is accessed by the
|
||||
// TargetCommand to provide the "isJavascriptEnabled" wrapper. It should NOT be
|
||||
// used anywhere else.
|
||||
|
@ -121,9 +120,13 @@ class BrowsingContextTargetFront extends TargetMixin(
|
|||
const response = await super.attach();
|
||||
|
||||
this.targetForm.threadActor = response.threadActor;
|
||||
this._javascriptEnabled = response.javascriptEnabled;
|
||||
this.traits = response.traits || {};
|
||||
|
||||
if (response.javascriptEnabled != null) {
|
||||
this.traits.javascriptEnabled = true;
|
||||
this._javascriptEnabled = response.javascriptEnabled;
|
||||
}
|
||||
|
||||
// xpcshell tests from devtools/server/tests/xpcshell/ are implementing
|
||||
// fake BrowsingContextTargetActor which do not expose any console actor.
|
||||
if (this.targetForm.consoleActor) {
|
||||
|
@ -133,16 +136,6 @@ class BrowsingContextTargetFront extends TargetMixin(
|
|||
return this._attach;
|
||||
}
|
||||
|
||||
async reconfigure({ options }) {
|
||||
const response = await super.reconfigure({ options });
|
||||
|
||||
if (typeof options.javascriptEnabled != "undefined") {
|
||||
this._javascriptEnabled = options.javascriptEnabled;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
async detach() {
|
||||
// When calling this.destroy() at the end of this method,
|
||||
// we will end up calling detach again from TargetMixin.destroy.
|
||||
|
|
|
@ -193,6 +193,17 @@ const TargetConfigurationActor = ActorClassWithSpec(targetConfigurationSpec, {
|
|||
case "customUserAgent":
|
||||
this._setCustomUserAgent(value);
|
||||
break;
|
||||
case "javascriptEnabled":
|
||||
if (value !== undefined) {
|
||||
const reload = value != this.isJavascriptEnabled();
|
||||
this._setJavascriptEnabled(value);
|
||||
// This flag requires a reload in order to take full effect,
|
||||
// so reload if it has changed.
|
||||
if (reload) {
|
||||
this._browsingContext.reload(0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "overrideDPPX":
|
||||
this._setDPPXOverride(value);
|
||||
break;
|
||||
|
@ -243,6 +254,10 @@ const TargetConfigurationActor = ActorClassWithSpec(targetConfigurationSpec, {
|
|||
this._setDPPXOverride(this._initialDPPXOverride);
|
||||
}
|
||||
|
||||
if (this._initialJavascriptEnabled !== undefined) {
|
||||
this._setJavascriptEnabled(this._initialJavascriptEnabled);
|
||||
}
|
||||
|
||||
if (this._initialTouchEventsOverride !== undefined) {
|
||||
this._setTouchEventsOverride(this._initialTouchEventsOverride);
|
||||
}
|
||||
|
@ -297,6 +312,18 @@ const TargetConfigurationActor = ActorClassWithSpec(targetConfigurationSpec, {
|
|||
this._browsingContext.customUserAgent = userAgent;
|
||||
},
|
||||
|
||||
isJavascriptEnabled() {
|
||||
return this._browsingContext.allowJavascript;
|
||||
},
|
||||
_setJavascriptEnabled(allow) {
|
||||
if (this._initialJavascriptEnabled === undefined) {
|
||||
this._initialJavascriptEnabled = this._browsingContext.allowJavascript;
|
||||
}
|
||||
if (allow !== undefined) {
|
||||
this._browsingContext.allowJavascript = allow;
|
||||
}
|
||||
},
|
||||
|
||||
/* DPPX override */
|
||||
_setDPPXOverride(dppx) {
|
||||
if (this._browsingContext.overrideDPPX === dppx) {
|
||||
|
|
|
@ -1090,7 +1090,6 @@ const browsingContextTargetPrototype = {
|
|||
return {
|
||||
threadActor: this.threadActor.actorID,
|
||||
cacheDisabled: this._getCacheDisabled(),
|
||||
javascriptEnabled: this._getJavascriptEnabled(),
|
||||
traits: this.traits,
|
||||
};
|
||||
},
|
||||
|
@ -1278,14 +1277,6 @@ const browsingContextTargetPrototype = {
|
|||
// propagated through the browsing context tree via the platform.
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
typeof options.javascriptEnabled !== "undefined" &&
|
||||
options.javascriptEnabled !== this._getJavascriptEnabled()
|
||||
) {
|
||||
this._setJavascriptEnabled(options.javascriptEnabled);
|
||||
reload = true;
|
||||
}
|
||||
if (
|
||||
typeof options.cacheDisabled !== "undefined" &&
|
||||
options.cacheDisabled !== this._getCacheDisabled()
|
||||
|
@ -1320,7 +1311,6 @@ const browsingContextTargetPrototype = {
|
|||
* state when closing the toolbox.
|
||||
*/
|
||||
_restoreTargetConfiguration() {
|
||||
this._restoreJavascript();
|
||||
this._setCacheDisabled(false);
|
||||
this._setPaintFlashingEnabled(false);
|
||||
|
||||
|
@ -1339,39 +1329,6 @@ const browsingContextTargetPrototype = {
|
|||
this.docShell.defaultLoadFlags = disabled ? disable : enable;
|
||||
},
|
||||
|
||||
/**
|
||||
* Disable or enable JS via docShell.
|
||||
*/
|
||||
_wasJavascriptEnabled: null,
|
||||
_setJavascriptEnabled(allow) {
|
||||
if (this._wasJavascriptEnabled === null) {
|
||||
this._wasJavascriptEnabled = this.docShell.allowJavascript;
|
||||
}
|
||||
this.docShell.allowJavascript = allow;
|
||||
},
|
||||
|
||||
/**
|
||||
* Restore JS state, before the actor modified it.
|
||||
*/
|
||||
_restoreJavascript() {
|
||||
if (this._wasJavascriptEnabled !== null) {
|
||||
this._setJavascriptEnabled(this._wasJavascriptEnabled);
|
||||
this._wasJavascriptEnabled = null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Return JS allowed status.
|
||||
*/
|
||||
_getJavascriptEnabled() {
|
||||
if (!this.docShell) {
|
||||
// The browsing context is already closed.
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.docShell.allowJavascript;
|
||||
},
|
||||
|
||||
/**
|
||||
* Disable or enable the paint flashing on the target.
|
||||
*/
|
||||
|
|
|
@ -61,20 +61,23 @@ class TargetConfigurationCommand {
|
|||
}
|
||||
|
||||
async isJavascriptEnabled() {
|
||||
if (
|
||||
this._hasTargetWatcherSupport() &&
|
||||
// `javascriptEnabled` is first read by the target and then forwarded by
|
||||
// the toolbox to the TargetConfigurationCommand, so it might be undefined at this
|
||||
// point.
|
||||
typeof this.configuration.javascriptEnabled !== "undefined"
|
||||
) {
|
||||
return this.configuration.javascriptEnabled;
|
||||
if (this._hasTargetWatcherSupport()) {
|
||||
const front = await this.getFront();
|
||||
return front.isJavascriptEnabled();
|
||||
}
|
||||
|
||||
// If the TargetConfigurationActor does not know the value yet, or if the target don't
|
||||
// support the Watcher + configuration actor, fallback on the initial value cached by
|
||||
// the target front.
|
||||
return this._commands.targetCommand.targetFront._javascriptEnabled;
|
||||
// support the Watcher + configuration actor, and we have an old version of the server
|
||||
// which handles `javascriptEnabled` in the target, fallback on the initial value
|
||||
// cached by the target front.
|
||||
const { targetFront } = this._commands.targetCommand;
|
||||
if (targetFront.traits.javascriptEnabled) {
|
||||
return targetFront._javascriptEnabled;
|
||||
}
|
||||
|
||||
// If we don't have target watcher support, we can't get this value, so just fall back
|
||||
// to the default.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -38,6 +38,12 @@ const targetConfigurationSpec = generateActorSpec({
|
|||
configuration: RetVal("target-configuration.configuration"),
|
||||
},
|
||||
},
|
||||
isJavascriptEnabled: {
|
||||
request: {},
|
||||
response: {
|
||||
javascriptEnabled: RetVal("boolean"),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ const {
|
|||
types.addDictType("browsingContextTarget.attach", {
|
||||
threadActor: "number",
|
||||
cacheDisabled: "boolean",
|
||||
javascriptEnabled: "boolean",
|
||||
javascriptEnabled: "nullable:boolean",
|
||||
traits: "json",
|
||||
});
|
||||
|
||||
|
@ -46,7 +46,6 @@ types.addDictType("browsingContextTarget.reload", {
|
|||
types.addDictType("browsingContextTarget.reconfigure", {
|
||||
cacheDisabled: "nullable:boolean",
|
||||
colorSchemeSimulation: "nullable:string",
|
||||
javascriptEnabled: "nullable:boolean",
|
||||
paintFlashing: "nullable:boolean",
|
||||
printSimulationEnabled: "nullable:boolean",
|
||||
restoreFocus: "nullable:boolean",
|
||||
|
|
|
@ -406,6 +406,8 @@ already_AddRefed<BrowsingContext> BrowsingContext::CreateDetached(
|
|||
|
||||
fields.mTouchEventsOverrideInternal = TouchEventsOverride::None;
|
||||
|
||||
fields.mAllowJavascript = inherit ? inherit->GetAllowJavascript() : true;
|
||||
|
||||
RefPtr<BrowsingContext> context;
|
||||
if (XRE_IsParentProcess()) {
|
||||
context = new CanonicalBrowsingContext(parentWC, group, id,
|
||||
|
@ -538,6 +540,7 @@ BrowsingContext::BrowsingContext(WindowContext* aParentWindow,
|
|||
mUseRemoteSubframes(false),
|
||||
mCreatedDynamically(false),
|
||||
mIsInBFCache(false),
|
||||
mCanExecuteScripts(true),
|
||||
mChildOffset(0) {
|
||||
MOZ_RELEASE_ASSERT(!mParentWindow || mParentWindow->Group() == mGroup);
|
||||
MOZ_RELEASE_ASSERT(mBrowsingContextId != 0);
|
||||
|
@ -742,6 +745,7 @@ void BrowsingContext::Attach(bool aFromIPC, ContentParent* aOriginProcess) {
|
|||
mChildOffset =
|
||||
mCreatedDynamically ? -1 : mParentWindow->Children().Length();
|
||||
mParentWindow->AppendChildBrowsingContext(this);
|
||||
RecomputeCanExecuteScripts();
|
||||
} else {
|
||||
mGroup->Toplevels().AppendElement(this);
|
||||
}
|
||||
|
@ -2628,6 +2632,43 @@ void BrowsingContext::DidSet(FieldIndex<IDX_HasMainMediaController>,
|
|||
Group()->UpdateToplevelsSuspendedIfNeeded();
|
||||
}
|
||||
|
||||
auto BrowsingContext::CanSet(FieldIndex<IDX_AllowJavascript>, bool aValue,
|
||||
ContentParent* aSource) -> CanSetResult {
|
||||
if (mozilla::SessionHistoryInParent()) {
|
||||
return XRE_IsParentProcess() && !aSource ? CanSetResult::Allow : CanSetResult::Deny;
|
||||
}
|
||||
|
||||
// Without Session History in Parent, session restore code still needs to set
|
||||
// this from content processes.
|
||||
return LegacyRevertIfNotOwningOrParentProcess(aSource);
|
||||
}
|
||||
|
||||
void BrowsingContext::DidSet(FieldIndex<IDX_AllowJavascript>, bool aOldValue) {
|
||||
RecomputeCanExecuteScripts();
|
||||
}
|
||||
|
||||
|
||||
void BrowsingContext::RecomputeCanExecuteScripts() {
|
||||
const bool old = mCanExecuteScripts;
|
||||
if (!AllowJavascript()) {
|
||||
// Scripting has been explicitly disabled on our BrowsingContext.
|
||||
mCanExecuteScripts = false;
|
||||
} else if (GetParentWindowContext()) {
|
||||
// Otherwise, inherit parent.
|
||||
mCanExecuteScripts = GetParentWindowContext()->CanExecuteScripts();
|
||||
} else {
|
||||
// Otherwise, we're the root of the tree, and we haven't explicitly disabled
|
||||
// script. Allow.
|
||||
mCanExecuteScripts = true;
|
||||
}
|
||||
|
||||
if (old != mCanExecuteScripts) {
|
||||
for (WindowContext* wc : GetWindowContexts()) {
|
||||
wc->RecomputeCanExecuteScripts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BrowsingContext::InactiveForSuspend() const {
|
||||
if (!StaticPrefs::dom_suspend_inactive_enabled()) {
|
||||
return false;
|
||||
|
|
|
@ -200,7 +200,10 @@ enum class ExplicitActiveStatus : uint8_t {
|
|||
/* Don't use the getter of the field, but IsInBFCache() method */ \
|
||||
FIELD(IsInBFCache, bool) \
|
||||
FIELD(HasRestoreData, bool) \
|
||||
FIELD(SessionStoreEpoch, uint32_t)
|
||||
FIELD(SessionStoreEpoch, uint32_t) \
|
||||
/* Whether we can execute scripts in this BrowsingContext. Has no effect \
|
||||
* unless scripts are also allowed in the parent WindowContext. */ \
|
||||
FIELD(AllowJavascript, bool)
|
||||
|
||||
// BrowsingContext, in this context, is the cross process replicated
|
||||
// environment in which information about documents is stored. In
|
||||
|
@ -851,6 +854,9 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
|||
|
||||
bool IsInBFCache() const { return mIsInBFCache; }
|
||||
|
||||
bool AllowJavascript() const { return GetAllowJavascript(); }
|
||||
bool CanExecuteScripts() const { return mCanExecuteScripts; }
|
||||
|
||||
protected:
|
||||
virtual ~BrowsingContext();
|
||||
BrowsingContext(WindowContext* aParentWindow, BrowsingContextGroup* aGroup,
|
||||
|
@ -865,6 +871,12 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
|||
private:
|
||||
void Attach(bool aFromIPC, ContentParent* aOriginProcess);
|
||||
|
||||
// Recomputes whether we can execute scripts in this BrowsingContext based on
|
||||
// the value of AllowJavascript() and whether scripts are allowed in the
|
||||
// parent WindowContext. Called whenever the AllowJavascript() flag or the
|
||||
// parent WC changes.
|
||||
void RecomputeCanExecuteScripts();
|
||||
|
||||
// Find the special browsing context if aName is '_self', '_parent',
|
||||
// '_top', but not '_blank'. The latter is handled in FindWithName
|
||||
BrowsingContext* FindWithSpecialName(const nsAString& aName,
|
||||
|
@ -1069,6 +1081,10 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
|||
ContentParent* aSource);
|
||||
void DidSet(FieldIndex<IDX_HasMainMediaController>, bool aOldValue);
|
||||
|
||||
CanSetResult CanSet(FieldIndex<IDX_AllowJavascript>, bool aValue,
|
||||
ContentParent* aSource);
|
||||
void DidSet(FieldIndex<IDX_AllowJavascript>, bool aOldValue);
|
||||
|
||||
bool CanSet(FieldIndex<IDX_HasRestoreData>, bool aNewValue,
|
||||
ContentParent* aSource);
|
||||
|
||||
|
@ -1185,6 +1201,11 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
|||
// before dispatching pageshow.
|
||||
bool mIsInBFCache : 1;
|
||||
|
||||
// Determines if we can execute scripts in this BrowsingContext. True if
|
||||
// AllowJavascript() is true and script execution is allowed in the parent
|
||||
// WindowContext.
|
||||
bool mCanExecuteScripts : 1;
|
||||
|
||||
// The original offset of this context in its container. This property is -1
|
||||
// if this BrowsingContext is for a frame that was added dynamically.
|
||||
int32_t mChildOffset;
|
||||
|
|
|
@ -262,6 +262,44 @@ bool WindowContext::CanSet(FieldIndex<IDX_HadLazyLoadImage>, const bool& aValue,
|
|||
return IsTop();
|
||||
}
|
||||
|
||||
bool WindowContext::CanSet(FieldIndex<IDX_AllowJavascript>, bool aValue,
|
||||
ContentParent* aSource) {
|
||||
return (XRE_IsParentProcess() && !aSource) || CheckOnlyOwningProcessCanSet(aSource);
|
||||
}
|
||||
|
||||
void WindowContext::DidSet(FieldIndex<IDX_AllowJavascript>, bool aOldValue) {
|
||||
RecomputeCanExecuteScripts();
|
||||
}
|
||||
|
||||
void WindowContext::RecomputeCanExecuteScripts(bool aApplyChanges) {
|
||||
const bool old = mCanExecuteScripts;
|
||||
if (!AllowJavascript()) {
|
||||
// Scripting has been explicitly disabled on our WindowContext.
|
||||
mCanExecuteScripts = false;
|
||||
} else {
|
||||
// Otherwise, inherit.
|
||||
mCanExecuteScripts = mBrowsingContext->CanExecuteScripts();
|
||||
}
|
||||
|
||||
if (aApplyChanges && old != mCanExecuteScripts) {
|
||||
// Inform our active DOM window.
|
||||
if (nsGlobalWindowInner* window = GetInnerWindow()) {
|
||||
// Only update scriptability if the window is current. Windows will have
|
||||
// scriptability disabled when entering the bfcache and updated when
|
||||
// coming out.
|
||||
if (window->IsCurrentInnerWindow()) {
|
||||
auto& scriptability = xpc::Scriptability::Get(
|
||||
window->GetGlobalJSObject());
|
||||
scriptability.SetWindowAllowsScript(mCanExecuteScripts);
|
||||
}
|
||||
}
|
||||
|
||||
for (const RefPtr<BrowsingContext>& child : Children()) {
|
||||
child->RecomputeCanExecuteScripts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WindowContext::DidSet(FieldIndex<IDX_SHEntryHasUserInteraction>,
|
||||
bool aOldValue) {
|
||||
MOZ_ASSERT(
|
||||
|
@ -473,6 +511,7 @@ WindowContext::WindowContext(BrowsingContext* aBrowsingContext,
|
|||
MOZ_ASSERT(mBrowsingContext);
|
||||
MOZ_ASSERT(mInnerWindowId);
|
||||
MOZ_ASSERT(mOuterWindowId);
|
||||
RecomputeCanExecuteScripts(/* aApplyChanges */ false);
|
||||
}
|
||||
|
||||
WindowContext::~WindowContext() {
|
||||
|
|
|
@ -31,62 +31,65 @@ class WindowGlobalInit;
|
|||
class BrowsingContext;
|
||||
class BrowsingContextGroup;
|
||||
|
||||
#define MOZ_EACH_WC_FIELD(FIELD) \
|
||||
/* Whether the SHEntry associated with the current top-level \
|
||||
* window has already seen user interaction. \
|
||||
* As such, this will be reset to false when a new SHEntry is \
|
||||
* created without changing the WC (e.g. when using pushState or \
|
||||
* sub-frame navigation) \
|
||||
* This flag is set for optimization purposes, to avoid \
|
||||
* having to get the top SHEntry and update it on every \
|
||||
* user interaction. \
|
||||
* This is only meaningful on the top-level WC. */ \
|
||||
FIELD(SHEntryHasUserInteraction, bool) \
|
||||
FIELD(CookieBehavior, Maybe<uint32_t>) \
|
||||
FIELD(IsOnContentBlockingAllowList, bool) \
|
||||
/* Whether the given window hierarchy is third party. See \
|
||||
* ThirdPartyUtil::IsThirdPartyWindow for details */ \
|
||||
FIELD(IsThirdPartyWindow, bool) \
|
||||
/* Whether this window's channel has been marked as a third-party \
|
||||
* tracking resource */ \
|
||||
FIELD(IsThirdPartyTrackingResourceWindow, bool) \
|
||||
FIELD(IsSecureContext, bool) \
|
||||
FIELD(IsOriginalFrameSource, bool) \
|
||||
/* Mixed-Content: If the corresponding documentURI is https, \
|
||||
* then this flag is true. */ \
|
||||
FIELD(IsSecure, bool) \
|
||||
/* Whether the user has overriden the mixed content blocker to allow \
|
||||
* mixed content loads to happen */ \
|
||||
FIELD(AllowMixedContent, bool) \
|
||||
/* Whether this window has registered a "beforeunload" event \
|
||||
* handler */ \
|
||||
FIELD(HasBeforeUnload, bool) \
|
||||
/* Controls whether the WindowContext is currently considered to be \
|
||||
* activated by a gesture */ \
|
||||
FIELD(UserActivationState, UserActivation::State) \
|
||||
FIELD(EmbedderPolicy, nsILoadInfo::CrossOriginEmbedderPolicy) \
|
||||
/* True if this document tree contained at least a HTMLMediaElement. \
|
||||
* This should only be set on top level context. */ \
|
||||
FIELD(DocTreeHadMedia, bool) \
|
||||
FIELD(AutoplayPermission, uint32_t) \
|
||||
FIELD(ShortcutsPermission, uint32_t) \
|
||||
/* Store the Id of the browsing context where active media session \
|
||||
* exists on the top level window context */ \
|
||||
FIELD(ActiveMediaSessionContextId, Maybe<uint64_t>) \
|
||||
/* ALLOW_ACTION if it is allowed to open popups for the sub-tree \
|
||||
* starting and including the current WindowContext */ \
|
||||
FIELD(PopupPermission, uint32_t) \
|
||||
FIELD(DelegatedPermissions, \
|
||||
PermissionDelegateHandler::DelegatedPermissionList) \
|
||||
FIELD(DelegatedExactHostMatchPermissions, \
|
||||
PermissionDelegateHandler::DelegatedPermissionList) \
|
||||
FIELD(HasReportedShadowDOMUsage, bool) \
|
||||
/* Whether the principal of this window is for a local \
|
||||
* IP address */ \
|
||||
FIELD(IsLocalIP, bool) \
|
||||
/* Whether the corresponding document has `loading='lazy'` \
|
||||
* images; It won't become false if the image becomes non-lazy */ \
|
||||
FIELD(HadLazyLoadImage, bool)
|
||||
#define MOZ_EACH_WC_FIELD(FIELD) \
|
||||
/* Whether the SHEntry associated with the current top-level \
|
||||
* window has already seen user interaction. \
|
||||
* As such, this will be reset to false when a new SHEntry is \
|
||||
* created without changing the WC (e.g. when using pushState or \
|
||||
* sub-frame navigation) \
|
||||
* This flag is set for optimization purposes, to avoid \
|
||||
* having to get the top SHEntry and update it on every \
|
||||
* user interaction. \
|
||||
* This is only meaningful on the top-level WC. */ \
|
||||
FIELD(SHEntryHasUserInteraction, bool) \
|
||||
FIELD(CookieBehavior, Maybe<uint32_t>) \
|
||||
FIELD(IsOnContentBlockingAllowList, bool) \
|
||||
/* Whether the given window hierarchy is third party. See \
|
||||
* ThirdPartyUtil::IsThirdPartyWindow for details */ \
|
||||
FIELD(IsThirdPartyWindow, bool) \
|
||||
/* Whether this window's channel has been marked as a third-party \
|
||||
* tracking resource */ \
|
||||
FIELD(IsThirdPartyTrackingResourceWindow, bool) \
|
||||
FIELD(IsSecureContext, bool) \
|
||||
FIELD(IsOriginalFrameSource, bool) \
|
||||
/* Mixed-Content: If the corresponding documentURI is https, \
|
||||
* then this flag is true. */ \
|
||||
FIELD(IsSecure, bool) \
|
||||
/* Whether the user has overriden the mixed content blocker to allow \
|
||||
* mixed content loads to happen */ \
|
||||
FIELD(AllowMixedContent, bool) \
|
||||
/* Whether this window has registered a "beforeunload" event \
|
||||
* handler */ \
|
||||
FIELD(HasBeforeUnload, bool) \
|
||||
/* Controls whether the WindowContext is currently considered to be \
|
||||
* activated by a gesture */ \
|
||||
FIELD(UserActivationState, UserActivation::State) \
|
||||
FIELD(EmbedderPolicy, nsILoadInfo::CrossOriginEmbedderPolicy) \
|
||||
/* True if this document tree contained at least a HTMLMediaElement. \
|
||||
* This should only be set on top level context. */ \
|
||||
FIELD(DocTreeHadMedia, bool) \
|
||||
FIELD(AutoplayPermission, uint32_t) \
|
||||
FIELD(ShortcutsPermission, uint32_t) \
|
||||
/* Store the Id of the browsing context where active media session \
|
||||
* exists on the top level window context */ \
|
||||
FIELD(ActiveMediaSessionContextId, Maybe<uint64_t>) \
|
||||
/* ALLOW_ACTION if it is allowed to open popups for the sub-tree \
|
||||
* starting and including the current WindowContext */ \
|
||||
FIELD(PopupPermission, uint32_t) \
|
||||
FIELD(DelegatedPermissions, \
|
||||
PermissionDelegateHandler::DelegatedPermissionList) \
|
||||
FIELD(DelegatedExactHostMatchPermissions, \
|
||||
PermissionDelegateHandler::DelegatedPermissionList) \
|
||||
FIELD(HasReportedShadowDOMUsage, bool) \
|
||||
/* Whether the principal of this window is for a local \
|
||||
* IP address */ \
|
||||
FIELD(IsLocalIP, bool) \
|
||||
/* Whether the corresponding document has `loading='lazy'` \
|
||||
* images; It won't become false if the image becomes non-lazy */ \
|
||||
FIELD(HadLazyLoadImage, bool) \
|
||||
/* Whether we can execute scripts in this WindowContext. Has no effect \
|
||||
* unless scripts are also allowed in the BrowsingContext. */ \
|
||||
FIELD(AllowJavascript, bool)
|
||||
|
||||
class WindowContext : public nsISupports, public nsWrapperCache {
|
||||
MOZ_DECL_SYNCED_CONTEXT(WindowContext, MOZ_EACH_WC_FIELD)
|
||||
|
@ -182,6 +185,9 @@ class WindowContext : public nsISupports, public nsWrapperCache {
|
|||
|
||||
bool HadLazyLoadImage() const { return GetHadLazyLoadImage(); }
|
||||
|
||||
bool AllowJavascript() const { return GetAllowJavascript(); }
|
||||
bool CanExecuteScripts() const { return mCanExecuteScripts; }
|
||||
|
||||
protected:
|
||||
WindowContext(BrowsingContext* aBrowsingContext, uint64_t aInnerWindowId,
|
||||
uint64_t aOuterWindowId, FieldValues&& aFields);
|
||||
|
@ -271,6 +277,10 @@ class WindowContext : public nsISupports, public nsWrapperCache {
|
|||
bool CanSet(FieldIndex<IDX_HadLazyLoadImage>, const bool& aValue,
|
||||
ContentParent* aSource);
|
||||
|
||||
bool CanSet(FieldIndex<IDX_AllowJavascript>, bool aValue,
|
||||
ContentParent* aSource);
|
||||
void DidSet(FieldIndex<IDX_AllowJavascript>, bool aOldValue);
|
||||
|
||||
void DidSet(FieldIndex<IDX_HasReportedShadowDOMUsage>, bool aOldValue);
|
||||
|
||||
void DidSet(FieldIndex<IDX_SHEntryHasUserInteraction>, bool aOldValue);
|
||||
|
@ -284,6 +294,11 @@ class WindowContext : public nsISupports, public nsWrapperCache {
|
|||
void DidSet(FieldIndex<I>, T&& aOldValue) {}
|
||||
void DidSet(FieldIndex<IDX_UserActivationState>);
|
||||
|
||||
// Recomputes whether we can execute scripts in this WindowContext based on
|
||||
// the value of AllowJavascript() and whether scripts are allowed in the
|
||||
// BrowsingContext.
|
||||
void RecomputeCanExecuteScripts(bool aApplyChanges = true);
|
||||
|
||||
const uint64_t mInnerWindowId;
|
||||
const uint64_t mOuterWindowId;
|
||||
RefPtr<BrowsingContext> mBrowsingContext;
|
||||
|
@ -298,6 +313,11 @@ class WindowContext : public nsISupports, public nsWrapperCache {
|
|||
bool mIsDiscarded = false;
|
||||
bool mIsInProcess = false;
|
||||
|
||||
// Determines if we can execute scripts in this WindowContext. True if
|
||||
// AllowJavascript() is true and script execution is allowed in the
|
||||
// BrowsingContext.
|
||||
bool mCanExecuteScripts = true;
|
||||
|
||||
// The start time of user gesture, this is only available if the window
|
||||
// context is in process.
|
||||
TimeStamp mUserGestureStart;
|
||||
|
|
|
@ -393,7 +393,6 @@ nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext,
|
|||
#endif
|
||||
mInitialized(false),
|
||||
mAllowSubframes(true),
|
||||
mAllowJavascript(true),
|
||||
mAllowMetaRedirects(true),
|
||||
mAllowImages(true),
|
||||
mAllowMedia(true),
|
||||
|
@ -407,7 +406,6 @@ nsDocShell::nsDocShell(BrowsingContext* aBrowsingContext,
|
|||
mDeviceSizeIsPageSize(false),
|
||||
mWindowDraggingAllowed(false),
|
||||
mInFrameSwap(false),
|
||||
mCanExecuteScripts(false),
|
||||
mFiredUnloadEvent(false),
|
||||
mEODForCurrentDocument(false),
|
||||
mURIResultedInDocument(false),
|
||||
|
@ -1749,14 +1747,6 @@ nsDocShell::SetAllowPlugins(bool aAllowPlugins) {
|
|||
return mBrowsingContext->SetAllowPlugins(aAllowPlugins);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GetAllowJavascript(bool* aAllowJavascript) {
|
||||
NS_ENSURE_ARG_POINTER(aAllowJavascript);
|
||||
|
||||
*aAllowJavascript = mAllowJavascript;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GetCssErrorReportingEnabled(bool* aEnabled) {
|
||||
MOZ_ASSERT(aEnabled);
|
||||
|
@ -1770,13 +1760,6 @@ nsDocShell::SetCssErrorReportingEnabled(bool aEnabled) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::SetAllowJavascript(bool aAllowJavascript) {
|
||||
mAllowJavascript = aAllowJavascript;
|
||||
RecomputeCanExecuteScripts();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GetUsePrivateBrowsing(bool* aUsePrivateBrowsing) {
|
||||
NS_ENSURE_ARG_POINTER(aUsePrivateBrowsing);
|
||||
|
@ -2653,50 +2636,6 @@ Maybe<ClientInfo> nsDocShell::GetInitialClientInfo() const {
|
|||
return innerWindow->GetClientInfo();
|
||||
}
|
||||
|
||||
void nsDocShell::RecomputeCanExecuteScripts() {
|
||||
bool old = mCanExecuteScripts;
|
||||
RefPtr<nsDocShell> parent = GetInProcessParentDocshell();
|
||||
|
||||
// If we have no tree owner, that means that we've been detached from the
|
||||
// docshell tree (this is distinct from having no parent docshell, which
|
||||
// is the case for root docshells). It would be nice to simply disallow
|
||||
// script in detached docshells, but bug 986542 demonstrates that this
|
||||
// behavior breaks at least one website.
|
||||
//
|
||||
// So instead, we use our previous value, unless mAllowJavascript has been
|
||||
// explicitly set to false.
|
||||
if (!mTreeOwner) {
|
||||
mCanExecuteScripts = mCanExecuteScripts && mAllowJavascript;
|
||||
// If scripting has been explicitly disabled on our docshell, we're done.
|
||||
} else if (!mAllowJavascript) {
|
||||
mCanExecuteScripts = false;
|
||||
// If we have a parent, inherit.
|
||||
} else if (parent) {
|
||||
mCanExecuteScripts = parent->mCanExecuteScripts;
|
||||
// Otherwise, we're the root of the tree, and we haven't explicitly disabled
|
||||
// script. Allow.
|
||||
} else {
|
||||
mCanExecuteScripts = true;
|
||||
}
|
||||
|
||||
// Inform our active DOM window.
|
||||
//
|
||||
// This will pass the outer, which will be in the scope of the active inner.
|
||||
if (mScriptGlobal && mScriptGlobal->GetGlobalJSObject()) {
|
||||
xpc::Scriptability& scriptability =
|
||||
xpc::Scriptability::Get(mScriptGlobal->GetGlobalJSObject());
|
||||
scriptability.SetDocShellAllowsScript(mCanExecuteScripts);
|
||||
}
|
||||
|
||||
// If our value has changed, our children might be affected. Recompute their
|
||||
// value as well.
|
||||
if (old != mCanExecuteScripts) {
|
||||
for (auto* child : mChildList.ForwardRange()) {
|
||||
static_cast<nsDocShell*>(child)->RecomputeCanExecuteScripts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult nsDocShell::SetDocLoaderParent(nsDocLoader* aParent) {
|
||||
bool wasFrame = IsFrame();
|
||||
|
||||
|
@ -2717,10 +2656,6 @@ nsresult nsDocShell::SetDocLoaderParent(nsDocLoader* aParent) {
|
|||
nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(parent));
|
||||
|
||||
if (parentAsDocShell) {
|
||||
if (mAllowJavascript &&
|
||||
NS_SUCCEEDED(parentAsDocShell->GetAllowJavascript(&value))) {
|
||||
SetAllowJavascript(value);
|
||||
}
|
||||
if (mAllowMetaRedirects &&
|
||||
NS_SUCCEEDED(parentAsDocShell->GetAllowMetaRedirects(&value))) {
|
||||
SetAllowMetaRedirects(value);
|
||||
|
@ -2755,9 +2690,6 @@ nsresult nsDocShell::SetDocLoaderParent(nsDocLoader* aParent) {
|
|||
mContentListener->SetParentContentListener(parentURIListener);
|
||||
}
|
||||
|
||||
// Our parent has changed. Recompute scriptability.
|
||||
RecomputeCanExecuteScripts();
|
||||
|
||||
// Inform windows when they're being removed from their parent.
|
||||
if (!aParent) {
|
||||
MaybeClearStorageAccessFlag();
|
||||
|
@ -2982,16 +2914,6 @@ nsDocShell::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner) {
|
|||
}
|
||||
}
|
||||
|
||||
// Our tree owner has changed. Recompute scriptability.
|
||||
//
|
||||
// Note that this is near-redundant with the recomputation in
|
||||
// SetDocLoaderParent(), but not so for the root DocShell, where the call to
|
||||
// SetTreeOwner() happens after the initial AddDocLoaderAsChildOfRoot(),
|
||||
// and we never set another parent. Given that this is neither expensive nor
|
||||
// performance-critical, let's be safe and unconditionally recompute this
|
||||
// state whenever dependent state changes.
|
||||
RecomputeCanExecuteScripts();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -7658,9 +7580,6 @@ nsresult nsDocShell::RestoreFromHistory() {
|
|||
|
||||
// Make sure to not clobber the state of the child. Since AddChild
|
||||
// always clobbers it, save it off first.
|
||||
bool allowJavascript;
|
||||
childShell->GetAllowJavascript(&allowJavascript);
|
||||
|
||||
bool allowRedirects;
|
||||
childShell->GetAllowMetaRedirects(&allowRedirects);
|
||||
|
||||
|
@ -7684,7 +7603,6 @@ nsresult nsDocShell::RestoreFromHistory() {
|
|||
// child inherits our mPrivateBrowsingId, which is what we want.
|
||||
AddChild(childItem);
|
||||
|
||||
childShell->SetAllowJavascript(allowJavascript);
|
||||
childShell->SetAllowMetaRedirects(allowRedirects);
|
||||
childShell->SetAllowSubframes(allowSubframes);
|
||||
childShell->SetAllowImages(allowImages);
|
||||
|
@ -13091,12 +13009,6 @@ NS_IMETHODIMP nsDocShell::ExitPrintPreview() {
|
|||
#endif
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GetCanExecuteScripts(bool* aResult) {
|
||||
*aResult = mCanExecuteScripts;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* [infallible] */
|
||||
NS_IMETHODIMP nsDocShell::GetIsTopLevelContentDocShell(
|
||||
bool* aIsTopLevelContentDocShell) {
|
||||
|
|
|
@ -952,7 +952,6 @@ class nsDocShell final : public nsDocLoader,
|
|||
void SetupReferrerInfoFromChannel(nsIChannel* aChannel);
|
||||
void SetReferrerInfo(nsIReferrerInfo* aReferrerInfo);
|
||||
void ReattachEditorToWindow(nsISHEntry* aSHEntry);
|
||||
void RecomputeCanExecuteScripts();
|
||||
void ClearFrameHistory(nsISHEntry* aEntry);
|
||||
// Determine if this type of load should update history.
|
||||
static bool ShouldUpdateGlobalHistory(uint32_t aLoadType);
|
||||
|
@ -1245,7 +1244,6 @@ class nsDocShell final : public nsDocLoader,
|
|||
|
||||
bool mInitialized : 1;
|
||||
bool mAllowSubframes : 1;
|
||||
bool mAllowJavascript : 1;
|
||||
bool mAllowMetaRedirects : 1;
|
||||
bool mAllowImages : 1;
|
||||
bool mAllowMedia : 1;
|
||||
|
@ -1260,11 +1258,6 @@ class nsDocShell final : public nsDocLoader,
|
|||
bool mWindowDraggingAllowed : 1;
|
||||
bool mInFrameSwap : 1;
|
||||
|
||||
// Because scriptability depends on the mAllowJavascript values of our
|
||||
// ancestors, we cache the effective scriptability and recompute it when
|
||||
// it might have changed;
|
||||
bool mCanExecuteScripts : 1;
|
||||
|
||||
// This boolean is set to true right before we fire pagehide and generally
|
||||
// unset when we embed a new content viewer. While it's true no navigation
|
||||
// is allowed in this docshell.
|
||||
|
|
|
@ -192,11 +192,6 @@ interface nsIDocShell : nsIDocShellTreeItem
|
|||
*/
|
||||
attribute boolean allowPlugins;
|
||||
|
||||
/**
|
||||
* Whether to allow Javascript execution
|
||||
*/
|
||||
attribute boolean allowJavascript;
|
||||
|
||||
/**
|
||||
* Attribute stating if refresh based redirects can be allowed
|
||||
*/
|
||||
|
@ -468,13 +463,6 @@ interface nsIDocShell : nsIDocShellTreeItem
|
|||
*/
|
||||
void exitPrintPreview();
|
||||
|
||||
/**
|
||||
* Whether this docshell can execute scripts based on its hierarchy.
|
||||
* The rule of thumb here is that we disable js if this docshell or any
|
||||
* of its parents disallow scripting.
|
||||
*/
|
||||
[infallible] readonly attribute boolean canExecuteScripts;
|
||||
|
||||
/**
|
||||
* The ID of the docshell in the session history.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
"use strict";
|
||||
var EXPORTED_SYMBOLS = ["AllowJavascriptChild"];
|
||||
|
||||
class AllowJavascriptChild extends JSWindowActorChild {
|
||||
async receiveMessage(msg) {
|
||||
switch (msg.name) {
|
||||
case "CheckScriptsAllowed":
|
||||
return this.checkScriptsAllowed();
|
||||
case "CheckFiredLoadEvent":
|
||||
return this.contentWindow.wrappedJSObject.gFiredOnload;
|
||||
case "CreateIframe":
|
||||
return this.createIframe(msg.data.url);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
handleEvent(event) {
|
||||
if (event.type === "load") {
|
||||
this.sendAsyncMessage("LoadFired");
|
||||
}
|
||||
}
|
||||
|
||||
checkScriptsAllowed() {
|
||||
let win = this.contentWindow;
|
||||
|
||||
win.wrappedJSObject.gFiredOnclick = false;
|
||||
win.document.body.click();
|
||||
return win.wrappedJSObject.gFiredOnclick;
|
||||
}
|
||||
|
||||
async createIframe(url) {
|
||||
let doc = this.contentWindow.document;
|
||||
|
||||
let iframe = doc.createElement("iframe");
|
||||
iframe.src = url;
|
||||
doc.body.appendChild(iframe);
|
||||
|
||||
await new Promise(resolve => {
|
||||
iframe.addEventListener("load", resolve, { once: true });
|
||||
});
|
||||
|
||||
return iframe.browsingContext;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
"use strict";
|
||||
var EXPORTED_SYMBOLS = ["AllowJavascriptParent"];
|
||||
|
||||
let loadPromises = new WeakMap();
|
||||
|
||||
class AllowJavascriptParent extends JSWindowActorParent {
|
||||
async receiveMessage(msg) {
|
||||
switch (msg.name) {
|
||||
case "LoadFired":
|
||||
let bc = this.browsingContext;
|
||||
let deferred = loadPromises.get(bc);
|
||||
if (deferred) {
|
||||
loadPromises.delete(bc);
|
||||
deferred.resolve(this);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static promiseLoad(bc) {
|
||||
let deferred = loadPromises.get(bc);
|
||||
if (!deferred) {
|
||||
deferred = {};
|
||||
deferred.promise = new Promise(resolve => {
|
||||
deferred.resolve = resolve;
|
||||
});
|
||||
loadPromises.set(bc, deferred);
|
||||
}
|
||||
return deferred.promise;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,269 @@
|
|||
"use strict";
|
||||
|
||||
const { XPCShellContentUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/XPCShellContentUtils.jsm"
|
||||
);
|
||||
|
||||
XPCShellContentUtils.init(this);
|
||||
|
||||
const ACTOR = "AllowJavascript";
|
||||
|
||||
const HTML = String.raw`<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<script type="application/javascript">
|
||||
"use strict";
|
||||
var gFiredOnload = false;
|
||||
var gFiredOnclick = false;
|
||||
</script>
|
||||
</head>
|
||||
<body onload="gFiredOnload = true;" onclick="gFiredOnclick = true;">
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
const server = XPCShellContentUtils.createHttpServer({
|
||||
hosts: ["example.com", "example.org"],
|
||||
});
|
||||
|
||||
server.registerPathHandler("/", (request, response) => {
|
||||
response.setHeader("Content-Type", "text/html");
|
||||
response.write(HTML);
|
||||
});
|
||||
|
||||
function getResourceURI(file) {
|
||||
return Services.io.newFileURI(do_get_file(file)).spec;
|
||||
}
|
||||
|
||||
const { AllowJavascriptParent } = ChromeUtils.import(
|
||||
getResourceURI("AllowJavascriptParent.jsm")
|
||||
);
|
||||
|
||||
async function assertScriptsAllowed(bc, expectAllowed, desc) {
|
||||
let actor = bc.currentWindowGlobal.getActor(ACTOR);
|
||||
let allowed = await actor.sendQuery("CheckScriptsAllowed");
|
||||
equal(
|
||||
allowed,
|
||||
expectAllowed,
|
||||
`Scripts should be ${expectAllowed ? "" : "dis"}allowed for ${desc}`
|
||||
);
|
||||
}
|
||||
|
||||
async function assertLoadFired(bc, expectFired, desc) {
|
||||
let actor = bc.currentWindowGlobal.getActor(ACTOR);
|
||||
let fired = await actor.sendQuery("CheckFiredLoadEvent");
|
||||
equal(
|
||||
fired,
|
||||
expectFired,
|
||||
`Should ${expectFired ? "" : "not "}have fired load for ${desc}`
|
||||
);
|
||||
}
|
||||
|
||||
function createSubframe(bc, url) {
|
||||
let actor = bc.currentWindowGlobal.getActor(ACTOR);
|
||||
return actor.sendQuery("CreateIframe", { url });
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
ChromeUtils.registerWindowActor(ACTOR, {
|
||||
allFrames: true,
|
||||
child: {
|
||||
moduleURI: getResourceURI("AllowJavascriptChild.jsm"),
|
||||
events: { load: { capture: true } },
|
||||
},
|
||||
parent: {
|
||||
moduleURI: getResourceURI("AllowJavascriptParent.jsm"),
|
||||
},
|
||||
});
|
||||
|
||||
let page = await XPCShellContentUtils.loadContentPage("http://example.com/", {
|
||||
remote: true,
|
||||
remoteSubframes: true,
|
||||
});
|
||||
|
||||
let bc = page.browsingContext;
|
||||
|
||||
{
|
||||
let oopFrame1 = await createSubframe(bc, "http://example.org/");
|
||||
let inprocFrame1 = await createSubframe(bc, "http://example.com/");
|
||||
|
||||
let oopFrame1OopSub = await createSubframe(
|
||||
oopFrame1,
|
||||
"http://example.com/"
|
||||
);
|
||||
let inprocFrame1OopSub = await createSubframe(
|
||||
inprocFrame1,
|
||||
"http://example.org/"
|
||||
);
|
||||
|
||||
equal(
|
||||
oopFrame1.allowJavascript,
|
||||
true,
|
||||
"OOP BC should inherit allowJavascript from parent"
|
||||
);
|
||||
equal(
|
||||
inprocFrame1.allowJavascript,
|
||||
true,
|
||||
"In-process BC should inherit allowJavascript from parent"
|
||||
);
|
||||
equal(
|
||||
oopFrame1OopSub.allowJavascript,
|
||||
true,
|
||||
"OOP BC child should inherit allowJavascript from parent"
|
||||
);
|
||||
equal(
|
||||
inprocFrame1OopSub.allowJavascript,
|
||||
true,
|
||||
"In-process child BC should inherit allowJavascript from parent"
|
||||
);
|
||||
|
||||
await assertLoadFired(bc, true, "top BC");
|
||||
await assertScriptsAllowed(bc, true, "top BC");
|
||||
|
||||
await assertLoadFired(oopFrame1, true, "OOP frame 1");
|
||||
await assertScriptsAllowed(oopFrame1, true, "OOP frame 1");
|
||||
|
||||
await assertLoadFired(inprocFrame1, true, "In-process frame 1");
|
||||
await assertScriptsAllowed(inprocFrame1, true, "In-process frame 1");
|
||||
|
||||
await assertLoadFired(oopFrame1OopSub, true, "OOP frame 1 subframe");
|
||||
await assertScriptsAllowed(oopFrame1OopSub, true, "OOP frame 1 subframe");
|
||||
|
||||
await assertLoadFired(
|
||||
inprocFrame1OopSub,
|
||||
true,
|
||||
"In-process frame 1 subframe"
|
||||
);
|
||||
await assertScriptsAllowed(
|
||||
inprocFrame1OopSub,
|
||||
true,
|
||||
"In-process frame 1 subframe"
|
||||
);
|
||||
|
||||
bc.allowJavascript = false;
|
||||
await assertScriptsAllowed(bc, false, "top BC with scripts disallowed");
|
||||
await assertScriptsAllowed(
|
||||
oopFrame1,
|
||||
false,
|
||||
"OOP frame 1 with top BC with scripts disallowed"
|
||||
);
|
||||
await assertScriptsAllowed(
|
||||
inprocFrame1,
|
||||
false,
|
||||
"In-process frame 1 with top BC with scripts disallowed"
|
||||
);
|
||||
await assertScriptsAllowed(
|
||||
oopFrame1OopSub,
|
||||
false,
|
||||
"OOP frame 1 subframe with top BC with scripts disallowed"
|
||||
);
|
||||
await assertScriptsAllowed(
|
||||
inprocFrame1OopSub,
|
||||
false,
|
||||
"In-process frame 1 subframe with top BC with scripts disallowed"
|
||||
);
|
||||
|
||||
let oopFrame2 = await createSubframe(bc, "http://example.org/");
|
||||
let inprocFrame2 = await createSubframe(bc, "http://example.com/");
|
||||
|
||||
equal(
|
||||
oopFrame2.allowJavascript,
|
||||
false,
|
||||
"OOP BC 2 should inherit allowJavascript from parent"
|
||||
);
|
||||
equal(
|
||||
inprocFrame2.allowJavascript,
|
||||
false,
|
||||
"In-process BC 2 should inherit allowJavascript from parent"
|
||||
);
|
||||
|
||||
await assertLoadFired(
|
||||
oopFrame2,
|
||||
undefined,
|
||||
"OOP frame 2 with top BC with scripts disallowed"
|
||||
);
|
||||
await assertScriptsAllowed(
|
||||
oopFrame2,
|
||||
false,
|
||||
"OOP frame 2 with top BC with scripts disallowed"
|
||||
);
|
||||
await assertLoadFired(
|
||||
inprocFrame2,
|
||||
undefined,
|
||||
"In-process frame 2 with top BC with scripts disallowed"
|
||||
);
|
||||
await assertScriptsAllowed(
|
||||
inprocFrame2,
|
||||
false,
|
||||
"In-process frame 2 with top BC with scripts disallowed"
|
||||
);
|
||||
|
||||
bc.allowJavascript = true;
|
||||
await assertScriptsAllowed(bc, true, "top BC");
|
||||
|
||||
await assertScriptsAllowed(oopFrame1, true, "OOP frame 1");
|
||||
await assertScriptsAllowed(inprocFrame1, true, "In-process frame 1");
|
||||
await assertScriptsAllowed(oopFrame1OopSub, true, "OOP frame 1 subframe");
|
||||
await assertScriptsAllowed(
|
||||
inprocFrame1OopSub,
|
||||
true,
|
||||
"In-process frame 1 subframe"
|
||||
);
|
||||
|
||||
await assertScriptsAllowed(oopFrame2, false, "OOP frame 2");
|
||||
await assertScriptsAllowed(inprocFrame2, false, "In-process frame 2");
|
||||
|
||||
oopFrame1.currentWindowGlobal.allowJavascript = false;
|
||||
inprocFrame1.currentWindowGlobal.allowJavascript = false;
|
||||
|
||||
await assertScriptsAllowed(
|
||||
oopFrame1,
|
||||
false,
|
||||
"OOP frame 1 with second level WC scripts disallowed"
|
||||
);
|
||||
await assertScriptsAllowed(
|
||||
inprocFrame1,
|
||||
false,
|
||||
"In-process frame 1 with second level WC scripts disallowed"
|
||||
);
|
||||
await assertScriptsAllowed(
|
||||
oopFrame1OopSub,
|
||||
false,
|
||||
"OOP frame 1 subframe second level WC scripts disallowed"
|
||||
);
|
||||
await assertScriptsAllowed(
|
||||
inprocFrame1OopSub,
|
||||
false,
|
||||
"In-process frame 1 subframe with second level WC scripts disallowed"
|
||||
);
|
||||
|
||||
oopFrame1.reload(0);
|
||||
inprocFrame1.reload(0);
|
||||
await AllowJavascriptParent.promiseLoad(oopFrame1);
|
||||
await AllowJavascriptParent.promiseLoad(inprocFrame1);
|
||||
|
||||
equal(
|
||||
oopFrame1.currentWindowGlobal.allowJavascript,
|
||||
true,
|
||||
"WindowContext.allowJavascript does not persist after navigation for OOP frame 1"
|
||||
);
|
||||
equal(
|
||||
inprocFrame1.currentWindowGlobal.allowJavascript,
|
||||
true,
|
||||
"WindowContext.allowJavascript does not persist after navigation for in-process frame 1"
|
||||
);
|
||||
|
||||
await assertScriptsAllowed(oopFrame1, true, "OOP frame 1");
|
||||
await assertScriptsAllowed(inprocFrame1, true, "In-process frame 1");
|
||||
}
|
||||
|
||||
bc.allowJavascript = false;
|
||||
|
||||
bc.reload(0);
|
||||
await AllowJavascriptParent.promiseLoad(bc);
|
||||
|
||||
await assertLoadFired(bc, undefined, "top BC with scripts disabled");
|
||||
await assertScriptsAllowed(bc, false, "top BC with scripts disabled");
|
||||
|
||||
await page.close();
|
||||
});
|
|
@ -1,6 +1,11 @@
|
|||
[DEFAULT]
|
||||
head = head_docshell.js
|
||||
|
||||
[test_allowJavascript.js]
|
||||
skip-if = os == 'android'
|
||||
support-files =
|
||||
AllowJavascriptChild.jsm
|
||||
AllowJavascriptParent.jsm
|
||||
[test_bug442584.js]
|
||||
[test_browsing_context_structured_clone.js]
|
||||
[test_URIFixup.js]
|
||||
|
|
|
@ -1847,7 +1847,7 @@ WindowStateHolder::WindowStateHolder(nsGlobalWindowInner* aWindow)
|
|||
aWindow->Suspend();
|
||||
|
||||
// When a global goes into the bfcache, we disable script.
|
||||
xpc::Scriptability::Get(mInnerWindowReflector).SetDocShellAllowsScript(false);
|
||||
xpc::Scriptability::Get(mInnerWindowReflector).SetWindowAllowsScript(false);
|
||||
}
|
||||
|
||||
WindowStateHolder::~WindowStateHolder() {
|
||||
|
@ -2331,10 +2331,11 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument,
|
|||
mBrowsingContext->SetWindowProxy(outer);
|
||||
}
|
||||
|
||||
// Set scriptability based on the state of the docshell.
|
||||
bool allow = GetDocShell()->GetCanExecuteScripts();
|
||||
// Set scriptability based on the state of the WindowContext.
|
||||
WindowContext* wc = mInnerWindow->GetWindowContext();
|
||||
bool allow = wc ? wc->CanExecuteScripts() : mBrowsingContext->CanExecuteScripts();
|
||||
xpc::Scriptability::Get(GetWrapperPreserveColor())
|
||||
.SetDocShellAllowsScript(allow);
|
||||
.SetWindowAllowsScript(allow);
|
||||
|
||||
if (!aState) {
|
||||
// Get the "window" property once so it will be cached on our inner. We
|
||||
|
|
|
@ -193,6 +193,16 @@ interface BrowsingContext {
|
|||
*/
|
||||
readonly attribute TouchEventsOverride touchEventsOverride;
|
||||
|
||||
/**
|
||||
* Partially determines whether script execution is allowed in this
|
||||
* BrowsingContext. Script execution will be permitted only if this
|
||||
* attribute is true and script execution is allowed in the parent
|
||||
* WindowContext.
|
||||
*
|
||||
* May only be set in the parent process.
|
||||
*/
|
||||
[SetterThrows] attribute boolean allowJavascript;
|
||||
|
||||
/**
|
||||
* The nsID of the browsing context in the session history.
|
||||
*/
|
||||
|
|
|
@ -29,6 +29,16 @@ interface WindowContext {
|
|||
// True if the corresponding document has `loading='lazy'` images;
|
||||
// It won't become false if the image becomes non-lazy.
|
||||
readonly attribute boolean hadLazyLoadImage;
|
||||
|
||||
/**
|
||||
* Partially determines whether script execution is allowed in this
|
||||
* BrowsingContext. Script execution will be permitted only if this
|
||||
* attribute is true and script execution is allowed in the owner
|
||||
* BrowsingContext.
|
||||
*
|
||||
* May only be set in the context's owning process.
|
||||
*/
|
||||
[SetterThrows] attribute boolean allowJavascript;
|
||||
};
|
||||
|
||||
// Keep this in sync with nsIContentViewer::PermitUnloadAction.
|
||||
|
|
|
@ -56,6 +56,7 @@ WindowGlobalInit WindowGlobalActor::BaseInitializer(
|
|||
auto& fields = ctx.mFields;
|
||||
fields.mEmbedderPolicy = InheritedPolicy(aBrowsingContext);
|
||||
fields.mAutoplayPermission = nsIPermissionManager::UNKNOWN_ACTION;
|
||||
fields.mAllowJavascript = true;
|
||||
return init;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "nsStringFwd.h" // for nsString
|
||||
#include "mozilla/dom/BrowsingContext.h" // for BrowsingContext
|
||||
#include "mozilla/dom/Selection.h" // for AutoHideSelectionChanges, etc
|
||||
#include "mozilla/dom/WindowContext.h" // for WindowContext
|
||||
#include "nsFrameSelection.h" // for nsFrameSelection
|
||||
#include "nsBaseCommandController.h" // for nsBaseCommandController
|
||||
#include "mozilla/dom/LoadURIOptionsBinding.h"
|
||||
|
@ -120,7 +121,7 @@ nsEditingSession::MakeWindowEditable(mozIDOMWindowProxy* aWindow,
|
|||
|
||||
nsresult rv;
|
||||
if (!mInteractive) {
|
||||
rv = DisableJSAndPlugins(*docShell);
|
||||
rv = DisableJSAndPlugins(window->GetCurrentInnerWindow());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
|
@ -172,28 +173,25 @@ nsEditingSession::MakeWindowEditable(mozIDOMWindowProxy* aWindow,
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsresult nsEditingSession::DisableJSAndPlugins(nsIDocShell& aDocShell) {
|
||||
bool tmp;
|
||||
nsresult rv = aDocShell.GetAllowJavascript(&tmp);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsresult nsEditingSession::DisableJSAndPlugins(nsPIDOMWindowInner* aWindow) {
|
||||
WindowContext* wc = aWindow->GetWindowContext();
|
||||
BrowsingContext* bc = wc->GetBrowsingContext();
|
||||
|
||||
mScriptsEnabled = tmp;
|
||||
mScriptsEnabled = wc->GetAllowJavascript();
|
||||
|
||||
rv = aDocShell.SetAllowJavascript(false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
MOZ_TRY(wc->SetAllowJavascript(false));
|
||||
|
||||
// Disable plugins in this document:
|
||||
mPluginsEnabled = aDocShell.PluginsAllowedInCurrentDoc();
|
||||
mPluginsEnabled = bc->GetAllowPlugins();
|
||||
|
||||
rv = aDocShell.GetBrowsingContext()->SetAllowPlugins(false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
MOZ_TRY(bc->SetAllowPlugins(false));
|
||||
|
||||
mDisabledJSAndPlugins = true;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsEditingSession::RestoreJSAndPlugins(nsPIDOMWindowOuter* aWindow) {
|
||||
nsresult nsEditingSession::RestoreJSAndPlugins(nsPIDOMWindowInner* aWindow) {
|
||||
if (!mDisabledJSAndPlugins) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -204,17 +202,15 @@ nsresult nsEditingSession::RestoreJSAndPlugins(nsPIDOMWindowOuter* aWindow) {
|
|||
// DetachFromWindow may call this method with nullptr.
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsIDocShell* docShell = aWindow->GetDocShell();
|
||||
NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
|
||||
|
||||
nsresult rv = docShell->SetAllowJavascript(mScriptsEnabled);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
WindowContext* wc = aWindow->GetWindowContext();
|
||||
BrowsingContext* bc = wc->GetBrowsingContext();
|
||||
|
||||
MOZ_TRY(wc->SetAllowJavascript(mScriptsEnabled));
|
||||
|
||||
// Disable plugins in this document:
|
||||
auto* browsingContext = aWindow->GetBrowsingContext();
|
||||
NS_ENSURE_TRUE(browsingContext, NS_ERROR_FAILURE);
|
||||
|
||||
return browsingContext->SetAllowPlugins(mPluginsEnabled);
|
||||
return bc->SetAllowPlugins(mPluginsEnabled);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
|
@ -510,7 +506,7 @@ nsEditingSession::TearDownEditorOnWindow(mozIDOMWindowProxy* aWindow) {
|
|||
|
||||
if (stopEditing) {
|
||||
// Make things the way they were before we started editing.
|
||||
RestoreJSAndPlugins(window);
|
||||
RestoreJSAndPlugins(window->GetCurrentInnerWindow());
|
||||
RestoreAnimationMode(window);
|
||||
|
||||
if (mMakeWholeDocumentEditable) {
|
||||
|
@ -1192,7 +1188,7 @@ nsresult nsEditingSession::DetachFromWindow(nsPIDOMWindowOuter* aWindow) {
|
|||
// make things the way they were before we started editing.
|
||||
RemoveEditorControllers(aWindow);
|
||||
RemoveWebProgressListener(aWindow);
|
||||
RestoreJSAndPlugins(aWindow);
|
||||
RestoreJSAndPlugins(aWindow->GetCurrentInnerWindow());
|
||||
RestoreAnimationMode(aWindow);
|
||||
|
||||
// Kill our weak reference to our original window, in case
|
||||
|
@ -1219,7 +1215,7 @@ nsresult nsEditingSession::ReattachToWindow(nsPIDOMWindowOuter* aWindow) {
|
|||
|
||||
// Disable plugins.
|
||||
if (!mInteractive) {
|
||||
rv = DisableJSAndPlugins(*docShell);
|
||||
rv = DisableJSAndPlugins(aWindow->GetCurrentInnerWindow());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,8 @@ class nsIChannel;
|
|||
class nsIControllers;
|
||||
class nsIDocShell;
|
||||
class nsIWebProgress;
|
||||
class nsIPIDOMWindowOuter;
|
||||
class nsIPIDOMWindowInner;
|
||||
|
||||
namespace mozilla {
|
||||
class ComposerCommandsUpdater;
|
||||
|
@ -113,13 +115,13 @@ class nsEditingSession final : public nsIEditingSession,
|
|||
/**
|
||||
* Disable scripts and plugins in aDocShell.
|
||||
*/
|
||||
nsresult DisableJSAndPlugins(nsIDocShell& aDocShell);
|
||||
nsresult DisableJSAndPlugins(nsPIDOMWindowInner* aWindow);
|
||||
|
||||
/**
|
||||
* Restore JS and plugins (enable/disable them) according to the state they
|
||||
* were before the last call to disableJSAndPlugins.
|
||||
*/
|
||||
nsresult RestoreJSAndPlugins(nsPIDOMWindowOuter* aWindow);
|
||||
nsresult RestoreJSAndPlugins(nsPIDOMWindowInner* aWindow);
|
||||
|
||||
protected:
|
||||
bool mDoneSetup; // have we prepared for editing yet?
|
||||
|
|
|
@ -22,7 +22,7 @@ var iframe = document.getElementById("load-frame");
|
|||
function enableJS() { allowJS(true, iframe); }
|
||||
function disableJS() { allowJS(false, iframe); }
|
||||
function allowJS(allow, frame) {
|
||||
SpecialPowers.wrap(frame.contentWindow).docShell.allowJavascript = allow;
|
||||
SpecialPowers.wrap(frame.contentWindow).windowGlobalChild.windowContext.allowJavascript = allow;
|
||||
}
|
||||
|
||||
function expectJSAllowed(allowed, testCondition, callback) {
|
||||
|
|
|
@ -456,7 +456,7 @@ void NukeJSStackFrames(JS::Realm* aRealm) {
|
|||
|
||||
Scriptability::Scriptability(JS::Realm* realm)
|
||||
: mScriptBlocks(0),
|
||||
mDocShellAllowsScript(true),
|
||||
mWindowAllowsScript(true),
|
||||
mScriptBlockedByPolicy(false) {
|
||||
nsIPrincipal* prin = nsJSPrincipals::get(JS::GetRealmPrincipals(realm));
|
||||
|
||||
|
@ -477,7 +477,7 @@ Scriptability::Scriptability(JS::Realm* realm)
|
|||
}
|
||||
|
||||
bool Scriptability::Allowed() {
|
||||
return mDocShellAllowsScript && !mScriptBlockedByPolicy && mScriptBlocks == 0;
|
||||
return mWindowAllowsScript && !mScriptBlockedByPolicy && mScriptBlocks == 0;
|
||||
}
|
||||
|
||||
bool Scriptability::IsImmuneToScriptPolicy() { return mImmuneToScriptPolicy; }
|
||||
|
@ -489,8 +489,8 @@ void Scriptability::Unblock() {
|
|||
--mScriptBlocks;
|
||||
}
|
||||
|
||||
void Scriptability::SetDocShellAllowsScript(bool aAllowed) {
|
||||
mDocShellAllowsScript = aAllowed || mImmuneToScriptPolicy;
|
||||
void Scriptability::SetWindowAllowsScript(bool aAllowed) {
|
||||
mWindowAllowsScript = aAllowed || mImmuneToScriptPolicy;
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
|
|
@ -81,7 +81,7 @@ class Scriptability {
|
|||
|
||||
void Block();
|
||||
void Unblock();
|
||||
void SetDocShellAllowsScript(bool aAllowed);
|
||||
void SetWindowAllowsScript(bool aAllowed);
|
||||
|
||||
static Scriptability& Get(JSObject* aScope);
|
||||
|
||||
|
@ -92,9 +92,9 @@ class Scriptability {
|
|||
// Script may not run if this value is non-zero.
|
||||
uint32_t mScriptBlocks;
|
||||
|
||||
// Whether the docshell allows javascript in this scope. If this scope
|
||||
// doesn't have a docshell, this value is always true.
|
||||
bool mDocShellAllowsScript;
|
||||
// Whether the DOM window allows javascript in this scope. If this scope
|
||||
// doesn't have a window, this value is always true.
|
||||
bool mWindowAllowsScript;
|
||||
|
||||
// Whether this scope is immune to user-defined or addon-defined script
|
||||
// policy.
|
||||
|
|
|
@ -28,7 +28,6 @@ class GeckoViewSettingsChild extends GeckoViewActorChild {
|
|||
case "SettingsUpdate": {
|
||||
const settings = message.data;
|
||||
|
||||
this.allowJavascript = settings.allowJavascript;
|
||||
this.viewportMode = settings.viewportMode;
|
||||
if (settings.isPopup) {
|
||||
// Allow web extensions to close their own action popups (bz1612363)
|
||||
|
@ -38,14 +37,6 @@ class GeckoViewSettingsChild extends GeckoViewActorChild {
|
|||
}
|
||||
}
|
||||
|
||||
get allowJavascript() {
|
||||
return this.docShell.allowJavascript;
|
||||
}
|
||||
|
||||
set allowJavascript(aAllowJavascript) {
|
||||
this.docShell.allowJavascript = aAllowJavascript;
|
||||
}
|
||||
|
||||
set viewportMode(aMode) {
|
||||
const { windowUtils } = this.contentWindow;
|
||||
if (aMode === windowUtils.desktopModeViewport) {
|
||||
|
|
|
@ -88,6 +88,14 @@ class GeckoViewSettings extends GeckoViewModule {
|
|||
);
|
||||
}
|
||||
|
||||
get allowJavascript() {
|
||||
return this.browsingContext.allowJavascript;
|
||||
}
|
||||
|
||||
set allowJavascript(aAllowJavascript) {
|
||||
this.browsingContext.allowJavascript = aAllowJavascript;
|
||||
}
|
||||
|
||||
get customUserAgent() {
|
||||
if (this.userAgentOverride !== null) {
|
||||
return this.userAgentOverride;
|
||||
|
|
|
@ -111,7 +111,7 @@ async function starttest(){
|
|||
|
||||
// Play with the window object.
|
||||
var docShell = SpecialPowers.wrap(window).docShell;
|
||||
ok(docShell.allowJavascript, "Able to pull properties off of docshell!");
|
||||
ok(docShell.browsingContext, "Able to pull properties off of docshell!");
|
||||
|
||||
// Make sure Xray-wrapped functions work.
|
||||
try {
|
||||
|
|
|
@ -230,6 +230,10 @@ class ContentPage {
|
|||
return browser;
|
||||
}
|
||||
|
||||
get browsingContext() {
|
||||
return this.browser.browsingContext;
|
||||
}
|
||||
|
||||
sendMessage(msg, data) {
|
||||
return MessageChannel.sendMessage(this.browser.messageManager, msg, data);
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "nsIFormControl.h"
|
||||
#include "nsIScrollableFrame.h"
|
||||
#include "nsISHistory.h"
|
||||
#include "nsIXULRuntime.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
|
@ -222,7 +223,6 @@ void SessionStoreUtils::CollectDocShellCapabilities(const GlobalObject& aGlobal,
|
|||
void SessionStoreUtils::RestoreDocShellCapabilities(
|
||||
nsIDocShell* aDocShell, const nsCString& aDisallowCapabilities) {
|
||||
aDocShell->SetAllowPlugins(true);
|
||||
aDocShell->SetAllowJavascript(true);
|
||||
aDocShell->SetAllowMetaRedirects(true);
|
||||
aDocShell->SetAllowSubframes(true);
|
||||
aDocShell->SetAllowImages(true);
|
||||
|
@ -232,12 +232,13 @@ void SessionStoreUtils::RestoreDocShellCapabilities(
|
|||
aDocShell->SetAllowContentRetargeting(true);
|
||||
aDocShell->SetAllowContentRetargetingOnChildren(true);
|
||||
|
||||
bool allowJavascript = true;
|
||||
for (const nsACString& token :
|
||||
nsCCharSeparatedTokenizer(aDisallowCapabilities, ',').ToRange()) {
|
||||
if (token.EqualsLiteral("Plugins")) {
|
||||
aDocShell->SetAllowPlugins(false);
|
||||
} else if (token.EqualsLiteral("Javascript")) {
|
||||
aDocShell->SetAllowJavascript(false);
|
||||
allowJavascript = false;
|
||||
} else if (token.EqualsLiteral("MetaRedirects")) {
|
||||
aDocShell->SetAllowMetaRedirects(false);
|
||||
} else if (token.EqualsLiteral("Subframes")) {
|
||||
|
@ -261,6 +262,12 @@ void SessionStoreUtils::RestoreDocShellCapabilities(
|
|||
aDocShell->SetAllowContentRetargetingOnChildren(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!mozilla::SessionHistoryInParent()) {
|
||||
// With SessionHistoryInParent, this is set from the parent process.
|
||||
BrowsingContext* bc = aDocShell->GetBrowsingContext();
|
||||
Unused << bc->SetAllowJavascript(allowJavascript);
|
||||
}
|
||||
}
|
||||
|
||||
static void CollectCurrentScrollPosition(JSContext* aCx, Document& aDocument,
|
||||
|
@ -1463,6 +1470,16 @@ already_AddRefed<Promise> SessionStoreUtils::RestoreDocShellState(
|
|||
}
|
||||
}
|
||||
|
||||
bool allowJavascript = true;
|
||||
for (const nsACString& token :
|
||||
nsCCharSeparatedTokenizer(aDocShellCaps, ',').ToRange()) {
|
||||
if (token.EqualsLiteral("Javascript")) {
|
||||
allowJavascript = false;
|
||||
}
|
||||
}
|
||||
|
||||
Unused << aContext.SetAllowJavascript(allowJavascript);
|
||||
|
||||
DocShellRestoreState state = {uri, aDocShellCaps};
|
||||
|
||||
// TODO (anny): Investigate removing this roundtrip.
|
||||
|
|
Загрузка…
Ссылка в новой задаче