Bug 1161072 - Reset docshell state (disabled js/cache, service workers) from actor instead of client. r=jryans

This commit is contained in:
Alexandre Poirot 2015-05-18 20:15:35 +02:00
parent d7a6584df7
commit 4d22bf0963
6 changed files with 124 additions and 69 deletions

View File

@ -3,15 +3,7 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
Cu.import("resource://gre/modules/Services.jsm");
let temp = {}
Cu.import("resource:///modules/devtools/gDevTools.jsm", temp);
let DevTools = temp.DevTools;
Cu.import("resource://gre/modules/devtools/LayoutHelpers.jsm", temp);
let LayoutHelpers = temp.LayoutHelpers;
Cu.import("resource://gre/modules/devtools/Loader.jsm", temp);
let devtools = temp.devtools;
let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
let Toolbox = devtools.Toolbox;
@ -40,19 +32,27 @@ function test() {
let json = JSON.parse(event.data);
if (json.name == "toolbox-close") {
ok("Got the `toolbox-close` message");
window.removeEventListener("message", onMessage);
cleanup();
}
}
function testCustomHost(toolbox) {
function testCustomHost(t) {
toolbox = t;
is(toolbox.doc.defaultView.top, window, "Toolbox is included in browser.xul");
is(toolbox.doc, iframe.contentDocument, "Toolbox is in the custom iframe");
executeSoon(() => gBrowser.removeCurrentTab());
}
function cleanup() {
window.removeEventListener("message", onMessage);
iframe.remove();
finish();
// Even if we received "toolbox-close", the toolbox may still be destroying
// toolbox.destroy() returns a singleton promise that ensures
// everything is cleaned up before proceeding.
toolbox.destroy().then(() => {
toolbox = iframe = target = tab = null;
finish();
});
}
}

View File

@ -37,11 +37,15 @@ function start() {
function testSelectTool(aToolbox) {
toolbox = aToolbox;
toolbox.once("options-selected", testRegisterFails);
toolbox.once("options-selected", () => {
testRegisterFails().then(testRegisterInstallingWorker);
});
toolbox.selectTool("options");
}
function testRegisterFails() {
let deferred = promise.defer();
let output = doc.getElementById("output");
let button = doc.getElementById("button");
@ -50,7 +54,7 @@ function testRegisterFails() {
is(output.textContent,
"SecurityError",
"SecurityError expected");
testRegisterInstallingWorker();
deferred.resolve();
}
if (output.textContent !== "No output") {
@ -61,6 +65,8 @@ function testRegisterFails() {
button.removeEventListener('click', onClick);
doTheCheck();
});
return deferred.promise;
}
function testRegisterInstallingWorker() {
@ -73,7 +79,7 @@ function testRegisterInstallingWorker() {
is(output.textContent,
"Installing worker/",
"Installing worker expected");
toggleServiceWorkersTestingCheckbox().then(finishUp);
testRegisterFailsWhenToolboxCloses();
}
if (output.textContent !== "No output") {
@ -87,6 +93,30 @@ function testRegisterInstallingWorker() {
});
}
// Workers should be turned back off when we closes the toolbox
function testRegisterFailsWhenToolboxCloses() {
info("Testing it disable worker when closing the toolbox");
toolbox.destroy()
.then(reload)
.then(testRegisterFails)
.then(finishUp);
}
function reload() {
let deferred = promise.defer();
gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
doc = content.document;
deferred.resolve();
}, true);
let mm = getFrameScript();
mm.sendAsyncMessage("devtools:test:reload");
return deferred.promise;
}
function toggleServiceWorkersTestingCheckbox() {
let deferred = promise.defer();
@ -101,24 +131,13 @@ function toggleServiceWorkersTestingCheckbox() {
info("Checking checkbox to enable service workers testing");
}
gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
doc = content.document;
deferred.resolve();
}, true);
cbx.click();
let mm = getFrameScript();
mm.sendAsyncMessage("devtools:test:reload");
return deferred.promise;
return reload();
}
function finishUp() {
toolbox.destroy().then(function() {
gBrowser.removeCurrentTab();
toolbox = doc = null;
finish();
});
gBrowser.removeCurrentTab();
toolbox = doc = null;
finish();
}

View File

@ -316,8 +316,8 @@ OptionsPanel.prototype = {
if (this.target.activeTab) {
this.target.client.attachTab(this.target.activeTab._actor, (response) => {
this._origJavascriptEnabled = response.javascriptEnabled;
this.disableJSNode.checked = !this._origJavascriptEnabled;
this._origJavascriptEnabled = !response.javascriptEnabled;
this.disableJSNode.checked = this._origJavascriptEnabled;
this.disableJSNode.addEventListener("click", this._disableJSClicked, false);
});
} else {
@ -370,25 +370,29 @@ OptionsPanel.prototype = {
}
let deferred = promise.defer();
this.destroyPromise = deferred.promise;
this._removeListeners();
if (this.target.activeTab) {
this.disableJSNode.removeEventListener("click", this._disableJSClicked, false);
// If JavaScript is disabled we need to revert it to it's original value.
let options = {
"javascriptEnabled": this._origJavascriptEnabled
};
this.target.activeTab.reconfigure(options, () => {
this.toolbox = null;
this.disableJSNode.removeEventListener("click", this._disableJSClicked);
// FF41+ automatically cleans up state in actor on disconnect
if (!this.target.activeTab.traits.noTabReconfigureOnClose) {
let options = {
"javascriptEnabled": this._origJavascriptEnabled,
"performReload": false
};
this.target.activeTab.reconfigure(options, deferred.resolve);
} else {
deferred.resolve();
}, true);
}
} else {
deferred.resolve();
}
this.panelWin = this.panelDoc = this.disableJSNode = null;
this.panelWin = this.panelDoc = this.disableJSNode = this.toolbox = null;
return deferred.promise;
return this.destroyPromise;
}
};

View File

@ -1753,7 +1753,8 @@ Toolbox.prototype = {
// Now that we are closing the toolbox we can re-enable the cache settings
// and disable the service workers testing settings for the current tab.
if (this.target.activeTab) {
// FF41+ automatically cleans up state in actor on disconnect.
if (this.target.activeTab && !this.target.activeTab.traits.noTabReconfigureOnClose) {
this.target.activeTab.reconfigure({
"cacheDisabled": false,
"serviceWorkersTestingEnabled": false

View File

@ -131,11 +131,13 @@ StyleEditorPanel.prototype = {
this._target.off("close", this.destroy);
this._target = null;
this._toolbox = null;
this._panelWin = null;
this._panelDoc = null;
this._debuggee.destroy();
this._debuggee = null;
this.UI.destroy();
this.UI = null;
}
return promise.resolve(null);

View File

@ -725,7 +725,15 @@ function TabActor(aConnection)
// Used on b2g to catch activity frames and in chrome to list all frames
this.listenForNewDocShells = Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT;
this.traits = { reconfigure: true, frames: true };
this.traits = {
reconfigure: true,
// Supports frame listing via `listFrames` request and `frameUpdate` events
// as well as frame switching via `switchToFrame` request
frames: true,
// Do not require to send reconfigure request to reset the document state
// to what it was before using the TabActor
noTabReconfigureOnClose: true
};
this._workerActorList = null;
this._workerActorPool = null;
@ -1300,6 +1308,7 @@ TabActor.prototype = {
// during Firefox shutdown.
if (this.docShell) {
this._progressListener.unwatch(this.docShell);
this._restoreDocumentSettings();
}
if (this._progressListener) {
this._progressListener.destroy();
@ -1390,14 +1399,19 @@ TabActor.prototype = {
onReconfigure: function (aRequest) {
let options = aRequest.options || {};
this._toggleDevtoolsSettings(options);
if (!this.docShell) {
// The tab is already closed.
return {};
}
this._toggleDevToolsSettings(options);
return {};
},
/**
* Handle logic to enable/disable JS/cache/Service Worker testing.
*/
_toggleDevtoolsSettings: function(options) {
_toggleDevToolsSettings: function(options) {
// Wait a tick so that the response packet can be dispatched before the
// subsequent navigation event packet.
let reload = false;
@ -1429,6 +1443,16 @@ TabActor.prototype = {
}
},
/**
* Opposite of the _toggleDevToolsSettings method, that reset document state
* when closing the toolbox.
*/
_restoreDocumentSettings: function () {
this._restoreJavascript();
this._setCacheDisabled(false);
this._setServiceWorkersTestingEnabled(false);
},
/**
* Disable or enable the cache via docShell.
*/
@ -1437,29 +1461,46 @@ TabActor.prototype = {
let disable = Ci.nsIRequest.LOAD_BYPASS_CACHE |
Ci.nsIRequest.INHIBIT_CACHING;
if (this.docShell) {
this.docShell.defaultLoadFlags = disabled ? disable : enable;
}
this.docShell.defaultLoadFlags = disabled ? disable : enable;
},
/**
* Disable or enable JS via docShell.
*/
_wasJavascriptEnabled: null,
_setJavascriptEnabled: function(allow) {
if (this.docShell) {
this.docShell.allowJavascript = allow;
if (this._wasJavascriptEnabled === null) {
this._wasJavascriptEnabled = this.docShell.allowJavascript;
}
this.docShell.allowJavascript = allow;
},
/**
* Restore JS state, before the actor modified it.
*/
_restoreJavascript: function () {
if (this._wasJavascriptEnabled !== null) {
this._setJavascriptEnabled(this._wasJavascriptEnabled);
this._wasJavascriptEnabled = null;
}
},
/**
* Return JS allowed status.
*/
_getJavascriptEnabled: function() {
if (!this.docShell) {
// The tab is already closed.
return null;
}
return this.docShell.allowJavascript;
},
/**
* Disable or enable the service workers testing features.
*/
_setServiceWorkersTestingEnabled: function(enabled) {
if (!this.docShell) {
// The tab is already closed.
return null;
}
let windowUtils = this.window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
windowUtils.serviceWorkersTestingEnabled = enabled;
@ -1479,18 +1520,6 @@ TabActor.prototype = {
return this.docShell.defaultLoadFlags === disable;
},
/**
* Return JS allowed status.
*/
_getJavascriptEnabled: function() {
if (!this.docShell) {
// The tab is already closed.
return null;
}
return this.docShell.allowJavascript;
},
/**
* Return service workers testing allowed status.
*/