Bug 814768: Force marionette to move to window.top if we try access something the compartment is dead and handle OOP being pulled from under us; r=jgriffin

This commit is contained in:
David Burns 2013-01-16 15:00:00 +00:00
parent 6f5e201c89
commit d63819e9a5
5 changed files with 100 additions and 5 deletions

View File

@ -39,6 +39,25 @@ class TestSwitchFrame(MarionetteTestCase):
except JavascriptException as e: except JavascriptException as e:
self.assertTrue("foo" in e.msg) self.assertTrue("foo" in e.msg)
def testShouldBeAbleToCarryOnWorkingIfTheFrameIsDeletedFromUnderUs(self):
test_html = self.marionette.absolute_url("deletingFrame.html")
self.marionette.navigate(test_html)
self.marionette.switch_to_frame("iframe1");
killIframe = self.marionette.find_element("id" ,"killIframe")
killIframe.click()
self.marionette.switch_to_frame()
self.assertEqual(0, len(self.marionette.find_elements("id", "iframe1")))
addIFrame = self.marionette.find_element("id", "addBackFrame")
addIFrame.click()
self.marionette.find_element("id", "iframe1")
self.marionette.switch_to_frame("iframe1");
self.marionette.find_element("id", "checkbox")
class TestSwitchFrameChrome(MarionetteTestCase): class TestSwitchFrameChrome(MarionetteTestCase):
def setUp(self): def setUp(self):
MarionetteTestCase.setUp(self) MarionetteTestCase.setUp(self)

View File

@ -0,0 +1,29 @@
<html>
<head>
<title></title>
</head>
<script type="text/javascript">
function remove() {
var iframe = document.getElementById("iframe1");
var myDiv = document.getElementById("myDiv");
myDiv.removeChild(iframe);
}
function addBack() {
var iframe = '<iframe src="javascriptPage.html" marginheight="0" marginwidth="0" topmargin="0" leftmargin="600" allowtransparency="true" frameborder="0" height="600" scrolling="no" width="120" id="iframe1"></iframe>';
var myDiv2 = document.getElementById("myDiv2");
myDiv2.innerHTML = iframe;
}
</script>
<body>
<div id='myDiv'>
<iframe src="formPage.html" marginheight="0" marginwidth="0" topmargin="0" leftmargin="0" allowtransparency="true"
frameborder="1" height="900" scrolling="no" width="500" id="iframe1"></iframe>
</div>
<div id='myDiv2'>
</div>
<input type='button' id='addBackFrame' value='Add back frame' onclick='addBack();' />
</body>
</html>

View File

@ -0,0 +1,16 @@
<html>
<head>
<title>We Leave From Here</title>
<script type="text/javascript">
function changePage() {
var newLocation = '/common/page/3';
window.location = newLocation;
}
</script>
</head>
<body>
<input type='button' id='killIframe' onclick='top.remove();' value="Kill containing iframe" />
</body>
</html>

View File

@ -160,6 +160,7 @@ function MarionetteDriverActor(aConnection)
this.importedScripts = FileUtils.getFile('TmpD', ['marionettescriptchrome']); this.importedScripts = FileUtils.getFile('TmpD', ['marionettescriptchrome']);
this.currentRemoteFrame = null; // a member of remoteFrames this.currentRemoteFrame = null; // a member of remoteFrames
this.testName = null; this.testName = null;
this.mozBrowserClose = null;
//register all message listeners //register all message listeners
this.addMessageManagerListeners(this.messageManager); this.addMessageManagerListeners(this.messageManager);
@ -1353,6 +1354,18 @@ MarionetteDriverActor.prototype = {
} }
} }
else { else {
// We need to protect against the click causing an OOP frame to close.
// This fires the mozbrowserclose event when it closes so we need to
// listen for it and then just send an error back. The person making the
// call should be aware something isnt right and handle accordingly
let curWindow = this.getCurrentWindow();
let self = this;
this.mozBrowserClose = function() {
curWindow.removeEventListener('mozbrowserclose', self.mozBrowserClose, true);
self.switchToGlobalMessageManager();
self.sendError("The frame closed during the click, recovering to allow further communications", 500, null, command_id);
};
curWindow.addEventListener('mozbrowserclose', this.mozBrowserClose, true);
this.sendAsync("clickElement", {element: aRequest.element, this.sendAsync("clickElement", {element: aRequest.element,
command_id: command_id}); command_id: command_id});
} }
@ -1848,6 +1861,13 @@ MarionetteDriverActor.prototype = {
* Receives all messages from content messageManager * Receives all messages from content messageManager
*/ */
receiveMessage: function MDA_receiveMessage(message) { receiveMessage: function MDA_receiveMessage(message) {
// We need to just check if we need to remove the mozbrowserclose listener
if (this.mozBrowserClose !== null){
let curWindow = this.getCurrentWindow();
curWindow.removeEventListener('mozbrowserclose', this.mozBrowserClose, true);
this.mozBrowserClose = null;
}
switch (message.name) { switch (message.name) {
case "DOMContentLoaded": case "DOMContentLoaded":
this.sendOk(); this.sendOk();

View File

@ -879,11 +879,22 @@ function switchToFrame(msg) {
checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT); checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
} }
let foundFrame = null; let foundFrame = null;
let frames = curWindow.document.getElementsByTagName("iframe"); let frames = []; //curWindow.document.getElementsByTagName("iframe");
//Until Bug 761935 lands, we won't have multiple nested OOP iframes. We will only have one. let parWindow = null; //curWindow.QueryInterface(Ci.nsIInterfaceRequestor)
//parWindow will refer to the iframe above the nested OOP frame. // Check of the curWindow reference is dead
let parWindow = curWindow.QueryInterface(Ci.nsIInterfaceRequestor) try {
.getInterface(Ci.nsIDOMWindowUtils).outerWindowID; frames = curWindow.document.getElementsByTagName("iframe");
//Until Bug 761935 lands, we won't have multiple nested OOP iframes. We will only have one.
//parWindow will refer to the iframe above the nested OOP frame.
parWindow = curWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
} catch (e) {
// We probably have a dead compartment so accessing it is going to make Firefox
// very upset. Let's now try redirect everything to the top frame even if the
// user has given us a frame since search doesnt look up.
msg.json.value = null;
msg.json.element = null;
}
if ((msg.json.value == null) && (msg.json.element == null)) { if ((msg.json.value == null) && (msg.json.element == null)) {
curWindow = content; curWindow = content;
if(msg.json.focus == true) { if(msg.json.focus == true) {