aw: Rendering test harness and end-to-end smoke test
[chromium-blink-merge.git] / content / browser / site_per_process_browsertest.cc
blobcc7e1fa3948a836a8c42f627173aa4f04ed8ba6c
1 // Copyright (c) 2012 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/site_per_process_browsertest.h"
7 #include "base/command_line.h"
8 #include "base/strings/stringprintf.h"
9 #include "content/browser/frame_host/cross_process_frame_connector.h"
10 #include "content/browser/frame_host/frame_tree.h"
11 #include "content/browser/frame_host/navigator.h"
12 #include "content/browser/frame_host/render_frame_proxy_host.h"
13 #include "content/browser/frame_host/render_widget_host_view_child_frame.h"
14 #include "content/browser/renderer_host/render_view_host_impl.h"
15 #include "content/browser/web_contents/web_contents_impl.h"
16 #include "content/public/browser/notification_observer.h"
17 #include "content/public/browser/notification_service.h"
18 #include "content/public/browser/notification_types.h"
19 #include "content/public/browser/web_contents_observer.h"
20 #include "content/public/common/content_switches.h"
21 #include "content/public/test/browser_test_utils.h"
22 #include "content/public/test/content_browser_test_utils.h"
23 #include "content/public/test/test_utils.h"
24 #include "content/shell/browser/shell.h"
25 #include "content/test/content_browser_test_utils_internal.h"
26 #include "content/test/test_frame_navigation_observer.h"
27 #include "net/dns/mock_host_resolver.h"
28 #include "net/test/embedded_test_server/embedded_test_server.h"
30 namespace content {
32 class SitePerProcessWebContentsObserver: public WebContentsObserver {
33 public:
34 explicit SitePerProcessWebContentsObserver(WebContents* web_contents)
35 : WebContentsObserver(web_contents),
36 navigation_succeeded_(false) {}
37 ~SitePerProcessWebContentsObserver() override {}
39 void DidStartProvisionalLoadForFrame(RenderFrameHost* render_frame_host,
40 const GURL& validated_url,
41 bool is_error_page,
42 bool is_iframe_srcdoc) override {
43 navigation_succeeded_ = false;
46 void DidFailProvisionalLoad(
47 RenderFrameHost* render_frame_host,
48 const GURL& validated_url,
49 int error_code,
50 const base::string16& error_description) override {
51 navigation_url_ = validated_url;
52 navigation_succeeded_ = false;
55 void DidCommitProvisionalLoadForFrame(
56 RenderFrameHost* render_frame_host,
57 const GURL& url,
58 ui::PageTransition transition_type) override {
59 navigation_url_ = url;
60 navigation_succeeded_ = true;
63 const GURL& navigation_url() const {
64 return navigation_url_;
67 int navigation_succeeded() const { return navigation_succeeded_; }
69 private:
70 GURL navigation_url_;
71 bool navigation_succeeded_;
73 DISALLOW_COPY_AND_ASSIGN(SitePerProcessWebContentsObserver);
76 class RedirectNotificationObserver : public NotificationObserver {
77 public:
78 // Register to listen for notifications of the given type from either a
79 // specific source, or from all sources if |source| is
80 // NotificationService::AllSources().
81 RedirectNotificationObserver(int notification_type,
82 const NotificationSource& source);
83 ~RedirectNotificationObserver() override;
85 // Wait until the specified notification occurs. If the notification was
86 // emitted between the construction of this object and this call then it
87 // returns immediately.
88 void Wait();
90 // Returns NotificationService::AllSources() if we haven't observed a
91 // notification yet.
92 const NotificationSource& source() const {
93 return source_;
96 const NotificationDetails& details() const {
97 return details_;
100 // NotificationObserver:
101 void Observe(int type,
102 const NotificationSource& source,
103 const NotificationDetails& details) override;
105 private:
106 bool seen_;
107 bool seen_twice_;
108 bool running_;
109 NotificationRegistrar registrar_;
111 NotificationSource source_;
112 NotificationDetails details_;
113 scoped_refptr<MessageLoopRunner> message_loop_runner_;
115 DISALLOW_COPY_AND_ASSIGN(RedirectNotificationObserver);
118 RedirectNotificationObserver::RedirectNotificationObserver(
119 int notification_type,
120 const NotificationSource& source)
121 : seen_(false),
122 running_(false),
123 source_(NotificationService::AllSources()) {
124 registrar_.Add(this, notification_type, source);
127 RedirectNotificationObserver::~RedirectNotificationObserver() {}
129 void RedirectNotificationObserver::Wait() {
130 if (seen_ && seen_twice_)
131 return;
133 running_ = true;
134 message_loop_runner_ = new MessageLoopRunner;
135 message_loop_runner_->Run();
136 EXPECT_TRUE(seen_);
139 void RedirectNotificationObserver::Observe(
140 int type,
141 const NotificationSource& source,
142 const NotificationDetails& details) {
143 source_ = source;
144 details_ = details;
145 seen_twice_ = seen_;
146 seen_ = true;
147 if (!running_)
148 return;
150 message_loop_runner_->Quit();
151 running_ = false;
154 // This observer keeps track of the number of created RenderFrameHosts. Tests
155 // can use this to ensure that a certain number of child frames has been
156 // created after navigating.
157 class RenderFrameHostCreatedObserver : public WebContentsObserver {
158 public:
159 RenderFrameHostCreatedObserver(WebContents* web_contents,
160 int expected_frame_count)
161 : WebContentsObserver(web_contents),
162 expected_frame_count_(expected_frame_count),
163 frames_created_(0),
164 message_loop_runner_(new MessageLoopRunner) {}
166 ~RenderFrameHostCreatedObserver() override;
168 // Runs a nested message loop and blocks until the expected number of
169 // RenderFrameHosts is created.
170 void Wait();
172 private:
173 // WebContentsObserver
174 void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
176 // The number of RenderFrameHosts to wait for.
177 int expected_frame_count_;
179 // The number of RenderFrameHosts that have been created.
180 int frames_created_;
182 // The MessageLoopRunner used to spin the message loop.
183 scoped_refptr<MessageLoopRunner> message_loop_runner_;
185 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostCreatedObserver);
188 RenderFrameHostCreatedObserver::~RenderFrameHostCreatedObserver() {
191 void RenderFrameHostCreatedObserver::Wait() {
192 message_loop_runner_->Run();
195 void RenderFrameHostCreatedObserver::RenderFrameCreated(
196 RenderFrameHost* render_frame_host) {
197 frames_created_++;
198 if (frames_created_ == expected_frame_count_) {
199 message_loop_runner_->Quit();
204 // SitePerProcessBrowserTest
207 SitePerProcessBrowserTest::SitePerProcessBrowserTest() {
210 void SitePerProcessBrowserTest::StartFrameAtDataURL() {
211 std::string data_url_script =
212 "var iframes = document.getElementById('test');iframes.src="
213 "'data:text/html,dataurl';";
214 ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script));
217 bool SitePerProcessBrowserTest::NavigateIframeToURL(Shell* window,
218 const GURL& url,
219 std::string iframe_id) {
220 // TODO(creis): This should wait for LOAD_STOP, but cross-site subframe
221 // navigations generate extra DidStartLoading and DidStopLoading messages.
222 // Until we replace swappedout:// with frame proxies, we need to listen for
223 // something else. For now, we trigger NEW_SUBFRAME navigations and listen
224 // for commit.
225 std::string script = base::StringPrintf(
226 "setTimeout(\""
227 "var iframes = document.getElementById('%s');iframes.src='%s';"
228 "\",0)",
229 iframe_id.c_str(), url.spec().c_str());
230 WindowedNotificationObserver load_observer(
231 NOTIFICATION_NAV_ENTRY_COMMITTED,
232 Source<NavigationController>(
233 &window->web_contents()->GetController()));
234 bool result = ExecuteScript(window->web_contents(), script);
235 load_observer.Wait();
236 return result;
239 void SitePerProcessBrowserTest::SetUpCommandLine(CommandLine* command_line) {
240 command_line->AppendSwitch(switches::kSitePerProcess);
243 void SitePerProcessBrowserTest::SetUpOnMainThread() {
244 host_resolver()->AddRule("*", "127.0.0.1");
245 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
246 SetupCrossSiteRedirector(embedded_test_server());
249 // Ensure that navigating subframes in --site-per-process mode works and the
250 // correct documents are committed.
251 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) {
252 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
253 NavigateToURL(shell(), main_url);
255 // It is safe to obtain the root frame tree node here, as it doesn't change.
256 FrameTreeNode* root =
257 static_cast<WebContentsImpl*>(shell()->web_contents())->
258 GetFrameTree()->root();
260 SitePerProcessWebContentsObserver observer(shell()->web_contents());
262 // Load same-site page into iframe.
263 FrameTreeNode* child = root->child_at(0);
264 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
265 NavigateFrameToURL(child, http_url);
266 EXPECT_EQ(http_url, observer.navigation_url());
267 EXPECT_TRUE(observer.navigation_succeeded());
269 // There should be only one RenderWidgetHost when there are no
270 // cross-process iframes.
271 std::set<RenderWidgetHostView*> views_set =
272 static_cast<WebContentsImpl*>(shell()->web_contents())
273 ->GetRenderWidgetHostViewsInTree();
274 EXPECT_EQ(1U, views_set.size());
276 RenderFrameProxyHost* proxy_to_parent =
277 child->render_manager()->GetRenderFrameProxyHost(
278 shell()->web_contents()->GetSiteInstance());
279 EXPECT_FALSE(proxy_to_parent);
281 // Load cross-site page into iframe.
282 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
283 NavigateFrameToURL(root->child_at(0), url);
284 // Verify that the navigation succeeded and the expected URL was loaded.
285 EXPECT_TRUE(observer.navigation_succeeded());
286 EXPECT_EQ(url, observer.navigation_url());
288 // Ensure that we have created a new process for the subframe.
289 ASSERT_EQ(2U, root->child_count());
290 SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
291 RenderViewHost* rvh = child->current_frame_host()->render_view_host();
292 RenderProcessHost* rph = child->current_frame_host()->GetProcess();
293 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh);
294 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
295 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph);
297 // There should be now two RenderWidgetHosts, one for each process
298 // rendering a frame.
299 std::set<RenderWidgetHostView*> views_set =
300 static_cast<WebContentsImpl*>(shell()->web_contents())
301 ->GetRenderWidgetHostViewsInTree();
302 EXPECT_EQ(2U, views_set.size());
304 proxy_to_parent = child->render_manager()->GetProxyToParent();
305 EXPECT_TRUE(proxy_to_parent);
306 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
307 EXPECT_EQ(
308 rvh->GetView(),
309 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
311 // Load another cross-site page into the same iframe.
312 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
313 NavigateFrameToURL(root->child_at(0), url);
314 EXPECT_TRUE(observer.navigation_succeeded());
315 EXPECT_EQ(url, observer.navigation_url());
317 // Check again that a new process is created and is different from the
318 // top level one and the previous one.
319 ASSERT_EQ(2U, root->child_count());
320 child = root->child_at(0);
321 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(),
322 child->current_frame_host()->render_view_host());
323 EXPECT_NE(rvh, child->current_frame_host()->render_view_host());
324 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
325 child->current_frame_host()->GetSiteInstance());
326 EXPECT_NE(site_instance,
327 child->current_frame_host()->GetSiteInstance());
328 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(),
329 child->current_frame_host()->GetProcess());
330 EXPECT_NE(rph, child->current_frame_host()->GetProcess());
332 std::set<RenderWidgetHostView*> views_set =
333 static_cast<WebContentsImpl*>(shell()->web_contents())
334 ->GetRenderWidgetHostViewsInTree();
335 EXPECT_EQ(2U, views_set.size());
337 EXPECT_EQ(proxy_to_parent, child->render_manager()->GetProxyToParent());
338 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
339 EXPECT_EQ(
340 child->current_frame_host()->render_view_host()->GetView(),
341 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
344 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigateRemoteFrame) {
345 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
346 NavigateToURL(shell(), main_url);
348 // It is safe to obtain the root frame tree node here, as it doesn't change.
349 FrameTreeNode* root =
350 static_cast<WebContentsImpl*>(shell()->web_contents())->
351 GetFrameTree()->root();
353 SitePerProcessWebContentsObserver observer(shell()->web_contents());
355 // Load same-site page into iframe.
356 FrameTreeNode* child = root->child_at(0);
357 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
358 NavigateFrameToURL(child, http_url);
359 EXPECT_EQ(http_url, observer.navigation_url());
360 EXPECT_TRUE(observer.navigation_succeeded());
362 // Load cross-site page into iframe.
363 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
364 NavigateFrameToURL(root->child_at(0), url);
365 EXPECT_TRUE(observer.navigation_succeeded());
366 EXPECT_EQ(url, observer.navigation_url());
368 // Ensure that we have created a new process for the subframe.
369 ASSERT_EQ(2U, root->child_count());
370 SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
371 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
373 // Emulate the main frame changing the src of the iframe such that it
374 // navigates cross-site.
375 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
376 NavigateIframeToURL(shell(), url, "test");
377 EXPECT_TRUE(observer.navigation_succeeded());
378 EXPECT_EQ(url, observer.navigation_url());
380 // Check again that a new process is created and is different from the
381 // top level one and the previous one.
382 ASSERT_EQ(2U, root->child_count());
383 child = root->child_at(0);
384 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
385 child->current_frame_host()->GetSiteInstance());
386 EXPECT_NE(site_instance,
387 child->current_frame_host()->GetSiteInstance());
389 // Navigate back to the parent's origin and ensure we return to the
390 // parent's process.
391 NavigateFrameToURL(child, http_url);
392 EXPECT_EQ(http_url, observer.navigation_url());
393 EXPECT_TRUE(observer.navigation_succeeded());
394 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
395 child->current_frame_host()->GetSiteInstance());
398 // Crash a subframe and ensures its children are cleared from the FrameTree.
399 // See http://crbug.com/338508.
400 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrashSubframe) {
401 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
402 NavigateToURL(shell(), main_url);
404 StartFrameAtDataURL();
406 // These must stay in scope with replace_host.
407 GURL::Replacements replace_host;
408 std::string foo_com("foo.com");
410 // Load cross-site page into iframe.
411 EXPECT_TRUE(NavigateIframeToURL(
412 shell(),
413 embedded_test_server()->GetURL("/cross-site/foo.com/title2.html"),
414 "test"));
416 // Check the subframe process.
417 FrameTreeNode* root =
418 static_cast<WebContentsImpl*>(shell()->web_contents())->
419 GetFrameTree()->root();
420 ASSERT_EQ(2U, root->child_count());
421 FrameTreeNode* child = root->child_at(0);
422 EXPECT_EQ(main_url, root->current_url());
423 EXPECT_EQ("foo.com", child->current_url().host());
424 EXPECT_EQ("/title2.html", child->current_url().path());
426 EXPECT_TRUE(
427 child->current_frame_host()->render_view_host()->IsRenderViewLive());
428 EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive());
430 // Crash the subframe process.
431 RenderProcessHost* root_process = root->current_frame_host()->GetProcess();
432 RenderProcessHost* child_process = child->current_frame_host()->GetProcess();
434 RenderProcessHostWatcher crash_observer(
435 child_process,
436 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
437 child_process->Shutdown(0, false);
438 crash_observer.Wait();
441 // Ensure that the child frame still exists but has been cleared.
442 EXPECT_EQ(2U, root->child_count());
443 EXPECT_EQ(main_url, root->current_url());
444 EXPECT_EQ(GURL(), child->current_url());
446 EXPECT_FALSE(
447 child->current_frame_host()->render_view_host()->IsRenderViewLive());
448 EXPECT_FALSE(child->current_frame_host()->IsRenderFrameLive());
449 EXPECT_FALSE(child->current_frame_host()->render_frame_created_);
451 // Now crash the top-level page to clear the child frame.
453 RenderProcessHostWatcher crash_observer(
454 root_process,
455 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
456 root_process->Shutdown(0, false);
457 crash_observer.Wait();
459 EXPECT_EQ(0U, root->child_count());
460 EXPECT_EQ(GURL(), root->current_url());
463 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
464 // security checks are back in place.
465 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
466 // on Android (http://crbug.com/187570).
467 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
468 DISABLED_CrossSiteIframeRedirectOnce) {
469 ASSERT_TRUE(test_server()->Start());
470 net::SpawnedTestServer https_server(
471 net::SpawnedTestServer::TYPE_HTTPS,
472 net::SpawnedTestServer::kLocalhost,
473 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
474 ASSERT_TRUE(https_server.Start());
476 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
477 GURL http_url(test_server()->GetURL("files/title1.html"));
478 GURL https_url(https_server.GetURL("files/title1.html"));
480 NavigateToURL(shell(), main_url);
482 SitePerProcessWebContentsObserver observer(shell()->web_contents());
484 // Load cross-site client-redirect page into Iframe.
485 // Should be blocked.
486 GURL client_redirect_https_url(https_server.GetURL(
487 "client-redirect?files/title1.html"));
488 EXPECT_TRUE(NavigateIframeToURL(shell(),
489 client_redirect_https_url, "test"));
490 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
491 EXPECT_EQ(observer.navigation_url(), client_redirect_https_url);
492 EXPECT_FALSE(observer.navigation_succeeded());
496 // Load cross-site server-redirect page into Iframe,
497 // which redirects to same-site page.
498 GURL server_redirect_http_url(https_server.GetURL(
499 "server-redirect?" + http_url.spec()));
500 EXPECT_TRUE(NavigateIframeToURL(shell(),
501 server_redirect_http_url, "test"));
502 EXPECT_EQ(observer.navigation_url(), http_url);
503 EXPECT_TRUE(observer.navigation_succeeded());
507 // Load cross-site server-redirect page into Iframe,
508 // which redirects to cross-site page.
509 GURL server_redirect_http_url(https_server.GetURL(
510 "server-redirect?files/title1.html"));
511 EXPECT_TRUE(NavigateIframeToURL(shell(),
512 server_redirect_http_url, "test"));
513 // DidFailProvisionalLoad when navigating to https_url.
514 EXPECT_EQ(observer.navigation_url(), https_url);
515 EXPECT_FALSE(observer.navigation_succeeded());
519 // Load same-site server-redirect page into Iframe,
520 // which redirects to cross-site page.
521 GURL server_redirect_http_url(test_server()->GetURL(
522 "server-redirect?" + https_url.spec()));
523 EXPECT_TRUE(NavigateIframeToURL(shell(),
524 server_redirect_http_url, "test"));
526 EXPECT_EQ(observer.navigation_url(), https_url);
527 EXPECT_FALSE(observer.navigation_succeeded());
531 // Load same-site client-redirect page into Iframe,
532 // which redirects to cross-site page.
533 GURL client_redirect_http_url(test_server()->GetURL(
534 "client-redirect?" + https_url.spec()));
536 RedirectNotificationObserver load_observer2(
537 NOTIFICATION_LOAD_STOP,
538 Source<NavigationController>(
539 &shell()->web_contents()->GetController()));
541 EXPECT_TRUE(NavigateIframeToURL(shell(),
542 client_redirect_http_url, "test"));
544 // Same-site Client-Redirect Page should be loaded successfully.
545 EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
546 EXPECT_TRUE(observer.navigation_succeeded());
548 // Redirecting to Cross-site Page should be blocked.
549 load_observer2.Wait();
550 EXPECT_EQ(observer.navigation_url(), https_url);
551 EXPECT_FALSE(observer.navigation_succeeded());
555 // Load same-site server-redirect page into Iframe,
556 // which redirects to same-site page.
557 GURL server_redirect_http_url(test_server()->GetURL(
558 "server-redirect?files/title1.html"));
559 EXPECT_TRUE(NavigateIframeToURL(shell(),
560 server_redirect_http_url, "test"));
561 EXPECT_EQ(observer.navigation_url(), http_url);
562 EXPECT_TRUE(observer.navigation_succeeded());
566 // Load same-site client-redirect page into Iframe,
567 // which redirects to same-site page.
568 GURL client_redirect_http_url(test_server()->GetURL(
569 "client-redirect?" + http_url.spec()));
570 RedirectNotificationObserver load_observer2(
571 NOTIFICATION_LOAD_STOP,
572 Source<NavigationController>(
573 &shell()->web_contents()->GetController()));
575 EXPECT_TRUE(NavigateIframeToURL(shell(),
576 client_redirect_http_url, "test"));
578 // Same-site Client-Redirect Page should be loaded successfully.
579 EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
580 EXPECT_TRUE(observer.navigation_succeeded());
582 // Redirecting to Same-site Page should be loaded successfully.
583 load_observer2.Wait();
584 EXPECT_EQ(observer.navigation_url(), http_url);
585 EXPECT_TRUE(observer.navigation_succeeded());
589 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
590 // security checks are back in place.
591 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
592 // on Android (http://crbug.com/187570).
593 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
594 DISABLED_CrossSiteIframeRedirectTwice) {
595 ASSERT_TRUE(test_server()->Start());
596 net::SpawnedTestServer https_server(
597 net::SpawnedTestServer::TYPE_HTTPS,
598 net::SpawnedTestServer::kLocalhost,
599 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
600 ASSERT_TRUE(https_server.Start());
602 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
603 GURL http_url(test_server()->GetURL("files/title1.html"));
604 GURL https_url(https_server.GetURL("files/title1.html"));
606 NavigateToURL(shell(), main_url);
608 SitePerProcessWebContentsObserver observer(shell()->web_contents());
610 // Load client-redirect page pointing to a cross-site client-redirect page,
611 // which eventually redirects back to same-site page.
612 GURL client_redirect_https_url(https_server.GetURL(
613 "client-redirect?" + http_url.spec()));
614 GURL client_redirect_http_url(test_server()->GetURL(
615 "client-redirect?" + client_redirect_https_url.spec()));
617 // We should wait until second client redirect get cancelled.
618 RedirectNotificationObserver load_observer2(
619 NOTIFICATION_LOAD_STOP,
620 Source<NavigationController>(
621 &shell()->web_contents()->GetController()));
623 EXPECT_TRUE(NavigateIframeToURL(shell(), client_redirect_http_url, "test"));
625 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
626 load_observer2.Wait();
627 EXPECT_EQ(observer.navigation_url(), client_redirect_https_url);
628 EXPECT_FALSE(observer.navigation_succeeded());
632 // Load server-redirect page pointing to a cross-site server-redirect page,
633 // which eventually redirect back to same-site page.
634 GURL server_redirect_https_url(https_server.GetURL(
635 "server-redirect?" + http_url.spec()));
636 GURL server_redirect_http_url(test_server()->GetURL(
637 "server-redirect?" + server_redirect_https_url.spec()));
638 EXPECT_TRUE(NavigateIframeToURL(shell(),
639 server_redirect_http_url, "test"));
640 EXPECT_EQ(observer.navigation_url(), http_url);
641 EXPECT_TRUE(observer.navigation_succeeded());
645 // Load server-redirect page pointing to a cross-site server-redirect page,
646 // which eventually redirects back to cross-site page.
647 GURL server_redirect_https_url(https_server.GetURL(
648 "server-redirect?" + https_url.spec()));
649 GURL server_redirect_http_url(test_server()->GetURL(
650 "server-redirect?" + server_redirect_https_url.spec()));
651 EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url, "test"));
653 // DidFailProvisionalLoad when navigating to https_url.
654 EXPECT_EQ(observer.navigation_url(), https_url);
655 EXPECT_FALSE(observer.navigation_succeeded());
659 // Load server-redirect page pointing to a cross-site client-redirect page,
660 // which eventually redirects back to same-site page.
661 GURL client_redirect_http_url(https_server.GetURL(
662 "client-redirect?" + http_url.spec()));
663 GURL server_redirect_http_url(test_server()->GetURL(
664 "server-redirect?" + client_redirect_http_url.spec()));
665 EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url, "test"));
667 // DidFailProvisionalLoad when navigating to client_redirect_http_url.
668 EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
669 EXPECT_FALSE(observer.navigation_succeeded());
673 // Ensure that when navigating a frame cross-process RenderFrameProxyHosts are
674 // created in the FrameTree skipping the subtree of the navigating frame.
676 // Disabled on Mac due to flakiness on ASAN. http://crbug.com/425248
677 #if defined(OS_MACOSX)
678 #define MAYBE_ProxyCreationSkipsSubtree DISABLED_ProxyCreationSkipsSubtree
679 #else
680 #define MAYBE_ProxyCreationSkipsSubtree ProxyCreationSkipsSubtree
681 #endif
682 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
683 MAYBE_ProxyCreationSkipsSubtree) {
684 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
685 NavigateToURL(shell(), main_url);
687 // It is safe to obtain the root frame tree node here, as it doesn't change.
688 FrameTreeNode* root =
689 static_cast<WebContentsImpl*>(shell()->web_contents())->
690 GetFrameTree()->root();
692 EXPECT_TRUE(root->child_at(1) != NULL);
693 EXPECT_EQ(2U, root->child_at(1)->child_count());
696 // Load same-site page into iframe.
697 SitePerProcessWebContentsObserver observer(shell()->web_contents());
698 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
699 NavigateFrameToURL(root->child_at(0), http_url);
700 EXPECT_EQ(http_url, observer.navigation_url());
701 EXPECT_TRUE(observer.navigation_succeeded());
702 RenderFrameProxyHost* proxy_to_parent =
703 root->child_at(0)->render_manager()->GetRenderFrameProxyHost(
704 shell()->web_contents()->GetSiteInstance());
705 EXPECT_FALSE(proxy_to_parent);
708 // Create the cross-site URL to navigate to.
709 GURL cross_site_url =
710 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html");
712 // Load cross-site page into the second iframe without waiting for the
713 // navigation to complete. Once LoadURLWithParams returns, we would expect
714 // proxies to have been created in the frame tree, but children of the
715 // navigating frame to still be present. The reason is that we don't run the
716 // message loop, so no IPCs that alter the frame tree can be processed.
717 FrameTreeNode* child = root->child_at(1);
718 SiteInstance* site = NULL;
720 SitePerProcessWebContentsObserver observer(shell()->web_contents());
721 TestFrameNavigationObserver navigation_observer(child);
722 NavigationController::LoadURLParams params(cross_site_url);
723 params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
724 params.frame_tree_node_id = child->frame_tree_node_id();
725 child->navigator()->GetController()->LoadURLWithParams(params);
726 EXPECT_TRUE(child->render_manager()->pending_frame_host());
728 site = child->render_manager()->pending_frame_host()->GetSiteInstance();
729 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site);
731 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(site));
732 EXPECT_TRUE(
733 root->child_at(0)->render_manager()->GetRenderFrameProxyHost(site));
734 EXPECT_FALSE(child->render_manager()->GetRenderFrameProxyHost(site));
735 for (size_t i = 0; i < child->child_count(); ++i) {
736 EXPECT_FALSE(
737 child->child_at(i)->render_manager()->GetRenderFrameProxyHost(site));
739 // Now that the verification is done, run the message loop and wait for the
740 // navigation to complete.
741 navigation_observer.Wait();
742 EXPECT_FALSE(child->render_manager()->pending_frame_host());
743 EXPECT_TRUE(observer.navigation_succeeded());
744 EXPECT_EQ(cross_site_url, observer.navigation_url());
747 // Load another cross-site page into the same iframe.
748 cross_site_url = embedded_test_server()->GetURL("bar.com", "/title2.html");
750 // Perform the same checks as the first cross-site navigation, since
751 // there have been issues in subsequent cross-site navigations. Also ensure
752 // that the SiteInstance has properly changed.
753 // TODO(nasko): Once we have proper cleanup of resources, add code to
754 // verify that the intermediate SiteInstance/RenderFrameHost have been
755 // properly cleaned up.
756 SitePerProcessWebContentsObserver observer(shell()->web_contents());
757 TestFrameNavigationObserver navigation_observer(child);
758 NavigationController::LoadURLParams params(cross_site_url);
759 params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
760 params.frame_tree_node_id = child->frame_tree_node_id();
761 child->navigator()->GetController()->LoadURLWithParams(params);
762 EXPECT_TRUE(child->render_manager()->pending_frame_host() != NULL);
764 SiteInstance* site2 =
765 child->render_manager()->pending_frame_host()->GetSiteInstance();
766 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2);
767 EXPECT_NE(site, site2);
769 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(site2));
770 EXPECT_TRUE(
771 root->child_at(0)->render_manager()->GetRenderFrameProxyHost(site2));
772 EXPECT_FALSE(child->render_manager()->GetRenderFrameProxyHost(site2));
773 for (size_t i = 0; i < child->child_count(); ++i) {
774 EXPECT_FALSE(
775 child->child_at(i)->render_manager()->GetRenderFrameProxyHost(site2));
778 navigation_observer.Wait();
779 EXPECT_TRUE(observer.navigation_succeeded());
780 EXPECT_EQ(cross_site_url, observer.navigation_url());
781 EXPECT_EQ(0U, child->child_count());
785 // Verify that origin replication works for an A-embed-B-embed-C hierarchy.
786 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginReplication) {
787 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
788 EXPECT_TRUE(NavigateToURL(shell(), main_url));
790 // It is safe to obtain the root frame tree node here, as it doesn't change.
791 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
792 ->GetFrameTree()
793 ->root();
795 SitePerProcessWebContentsObserver observer(shell()->web_contents());
797 // Navigate the first subframe to a cross-site page with two subframes.
798 // NavigateFrameToURL can't be used here because it doesn't guarantee that
799 // FrameTreeNodes will have been created for child frames when it returns.
800 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 3);
801 GURL foo_url(
802 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
803 NavigationController::LoadURLParams params(foo_url);
804 params.transition_type = ui::PAGE_TRANSITION_LINK;
805 params.frame_tree_node_id = root->child_at(0)->frame_tree_node_id();
806 root->child_at(0)->navigator()->GetController()->LoadURLWithParams(params);
807 frame_observer.Wait();
809 // We can't use a SitePerProcessWebContentsObserver to verify the URL here,
810 // since the frame has children that may have clobbered it in the observer.
811 EXPECT_EQ(foo_url, root->child_at(0)->current_url());
813 // Ensure that a new process is created for the subframe.
814 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
815 root->child_at(0)->current_frame_host()->GetSiteInstance());
817 // Load cross-site page into subframe's subframe.
818 ASSERT_EQ(2U, root->child_at(0)->child_count());
819 GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
820 NavigateFrameToURL(root->child_at(0)->child_at(0), bar_url);
821 EXPECT_TRUE(observer.navigation_succeeded());
822 EXPECT_EQ(bar_url, observer.navigation_url());
824 // Check that a new process is created and is different from the top one and
825 // the middle one.
826 FrameTreeNode* bottom_child = root->child_at(0)->child_at(0);
827 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
828 bottom_child->current_frame_host()->GetSiteInstance());
829 EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
830 bottom_child->current_frame_host()->GetSiteInstance());
832 // Check that foo.com frame's location.ancestorOrigins contains the correct
833 // origin for the parent. The origin should have been replicated as part of
834 // the ViewMsg_New message that created the parent's RenderFrameProxy in
835 // foo.com's process.
836 int ancestor_origins_length = 0;
837 EXPECT_TRUE(ExecuteScriptAndExtractInt(
838 root->child_at(0)->current_frame_host(),
839 "window.domAutomationController.send(location.ancestorOrigins.length);",
840 &ancestor_origins_length));
841 EXPECT_EQ(1, ancestor_origins_length);
842 std::string result;
843 EXPECT_TRUE(ExecuteScriptAndExtractString(
844 root->child_at(0)->current_frame_host(),
845 "window.domAutomationController.send(location.ancestorOrigins[0]);",
846 &result));
847 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
849 // Check that bar.com frame's location.ancestorOrigins contains the correct
850 // origin for its two ancestors. The topmost parent origin should be
851 // replicated as part of ViewMsg_New, and the middle frame (foo.com's) origin
852 // should be replicated as part of FrameMsg_NewFrameProxy sent for foo.com's
853 // frame in bar.com's process.
854 EXPECT_TRUE(ExecuteScriptAndExtractInt(
855 bottom_child->current_frame_host(),
856 "window.domAutomationController.send(location.ancestorOrigins.length);",
857 &ancestor_origins_length));
858 EXPECT_EQ(2, ancestor_origins_length);
859 EXPECT_TRUE(ExecuteScriptAndExtractString(
860 bottom_child->current_frame_host(),
861 "window.domAutomationController.send(location.ancestorOrigins[0]);",
862 &result));
863 EXPECT_EQ(result + "/", foo_url.GetOrigin().spec());
864 EXPECT_TRUE(ExecuteScriptAndExtractString(
865 bottom_child->current_frame_host(),
866 "window.domAutomationController.send(location.ancestorOrigins[1]);",
867 &result));
868 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
871 } // namespace content