1d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)// found in the LICENSE file.
4d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
5d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)#include "config.h"
6d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)#include "core/dom/ChildFrameDisconnector.h"
7d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
8d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)#include "core/dom/shadow/ElementShadow.h"
9d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)#include "core/dom/shadow/ShadowRoot.h"
1076c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles)#include "core/html/HTMLFrameOwnerElement.h"
11d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)#include "wtf/Assertions.h"
12d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
13c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink {
14d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
15197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#if ENABLE(ASSERT)
165d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)static unsigned checkConnectedSubframeCountIsConsistent(Node&);
17d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)#endif
18d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
19d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)void ChildFrameDisconnector::disconnect(DisconnectPolicy policy)
20d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles){
21197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#if ENABLE(ASSERT)
22c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    checkConnectedSubframeCountIsConsistent(root());
23d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)#endif
24d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
25c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    if (!root().connectedSubframeCount())
26d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        return;
27d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
28d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (policy == RootAndDescendants) {
29c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        collectFrameOwners(root());
30d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    } else {
31c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        for (Node* child = root().firstChild(); child; child = child->nextSibling())
32d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)            collectFrameOwners(*child);
33d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    }
34d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
35d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    disconnectCollectedFrameOwners();
36d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)}
37d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
38d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)void ChildFrameDisconnector::collectFrameOwners(Node& root)
39d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles){
40d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (!root.connectedSubframeCount())
41d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        return;
42d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
43d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (root.isHTMLElement() && root.isFrameOwnerElement())
44d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        m_frameOwners.append(&toHTMLFrameOwnerElement(root));
45d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
46d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    for (Node* child = root.firstChild(); child; child = child->nextSibling())
47d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        collectFrameOwners(*child);
48d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
49d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    ElementShadow* shadow = root.isElementNode() ? toElement(root).shadow() : 0;
50d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (shadow)
51d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        collectFrameOwners(*shadow);
52d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)}
53d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
54d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)void ChildFrameDisconnector::disconnectCollectedFrameOwners()
55d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles){
56d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // Must disable frame loading in the subtree so an unload handler cannot
57d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // insert more frames and create loaded frames in detached subtrees.
58c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    SubframeLoadingDisabler disabler(root());
59d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
60d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    for (unsigned i = 0; i < m_frameOwners.size(); ++i) {
61d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        HTMLFrameOwnerElement* owner = m_frameOwners[i].get();
62d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        // Don't need to traverse up the tree for the first owner since no
63d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        // script could have moved it.
64c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        if (!i || root().containsIncludingShadowDOM(owner))
65d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)            owner->disconnectContentFrame();
66d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    }
67d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)}
68d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
69d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)void ChildFrameDisconnector::collectFrameOwners(ElementShadow& shadow)
70d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles){
71d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    for (ShadowRoot* root = shadow.youngestShadowRoot(); root; root = root->olderShadowRoot())
72d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        collectFrameOwners(*root);
73d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)}
74d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
75197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch#if ENABLE(ASSERT)
765d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)static unsigned checkConnectedSubframeCountIsConsistent(Node& node)
77d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles){
78d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    unsigned count = 0;
79d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
80d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    if (node.isElementNode()) {
81d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        if (node.isFrameOwnerElement() && toHTMLFrameOwnerElement(node).contentFrame())
82d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)            count++;
83d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
84d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        if (ElementShadow* shadow = toElement(node).shadow()) {
85d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)            for (ShadowRoot* root = shadow->youngestShadowRoot(); root; root = root->olderShadowRoot())
865d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)                count += checkConnectedSubframeCountIsConsistent(*root);
87d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)        }
88d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    }
89d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
90d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    for (Node* child = node.firstChild(); child; child = child->nextSibling())
915d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)        count += checkConnectedSubframeCountIsConsistent(*child);
92d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
93d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // If we undercount there's possibly a security bug since we'd leave frames
94d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // in subtrees outside the document.
95d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    ASSERT(node.connectedSubframeCount() >= count);
96d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
97d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // If we overcount it's safe, but not optimal because it means we'll traverse
98d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // through the document in ChildFrameDisconnector looking for frames that have
99d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    // already been disconnected.
100d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    ASSERT(node.connectedSubframeCount() == count);
101d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
102d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    return count;
103d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)}
104d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)#endif
105d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)
106d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)}
107