Battery Status API: add UMA logging for Linux.
[chromium-blink-merge.git] / content / browser / site_per_process_browsertest.cc
blob88d04041b14e6a1ac1ddf90dd68425ee1a36e410
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): Disabled for flakiness; see http://crbug.com/405582.
303 // TODO(creis): Enable this on Android when we can kill the process there.
304 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DISABLED_CrashSubframe) {
305 host_resolver()->AddRule("*", "127.0.0.1");
306 ASSERT_TRUE(test_server()->Start());
307 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
308 NavigateToURL(shell(), main_url);
310 StartFrameAtDataURL();
312 // These must stay in scope with replace_host.
313 GURL::Replacements replace_host;
314 std::string foo_com("foo.com");
316 // Load cross-site page into iframe.
317 GURL cross_site_url(test_server()->GetURL("files/title2.html"));
318 replace_host.SetHostStr(foo_com);
319 cross_site_url = cross_site_url.ReplaceComponents(replace_host);
320 EXPECT_TRUE(NavigateIframeToURL(shell(), cross_site_url, "test"));
322 // Check the subframe process.
323 FrameTreeNode* root =
324 static_cast<WebContentsImpl*>(shell()->web_contents())->
325 GetFrameTree()->root();
326 ASSERT_EQ(1U, root->child_count());
327 FrameTreeNode* child = root->child_at(0);
328 EXPECT_EQ(main_url, root->current_url());
329 EXPECT_EQ(cross_site_url, child->current_url());
331 // Crash the subframe process.
332 RenderProcessHost* root_process = root->current_frame_host()->GetProcess();
333 RenderProcessHost* child_process = child->current_frame_host()->GetProcess();
335 RenderProcessHostWatcher crash_observer(
336 child_process,
337 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
338 base::KillProcess(child_process->GetHandle(), 0, false);
339 crash_observer.Wait();
342 // Ensure that the child frame still exists but has been cleared.
343 EXPECT_EQ(1U, root->child_count());
344 EXPECT_EQ(main_url, root->current_url());
345 EXPECT_EQ(GURL(), child->current_url());
347 // Now crash the top-level page to clear the child frame.
349 RenderProcessHostWatcher crash_observer(
350 root_process,
351 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
352 base::KillProcess(root_process->GetHandle(), 0, false);
353 crash_observer.Wait();
355 EXPECT_EQ(0U, root->child_count());
356 EXPECT_EQ(GURL(), root->current_url());
359 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
360 // security checks are back in place.
361 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
362 // on Android (http://crbug.com/187570).
363 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
364 DISABLED_CrossSiteIframeRedirectOnce) {
365 ASSERT_TRUE(test_server()->Start());
366 net::SpawnedTestServer https_server(
367 net::SpawnedTestServer::TYPE_HTTPS,
368 net::SpawnedTestServer::kLocalhost,
369 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
370 ASSERT_TRUE(https_server.Start());
372 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
373 GURL http_url(test_server()->GetURL("files/title1.html"));
374 GURL https_url(https_server.GetURL("files/title1.html"));
376 NavigateToURL(shell(), main_url);
378 SitePerProcessWebContentsObserver observer(shell()->web_contents());
380 // Load cross-site client-redirect page into Iframe.
381 // Should be blocked.
382 GURL client_redirect_https_url(https_server.GetURL(
383 "client-redirect?files/title1.html"));
384 EXPECT_TRUE(NavigateIframeToURL(shell(),
385 client_redirect_https_url, "test"));
386 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
387 EXPECT_EQ(observer.navigation_url(), client_redirect_https_url);
388 EXPECT_FALSE(observer.navigation_succeeded());
392 // Load cross-site server-redirect page into Iframe,
393 // which redirects to same-site page.
394 GURL server_redirect_http_url(https_server.GetURL(
395 "server-redirect?" + http_url.spec()));
396 EXPECT_TRUE(NavigateIframeToURL(shell(),
397 server_redirect_http_url, "test"));
398 EXPECT_EQ(observer.navigation_url(), http_url);
399 EXPECT_TRUE(observer.navigation_succeeded());
403 // Load cross-site server-redirect page into Iframe,
404 // which redirects to cross-site page.
405 GURL server_redirect_http_url(https_server.GetURL(
406 "server-redirect?files/title1.html"));
407 EXPECT_TRUE(NavigateIframeToURL(shell(),
408 server_redirect_http_url, "test"));
409 // DidFailProvisionalLoad when navigating to https_url.
410 EXPECT_EQ(observer.navigation_url(), https_url);
411 EXPECT_FALSE(observer.navigation_succeeded());
415 // Load same-site server-redirect page into Iframe,
416 // which redirects to cross-site page.
417 GURL server_redirect_http_url(test_server()->GetURL(
418 "server-redirect?" + https_url.spec()));
419 EXPECT_TRUE(NavigateIframeToURL(shell(),
420 server_redirect_http_url, "test"));
422 EXPECT_EQ(observer.navigation_url(), https_url);
423 EXPECT_FALSE(observer.navigation_succeeded());
427 // Load same-site client-redirect page into Iframe,
428 // which redirects to cross-site page.
429 GURL client_redirect_http_url(test_server()->GetURL(
430 "client-redirect?" + https_url.spec()));
432 RedirectNotificationObserver load_observer2(
433 NOTIFICATION_LOAD_STOP,
434 Source<NavigationController>(
435 &shell()->web_contents()->GetController()));
437 EXPECT_TRUE(NavigateIframeToURL(shell(),
438 client_redirect_http_url, "test"));
440 // Same-site Client-Redirect Page should be loaded successfully.
441 EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
442 EXPECT_TRUE(observer.navigation_succeeded());
444 // Redirecting to Cross-site Page should be blocked.
445 load_observer2.Wait();
446 EXPECT_EQ(observer.navigation_url(), https_url);
447 EXPECT_FALSE(observer.navigation_succeeded());
451 // Load same-site server-redirect page into Iframe,
452 // which redirects to same-site page.
453 GURL server_redirect_http_url(test_server()->GetURL(
454 "server-redirect?files/title1.html"));
455 EXPECT_TRUE(NavigateIframeToURL(shell(),
456 server_redirect_http_url, "test"));
457 EXPECT_EQ(observer.navigation_url(), http_url);
458 EXPECT_TRUE(observer.navigation_succeeded());
462 // Load same-site client-redirect page into Iframe,
463 // which redirects to same-site page.
464 GURL client_redirect_http_url(test_server()->GetURL(
465 "client-redirect?" + http_url.spec()));
466 RedirectNotificationObserver load_observer2(
467 NOTIFICATION_LOAD_STOP,
468 Source<NavigationController>(
469 &shell()->web_contents()->GetController()));
471 EXPECT_TRUE(NavigateIframeToURL(shell(),
472 client_redirect_http_url, "test"));
474 // Same-site Client-Redirect Page should be loaded successfully.
475 EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
476 EXPECT_TRUE(observer.navigation_succeeded());
478 // Redirecting to Same-site Page should be loaded successfully.
479 load_observer2.Wait();
480 EXPECT_EQ(observer.navigation_url(), http_url);
481 EXPECT_TRUE(observer.navigation_succeeded());
485 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
486 // security checks are back in place.
487 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
488 // on Android (http://crbug.com/187570).
489 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
490 DISABLED_CrossSiteIframeRedirectTwice) {
491 ASSERT_TRUE(test_server()->Start());
492 net::SpawnedTestServer https_server(
493 net::SpawnedTestServer::TYPE_HTTPS,
494 net::SpawnedTestServer::kLocalhost,
495 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
496 ASSERT_TRUE(https_server.Start());
498 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
499 GURL http_url(test_server()->GetURL("files/title1.html"));
500 GURL https_url(https_server.GetURL("files/title1.html"));
502 NavigateToURL(shell(), main_url);
504 SitePerProcessWebContentsObserver observer(shell()->web_contents());
506 // Load client-redirect page pointing to a cross-site client-redirect page,
507 // which eventually redirects back to same-site page.
508 GURL client_redirect_https_url(https_server.GetURL(
509 "client-redirect?" + http_url.spec()));
510 GURL client_redirect_http_url(test_server()->GetURL(
511 "client-redirect?" + client_redirect_https_url.spec()));
513 // We should wait until second client redirect get cancelled.
514 RedirectNotificationObserver load_observer2(
515 NOTIFICATION_LOAD_STOP,
516 Source<NavigationController>(
517 &shell()->web_contents()->GetController()));
519 EXPECT_TRUE(NavigateIframeToURL(shell(), client_redirect_http_url, "test"));
521 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
522 load_observer2.Wait();
523 EXPECT_EQ(observer.navigation_url(), client_redirect_https_url);
524 EXPECT_FALSE(observer.navigation_succeeded());
528 // Load server-redirect page pointing to a cross-site server-redirect page,
529 // which eventually redirect back to same-site page.
530 GURL server_redirect_https_url(https_server.GetURL(
531 "server-redirect?" + http_url.spec()));
532 GURL server_redirect_http_url(test_server()->GetURL(
533 "server-redirect?" + server_redirect_https_url.spec()));
534 EXPECT_TRUE(NavigateIframeToURL(shell(),
535 server_redirect_http_url, "test"));
536 EXPECT_EQ(observer.navigation_url(), http_url);
537 EXPECT_TRUE(observer.navigation_succeeded());
541 // Load server-redirect page pointing to a cross-site server-redirect page,
542 // which eventually redirects back to cross-site page.
543 GURL server_redirect_https_url(https_server.GetURL(
544 "server-redirect?" + https_url.spec()));
545 GURL server_redirect_http_url(test_server()->GetURL(
546 "server-redirect?" + server_redirect_https_url.spec()));
547 EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url, "test"));
549 // DidFailProvisionalLoad when navigating to https_url.
550 EXPECT_EQ(observer.navigation_url(), https_url);
551 EXPECT_FALSE(observer.navigation_succeeded());
555 // Load server-redirect page pointing to a cross-site client-redirect page,
556 // which eventually redirects back to same-site page.
557 GURL client_redirect_http_url(https_server.GetURL(
558 "client-redirect?" + http_url.spec()));
559 GURL server_redirect_http_url(test_server()->GetURL(
560 "server-redirect?" + client_redirect_http_url.spec()));
561 EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url, "test"));
563 // DidFailProvisionalLoad when navigating to client_redirect_http_url.
564 EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
565 EXPECT_FALSE(observer.navigation_succeeded());
569 } // namespace content