[refactor] More post-NSS WebCrypto cleanups (utility functions).
[chromium-blink-merge.git] / content / browser / frame_host / frame_tree_browsertest.cc
bloba0450de934bd091aff5a65f218748f08409f998a
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/frame_host/frame_tree.h"
6 #include "content/browser/frame_host/frame_tree_node.h"
7 #include "content/browser/renderer_host/render_view_host_impl.h"
8 #include "content/browser/web_contents/web_contents_impl.h"
9 #include "content/public/browser/notification_service.h"
10 #include "content/public/browser/notification_types.h"
11 #include "content/public/common/url_constants.h"
12 #include "content/public/test/browser_test_utils.h"
13 #include "content/public/test/content_browser_test.h"
14 #include "content/public/test/content_browser_test_utils.h"
15 #include "content/public/test/test_navigation_observer.h"
16 #include "content/public/test/test_utils.h"
17 #include "content/shell/browser/shell.h"
18 #include "content/test/content_browser_test_utils_internal.h"
19 #include "net/dns/mock_host_resolver.h"
20 #include "net/test/embedded_test_server/embedded_test_server.h"
21 #include "third_party/WebKit/public/web/WebSandboxFlags.h"
23 // For fine-grained suppression on flaky tests.
24 #if defined(OS_WIN)
25 #include "base/win/windows_version.h"
26 #endif
28 namespace content {
30 class FrameTreeBrowserTest : public ContentBrowserTest {
31 public:
32 FrameTreeBrowserTest() {}
34 void SetUpOnMainThread() override {
35 host_resolver()->AddRule("*", "127.0.0.1");
36 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
37 SetupCrossSiteRedirector(embedded_test_server());
40 private:
41 DISALLOW_COPY_AND_ASSIGN(FrameTreeBrowserTest);
44 // Ensures FrameTree correctly reflects page structure during navigations.
45 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeShape) {
46 GURL base_url = embedded_test_server()->GetURL("A.com", "/site_isolation/");
48 // Load doc without iframes. Verify FrameTree just has root.
49 // Frame tree:
50 // Site-A Root
51 NavigateToURL(shell(), base_url.Resolve("blank.html"));
52 FrameTreeNode* root =
53 static_cast<WebContentsImpl*>(shell()->web_contents())->
54 GetFrameTree()->root();
55 EXPECT_EQ(0U, root->child_count());
57 // Add 2 same-site frames. Verify 3 nodes in tree with proper names.
58 // Frame tree:
59 // Site-A Root -- Site-A frame1
60 // \-- Site-A frame2
61 WindowedNotificationObserver observer1(
62 content::NOTIFICATION_LOAD_STOP,
63 content::Source<NavigationController>(
64 &shell()->web_contents()->GetController()));
65 NavigateToURL(shell(), base_url.Resolve("frames-X-X.html"));
66 observer1.Wait();
67 ASSERT_EQ(2U, root->child_count());
68 EXPECT_EQ(0U, root->child_at(0)->child_count());
69 EXPECT_EQ(0U, root->child_at(1)->child_count());
72 // TODO(ajwong): Talk with nasko and merge this functionality with
73 // FrameTreeShape.
74 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeShape2) {
75 NavigateToURL(shell(),
76 embedded_test_server()->GetURL("/frame_tree/top.html"));
78 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
79 FrameTreeNode* root = wc->GetFrameTree()->root();
81 // Check that the root node is properly created.
82 ASSERT_EQ(3UL, root->child_count());
83 EXPECT_EQ(std::string(), root->frame_name());
85 ASSERT_EQ(2UL, root->child_at(0)->child_count());
86 EXPECT_STREQ("1-1-name", root->child_at(0)->frame_name().c_str());
88 // Verify the deepest node exists and has the right name.
89 ASSERT_EQ(2UL, root->child_at(2)->child_count());
90 EXPECT_EQ(1UL, root->child_at(2)->child_at(1)->child_count());
91 EXPECT_EQ(0UL, root->child_at(2)->child_at(1)->child_at(0)->child_count());
92 EXPECT_STREQ("3-1-name",
93 root->child_at(2)->child_at(1)->child_at(0)->frame_name().c_str());
95 // Navigate to about:blank, which should leave only the root node of the frame
96 // tree in the browser process.
97 NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
99 root = wc->GetFrameTree()->root();
100 EXPECT_EQ(0UL, root->child_count());
101 EXPECT_EQ(std::string(), root->frame_name());
104 // Test that we can navigate away if the previous renderer doesn't clean up its
105 // child frames.
106 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeAfterCrash) {
107 NavigateToURL(shell(),
108 embedded_test_server()->GetURL("/frame_tree/top.html"));
110 // Ensure the view and frame are live.
111 RenderViewHost* rvh = shell()->web_contents()->GetRenderViewHost();
112 RenderFrameHostImpl* rfh =
113 static_cast<RenderFrameHostImpl*>(rvh->GetMainFrame());
114 EXPECT_TRUE(rvh->IsRenderViewLive());
115 EXPECT_TRUE(rfh->IsRenderFrameLive());
117 // Crash the renderer so that it doesn't send any FrameDetached messages.
118 RenderProcessHostWatcher crash_observer(
119 shell()->web_contents(),
120 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
121 NavigateToURL(shell(), GURL(kChromeUICrashURL));
122 crash_observer.Wait();
124 // The frame tree should be cleared.
125 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
126 FrameTreeNode* root = wc->GetFrameTree()->root();
127 EXPECT_EQ(0UL, root->child_count());
129 // Ensure the view and frame aren't live anymore.
130 EXPECT_FALSE(rvh->IsRenderViewLive());
131 EXPECT_FALSE(rfh->IsRenderFrameLive());
133 // Navigate to a new URL.
134 GURL url(embedded_test_server()->GetURL("/title1.html"));
135 NavigateToURL(shell(), url);
136 EXPECT_EQ(0UL, root->child_count());
137 EXPECT_EQ(url, root->current_url());
139 // Ensure the view and frame are live again.
140 EXPECT_TRUE(rvh->IsRenderViewLive());
141 EXPECT_TRUE(rfh->IsRenderFrameLive());
144 // Test that we can navigate away if the previous renderer doesn't clean up its
145 // child frames.
146 // Flaky on Mac. http://crbug.com/452018
147 #if defined(OS_MACOSX)
148 #define MAYBE_NavigateWithLeftoverFrames DISABLED_NavigateWithLeftoverFrames
149 #else
150 #define MAYBE_NavigateWithLeftoverFrames NavigateWithLeftoverFrames
151 #endif
152 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, MAYBE_NavigateWithLeftoverFrames) {
153 #if defined(OS_WIN)
154 // Flaky on XP bot http://crbug.com/468713
155 if (base::win::GetVersion() <= base::win::VERSION_XP)
156 return;
157 #endif
158 GURL base_url = embedded_test_server()->GetURL("A.com", "/site_isolation/");
160 NavigateToURL(shell(),
161 embedded_test_server()->GetURL("/frame_tree/top.html"));
163 // Hang the renderer so that it doesn't send any FrameDetached messages.
164 // (This navigation will never complete, so don't wait for it.)
165 shell()->LoadURL(GURL(kChromeUIHangURL));
167 // Check that the frame tree still has children.
168 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
169 FrameTreeNode* root = wc->GetFrameTree()->root();
170 ASSERT_EQ(3UL, root->child_count());
172 // Navigate to a new URL. We use LoadURL because NavigateToURL will try to
173 // wait for the previous navigation to stop.
174 TestNavigationObserver tab_observer(wc, 1);
175 shell()->LoadURL(base_url.Resolve("blank.html"));
176 tab_observer.Wait();
178 // The frame tree should now be cleared.
179 EXPECT_EQ(0UL, root->child_count());
182 // Ensure that IsRenderFrameLive is true for main frames and same-site iframes.
183 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, IsRenderFrameLive) {
184 GURL main_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
185 NavigateToURL(shell(), main_url);
187 // It is safe to obtain the root frame tree node here, as it doesn't change.
188 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
189 ->GetFrameTree()->root();
191 // The root and subframe should each have a live RenderFrame.
192 EXPECT_TRUE(
193 root->current_frame_host()->render_view_host()->IsRenderViewLive());
194 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
195 EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
197 // Load a same-site page into iframe and it should still be live.
198 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
199 NavigateFrameToURL(root->child_at(0), http_url);
200 EXPECT_TRUE(
201 root->current_frame_host()->render_view_host()->IsRenderViewLive());
202 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
203 EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
206 // Ensure that origins are correctly set on navigations.
207 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, OriginSetOnNavigation) {
208 GURL main_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
209 EXPECT_TRUE(NavigateToURL(shell(), main_url));
211 // It is safe to obtain the root frame tree node here, as it doesn't change.
212 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
213 ->GetFrameTree()->root();
215 // Extra '/' is added because the replicated origin is serialized in RFC 6454
216 // format, which dictates no trailing '/', whereas GURL::GetOrigin does put a
217 // '/' at the end.
218 EXPECT_EQ(root->current_replication_state().origin.Serialize() + '/',
219 main_url.GetOrigin().spec());
221 GURL frame_url(embedded_test_server()->GetURL("/title1.html"));
222 NavigateFrameToURL(root->child_at(0), frame_url);
224 EXPECT_EQ(
225 root->child_at(0)->current_replication_state().origin.Serialize() + '/',
226 frame_url.GetOrigin().spec());
228 GURL data_url("data:text/html,foo");
229 EXPECT_TRUE(NavigateToURL(shell(), data_url));
231 // Navigating to a data URL should set a unique origin. This is represented
232 // as "null" per RFC 6454.
233 EXPECT_EQ(root->current_replication_state().origin.Serialize(), "null");
235 // Re-navigating to a normal URL should update the origin.
236 EXPECT_TRUE(NavigateToURL(shell(), main_url));
237 EXPECT_EQ(root->current_replication_state().origin.Serialize() + '/',
238 main_url.GetOrigin().spec());
241 // Ensure that sandbox flags are correctly set when child frames are created.
242 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, SandboxFlagsSetForChildFrames) {
243 GURL main_url(embedded_test_server()->GetURL("/sandboxed_frames.html"));
244 EXPECT_TRUE(NavigateToURL(shell(), main_url));
246 // It is safe to obtain the root frame tree node here, as it doesn't change.
247 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
248 ->GetFrameTree()->root();
250 // Verify that sandbox flags are set properly for all FrameTreeNodes.
251 // First frame is completely sandboxed; second frame uses "allow-scripts",
252 // which resets both SandboxFlags::Scripts and
253 // SandboxFlags::AutomaticFeatures bits per blink::parseSandboxPolicy(), and
254 // third frame has "allow-scripts allow-same-origin".
255 EXPECT_EQ(root->current_replication_state().sandbox_flags,
256 blink::WebSandboxFlags::None);
257 EXPECT_EQ(root->child_at(0)->current_replication_state().sandbox_flags,
258 blink::WebSandboxFlags::All);
259 EXPECT_EQ(root->child_at(1)->current_replication_state().sandbox_flags,
260 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
261 ~blink::WebSandboxFlags::AutomaticFeatures);
262 EXPECT_EQ(root->child_at(2)->current_replication_state().sandbox_flags,
263 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
264 ~blink::WebSandboxFlags::AutomaticFeatures &
265 ~blink::WebSandboxFlags::Origin);
267 // Sandboxed frames should set a unique origin unless they have the
268 // "allow-same-origin" directive.
269 EXPECT_EQ(root->child_at(0)->current_replication_state().origin.Serialize(),
270 "null");
271 EXPECT_EQ(root->child_at(1)->current_replication_state().origin.Serialize(),
272 "null");
273 EXPECT_EQ(
274 root->child_at(2)->current_replication_state().origin.Serialize() + "/",
275 main_url.GetOrigin().spec());
277 // Navigating to a different URL should not clear sandbox flags.
278 GURL frame_url(embedded_test_server()->GetURL("/title1.html"));
279 NavigateFrameToURL(root->child_at(0), frame_url);
280 EXPECT_EQ(root->child_at(0)->current_replication_state().sandbox_flags,
281 blink::WebSandboxFlags::All);
284 // Ensure that a popup opened from a subframe sets its opener to the subframe's
285 // FrameTreeNode, and that the opener is cleared if the subframe is destroyed.
286 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, SubframeOpenerSetForNewWindow) {
287 GURL main_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
288 EXPECT_TRUE(NavigateToURL(shell(), main_url));
290 // It is safe to obtain the root frame tree node here, as it doesn't change.
291 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
292 ->GetFrameTree()
293 ->root();
295 // Open a new window from a subframe.
296 ShellAddedObserver new_shell_observer;
297 GURL popup_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
298 EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
299 "window.open('" + popup_url.spec() + "');"));
300 Shell* new_shell = new_shell_observer.GetShell();
301 WebContents* new_contents = new_shell->web_contents();
302 WaitForLoadStop(new_contents);
304 // Check that the new window's opener points to the correct subframe on
305 // original window.
306 FrameTreeNode* popup_root =
307 static_cast<WebContentsImpl*>(new_contents)->GetFrameTree()->root();
308 EXPECT_EQ(root->child_at(0), popup_root->opener());
310 // Close the original window. This should clear the new window's opener.
311 shell()->Close();
312 EXPECT_EQ(nullptr, popup_root->opener());
315 class CrossProcessFrameTreeBrowserTest : public ContentBrowserTest {
316 public:
317 CrossProcessFrameTreeBrowserTest() {}
319 void SetUpCommandLine(base::CommandLine* command_line) override {
320 IsolateAllSitesForTesting(command_line);
323 void SetUpOnMainThread() override {
324 host_resolver()->AddRule("*", "127.0.0.1");
325 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
326 SetupCrossSiteRedirector(embedded_test_server());
329 private:
330 DISALLOW_COPY_AND_ASSIGN(CrossProcessFrameTreeBrowserTest);
333 // Ensure that we can complete a cross-process subframe navigation.
334 IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
335 CreateCrossProcessSubframeProxies) {
336 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
337 NavigateToURL(shell(), main_url);
339 // It is safe to obtain the root frame tree node here, as it doesn't change.
340 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
341 ->GetFrameTree()->root();
343 // There should not be a proxy for the root's own SiteInstance.
344 SiteInstance* root_instance = root->current_frame_host()->GetSiteInstance();
345 EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost(root_instance));
347 // Load same-site page into iframe.
348 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
349 NavigateFrameToURL(root->child_at(0), http_url);
351 // Load cross-site page into iframe.
352 GURL cross_site_url(
353 embedded_test_server()->GetURL("foo.com", "/title2.html"));
354 NavigateFrameToURL(root->child_at(0), cross_site_url);
356 // Ensure that we have created a new process for the subframe.
357 ASSERT_EQ(2U, root->child_count());
358 FrameTreeNode* child = root->child_at(0);
359 SiteInstance* child_instance = child->current_frame_host()->GetSiteInstance();
360 RenderViewHost* rvh = child->current_frame_host()->render_view_host();
361 RenderProcessHost* rph = child->current_frame_host()->GetProcess();
363 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh);
364 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), child_instance);
365 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph);
367 // Ensure that the root node has a proxy for the child node's SiteInstance.
368 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(child_instance));
370 // Also ensure that the child has a proxy for the root node's SiteInstance.
371 EXPECT_TRUE(child->render_manager()->GetRenderFrameProxyHost(root_instance));
373 // The nodes should not have proxies for their own SiteInstance.
374 EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost(root_instance));
375 EXPECT_FALSE(
376 child->render_manager()->GetRenderFrameProxyHost(child_instance));
378 // Ensure that the RenderViews and RenderFrames are all live.
379 EXPECT_TRUE(
380 root->current_frame_host()->render_view_host()->IsRenderViewLive());
381 EXPECT_TRUE(
382 child->current_frame_host()->render_view_host()->IsRenderViewLive());
383 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
384 EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
387 IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
388 OriginSetOnCrossProcessNavigations) {
389 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
390 EXPECT_TRUE(NavigateToURL(shell(), main_url));
392 // It is safe to obtain the root frame tree node here, as it doesn't change.
393 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
394 ->GetFrameTree()->root();
396 EXPECT_EQ(root->current_replication_state().origin.Serialize() + '/',
397 main_url.GetOrigin().spec());
399 // First frame is an about:blank frame. Check that its origin is correctly
400 // inherited from the parent.
401 EXPECT_EQ(
402 root->child_at(0)->current_replication_state().origin.Serialize() + '/',
403 main_url.GetOrigin().spec());
405 // Second frame loads a same-site page. Its origin should also be the same
406 // as the parent.
407 EXPECT_EQ(
408 root->child_at(1)->current_replication_state().origin.Serialize() + '/',
409 main_url.GetOrigin().spec());
411 // Load cross-site page into the first frame.
412 GURL cross_site_url(
413 embedded_test_server()->GetURL("foo.com", "/title2.html"));
414 NavigateFrameToURL(root->child_at(0), cross_site_url);
416 EXPECT_EQ(
417 root->child_at(0)->current_replication_state().origin.Serialize() + '/',
418 cross_site_url.GetOrigin().spec());
420 // The root's origin shouldn't have changed.
421 EXPECT_EQ(root->current_replication_state().origin.Serialize() + '/',
422 main_url.GetOrigin().spec());
424 GURL data_url("data:text/html,foo");
425 NavigateFrameToURL(root->child_at(1), data_url);
427 // Navigating to a data URL should set a unique origin. This is represented
428 // as "null" per RFC 6454.
429 EXPECT_EQ(root->child_at(1)->current_replication_state().origin.Serialize(),
430 "null");
433 } // namespace content