WebContentsAudioMuter: Mute all audio output from a WebContentsImpl.
[chromium-blink-merge.git] / content / browser / site_per_process_browsertest.cc
blobf900e58675951e18eb17921e8d3dfde70aa327db
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/render_frame_proxy_host.h"
12 #include "content/browser/frame_host/render_widget_host_view_child_frame.h"
13 #include "content/browser/renderer_host/render_view_host_impl.h"
14 #include "content/browser/web_contents/web_contents_impl.h"
15 #include "content/public/browser/notification_observer.h"
16 #include "content/public/browser/notification_service.h"
17 #include "content/public/browser/notification_types.h"
18 #include "content/public/browser/web_contents_observer.h"
19 #include "content/public/common/content_switches.h"
20 #include "content/public/test/browser_test_utils.h"
21 #include "content/public/test/content_browser_test_utils.h"
22 #include "content/public/test/test_utils.h"
23 #include "content/shell/browser/shell.h"
24 #include "content/test/content_browser_test_utils_internal.h"
25 #include "net/dns/mock_host_resolver.h"
27 namespace content {
29 class SitePerProcessWebContentsObserver: public WebContentsObserver {
30 public:
31 explicit SitePerProcessWebContentsObserver(WebContents* web_contents)
32 : WebContentsObserver(web_contents),
33 navigation_succeeded_(false) {}
34 virtual ~SitePerProcessWebContentsObserver() {}
36 virtual void DidStartProvisionalLoadForFrame(
37 RenderFrameHost* render_frame_host,
38 const GURL& validated_url,
39 bool is_error_page,
40 bool is_iframe_srcdoc) OVERRIDE {
41 navigation_succeeded_ = false;
44 virtual void DidFailProvisionalLoad(
45 RenderFrameHost* render_frame_host,
46 const GURL& validated_url,
47 int error_code,
48 const base::string16& error_description) OVERRIDE {
49 navigation_url_ = validated_url;
50 navigation_succeeded_ = false;
53 virtual void DidCommitProvisionalLoadForFrame(
54 RenderFrameHost* render_frame_host,
55 const GURL& url,
56 ui::PageTransition transition_type) OVERRIDE {
57 navigation_url_ = url;
58 navigation_succeeded_ = true;
61 const GURL& navigation_url() const {
62 return navigation_url_;
65 int navigation_succeeded() const { return navigation_succeeded_; }
67 private:
68 GURL navigation_url_;
69 bool navigation_succeeded_;
71 DISALLOW_COPY_AND_ASSIGN(SitePerProcessWebContentsObserver);
74 class RedirectNotificationObserver : public NotificationObserver {
75 public:
76 // Register to listen for notifications of the given type from either a
77 // specific source, or from all sources if |source| is
78 // NotificationService::AllSources().
79 RedirectNotificationObserver(int notification_type,
80 const NotificationSource& source);
81 virtual ~RedirectNotificationObserver();
83 // Wait until the specified notification occurs. If the notification was
84 // emitted between the construction of this object and this call then it
85 // returns immediately.
86 void Wait();
88 // Returns NotificationService::AllSources() if we haven't observed a
89 // notification yet.
90 const NotificationSource& source() const {
91 return source_;
94 const NotificationDetails& details() const {
95 return details_;
98 // NotificationObserver:
99 virtual void Observe(int type,
100 const NotificationSource& source,
101 const NotificationDetails& details) OVERRIDE;
103 private:
104 bool seen_;
105 bool seen_twice_;
106 bool running_;
107 NotificationRegistrar registrar_;
109 NotificationSource source_;
110 NotificationDetails details_;
111 scoped_refptr<MessageLoopRunner> message_loop_runner_;
113 DISALLOW_COPY_AND_ASSIGN(RedirectNotificationObserver);
116 RedirectNotificationObserver::RedirectNotificationObserver(
117 int notification_type,
118 const NotificationSource& source)
119 : seen_(false),
120 running_(false),
121 source_(NotificationService::AllSources()) {
122 registrar_.Add(this, notification_type, source);
125 RedirectNotificationObserver::~RedirectNotificationObserver() {}
127 void RedirectNotificationObserver::Wait() {
128 if (seen_ && seen_twice_)
129 return;
131 running_ = true;
132 message_loop_runner_ = new MessageLoopRunner;
133 message_loop_runner_->Run();
134 EXPECT_TRUE(seen_);
137 void RedirectNotificationObserver::Observe(
138 int type,
139 const NotificationSource& source,
140 const NotificationDetails& details) {
141 source_ = source;
142 details_ = details;
143 seen_twice_ = seen_;
144 seen_ = true;
145 if (!running_)
146 return;
148 message_loop_runner_->Quit();
149 running_ = false;
153 // SitePerProcessBrowserTest
156 SitePerProcessBrowserTest::SitePerProcessBrowserTest() {
159 void SitePerProcessBrowserTest::StartFrameAtDataURL() {
160 std::string data_url_script =
161 "var iframes = document.getElementById('test');iframes.src="
162 "'data:text/html,dataurl';";
163 ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script));
166 bool SitePerProcessBrowserTest::NavigateIframeToURL(Shell* window,
167 const GURL& url,
168 std::string iframe_id) {
169 // TODO(creis): This should wait for LOAD_STOP, but cross-site subframe
170 // navigations generate extra DidStartLoading and DidStopLoading messages.
171 // Until we replace swappedout:// with frame proxies, we need to listen for
172 // something else. For now, we trigger NEW_SUBFRAME navigations and listen
173 // for commit.
174 std::string script = base::StringPrintf(
175 "setTimeout(\""
176 "var iframes = document.getElementById('%s');iframes.src='%s';"
177 "\",0)",
178 iframe_id.c_str(), url.spec().c_str());
179 WindowedNotificationObserver load_observer(
180 NOTIFICATION_NAV_ENTRY_COMMITTED,
181 Source<NavigationController>(
182 &window->web_contents()->GetController()));
183 bool result = ExecuteScript(window->web_contents(), script);
184 load_observer.Wait();
185 return result;
188 void SitePerProcessBrowserTest::SetUpCommandLine(CommandLine* command_line) {
189 command_line->AppendSwitch(switches::kSitePerProcess);
192 // It fails on ChromeOS and Android, so disabled while investigating.
193 // http://crbug.com/399775
194 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
195 #define MAYBE_CrossSiteIframe DISABLED_CrossSiteIframe
196 #else
197 #define MAYBE_CrossSiteIframe CrossSiteIframe
198 #endif
199 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_CrossSiteIframe) {
200 host_resolver()->AddRule("*", "127.0.0.1");
201 ASSERT_TRUE(test_server()->Start());
202 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
203 NavigateToURL(shell(), main_url);
205 // It is safe to obtain the root frame tree node here, as it doesn't change.
206 FrameTreeNode* root =
207 static_cast<WebContentsImpl*>(shell()->web_contents())->
208 GetFrameTree()->root();
210 SitePerProcessWebContentsObserver observer(shell()->web_contents());
212 // Load same-site page into iframe.
213 FrameTreeNode* child = root->child_at(0);
214 GURL http_url(test_server()->GetURL("files/title1.html"));
215 NavigateFrameToURL(child, http_url);
216 EXPECT_EQ(http_url, observer.navigation_url());
217 EXPECT_TRUE(observer.navigation_succeeded());
219 // There should be only one RenderWidgetHost when there are no
220 // cross-process iframes.
221 std::set<RenderWidgetHostView*> views_set =
222 static_cast<WebContentsImpl*>(shell()->web_contents())
223 ->GetRenderWidgetHostViewsInTree();
224 EXPECT_EQ(1U, views_set.size());
226 RenderFrameProxyHost* proxy_to_parent =
227 child->render_manager()->GetRenderFrameProxyHost(
228 shell()->web_contents()->GetSiteInstance());
229 EXPECT_FALSE(proxy_to_parent);
231 // These must stay in scope with replace_host.
232 GURL::Replacements replace_host;
233 std::string foo_com("foo.com");
235 // Load cross-site page into iframe.
236 GURL cross_site_url(test_server()->GetURL("files/title2.html"));
237 replace_host.SetHostStr(foo_com);
238 cross_site_url = cross_site_url.ReplaceComponents(replace_host);
239 NavigateFrameToURL(root->child_at(0), cross_site_url);
240 EXPECT_EQ(cross_site_url, observer.navigation_url());
241 EXPECT_TRUE(observer.navigation_succeeded());
243 // Ensure that we have created a new process for the subframe.
244 ASSERT_EQ(1U, root->child_count());
245 SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
246 RenderViewHost* rvh = child->current_frame_host()->render_view_host();
247 RenderProcessHost* rph = child->current_frame_host()->GetProcess();
248 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh);
249 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
250 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph);
252 // There should be now two RenderWidgetHosts, one for each process
253 // rendering a frame.
254 std::set<RenderWidgetHostView*> views_set =
255 static_cast<WebContentsImpl*>(shell()->web_contents())
256 ->GetRenderWidgetHostViewsInTree();
257 EXPECT_EQ(2U, views_set.size());
259 proxy_to_parent = child->render_manager()->GetProxyToParent();
260 EXPECT_TRUE(proxy_to_parent);
261 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
262 EXPECT_EQ(
263 rvh->GetView(),
264 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
266 // Load another cross-site page into the same iframe.
267 cross_site_url = test_server()->GetURL("files/title3.html");
268 std::string bar_com("bar.com");
269 replace_host.SetHostStr(bar_com);
270 cross_site_url = cross_site_url.ReplaceComponents(replace_host);
271 NavigateFrameToURL(root->child_at(0), cross_site_url);
272 EXPECT_EQ(cross_site_url, observer.navigation_url());
273 EXPECT_TRUE(observer.navigation_succeeded());
275 // Check again that a new process is created and is different from the
276 // top level one and the previous one.
277 ASSERT_EQ(1U, root->child_count());
278 child = root->child_at(0);
279 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(),
280 child->current_frame_host()->render_view_host());
281 EXPECT_NE(rvh, child->current_frame_host()->render_view_host());
282 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
283 child->current_frame_host()->GetSiteInstance());
284 EXPECT_NE(site_instance,
285 child->current_frame_host()->GetSiteInstance());
286 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(),
287 child->current_frame_host()->GetProcess());
288 EXPECT_NE(rph, child->current_frame_host()->GetProcess());
290 std::set<RenderWidgetHostView*> views_set =
291 static_cast<WebContentsImpl*>(shell()->web_contents())
292 ->GetRenderWidgetHostViewsInTree();
293 EXPECT_EQ(2U, views_set.size());
295 EXPECT_EQ(proxy_to_parent, child->render_manager()->GetProxyToParent());
296 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
297 EXPECT_EQ(
298 child->current_frame_host()->render_view_host()->GetView(),
299 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
302 // Crash a subframe and ensures its children are cleared from the FrameTree.
303 // See http://crbug.com/338508.
304 // TODO(creis): Disabled for flakiness; see http://crbug.com/405582.
305 // TODO(creis): Enable this on Android when we can kill the process there.
306 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DISABLED_CrashSubframe) {
307 host_resolver()->AddRule("*", "127.0.0.1");
308 ASSERT_TRUE(test_server()->Start());
309 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
310 NavigateToURL(shell(), main_url);
312 StartFrameAtDataURL();
314 // These must stay in scope with replace_host.
315 GURL::Replacements replace_host;
316 std::string foo_com("foo.com");
318 // Load cross-site page into iframe.
319 GURL cross_site_url(test_server()->GetURL("files/title2.html"));
320 replace_host.SetHostStr(foo_com);
321 cross_site_url = cross_site_url.ReplaceComponents(replace_host);
322 EXPECT_TRUE(NavigateIframeToURL(shell(), cross_site_url, "test"));
324 // Check the subframe process.
325 FrameTreeNode* root =
326 static_cast<WebContentsImpl*>(shell()->web_contents())->
327 GetFrameTree()->root();
328 ASSERT_EQ(1U, root->child_count());
329 FrameTreeNode* child = root->child_at(0);
330 EXPECT_EQ(main_url, root->current_url());
331 EXPECT_EQ(cross_site_url, child->current_url());
333 EXPECT_TRUE(
334 child->current_frame_host()->render_view_host()->IsRenderViewLive());
335 EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive());
337 // Crash the subframe process.
338 RenderProcessHost* root_process = root->current_frame_host()->GetProcess();
339 RenderProcessHost* child_process = child->current_frame_host()->GetProcess();
341 RenderProcessHostWatcher crash_observer(
342 child_process,
343 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
344 base::KillProcess(child_process->GetHandle(), 0, false);
345 crash_observer.Wait();
348 // Ensure that the child frame still exists but has been cleared.
349 EXPECT_EQ(1U, root->child_count());
350 EXPECT_EQ(main_url, root->current_url());
351 EXPECT_EQ(GURL(), child->current_url());
353 EXPECT_FALSE(
354 child->current_frame_host()->render_view_host()->IsRenderViewLive());
355 EXPECT_FALSE(child->current_frame_host()->IsRenderFrameLive());
356 EXPECT_FALSE(child->current_frame_host()->render_frame_created_);
358 // Now crash the top-level page to clear the child frame.
360 RenderProcessHostWatcher crash_observer(
361 root_process,
362 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
363 base::KillProcess(root_process->GetHandle(), 0, false);
364 crash_observer.Wait();
366 EXPECT_EQ(0U, root->child_count());
367 EXPECT_EQ(GURL(), root->current_url());
370 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
371 // security checks are back in place.
372 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
373 // on Android (http://crbug.com/187570).
374 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
375 DISABLED_CrossSiteIframeRedirectOnce) {
376 ASSERT_TRUE(test_server()->Start());
377 net::SpawnedTestServer https_server(
378 net::SpawnedTestServer::TYPE_HTTPS,
379 net::SpawnedTestServer::kLocalhost,
380 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
381 ASSERT_TRUE(https_server.Start());
383 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
384 GURL http_url(test_server()->GetURL("files/title1.html"));
385 GURL https_url(https_server.GetURL("files/title1.html"));
387 NavigateToURL(shell(), main_url);
389 SitePerProcessWebContentsObserver observer(shell()->web_contents());
391 // Load cross-site client-redirect page into Iframe.
392 // Should be blocked.
393 GURL client_redirect_https_url(https_server.GetURL(
394 "client-redirect?files/title1.html"));
395 EXPECT_TRUE(NavigateIframeToURL(shell(),
396 client_redirect_https_url, "test"));
397 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
398 EXPECT_EQ(observer.navigation_url(), client_redirect_https_url);
399 EXPECT_FALSE(observer.navigation_succeeded());
403 // Load cross-site server-redirect page into Iframe,
404 // which redirects to same-site page.
405 GURL server_redirect_http_url(https_server.GetURL(
406 "server-redirect?" + http_url.spec()));
407 EXPECT_TRUE(NavigateIframeToURL(shell(),
408 server_redirect_http_url, "test"));
409 EXPECT_EQ(observer.navigation_url(), http_url);
410 EXPECT_TRUE(observer.navigation_succeeded());
414 // Load cross-site server-redirect page into Iframe,
415 // which redirects to cross-site page.
416 GURL server_redirect_http_url(https_server.GetURL(
417 "server-redirect?files/title1.html"));
418 EXPECT_TRUE(NavigateIframeToURL(shell(),
419 server_redirect_http_url, "test"));
420 // DidFailProvisionalLoad when navigating to https_url.
421 EXPECT_EQ(observer.navigation_url(), https_url);
422 EXPECT_FALSE(observer.navigation_succeeded());
426 // Load same-site server-redirect page into Iframe,
427 // which redirects to cross-site page.
428 GURL server_redirect_http_url(test_server()->GetURL(
429 "server-redirect?" + https_url.spec()));
430 EXPECT_TRUE(NavigateIframeToURL(shell(),
431 server_redirect_http_url, "test"));
433 EXPECT_EQ(observer.navigation_url(), https_url);
434 EXPECT_FALSE(observer.navigation_succeeded());
438 // Load same-site client-redirect page into Iframe,
439 // which redirects to cross-site page.
440 GURL client_redirect_http_url(test_server()->GetURL(
441 "client-redirect?" + https_url.spec()));
443 RedirectNotificationObserver load_observer2(
444 NOTIFICATION_LOAD_STOP,
445 Source<NavigationController>(
446 &shell()->web_contents()->GetController()));
448 EXPECT_TRUE(NavigateIframeToURL(shell(),
449 client_redirect_http_url, "test"));
451 // Same-site Client-Redirect Page should be loaded successfully.
452 EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
453 EXPECT_TRUE(observer.navigation_succeeded());
455 // Redirecting to Cross-site Page should be blocked.
456 load_observer2.Wait();
457 EXPECT_EQ(observer.navigation_url(), https_url);
458 EXPECT_FALSE(observer.navigation_succeeded());
462 // Load same-site server-redirect page into Iframe,
463 // which redirects to same-site page.
464 GURL server_redirect_http_url(test_server()->GetURL(
465 "server-redirect?files/title1.html"));
466 EXPECT_TRUE(NavigateIframeToURL(shell(),
467 server_redirect_http_url, "test"));
468 EXPECT_EQ(observer.navigation_url(), http_url);
469 EXPECT_TRUE(observer.navigation_succeeded());
473 // Load same-site client-redirect page into Iframe,
474 // which redirects to same-site page.
475 GURL client_redirect_http_url(test_server()->GetURL(
476 "client-redirect?" + http_url.spec()));
477 RedirectNotificationObserver load_observer2(
478 NOTIFICATION_LOAD_STOP,
479 Source<NavigationController>(
480 &shell()->web_contents()->GetController()));
482 EXPECT_TRUE(NavigateIframeToURL(shell(),
483 client_redirect_http_url, "test"));
485 // Same-site Client-Redirect Page should be loaded successfully.
486 EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
487 EXPECT_TRUE(observer.navigation_succeeded());
489 // Redirecting to Same-site Page should be loaded successfully.
490 load_observer2.Wait();
491 EXPECT_EQ(observer.navigation_url(), http_url);
492 EXPECT_TRUE(observer.navigation_succeeded());
496 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
497 // security checks are back in place.
498 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
499 // on Android (http://crbug.com/187570).
500 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
501 DISABLED_CrossSiteIframeRedirectTwice) {
502 ASSERT_TRUE(test_server()->Start());
503 net::SpawnedTestServer https_server(
504 net::SpawnedTestServer::TYPE_HTTPS,
505 net::SpawnedTestServer::kLocalhost,
506 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
507 ASSERT_TRUE(https_server.Start());
509 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
510 GURL http_url(test_server()->GetURL("files/title1.html"));
511 GURL https_url(https_server.GetURL("files/title1.html"));
513 NavigateToURL(shell(), main_url);
515 SitePerProcessWebContentsObserver observer(shell()->web_contents());
517 // Load client-redirect page pointing to a cross-site client-redirect page,
518 // which eventually redirects back to same-site page.
519 GURL client_redirect_https_url(https_server.GetURL(
520 "client-redirect?" + http_url.spec()));
521 GURL client_redirect_http_url(test_server()->GetURL(
522 "client-redirect?" + client_redirect_https_url.spec()));
524 // We should wait until second client redirect get cancelled.
525 RedirectNotificationObserver load_observer2(
526 NOTIFICATION_LOAD_STOP,
527 Source<NavigationController>(
528 &shell()->web_contents()->GetController()));
530 EXPECT_TRUE(NavigateIframeToURL(shell(), client_redirect_http_url, "test"));
532 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
533 load_observer2.Wait();
534 EXPECT_EQ(observer.navigation_url(), client_redirect_https_url);
535 EXPECT_FALSE(observer.navigation_succeeded());
539 // Load server-redirect page pointing to a cross-site server-redirect page,
540 // which eventually redirect back to same-site page.
541 GURL server_redirect_https_url(https_server.GetURL(
542 "server-redirect?" + http_url.spec()));
543 GURL server_redirect_http_url(test_server()->GetURL(
544 "server-redirect?" + server_redirect_https_url.spec()));
545 EXPECT_TRUE(NavigateIframeToURL(shell(),
546 server_redirect_http_url, "test"));
547 EXPECT_EQ(observer.navigation_url(), http_url);
548 EXPECT_TRUE(observer.navigation_succeeded());
552 // Load server-redirect page pointing to a cross-site server-redirect page,
553 // which eventually redirects back to cross-site page.
554 GURL server_redirect_https_url(https_server.GetURL(
555 "server-redirect?" + https_url.spec()));
556 GURL server_redirect_http_url(test_server()->GetURL(
557 "server-redirect?" + server_redirect_https_url.spec()));
558 EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url, "test"));
560 // DidFailProvisionalLoad when navigating to https_url.
561 EXPECT_EQ(observer.navigation_url(), https_url);
562 EXPECT_FALSE(observer.navigation_succeeded());
566 // Load server-redirect page pointing to a cross-site client-redirect page,
567 // which eventually redirects back to same-site page.
568 GURL client_redirect_http_url(https_server.GetURL(
569 "client-redirect?" + http_url.spec()));
570 GURL server_redirect_http_url(test_server()->GetURL(
571 "server-redirect?" + client_redirect_http_url.spec()));
572 EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url, "test"));
574 // DidFailProvisionalLoad when navigating to client_redirect_http_url.
575 EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
576 EXPECT_FALSE(observer.navigation_succeeded());
580 } // namespace content