- remove mojo_view_manager_lib_unittests from chrome_tests.py
[chromium-blink-merge.git] / content / browser / site_per_process_browsertest.cc
blobc40e43493b4acc6ba452f9fe704fa5ac4b59df18
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 "base/command_line.h"
6 #include "base/strings/stringprintf.h"
7 #include "content/browser/frame_host/cross_process_frame_connector.h"
8 #include "content/browser/frame_host/frame_tree.h"
9 #include "content/browser/frame_host/render_frame_proxy_host.h"
10 #include "content/browser/frame_host/render_widget_host_view_child_frame.h"
11 #include "content/browser/renderer_host/render_view_host_impl.h"
12 #include "content/browser/web_contents/web_contents_impl.h"
13 #include "content/public/browser/notification_observer.h"
14 #include "content/public/browser/notification_service.h"
15 #include "content/public/browser/notification_types.h"
16 #include "content/public/browser/web_contents_observer.h"
17 #include "content/public/common/content_switches.h"
18 #include "content/public/test/browser_test_utils.h"
19 #include "content/public/test/content_browser_test.h"
20 #include "content/public/test/content_browser_test_utils.h"
21 #include "content/public/test/test_utils.h"
22 #include "content/shell/browser/shell.h"
23 #include "content/test/content_browser_test_utils_internal.h"
24 #include "net/dns/mock_host_resolver.h"
25 #include "url/gurl.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 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;
152 class SitePerProcessBrowserTest : public ContentBrowserTest {
153 public:
154 SitePerProcessBrowserTest() {}
156 protected:
157 // Start at a data URL so each extra navigation creates a navigation entry.
158 // (The first navigation will silently be classified as AUTO_SUBFRAME.)
159 // TODO(creis): This won't be necessary when we can wait for LOAD_STOP.
160 void StartFrameAtDataURL() {
161 std::string data_url_script =
162 "var iframes = document.getElementById('test');iframes.src="
163 "'data:text/html,dataurl';";
164 ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script));
167 bool NavigateIframeToURL(Shell* window,
168 const GURL& url,
169 std::string iframe_id) {
170 // TODO(creis): This should wait for LOAD_STOP, but cross-site subframe
171 // navigations generate extra DidStartLoading and DidStopLoading messages.
172 // Until we replace swappedout:// with frame proxies, we need to listen for
173 // something else. For now, we trigger NEW_SUBFRAME navigations and listen
174 // for commit.
175 std::string script = base::StringPrintf(
176 "setTimeout(\""
177 "var iframes = document.getElementById('%s');iframes.src='%s';"
178 "\",0)",
179 iframe_id.c_str(), url.spec().c_str());
180 WindowedNotificationObserver load_observer(
181 NOTIFICATION_NAV_ENTRY_COMMITTED,
182 Source<NavigationController>(
183 &window->web_contents()->GetController()));
184 bool result = ExecuteScript(window->web_contents(), script);
185 load_observer.Wait();
186 return result;
189 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
190 command_line->AppendSwitch(switches::kSitePerProcess);
194 // Ensure that we can complete a cross-process subframe navigation.
195 // Crashes ChromeOS bot, but the bug is probably present on other platforms
196 // also. http://crbug.com/399775
197 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DISABLED_CrossSiteIframe) {
198 host_resolver()->AddRule("*", "127.0.0.1");
199 ASSERT_TRUE(test_server()->Start());
200 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
201 NavigateToURL(shell(), main_url);
203 // It is safe to obtain the root frame tree node here, as it doesn't change.
204 FrameTreeNode* root =
205 static_cast<WebContentsImpl*>(shell()->web_contents())->
206 GetFrameTree()->root();
208 SitePerProcessWebContentsObserver observer(shell()->web_contents());
210 // Load same-site page into iframe.
211 FrameTreeNode* child = root->child_at(0);
212 GURL http_url(test_server()->GetURL("files/title1.html"));
213 NavigateFrameToURL(child, http_url);
214 EXPECT_EQ(http_url, observer.navigation_url());
215 EXPECT_TRUE(observer.navigation_succeeded());
217 // There should be only one RenderWidgetHost when there are no
218 // cross-process iframes.
219 std::set<RenderWidgetHostView*> views_set =
220 static_cast<WebContentsImpl*>(shell()->web_contents())
221 ->GetRenderWidgetHostViewsInTree();
222 EXPECT_EQ(1U, views_set.size());
224 RenderFrameProxyHost* proxy_to_parent =
225 child->render_manager()->GetRenderFrameProxyHost(
226 shell()->web_contents()->GetSiteInstance());
227 EXPECT_FALSE(proxy_to_parent);
229 // These must stay in scope with replace_host.
230 GURL::Replacements replace_host;
231 std::string foo_com("foo.com");
233 // Load cross-site page into iframe.
234 GURL cross_site_url(test_server()->GetURL("files/title2.html"));
235 replace_host.SetHostStr(foo_com);
236 cross_site_url = cross_site_url.ReplaceComponents(replace_host);
237 NavigateFrameToURL(root->child_at(0), cross_site_url);
238 EXPECT_EQ(cross_site_url, observer.navigation_url());
239 EXPECT_TRUE(observer.navigation_succeeded());
241 // Ensure that we have created a new process for the subframe.
242 ASSERT_EQ(1U, root->child_count());
243 SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
244 RenderViewHost* rvh = child->current_frame_host()->render_view_host();
245 RenderProcessHost* rph = child->current_frame_host()->GetProcess();
246 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh);
247 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
248 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph);
250 // There should be now two RenderWidgetHosts, one for each process
251 // rendering a frame.
252 std::set<RenderWidgetHostView*> views_set =
253 static_cast<WebContentsImpl*>(shell()->web_contents())
254 ->GetRenderWidgetHostViewsInTree();
255 EXPECT_EQ(2U, views_set.size());
257 proxy_to_parent = child->render_manager()->GetProxyToParent();
258 EXPECT_TRUE(proxy_to_parent);
259 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
260 EXPECT_EQ(
261 rvh->GetView(),
262 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
264 // Load another cross-site page into the same iframe.
265 cross_site_url = test_server()->GetURL("files/title3.html");
266 std::string bar_com("bar.com");
267 replace_host.SetHostStr(bar_com);
268 cross_site_url = cross_site_url.ReplaceComponents(replace_host);
269 NavigateFrameToURL(root->child_at(0), cross_site_url);
270 EXPECT_EQ(cross_site_url, observer.navigation_url());
271 EXPECT_TRUE(observer.navigation_succeeded());
273 // Check again that a new process is created and is different from the
274 // top level one and the previous one.
275 ASSERT_EQ(1U, root->child_count());
276 child = root->child_at(0);
277 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(),
278 child->current_frame_host()->render_view_host());
279 EXPECT_NE(rvh, child->current_frame_host()->render_view_host());
280 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
281 child->current_frame_host()->GetSiteInstance());
282 EXPECT_NE(site_instance,
283 child->current_frame_host()->GetSiteInstance());
284 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(),
285 child->current_frame_host()->GetProcess());
286 EXPECT_NE(rph, child->current_frame_host()->GetProcess());
288 std::set<RenderWidgetHostView*> views_set =
289 static_cast<WebContentsImpl*>(shell()->web_contents())
290 ->GetRenderWidgetHostViewsInTree();
291 EXPECT_EQ(2U, views_set.size());
293 EXPECT_EQ(proxy_to_parent, child->render_manager()->GetProxyToParent());
294 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
295 EXPECT_EQ(
296 child->current_frame_host()->render_view_host()->GetView(),
297 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
300 // Crash a subframe and ensures its children are cleared from the FrameTree.
301 // See http://crbug.com/338508.
302 // TODO(creis): Enable this on Android when we can kill the process there.
303 #if defined(OS_ANDROID)
304 #define MAYBE_CrashSubframe DISABLED_CrashSubframe
305 #else
306 #define MAYBE_CrashSubframe CrashSubframe
307 #endif
308 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_CrashSubframe) {
309 host_resolver()->AddRule("*", "127.0.0.1");
310 ASSERT_TRUE(test_server()->Start());
311 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
312 NavigateToURL(shell(), main_url);
314 StartFrameAtDataURL();
316 // These must stay in scope with replace_host.
317 GURL::Replacements replace_host;
318 std::string foo_com("foo.com");
320 // Load cross-site page into iframe.
321 GURL cross_site_url(test_server()->GetURL("files/title2.html"));
322 replace_host.SetHostStr(foo_com);
323 cross_site_url = cross_site_url.ReplaceComponents(replace_host);
324 EXPECT_TRUE(NavigateIframeToURL(shell(), cross_site_url, "test"));
326 // Check the subframe process.
327 FrameTreeNode* root =
328 static_cast<WebContentsImpl*>(shell()->web_contents())->
329 GetFrameTree()->root();
330 ASSERT_EQ(1U, root->child_count());
331 FrameTreeNode* child = root->child_at(0);
332 EXPECT_EQ(main_url, root->current_url());
333 EXPECT_EQ(cross_site_url, child->current_url());
335 // Crash the subframe process.
336 RenderProcessHost* root_process = root->current_frame_host()->GetProcess();
337 RenderProcessHost* child_process = child->current_frame_host()->GetProcess();
339 RenderProcessHostWatcher crash_observer(
340 child_process,
341 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
342 base::KillProcess(child_process->GetHandle(), 0, false);
343 crash_observer.Wait();
346 // Ensure that the child frame still exists but has been cleared.
347 EXPECT_EQ(1U, root->child_count());
348 EXPECT_EQ(main_url, root->current_url());
349 EXPECT_EQ(GURL(), child->current_url());
351 // Now crash the top-level page to clear the child frame.
353 RenderProcessHostWatcher crash_observer(
354 root_process,
355 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
356 base::KillProcess(root_process->GetHandle(), 0, false);
357 crash_observer.Wait();
359 EXPECT_EQ(0U, root->child_count());
360 EXPECT_EQ(GURL(), root->current_url());
363 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
364 // security checks are back in place.
365 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
366 // on Android (http://crbug.com/187570).
367 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
368 DISABLED_CrossSiteIframeRedirectOnce) {
369 ASSERT_TRUE(test_server()->Start());
370 net::SpawnedTestServer https_server(
371 net::SpawnedTestServer::TYPE_HTTPS,
372 net::SpawnedTestServer::kLocalhost,
373 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
374 ASSERT_TRUE(https_server.Start());
376 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
377 GURL http_url(test_server()->GetURL("files/title1.html"));
378 GURL https_url(https_server.GetURL("files/title1.html"));
380 NavigateToURL(shell(), main_url);
382 SitePerProcessWebContentsObserver observer(shell()->web_contents());
384 // Load cross-site client-redirect page into Iframe.
385 // Should be blocked.
386 GURL client_redirect_https_url(https_server.GetURL(
387 "client-redirect?files/title1.html"));
388 EXPECT_TRUE(NavigateIframeToURL(shell(),
389 client_redirect_https_url, "test"));
390 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
391 EXPECT_EQ(observer.navigation_url(), client_redirect_https_url);
392 EXPECT_FALSE(observer.navigation_succeeded());
396 // Load cross-site server-redirect page into Iframe,
397 // which redirects to same-site page.
398 GURL server_redirect_http_url(https_server.GetURL(
399 "server-redirect?" + http_url.spec()));
400 EXPECT_TRUE(NavigateIframeToURL(shell(),
401 server_redirect_http_url, "test"));
402 EXPECT_EQ(observer.navigation_url(), http_url);
403 EXPECT_TRUE(observer.navigation_succeeded());
407 // Load cross-site server-redirect page into Iframe,
408 // which redirects to cross-site page.
409 GURL server_redirect_http_url(https_server.GetURL(
410 "server-redirect?files/title1.html"));
411 EXPECT_TRUE(NavigateIframeToURL(shell(),
412 server_redirect_http_url, "test"));
413 // DidFailProvisionalLoad when navigating to https_url.
414 EXPECT_EQ(observer.navigation_url(), https_url);
415 EXPECT_FALSE(observer.navigation_succeeded());
419 // Load same-site server-redirect page into Iframe,
420 // which redirects to cross-site page.
421 GURL server_redirect_http_url(test_server()->GetURL(
422 "server-redirect?" + https_url.spec()));
423 EXPECT_TRUE(NavigateIframeToURL(shell(),
424 server_redirect_http_url, "test"));
426 EXPECT_EQ(observer.navigation_url(), https_url);
427 EXPECT_FALSE(observer.navigation_succeeded());
431 // Load same-site client-redirect page into Iframe,
432 // which redirects to cross-site page.
433 GURL client_redirect_http_url(test_server()->GetURL(
434 "client-redirect?" + https_url.spec()));
436 RedirectNotificationObserver load_observer2(
437 NOTIFICATION_LOAD_STOP,
438 Source<NavigationController>(
439 &shell()->web_contents()->GetController()));
441 EXPECT_TRUE(NavigateIframeToURL(shell(),
442 client_redirect_http_url, "test"));
444 // Same-site Client-Redirect Page should be loaded successfully.
445 EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
446 EXPECT_TRUE(observer.navigation_succeeded());
448 // Redirecting to Cross-site Page should be blocked.
449 load_observer2.Wait();
450 EXPECT_EQ(observer.navigation_url(), https_url);
451 EXPECT_FALSE(observer.navigation_succeeded());
455 // Load same-site server-redirect page into Iframe,
456 // which redirects to same-site page.
457 GURL server_redirect_http_url(test_server()->GetURL(
458 "server-redirect?files/title1.html"));
459 EXPECT_TRUE(NavigateIframeToURL(shell(),
460 server_redirect_http_url, "test"));
461 EXPECT_EQ(observer.navigation_url(), http_url);
462 EXPECT_TRUE(observer.navigation_succeeded());
466 // Load same-site client-redirect page into Iframe,
467 // which redirects to same-site page.
468 GURL client_redirect_http_url(test_server()->GetURL(
469 "client-redirect?" + http_url.spec()));
470 RedirectNotificationObserver load_observer2(
471 NOTIFICATION_LOAD_STOP,
472 Source<NavigationController>(
473 &shell()->web_contents()->GetController()));
475 EXPECT_TRUE(NavigateIframeToURL(shell(),
476 client_redirect_http_url, "test"));
478 // Same-site Client-Redirect Page should be loaded successfully.
479 EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
480 EXPECT_TRUE(observer.navigation_succeeded());
482 // Redirecting to Same-site Page should be loaded successfully.
483 load_observer2.Wait();
484 EXPECT_EQ(observer.navigation_url(), http_url);
485 EXPECT_TRUE(observer.navigation_succeeded());
489 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
490 // security checks are back in place.
491 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
492 // on Android (http://crbug.com/187570).
493 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
494 DISABLED_CrossSiteIframeRedirectTwice) {
495 ASSERT_TRUE(test_server()->Start());
496 net::SpawnedTestServer https_server(
497 net::SpawnedTestServer::TYPE_HTTPS,
498 net::SpawnedTestServer::kLocalhost,
499 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
500 ASSERT_TRUE(https_server.Start());
502 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
503 GURL http_url(test_server()->GetURL("files/title1.html"));
504 GURL https_url(https_server.GetURL("files/title1.html"));
506 NavigateToURL(shell(), main_url);
508 SitePerProcessWebContentsObserver observer(shell()->web_contents());
510 // Load client-redirect page pointing to a cross-site client-redirect page,
511 // which eventually redirects back to same-site page.
512 GURL client_redirect_https_url(https_server.GetURL(
513 "client-redirect?" + http_url.spec()));
514 GURL client_redirect_http_url(test_server()->GetURL(
515 "client-redirect?" + client_redirect_https_url.spec()));
517 // We should wait until second client redirect get cancelled.
518 RedirectNotificationObserver load_observer2(
519 NOTIFICATION_LOAD_STOP,
520 Source<NavigationController>(
521 &shell()->web_contents()->GetController()));
523 EXPECT_TRUE(NavigateIframeToURL(shell(), client_redirect_http_url, "test"));
525 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
526 load_observer2.Wait();
527 EXPECT_EQ(observer.navigation_url(), client_redirect_https_url);
528 EXPECT_FALSE(observer.navigation_succeeded());
532 // Load server-redirect page pointing to a cross-site server-redirect page,
533 // which eventually redirect back to same-site page.
534 GURL server_redirect_https_url(https_server.GetURL(
535 "server-redirect?" + http_url.spec()));
536 GURL server_redirect_http_url(test_server()->GetURL(
537 "server-redirect?" + server_redirect_https_url.spec()));
538 EXPECT_TRUE(NavigateIframeToURL(shell(),
539 server_redirect_http_url, "test"));
540 EXPECT_EQ(observer.navigation_url(), http_url);
541 EXPECT_TRUE(observer.navigation_succeeded());
545 // Load server-redirect page pointing to a cross-site server-redirect page,
546 // which eventually redirects back to cross-site page.
547 GURL server_redirect_https_url(https_server.GetURL(
548 "server-redirect?" + https_url.spec()));
549 GURL server_redirect_http_url(test_server()->GetURL(
550 "server-redirect?" + server_redirect_https_url.spec()));
551 EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url, "test"));
553 // DidFailProvisionalLoad when navigating to https_url.
554 EXPECT_EQ(observer.navigation_url(), https_url);
555 EXPECT_FALSE(observer.navigation_succeeded());
559 // Load server-redirect page pointing to a cross-site client-redirect page,
560 // which eventually redirects back to same-site page.
561 GURL client_redirect_http_url(https_server.GetURL(
562 "client-redirect?" + http_url.spec()));
563 GURL server_redirect_http_url(test_server()->GetURL(
564 "server-redirect?" + client_redirect_http_url.spec()));
565 EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url, "test"));
567 // DidFailProvisionalLoad when navigating to client_redirect_http_url.
568 EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
569 EXPECT_FALSE(observer.navigation_succeeded());
573 } // namespace content