Use multiline attribute to check for IA2_STATE_MULTILINE.
[chromium-blink-merge.git] / content / browser / frame_host / frame_tree_browsertest.cc
blob15e72e7e0e7e7e2874e3e695e8b478604fd49a89
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 "base/command_line.h"
6 #include "content/browser/frame_host/frame_tree.h"
7 #include "content/browser/frame_host/frame_tree_node.h"
8 #include "content/browser/renderer_host/render_view_host_impl.h"
9 #include "content/browser/web_contents/web_contents_impl.h"
10 #include "content/public/browser/notification_service.h"
11 #include "content/public/browser/notification_types.h"
12 #include "content/public/common/content_switches.h"
13 #include "content/public/common/url_constants.h"
14 #include "content/public/test/browser_test_utils.h"
15 #include "content/public/test/content_browser_test.h"
16 #include "content/public/test/content_browser_test_utils.h"
17 #include "content/public/test/test_navigation_observer.h"
18 #include "content/public/test/test_utils.h"
19 #include "content/shell/browser/shell.h"
20 #include "content/test/content_browser_test_utils_internal.h"
21 #include "net/dns/mock_host_resolver.h"
22 #include "net/test/embedded_test_server/embedded_test_server.h"
24 // For fine-grained suppression on flaky tests.
25 #if defined(OS_WIN)
26 #include "base/win/windows_version.h"
27 #endif
29 namespace content {
31 class FrameTreeBrowserTest : public ContentBrowserTest {
32 public:
33 FrameTreeBrowserTest() {}
35 void SetUpOnMainThread() override {
36 host_resolver()->AddRule("*", "127.0.0.1");
37 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
38 SetupCrossSiteRedirector(embedded_test_server());
41 private:
42 DISALLOW_COPY_AND_ASSIGN(FrameTreeBrowserTest);
45 // Ensures FrameTree correctly reflects page structure during navigations.
46 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeShape) {
47 GURL base_url = embedded_test_server()->GetURL("A.com", "/site_isolation/");
49 // Load doc without iframes. Verify FrameTree just has root.
50 // Frame tree:
51 // Site-A Root
52 NavigateToURL(shell(), base_url.Resolve("blank.html"));
53 FrameTreeNode* root =
54 static_cast<WebContentsImpl*>(shell()->web_contents())->
55 GetFrameTree()->root();
56 EXPECT_EQ(0U, root->child_count());
58 // Add 2 same-site frames. Verify 3 nodes in tree with proper names.
59 // Frame tree:
60 // Site-A Root -- Site-A frame1
61 // \-- Site-A frame2
62 WindowedNotificationObserver observer1(
63 content::NOTIFICATION_LOAD_STOP,
64 content::Source<NavigationController>(
65 &shell()->web_contents()->GetController()));
66 NavigateToURL(shell(), base_url.Resolve("frames-X-X.html"));
67 observer1.Wait();
68 ASSERT_EQ(2U, root->child_count());
69 EXPECT_EQ(0U, root->child_at(0)->child_count());
70 EXPECT_EQ(0U, root->child_at(1)->child_count());
73 // TODO(ajwong): Talk with nasko and merge this functionality with
74 // FrameTreeShape.
75 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeShape2) {
76 NavigateToURL(shell(),
77 embedded_test_server()->GetURL("/frame_tree/top.html"));
79 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
80 FrameTreeNode* root = wc->GetFrameTree()->root();
82 // Check that the root node is properly created.
83 ASSERT_EQ(3UL, root->child_count());
84 EXPECT_EQ(std::string(), root->frame_name());
86 ASSERT_EQ(2UL, root->child_at(0)->child_count());
87 EXPECT_STREQ("1-1-name", root->child_at(0)->frame_name().c_str());
89 // Verify the deepest node exists and has the right name.
90 ASSERT_EQ(2UL, root->child_at(2)->child_count());
91 EXPECT_EQ(1UL, root->child_at(2)->child_at(1)->child_count());
92 EXPECT_EQ(0UL, root->child_at(2)->child_at(1)->child_at(0)->child_count());
93 EXPECT_STREQ("3-1-name",
94 root->child_at(2)->child_at(1)->child_at(0)->frame_name().c_str());
96 // Navigate to about:blank, which should leave only the root node of the frame
97 // tree in the browser process.
98 NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
100 root = wc->GetFrameTree()->root();
101 EXPECT_EQ(0UL, root->child_count());
102 EXPECT_EQ(std::string(), root->frame_name());
105 // Test that we can navigate away if the previous renderer doesn't clean up its
106 // child frames.
107 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeAfterCrash) {
108 NavigateToURL(shell(),
109 embedded_test_server()->GetURL("/frame_tree/top.html"));
111 // Ensure the view and frame are live.
112 RenderViewHost* rvh = shell()->web_contents()->GetRenderViewHost();
113 RenderFrameHostImpl* rfh =
114 static_cast<RenderFrameHostImpl*>(rvh->GetMainFrame());
115 EXPECT_TRUE(rvh->IsRenderViewLive());
116 EXPECT_TRUE(rfh->IsRenderFrameLive());
118 // Crash the renderer so that it doesn't send any FrameDetached messages.
119 RenderProcessHostWatcher crash_observer(
120 shell()->web_contents(),
121 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
122 NavigateToURL(shell(), GURL(kChromeUICrashURL));
123 crash_observer.Wait();
125 // The frame tree should be cleared.
126 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
127 FrameTreeNode* root = wc->GetFrameTree()->root();
128 EXPECT_EQ(0UL, root->child_count());
130 // Ensure the view and frame aren't live anymore.
131 EXPECT_FALSE(rvh->IsRenderViewLive());
132 EXPECT_FALSE(rfh->IsRenderFrameLive());
134 // Navigate to a new URL.
135 GURL url(embedded_test_server()->GetURL("/title1.html"));
136 NavigateToURL(shell(), url);
137 EXPECT_EQ(0UL, root->child_count());
138 EXPECT_EQ(url, root->current_url());
140 // Ensure the view and frame are live again.
141 EXPECT_TRUE(rvh->IsRenderViewLive());
142 EXPECT_TRUE(rfh->IsRenderFrameLive());
145 // Test that we can navigate away if the previous renderer doesn't clean up its
146 // child frames.
147 // Flaky on Mac. http://crbug.com/452018
148 #if defined(OS_MACOSX)
149 #define MAYBE_NavigateWithLeftoverFrames DISABLED_NavigateWithLeftoverFrames
150 #else
151 #define MAYBE_NavigateWithLeftoverFrames NavigateWithLeftoverFrames
152 #endif
153 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, MAYBE_NavigateWithLeftoverFrames) {
154 #if defined(OS_WIN)
155 // Flaky on XP bot http://crbug.com/468713
156 if (base::win::GetVersion() <= base::win::VERSION_XP)
157 return;
158 #endif
159 GURL base_url = embedded_test_server()->GetURL("A.com", "/site_isolation/");
161 NavigateToURL(shell(),
162 embedded_test_server()->GetURL("/frame_tree/top.html"));
164 // Hang the renderer so that it doesn't send any FrameDetached messages.
165 // (This navigation will never complete, so don't wait for it.)
166 shell()->LoadURL(GURL(kChromeUIHangURL));
168 // Check that the frame tree still has children.
169 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
170 FrameTreeNode* root = wc->GetFrameTree()->root();
171 ASSERT_EQ(3UL, root->child_count());
173 // Navigate to a new URL. We use LoadURL because NavigateToURL will try to
174 // wait for the previous navigation to stop.
175 TestNavigationObserver tab_observer(wc, 1);
176 shell()->LoadURL(base_url.Resolve("blank.html"));
177 tab_observer.Wait();
179 // The frame tree should now be cleared.
180 EXPECT_EQ(0UL, root->child_count());
183 // Ensure that IsRenderFrameLive is true for main frames and same-site iframes.
184 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, IsRenderFrameLive) {
185 GURL main_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
186 NavigateToURL(shell(), main_url);
188 // It is safe to obtain the root frame tree node here, as it doesn't change.
189 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
190 ->GetFrameTree()->root();
192 // The root and subframe should each have a live RenderFrame.
193 EXPECT_TRUE(
194 root->current_frame_host()->render_view_host()->IsRenderViewLive());
195 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
196 EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
198 // Load a same-site page into iframe and it should still be live.
199 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
200 NavigateFrameToURL(root->child_at(0), http_url);
201 EXPECT_TRUE(
202 root->current_frame_host()->render_view_host()->IsRenderViewLive());
203 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
204 EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
207 // Ensure that origins are correctly set on navigations.
208 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, OriginSetOnNavigation) {
209 GURL main_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
210 EXPECT_TRUE(NavigateToURL(shell(), main_url));
212 // It is safe to obtain the root frame tree node here, as it doesn't change.
213 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
214 ->GetFrameTree()->root();
216 // Extra '/' is added because the replicated origin is serialized in RFC 6454
217 // format, which dictates no trailing '/', whereas GURL::GetOrigin does put a
218 // '/' at the end.
219 EXPECT_EQ(root->current_replication_state().origin.string() + '/',
220 main_url.GetOrigin().spec());
222 GURL frame_url(embedded_test_server()->GetURL("/title1.html"));
223 NavigateFrameToURL(root->child_at(0), frame_url);
225 EXPECT_EQ(
226 root->child_at(0)->current_replication_state().origin.string() + '/',
227 frame_url.GetOrigin().spec());
229 GURL data_url("data:text/html,foo");
230 EXPECT_TRUE(NavigateToURL(shell(), data_url));
232 // Navigating to a data URL should set a unique origin. This is represented
233 // as "null" per RFC 6454.
234 EXPECT_EQ(root->current_replication_state().origin.string(), "null");
236 // Re-navigating to a normal URL should update the origin.
237 EXPECT_TRUE(NavigateToURL(shell(), main_url));
238 EXPECT_EQ(root->current_replication_state().origin.string() + '/',
239 main_url.GetOrigin().spec());
242 // Ensure that sandbox flags are correctly set when child frames are created.
243 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, SandboxFlagsSetForChildFrames) {
244 GURL main_url(embedded_test_server()->GetURL("/sandboxed_frames.html"));
245 EXPECT_TRUE(NavigateToURL(shell(), main_url));
247 // It is safe to obtain the root frame tree node here, as it doesn't change.
248 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
249 ->GetFrameTree()->root();
251 // Verify that sandbox flags are set properly for all FrameTreeNodes.
252 // First frame is completely sandboxed; second frame uses "allow-scripts",
253 // which resets both SandboxFlags::Scripts and
254 // SandboxFlags::AutomaticFeatures bits per blink::parseSandboxPolicy(), and
255 // third frame has "allow-scripts allow-same-origin".
256 EXPECT_EQ(root->current_replication_state().sandbox_flags,
257 SandboxFlags::NONE);
258 EXPECT_EQ(root->child_at(0)->current_replication_state().sandbox_flags,
259 SandboxFlags::ALL);
260 EXPECT_EQ(root->child_at(1)->current_replication_state().sandbox_flags,
261 SandboxFlags::ALL & ~SandboxFlags::SCRIPTS &
262 ~SandboxFlags::AUTOMATIC_FEATURES);
263 EXPECT_EQ(root->child_at(2)->current_replication_state().sandbox_flags,
264 SandboxFlags::ALL & ~SandboxFlags::SCRIPTS &
265 ~SandboxFlags::AUTOMATIC_FEATURES & ~SandboxFlags::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.string(),
270 "null");
271 EXPECT_EQ(root->child_at(1)->current_replication_state().origin.string(),
272 "null");
273 EXPECT_EQ(
274 root->child_at(2)->current_replication_state().origin.string() + "/",
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 SandboxFlags::ALL);
284 class CrossProcessFrameTreeBrowserTest : public ContentBrowserTest {
285 public:
286 CrossProcessFrameTreeBrowserTest() {}
288 void SetUpCommandLine(base::CommandLine* command_line) override {
289 command_line->AppendSwitch(switches::kSitePerProcess);
292 void SetUpOnMainThread() override {
293 host_resolver()->AddRule("*", "127.0.0.1");
294 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
295 SetupCrossSiteRedirector(embedded_test_server());
298 private:
299 DISALLOW_COPY_AND_ASSIGN(CrossProcessFrameTreeBrowserTest);
302 // Ensure that we can complete a cross-process subframe navigation.
303 #if defined(OS_ANDROID)
304 #define MAYBE_CreateCrossProcessSubframeProxies DISABLED_CreateCrossProcessSubframeProxies
305 #else
306 #define MAYBE_CreateCrossProcessSubframeProxies CreateCrossProcessSubframeProxies
307 #endif
308 IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
309 MAYBE_CreateCrossProcessSubframeProxies) {
310 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
311 NavigateToURL(shell(), main_url);
313 // It is safe to obtain the root frame tree node here, as it doesn't change.
314 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
315 ->GetFrameTree()->root();
317 // There should not be a proxy for the root's own SiteInstance.
318 SiteInstance* root_instance = root->current_frame_host()->GetSiteInstance();
319 EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost(root_instance));
321 // Load same-site page into iframe.
322 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
323 NavigateFrameToURL(root->child_at(0), http_url);
325 // Load cross-site page into iframe.
326 GURL cross_site_url(
327 embedded_test_server()->GetURL("foo.com", "/title2.html"));
328 NavigateFrameToURL(root->child_at(0), cross_site_url);
330 // Ensure that we have created a new process for the subframe.
331 ASSERT_EQ(2U, root->child_count());
332 FrameTreeNode* child = root->child_at(0);
333 SiteInstance* child_instance = child->current_frame_host()->GetSiteInstance();
334 RenderViewHost* rvh = child->current_frame_host()->render_view_host();
335 RenderProcessHost* rph = child->current_frame_host()->GetProcess();
337 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh);
338 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), child_instance);
339 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph);
341 // Ensure that the root node has a proxy for the child node's SiteInstance.
342 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(child_instance));
344 // Also ensure that the child has a proxy for the root node's SiteInstance.
345 EXPECT_TRUE(child->render_manager()->GetRenderFrameProxyHost(root_instance));
347 // The nodes should not have proxies for their own SiteInstance.
348 EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost(root_instance));
349 EXPECT_FALSE(
350 child->render_manager()->GetRenderFrameProxyHost(child_instance));
352 // Ensure that the RenderViews and RenderFrames are all live.
353 EXPECT_TRUE(
354 root->current_frame_host()->render_view_host()->IsRenderViewLive());
355 EXPECT_TRUE(
356 child->current_frame_host()->render_view_host()->IsRenderViewLive());
357 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
358 EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
361 IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
362 OriginSetOnCrossProcessNavigations) {
363 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
364 EXPECT_TRUE(NavigateToURL(shell(), main_url));
366 // It is safe to obtain the root frame tree node here, as it doesn't change.
367 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
368 ->GetFrameTree()->root();
370 EXPECT_EQ(root->current_replication_state().origin.string() + '/',
371 main_url.GetOrigin().spec());
373 // First frame is an about:blank frame. Check that its origin is correctly
374 // inherited from the parent.
375 EXPECT_EQ(
376 root->child_at(0)->current_replication_state().origin.string() + '/',
377 main_url.GetOrigin().spec());
379 // Second frame loads a same-site page. Its origin should also be the same
380 // as the parent.
381 EXPECT_EQ(
382 root->child_at(1)->current_replication_state().origin.string() + '/',
383 main_url.GetOrigin().spec());
385 // Load cross-site page into the first frame.
386 GURL cross_site_url(
387 embedded_test_server()->GetURL("foo.com", "/title2.html"));
388 NavigateFrameToURL(root->child_at(0), cross_site_url);
390 EXPECT_EQ(
391 root->child_at(0)->current_replication_state().origin.string() + '/',
392 cross_site_url.GetOrigin().spec());
394 // The root's origin shouldn't have changed.
395 EXPECT_EQ(root->current_replication_state().origin.string() + '/',
396 main_url.GetOrigin().spec());
398 GURL data_url("data:text/html,foo");
399 NavigateFrameToURL(root->child_at(1), data_url);
401 // Navigating to a data URL should set a unique origin. This is represented
402 // as "null" per RFC 6454.
403 EXPECT_EQ(root->child_at(1)->current_replication_state().origin.string(),
404 "null");
407 } // namespace content