https://bugs.webkit.org/show_bug.cgi?id=68267
Make adoptNode() to not enable live iframe transfer when the iframe's subtree contains plugins.
Reviewed by Adam Barth.
Source/WebCore:
Test: fast/frames/iframe-reparenting-embed-elements.html
* dom/Document.cpp:
(WebCore::Document::adoptNode):
* html/HTMLFrameElementBase.cpp:
(WebCore::hasPluginElements):
(WebCore::HTMLFrameElementBase::canRemainAliveOnRemovalFromTree):
* html/HTMLFrameElementBase.h:
LayoutTests:
* fast/frames/iframe-reparenting-embed-elements-expected.txt: Added.
* fast/frames/iframe-reparenting-embed-elements.html: Added.
* fast/frames/resources/iframe-reparenting-embed-frame1.html: Added.
* fast/frames/resources/iframe-reparenting-embed-iframe.html: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@95471
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2011-09-19 Dmitry Titov <dimich@chromium.org>
+
+ [Chromium] Crash after magic iframe transfer for Pepper/NaCl plugins.
+ https://bugs.webkit.org/show_bug.cgi?id=68267
+ Make adoptNode() to not enable live iframe transfer when the iframe's subtree contains plugins.
+
+ Reviewed by Adam Barth.
+
+ * fast/frames/iframe-reparenting-embed-elements-expected.txt: Added.
+ * fast/frames/iframe-reparenting-embed-elements.html: Added.
+ * fast/frames/resources/iframe-reparenting-embed-frame1.html: Added.
+ * fast/frames/resources/iframe-reparenting-embed-iframe.html: Added.
+
2011-09-19 Abhishek Arya <inferno@chromium.org>
Issues with merging ruby bases.
--- /dev/null
+This test moves an iframe between two documents 3 times: without plugins, with <embed> tag and then with <object> tag.
+
+Only the attempt without plugin elements should succeed. The presence of plugin elements should prevent the document.adoptNode() method from triggering live transfer - in which case the iframe will be reloaded.
+
+Test succeeds if there are 'PASS' messages below and no 'FAIL' messages.
+
+
+PASS: Test without plugins
+PASS: Test with <embed>
+PASS: Test with <object>
+Test Finished.
+
--- /dev/null
+<html>
+<script>
+function log(message) {
+ document.getElementById("log").innerText += message + "\n";
+}
+
+function verifyResult(message, actualToken, expectedToReload) {
+ var success = (expectedToReload != (actualToken == "modified"));
+ log((success ? "PASS" : "FAIL") + ": " + message);
+}
+
+function transferIframe(testStepDescription, expectedToReload, nextTest)
+{
+ var iframe = frame1.contentDocument.getElementsByTagName("iframe")[0];
+ if (iframe.contentWindow.token != "loaded")
+ log("FAIL: invalid initial state of test iframe");
+
+ iframe.contentWindow.token = "modified";
+
+ frame1.contentDocument.adoptNode(iframe);
+ frame2.contentDocument.body.appendChild(iframe);
+ verifyResult(testStepDescription, iframe.contentWindow.token, expectedToReload);
+
+ frame1.onload = nextTest;
+ frame1.contentWindow.location.reload();
+}
+
+function finish()
+{
+ log("Test Finished.");
+ if (window.layoutTestController)
+ layoutTestController.notifyDone();
+}
+
+function test() {
+ if (window.layoutTestController) {
+ layoutTestController.dumpAsText();
+ layoutTestController.waitUntilDone();
+ }
+
+ frame1 = document.getElementById("frame1");
+ frame2 = document.getElementById("frame2");
+
+ transferIframe("Test without plugins", false, test1);
+}
+
+function test1() {
+ var iframe = frame1.contentDocument.getElementsByTagName("iframe")[0];
+ iframe.contentDocument.body.appendChild(iframe.contentDocument.createElement("embed"));
+ transferIframe("Test with <embed>", true, test2);
+}
+
+function test2() {
+ var iframe = frame1.contentDocument.getElementsByTagName("iframe")[0];
+ iframe.contentDocument.body.appendChild(iframe.contentDocument.createElement("object"));
+ transferIframe("Test with <object>", true, finish);
+}
+
+</script>
+<body onload=test()>
+<p>This test moves an iframe between two documents 3 times: without plugins, with <embed> tag and then with <object> tag.</p>
+<p>Only the attempt without plugin elements should succeed. The presence of plugin elements should prevent the document.adoptNode() method from
+triggering live transfer - in which case the iframe will be reloaded.</p>
+<p>Test succeeds if there are 'PASS' messages below and no 'FAIL' messages.</p>
+<iframe id=frame1 src="resources/iframe-reparenting-embed-frame1.html"></iframe>
+<iframe id=frame2 src="resources/iframe-reparenting-frame2.html"></iframe>
+<pre id=log></pre>
+</body>
+</html>
--- /dev/null
+<body>
+<iframe src=iframe-reparenting-embed-iframe.html></iframe>
--- /dev/null
+<script>
+token = "loading";
+
+function init()
+{
+ token = "loaded";
+}
+
+</script>
+<body onload=init()>
+2011-09-19 Dmitry Titov <dimich@chromium.org>
+
+ [Chromium] Crash after magic iframe transfer for Pepper/NaCl plugins.
+ https://bugs.webkit.org/show_bug.cgi?id=68267
+ Make adoptNode() to not enable live iframe transfer when the iframe's subtree contains plugins.
+
+ Reviewed by Adam Barth.
+
+ Test: fast/frames/iframe-reparenting-embed-elements.html
+
+ * dom/Document.cpp:
+ (WebCore::Document::adoptNode):
+ * html/HTMLFrameElementBase.cpp:
+ (WebCore::hasPluginElements):
+ (WebCore::HTMLFrameElementBase::canRemainAliveOnRemovalFromTree):
+ * html/HTMLFrameElementBase.h:
+
2011-09-19 Abhishek Arya <inferno@chromium.org>
Issues with merging ruby bases.
ec = HIERARCHY_REQUEST_ERR;
return 0;
}
- iframe->setRemainsAliveOnRemovalFromTree(attached() && source->attached());
+ iframe->setRemainsAliveOnRemovalFromTree(attached() && source->attached() && iframe->canRemainAliveOnRemovalFromTree());
}
if (source->parentNode())
using namespace HTMLNames;
+// Helper to check if the Frame's document contains elements that can instantiate plugins.
+// Does a recursive check for nested Frames too.
+static bool hasPluginElements(Frame* frame)
+{
+ if (!frame)
+ return false;
+
+ // Search for a plugin element in this document.
+ Document* document = frame->document();
+ for (Node* node = document->firstChild(); node; node = node->traverseNextNode(document)) {
+ if (!node->isElementNode())
+ continue;
+
+ Element* element = static_cast<Element*>(node);
+ if (element->hasLocalName(embedTag) || element->hasLocalName(objectTag))
+ return true;
+ }
+
+ // Do the same for the nested frames.
+ for (Frame* child = frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
+ if (hasPluginElements(child))
+ return true;
+ }
+
+ return false;
+}
+
HTMLFrameElementBase::HTMLFrameElementBase(const QualifiedName& tagName, Document* document)
: HTMLFrameOwnerElement(tagName, document)
, m_scrolling(ScrollbarAuto)
return renderBox()->height();
}
+// Some types of content can restrict the ability to move the iframes between pages.
+// For example, the plugin infrastructure of an embedder may associate the plugin instances
+// with the top-level Frame for tracking various resources and failure to transfer those
+// resources correctly may lead to crashes and other ill effects (https://bugs.webkit.org/show_bug.cgi?id=68267)
+bool HTMLFrameElementBase::canRemainAliveOnRemovalFromTree()
+{
+ return !hasPluginElements(contentFrame());
+}
+
void HTMLFrameElementBase::setRemainsAliveOnRemovalFromTree(bool value)
{
+ ASSERT(!value || canRemainAliveOnRemovalFromTree());
m_remainsAliveOnRemovalFromTree = value;
// There is a possibility that JS will do document.adoptNode() on this element but will not insert it into the tree.
int width();
int height();
+ bool canRemainAliveOnRemovalFromTree();
void setRemainsAliveOnRemovalFromTree(bool);
#if ENABLE(FULLSCREEN_API)
virtual bool allowFullScreen() const;