Add remoting and PPAPI tests to GN build
[chromium-blink-merge.git] / content / browser / frame_host / frame_tree_browsertest.cc
blob6b46a7add62138a2438de365033a50bc5ce55021
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 namespace content {
26 class FrameTreeBrowserTest : public ContentBrowserTest {
27 public:
28 FrameTreeBrowserTest() {}
30 void SetUpOnMainThread() override {
31 host_resolver()->AddRule("*", "127.0.0.1");
32 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
33 SetupCrossSiteRedirector(embedded_test_server());
36 private:
37 DISALLOW_COPY_AND_ASSIGN(FrameTreeBrowserTest);
40 // Ensures FrameTree correctly reflects page structure during navigations.
41 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeShape) {
42 GURL base_url = embedded_test_server()->GetURL("A.com", "/site_isolation/");
44 // Load doc without iframes. Verify FrameTree just has root.
45 // Frame tree:
46 // Site-A Root
47 NavigateToURL(shell(), base_url.Resolve("blank.html"));
48 FrameTreeNode* root =
49 static_cast<WebContentsImpl*>(shell()->web_contents())->
50 GetFrameTree()->root();
51 EXPECT_EQ(0U, root->child_count());
53 // Add 2 same-site frames. Verify 3 nodes in tree with proper names.
54 // Frame tree:
55 // Site-A Root -- Site-A frame1
56 // \-- Site-A frame2
57 WindowedNotificationObserver observer1(
58 content::NOTIFICATION_LOAD_STOP,
59 content::Source<NavigationController>(
60 &shell()->web_contents()->GetController()));
61 NavigateToURL(shell(), base_url.Resolve("frames-X-X.html"));
62 observer1.Wait();
63 ASSERT_EQ(2U, root->child_count());
64 EXPECT_EQ(0U, root->child_at(0)->child_count());
65 EXPECT_EQ(0U, root->child_at(1)->child_count());
68 // TODO(ajwong): Talk with nasko and merge this functionality with
69 // FrameTreeShape.
70 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeShape2) {
71 NavigateToURL(shell(),
72 embedded_test_server()->GetURL("/frame_tree/top.html"));
74 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
75 FrameTreeNode* root = wc->GetFrameTree()->root();
77 // Check that the root node is properly created.
78 ASSERT_EQ(3UL, root->child_count());
79 EXPECT_EQ(std::string(), root->frame_name());
81 ASSERT_EQ(2UL, root->child_at(0)->child_count());
82 EXPECT_STREQ("1-1-name", root->child_at(0)->frame_name().c_str());
84 // Verify the deepest node exists and has the right name.
85 ASSERT_EQ(2UL, root->child_at(2)->child_count());
86 EXPECT_EQ(1UL, root->child_at(2)->child_at(1)->child_count());
87 EXPECT_EQ(0UL, root->child_at(2)->child_at(1)->child_at(0)->child_count());
88 EXPECT_STREQ("3-1-name",
89 root->child_at(2)->child_at(1)->child_at(0)->frame_name().c_str());
91 // Navigate to about:blank, which should leave only the root node of the frame
92 // tree in the browser process.
93 NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
95 root = wc->GetFrameTree()->root();
96 EXPECT_EQ(0UL, root->child_count());
97 EXPECT_EQ(std::string(), root->frame_name());
100 // Test that we can navigate away if the previous renderer doesn't clean up its
101 // child frames.
102 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, FrameTreeAfterCrash) {
103 NavigateToURL(shell(),
104 embedded_test_server()->GetURL("/frame_tree/top.html"));
106 // Ensure the view and frame are live.
107 RenderViewHost* rvh = shell()->web_contents()->GetRenderViewHost();
108 RenderFrameHostImpl* rfh =
109 static_cast<RenderFrameHostImpl*>(rvh->GetMainFrame());
110 EXPECT_TRUE(rvh->IsRenderViewLive());
111 EXPECT_TRUE(rfh->IsRenderFrameLive());
113 // Crash the renderer so that it doesn't send any FrameDetached messages.
114 RenderProcessHostWatcher crash_observer(
115 shell()->web_contents(),
116 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
117 NavigateToURL(shell(), GURL(kChromeUICrashURL));
118 crash_observer.Wait();
120 // The frame tree should be cleared.
121 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
122 FrameTreeNode* root = wc->GetFrameTree()->root();
123 EXPECT_EQ(0UL, root->child_count());
125 // Ensure the view and frame aren't live anymore.
126 EXPECT_FALSE(rvh->IsRenderViewLive());
127 EXPECT_FALSE(rfh->IsRenderFrameLive());
129 // Navigate to a new URL.
130 GURL url(embedded_test_server()->GetURL("/title1.html"));
131 NavigateToURL(shell(), url);
132 EXPECT_EQ(0UL, root->child_count());
133 EXPECT_EQ(url, root->current_url());
135 // Ensure the view and frame are live again.
136 EXPECT_TRUE(rvh->IsRenderViewLive());
137 EXPECT_TRUE(rfh->IsRenderFrameLive());
140 // Test that we can navigate away if the previous renderer doesn't clean up its
141 // child frames.
142 // Flaky on Mac. http://crbug.com/452018
143 #if defined(OS_MACOSX)
144 #define MAYBE_NavigateWithLeftoverFrames DISABLED_NavigateWithLeftoverFrames
145 #else
146 #define MAYBE_NavigateWithLeftoverFrames NavigateWithLeftoverFrames
147 #endif
148 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, MAYBE_NavigateWithLeftoverFrames) {
149 GURL base_url = embedded_test_server()->GetURL("A.com", "/site_isolation/");
151 NavigateToURL(shell(),
152 embedded_test_server()->GetURL("/frame_tree/top.html"));
154 // Hang the renderer so that it doesn't send any FrameDetached messages.
155 // (This navigation will never complete, so don't wait for it.)
156 shell()->LoadURL(GURL(kChromeUIHangURL));
158 // Check that the frame tree still has children.
159 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
160 FrameTreeNode* root = wc->GetFrameTree()->root();
161 ASSERT_EQ(3UL, root->child_count());
163 // Navigate to a new URL. We use LoadURL because NavigateToURL will try to
164 // wait for the previous navigation to stop.
165 TestNavigationObserver tab_observer(wc, 1);
166 shell()->LoadURL(base_url.Resolve("blank.html"));
167 tab_observer.Wait();
169 // The frame tree should now be cleared.
170 EXPECT_EQ(0UL, root->child_count());
173 // Ensure that IsRenderFrameLive is true for main frames and same-site iframes.
174 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, IsRenderFrameLive) {
175 GURL main_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
176 NavigateToURL(shell(), main_url);
178 // It is safe to obtain the root frame tree node here, as it doesn't change.
179 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
180 ->GetFrameTree()->root();
182 // The root and subframe should each have a live RenderFrame.
183 EXPECT_TRUE(
184 root->current_frame_host()->render_view_host()->IsRenderViewLive());
185 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
186 EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
188 // Load a same-site page into iframe and it should still be live.
189 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
190 NavigateFrameToURL(root->child_at(0), http_url);
191 EXPECT_TRUE(
192 root->current_frame_host()->render_view_host()->IsRenderViewLive());
193 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
194 EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
197 // Ensure that origins are correctly set on navigations.
198 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, OriginSetOnNavigation) {
199 GURL main_url(embedded_test_server()->GetURL("/frame_tree/top.html"));
200 EXPECT_TRUE(NavigateToURL(shell(), main_url));
202 // It is safe to obtain the root frame tree node here, as it doesn't change.
203 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
204 ->GetFrameTree()->root();
206 // Extra '/' is added because the replicated origin is serialized in RFC 6454
207 // format, which dictates no trailing '/', whereas GURL::GetOrigin does put a
208 // '/' at the end.
209 EXPECT_EQ(root->current_replication_state().origin.string() + '/',
210 main_url.GetOrigin().spec());
212 GURL frame_url(embedded_test_server()->GetURL("/title1.html"));
213 NavigateFrameToURL(root->child_at(0), frame_url);
215 EXPECT_EQ(
216 root->child_at(0)->current_replication_state().origin.string() + '/',
217 frame_url.GetOrigin().spec());
219 GURL data_url("data:text/html,foo");
220 EXPECT_TRUE(NavigateToURL(shell(), data_url));
222 // Navigating to a data URL should set a unique origin. This is represented
223 // as "null" per RFC 6454.
224 EXPECT_EQ(root->current_replication_state().origin.string(), "null");
226 // Re-navigating to a normal URL should update the origin.
227 EXPECT_TRUE(NavigateToURL(shell(), main_url));
228 EXPECT_EQ(root->current_replication_state().origin.string() + '/',
229 main_url.GetOrigin().spec());
232 // Ensure that sandbox flags are correctly set when child frames are created.
233 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, SandboxFlagsSetForChildFrames) {
234 GURL main_url(embedded_test_server()->GetURL("/sandboxed_frames.html"));
235 EXPECT_TRUE(NavigateToURL(shell(), main_url));
237 // It is safe to obtain the root frame tree node here, as it doesn't change.
238 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
239 ->GetFrameTree()->root();
241 // Verify that sandbox flags are set properly for all FrameTreeNodes.
242 // First frame is completely sandboxed; second frame uses "allow-scripts",
243 // which resets both SandboxFlags::Scripts and
244 // SandboxFlags::AutomaticFeatures bits per blink::parseSandboxPolicy(), and
245 // third frame has "allow-scripts allow-same-origin".
246 EXPECT_EQ(root->current_replication_state().sandbox_flags,
247 SandboxFlags::NONE);
248 EXPECT_EQ(root->child_at(0)->current_replication_state().sandbox_flags,
249 SandboxFlags::ALL);
250 EXPECT_EQ(root->child_at(1)->current_replication_state().sandbox_flags,
251 SandboxFlags::ALL & ~SandboxFlags::SCRIPTS &
252 ~SandboxFlags::AUTOMATIC_FEATURES);
253 EXPECT_EQ(root->child_at(2)->current_replication_state().sandbox_flags,
254 SandboxFlags::ALL & ~SandboxFlags::SCRIPTS &
255 ~SandboxFlags::AUTOMATIC_FEATURES & ~SandboxFlags::ORIGIN);
257 // Sandboxed frames should set a unique origin unless they have the
258 // "allow-same-origin" directive.
259 EXPECT_EQ(root->child_at(0)->current_replication_state().origin.string(),
260 "null");
261 EXPECT_EQ(root->child_at(1)->current_replication_state().origin.string(),
262 "null");
263 EXPECT_EQ(
264 root->child_at(2)->current_replication_state().origin.string() + "/",
265 main_url.GetOrigin().spec());
267 // Navigating to a different URL should not clear sandbox flags.
268 GURL frame_url(embedded_test_server()->GetURL("/title1.html"));
269 NavigateFrameToURL(root->child_at(0), frame_url);
270 EXPECT_EQ(root->child_at(0)->current_replication_state().sandbox_flags,
271 SandboxFlags::ALL);
274 class CrossProcessFrameTreeBrowserTest : public ContentBrowserTest {
275 public:
276 CrossProcessFrameTreeBrowserTest() {}
278 void SetUpCommandLine(base::CommandLine* command_line) override {
279 command_line->AppendSwitch(switches::kSitePerProcess);
282 void SetUpOnMainThread() override {
283 host_resolver()->AddRule("*", "127.0.0.1");
284 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
285 SetupCrossSiteRedirector(embedded_test_server());
288 private:
289 DISALLOW_COPY_AND_ASSIGN(CrossProcessFrameTreeBrowserTest);
292 // Ensure that we can complete a cross-process subframe navigation.
293 #if defined(OS_ANDROID)
294 #define MAYBE_CreateCrossProcessSubframeProxies DISABLED_CreateCrossProcessSubframeProxies
295 #else
296 #define MAYBE_CreateCrossProcessSubframeProxies CreateCrossProcessSubframeProxies
297 #endif
298 IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
299 MAYBE_CreateCrossProcessSubframeProxies) {
300 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
301 NavigateToURL(shell(), main_url);
303 // It is safe to obtain the root frame tree node here, as it doesn't change.
304 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
305 ->GetFrameTree()->root();
307 // There should not be a proxy for the root's own SiteInstance.
308 SiteInstance* root_instance = root->current_frame_host()->GetSiteInstance();
309 EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost(root_instance));
311 // Load same-site page into iframe.
312 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
313 NavigateFrameToURL(root->child_at(0), http_url);
315 // Load cross-site page into iframe.
316 GURL cross_site_url(
317 embedded_test_server()->GetURL("foo.com", "/title2.html"));
318 NavigateFrameToURL(root->child_at(0), cross_site_url);
320 // Ensure that we have created a new process for the subframe.
321 ASSERT_EQ(2U, root->child_count());
322 FrameTreeNode* child = root->child_at(0);
323 SiteInstance* child_instance = child->current_frame_host()->GetSiteInstance();
324 RenderViewHost* rvh = child->current_frame_host()->render_view_host();
325 RenderProcessHost* rph = child->current_frame_host()->GetProcess();
327 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh);
328 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), child_instance);
329 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph);
331 // Ensure that the root node has a proxy for the child node's SiteInstance.
332 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(child_instance));
334 // Also ensure that the child has a proxy for the root node's SiteInstance.
335 EXPECT_TRUE(child->render_manager()->GetRenderFrameProxyHost(root_instance));
337 // The nodes should not have proxies for their own SiteInstance.
338 EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost(root_instance));
339 EXPECT_FALSE(
340 child->render_manager()->GetRenderFrameProxyHost(child_instance));
342 // Ensure that the RenderViews and RenderFrames are all live.
343 EXPECT_TRUE(
344 root->current_frame_host()->render_view_host()->IsRenderViewLive());
345 EXPECT_TRUE(
346 child->current_frame_host()->render_view_host()->IsRenderViewLive());
347 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
348 EXPECT_TRUE(root->child_at(0)->current_frame_host()->IsRenderFrameLive());
351 IN_PROC_BROWSER_TEST_F(CrossProcessFrameTreeBrowserTest,
352 OriginSetOnCrossProcessNavigations) {
353 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
354 EXPECT_TRUE(NavigateToURL(shell(), main_url));
356 // It is safe to obtain the root frame tree node here, as it doesn't change.
357 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
358 ->GetFrameTree()->root();
360 EXPECT_EQ(root->current_replication_state().origin.string() + '/',
361 main_url.GetOrigin().spec());
363 // First frame is an about:blank frame. Check that its origin is correctly
364 // inherited from the parent.
365 EXPECT_EQ(
366 root->child_at(0)->current_replication_state().origin.string() + '/',
367 main_url.GetOrigin().spec());
369 // Second frame loads a same-site page. Its origin should also be the same
370 // as the parent.
371 EXPECT_EQ(
372 root->child_at(1)->current_replication_state().origin.string() + '/',
373 main_url.GetOrigin().spec());
375 // Load cross-site page into the first frame.
376 GURL cross_site_url(
377 embedded_test_server()->GetURL("foo.com", "/title2.html"));
378 NavigateFrameToURL(root->child_at(0), cross_site_url);
380 EXPECT_EQ(
381 root->child_at(0)->current_replication_state().origin.string() + '/',
382 cross_site_url.GetOrigin().spec());
384 // The root's origin shouldn't have changed.
385 EXPECT_EQ(root->current_replication_state().origin.string() + '/',
386 main_url.GetOrigin().spec());
388 GURL data_url("data:text/html,foo");
389 NavigateFrameToURL(root->child_at(1), data_url);
391 // Navigating to a data URL should set a unique origin. This is represented
392 // as "null" per RFC 6454.
393 EXPECT_EQ(root->child_at(1)->current_replication_state().origin.string(),
394 "null");
397 } // namespace content