OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/site_per_process_browsertest.h" | 5 #include "content/browser/site_per_process_browsertest.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/strings/stringprintf.h" | 8 #include "base/strings/stringprintf.h" |
9 #include "base/strings/utf_string_conversions.h" | 9 #include "base/strings/utf_string_conversions.h" |
10 #include "content/browser/frame_host/cross_process_frame_connector.h" | 10 #include "content/browser/frame_host/cross_process_frame_connector.h" |
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
330 | 330 |
331 // Navigate back to the parent's origin and ensure we return to the | 331 // Navigate back to the parent's origin and ensure we return to the |
332 // parent's process. | 332 // parent's process. |
333 NavigateFrameToURL(child, http_url); | 333 NavigateFrameToURL(child, http_url); |
334 EXPECT_EQ(http_url, observer.last_navigation_url()); | 334 EXPECT_EQ(http_url, observer.last_navigation_url()); |
335 EXPECT_TRUE(observer.last_navigation_succeeded()); | 335 EXPECT_TRUE(observer.last_navigation_succeeded()); |
336 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(), | 336 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(), |
337 child->current_frame_host()->GetSiteInstance()); | 337 child->current_frame_host()->GetSiteInstance()); |
338 } | 338 } |
339 | 339 |
| 340 // This test checks that killing a renderer process of a remote frame |
| 341 // and then navigating some other frame to the same SiteInstance of the killed |
| 342 // process works properly. |
| 343 // This can be illustrated as follows, |
| 344 // where 1/2/3 are FrameTreeNode-s and A/B are processes and B* is the killed |
| 345 // B process: |
| 346 // |
| 347 // 1 A A A |
| 348 // / \ -> / \ -> Kill B -> / \ -> Navigate 3 to B -> / \ . |
| 349 // 2 3 B A B* A B* B |
| 350 // |
| 351 // Initially, node1.proxy_hosts_ = {B} |
| 352 // After we kill B, we make sure B stays in node1.proxy_hosts_, then we navigate |
| 353 // 3 to B and we expect that to complete normally. |
| 354 // See http://crbug.com/432107. |
| 355 // |
| 356 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to |
| 357 // site B and stays in not rendered state. |
| 358 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 359 NavigateRemoteFrameToKilledProcess) { |
| 360 GURL main_url(embedded_test_server()->GetURL( |
| 361 "/frame_tree/page_with_two_frames.html")); |
| 362 NavigateToURL(shell(), main_url); |
| 363 |
| 364 // It is safe to obtain the root frame tree node here, as it doesn't change. |
| 365 FrameTreeNode* root = |
| 366 static_cast<WebContentsImpl*>(shell()->web_contents())-> |
| 367 GetFrameTree()->root(); |
| 368 |
| 369 TestNavigationObserver observer(shell()->web_contents()); |
| 370 ASSERT_EQ(2U, root->child_count()); |
| 371 |
| 372 // Make sure node2 points to the correct cross-site page. |
| 373 GURL site_b_url = embedded_test_server()->GetURL("bar.com", "/title1.html"); |
| 374 FrameTreeNode* node2 = root->child_at(0); |
| 375 EXPECT_EQ(site_b_url, node2->current_url()); |
| 376 |
| 377 // Kill that cross-site renderer. |
| 378 RenderProcessHost* child_process = |
| 379 node2->current_frame_host()->GetProcess(); |
| 380 RenderProcessHostWatcher crash_observer( |
| 381 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| 382 child_process->Shutdown(0, false); |
| 383 crash_observer.Wait(); |
| 384 |
| 385 // Now navigate the second iframe (node3) to the same site as the node2. |
| 386 FrameTreeNode* node3 = root->child_at(1); |
| 387 NavigateFrameToURL(node3, site_b_url); |
| 388 EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 389 EXPECT_EQ(site_b_url, observer.last_navigation_url()); |
| 390 } |
| 391 |
| 392 // This test is similar to |
| 393 // SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcess with |
| 394 // addition that node2 also has a cross-origin frame to site C. |
| 395 // |
| 396 // 1 A A A |
| 397 // / \ / \ / \ / \ . |
| 398 // 2 3 -> B A -> Kill B -> B* A -> Navigate 3 -> B* B |
| 399 // / / |
| 400 // 4 C |
| 401 // |
| 402 // Initially, node1.proxy_hosts_ = {B, C} |
| 403 // After we kill B, we make sure B stays in node1.proxy_hosts_, but |
| 404 // C gets cleared from node1.proxy_hosts_. |
| 405 // |
| 406 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to |
| 407 // site B and stays in not rendered state. |
| 408 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 409 NavigateRemoteFrameToKilledProcessWithSubtree) { |
| 410 GURL main_url( |
| 411 embedded_test_server()->GetURL( |
| 412 "/frame_tree/page_with_two_frames_nested.html")); |
| 413 NavigateToURL(shell(), main_url); |
| 414 |
| 415 // It is safe to obtain the root frame tree node here, as it doesn't change. |
| 416 FrameTreeNode* root = |
| 417 static_cast<WebContentsImpl*>(shell()->web_contents())-> |
| 418 GetFrameTree()->root(); |
| 419 TestNavigationObserver observer(shell()->web_contents()); |
| 420 |
| 421 ASSERT_EQ(2U, root->child_count()); |
| 422 |
| 423 GURL site_b_url( |
| 424 embedded_test_server()->GetURL( |
| 425 "bar.com", "/frame_tree/page_with_one_frame.html")); |
| 426 // We can't use a TestNavigationObserver to verify the URL here, |
| 427 // since the frame has children that may have clobbered it in the observer. |
| 428 EXPECT_EQ(site_b_url, root->child_at(0)->current_url()); |
| 429 |
| 430 // Ensure that a new process is created for node2. |
| 431 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), |
| 432 root->child_at(0)->current_frame_host()->GetSiteInstance()); |
| 433 // Ensure that a new process is *not* created for node3. |
| 434 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(), |
| 435 root->child_at(1)->current_frame_host()->GetSiteInstance()); |
| 436 |
| 437 ASSERT_EQ(1U, root->child_at(0)->child_count()); |
| 438 |
| 439 // Make sure node4 points to the correct cross-site page. |
| 440 FrameTreeNode* node4 = root->child_at(0)->child_at(0); |
| 441 GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html")); |
| 442 EXPECT_EQ(site_c_url, node4->current_url()); |
| 443 |
| 444 // |site_instance_c| is expected to go away once we kill |child_process_b| |
| 445 // below, so create a local scope so we can extend the lifetime of |
| 446 // |site_instance_c| with a refptr. |
| 447 { |
| 448 SiteInstance* site_instance_b = |
| 449 root->child_at(0)->current_frame_host()->GetSiteInstance(); |
| 450 // |site_c| will go away, so extend its lifetime with a refptr. |
| 451 scoped_refptr<SiteInstanceImpl> site_instance_c = |
| 452 node4->current_frame_host()->GetSiteInstance(); |
| 453 |
| 454 // Initially proxies for both B and C will be present in the root and node3. |
| 455 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost( |
| 456 site_instance_b)); |
| 457 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost( |
| 458 site_instance_c.get())); |
| 459 FrameTreeNode* node3 = root->child_at(1); |
| 460 EXPECT_TRUE(node3->render_manager()->GetRenderFrameProxyHost( |
| 461 site_instance_b)); |
| 462 EXPECT_TRUE(node3->render_manager()->GetRenderFrameProxyHost( |
| 463 site_instance_c.get())); |
| 464 |
| 465 // Kill that cross-site renderer/process B. |
| 466 RenderProcessHost* child_process_b = |
| 467 root->child_at(0)->current_frame_host()->GetProcess(); |
| 468 RenderProcessHostWatcher crash_observer( |
| 469 child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| 470 child_process_b->Shutdown(0, false); |
| 471 crash_observer.Wait(); |
| 472 |
| 473 // Make sure proxy B stays around in root and node3. |
| 474 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost( |
| 475 site_instance_b)); |
| 476 EXPECT_TRUE(node3->render_manager()->GetRenderFrameProxyHost( |
| 477 site_instance_b)); |
| 478 // Make sure proxy C goes away from root and node3. |
| 479 EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost( |
| 480 site_instance_c.get())); |
| 481 EXPECT_FALSE(node3->render_manager()->GetRenderFrameProxyHost( |
| 482 site_instance_c.get())); |
| 483 } |
| 484 |
| 485 // Now navigate the second iframe (node3) to the same site as the node2. |
| 486 FrameTreeNode* node3 = root->child_at(1); |
| 487 GURL url = embedded_test_server()->GetURL("bar.com", "/title1.html"); |
| 488 NavigateFrameToURL(node3, url); |
| 489 EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 490 EXPECT_EQ(url, observer.last_navigation_url()); |
| 491 } |
| 492 |
340 // In A-embed-B-embed-C scenario, verify that killing process B clears proxies | 493 // In A-embed-B-embed-C scenario, verify that killing process B clears proxies |
341 // of C from the tree. | 494 // of C from the tree. |
342 // | 495 // |
343 // 1 A A | 496 // 1 A A |
344 // / \ / \ / \ . | 497 // / \ / \ / \ . |
345 // 2 3 -> B A -> Kill B -> B* A | 498 // 2 3 -> B A -> Kill B -> B* A |
346 // / / | 499 // / / |
347 // 4 C | 500 // 4 C |
348 // | 501 // |
349 // node1 is the root. | 502 // node1 is the root. |
350 // Initially, both node1.proxy_hosts_ and node3.proxy_hosts_ contain C. | 503 // Initially, both node1.proxy_hosts_ and node3.proxy_hosts_ contain C. |
351 // After we kill B, make sure proxies for C are cleared. | 504 // After we kill B, make sure proxies for C are cleared. |
352 // | |
353 // TODO(lazyboy): Once http://crbug.com/432107 is fixed, we should also make | |
354 // sure that proxies for B are not cleared when we kill B. | |
355 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, | 505 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
356 KillingRendererClearsDescendantProxies) { | 506 KillingRendererClearsDescendantProxies) { |
357 GURL main_url( | 507 GURL main_url( |
358 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html")); | 508 embedded_test_server()->GetURL( |
| 509 "/frame_tree/page_with_two_frames_nested.html")); |
359 NavigateToURL(shell(), main_url); | 510 NavigateToURL(shell(), main_url); |
360 | 511 |
361 // It is safe to obtain the root frame tree node here, as it doesn't change. | 512 // It is safe to obtain the root frame tree node here, as it doesn't change. |
362 FrameTreeNode* root = | 513 FrameTreeNode* root = |
363 static_cast<WebContentsImpl*>(shell()->web_contents())-> | 514 static_cast<WebContentsImpl*>(shell()->web_contents())-> |
364 GetFrameTree()->root(); | 515 GetFrameTree()->root(); |
365 TestNavigationObserver observer(shell()->web_contents()); | 516 TestNavigationObserver observer(shell()->web_contents()); |
366 | 517 |
367 ASSERT_EQ(2U, root->child_count()); | 518 ASSERT_EQ(2U, root->child_count()); |
368 | 519 |
369 // Navigate the second subframe (node3) to a local frame. | |
370 GURL site_a_url(embedded_test_server()->GetURL("/title1.html")); | |
371 NavigateFrameToURL(root->child_at(1), site_a_url); | |
372 | |
373 // Navigate the first subframe (node2) to a cross-site page with two | |
374 // subframes. | |
375 // NavigateFrameToURL can't be used here because it doesn't guarantee that | |
376 // FrameTreeNodes will have been created for child frames when it returns. | |
377 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 3); | |
378 GURL site_b_url( | 520 GURL site_b_url( |
379 embedded_test_server()->GetURL( | 521 embedded_test_server()->GetURL( |
380 "bar.com", "/frame_tree/page_with_one_frame.html")); | 522 "bar.com", "/frame_tree/page_with_one_frame.html")); |
381 NavigationController::LoadURLParams params_b(site_b_url); | |
382 params_b.transition_type = ui::PAGE_TRANSITION_LINK; | |
383 params_b.frame_tree_node_id = root->child_at(0)->frame_tree_node_id(); | |
384 root->child_at(0)->navigator()->GetController()->LoadURLWithParams(params_b); | |
385 frame_observer.Wait(); | |
386 | |
387 // We can't use a TestNavigationObserver to verify the URL here, | 523 // We can't use a TestNavigationObserver to verify the URL here, |
388 // since the frame has children that may have clobbered it in the observer. | 524 // since the frame has children that may have clobbered it in the observer. |
389 EXPECT_EQ(site_b_url, root->child_at(0)->current_url()); | 525 EXPECT_EQ(site_b_url, root->child_at(0)->current_url()); |
390 | 526 |
391 // Ensure that a new process is created for node2. | 527 // Ensure that a new process is created for node2. |
392 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), | 528 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), |
393 root->child_at(0)->current_frame_host()->GetSiteInstance()); | 529 root->child_at(0)->current_frame_host()->GetSiteInstance()); |
394 // Ensure that a new process is *not* created for node3. | 530 // Ensure that a new process is *not* created for node3. |
395 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(), | 531 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(), |
396 root->child_at(1)->current_frame_host()->GetSiteInstance()); | 532 root->child_at(1)->current_frame_host()->GetSiteInstance()); |
397 | 533 |
398 ASSERT_EQ(1U, root->child_at(0)->child_count()); | 534 ASSERT_EQ(1U, root->child_at(0)->child_count()); |
399 | 535 |
400 // Navigate node4 to cross-site-page. | 536 // Make sure node4 points to the correct cross-site-page. |
401 FrameTreeNode* node4 = root->child_at(0)->child_at(0); | 537 FrameTreeNode* node4 = root->child_at(0)->child_at(0); |
402 GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title2.html")); | 538 GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html")); |
403 NavigateFrameToURL(node4, site_c_url); | 539 EXPECT_EQ(site_c_url, node4->current_url()); |
404 EXPECT_TRUE(observer.last_navigation_succeeded()); | |
405 EXPECT_EQ(site_c_url, observer.last_navigation_url()); | |
406 | 540 |
407 // |site_instance_c| is expected to go away once we kill |child_process_b| | 541 // |site_instance_c| is expected to go away once we kill |child_process_b| |
408 // below, so create a local scope so we can extend the lifetime of | 542 // below, so create a local scope so we can extend the lifetime of |
409 // |site_instance_c| with a refptr. | 543 // |site_instance_c| with a refptr. |
410 { | 544 { |
411 SiteInstance* site_instance_b = | 545 SiteInstance* site_instance_b = |
412 root->child_at(0)->current_frame_host()->GetSiteInstance(); | 546 root->child_at(0)->current_frame_host()->GetSiteInstance(); |
413 scoped_refptr<SiteInstanceImpl> site_instance_c = | 547 scoped_refptr<SiteInstanceImpl> site_instance_c = |
414 node4->current_frame_host()->GetSiteInstance(); | 548 node4->current_frame_host()->GetSiteInstance(); |
415 | 549 |
(...skipping 10 matching lines...) Expand all Loading... |
426 child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); | 560 child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
427 child_process_b->Shutdown(0, false); | 561 child_process_b->Shutdown(0, false); |
428 crash_observer.Wait(); | 562 crash_observer.Wait(); |
429 | 563 |
430 // Make sure proxy C has gone from root. | 564 // Make sure proxy C has gone from root. |
431 EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost( | 565 EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost( |
432 site_instance_c.get())); | 566 site_instance_c.get())); |
433 // Make sure proxy C has gone from node3 as well. | 567 // Make sure proxy C has gone from node3 as well. |
434 EXPECT_FALSE(root->child_at(1)->render_manager()->GetRenderFrameProxyHost( | 568 EXPECT_FALSE(root->child_at(1)->render_manager()->GetRenderFrameProxyHost( |
435 site_instance_c.get())); | 569 site_instance_c.get())); |
436 // TODO(lazyboy): Once http://crbug.com/432107 is fixed, we should also | 570 // Make sure proxy B stays around in root and node3. |
437 // check that proxy B exists in both root and node3. | 571 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost( |
| 572 site_instance_b)); |
| 573 EXPECT_TRUE(root->child_at(1)->render_manager()->GetRenderFrameProxyHost( |
| 574 site_instance_b)); |
438 } | 575 } |
439 } | 576 } |
440 | 577 |
441 // Crash a subframe and ensures its children are cleared from the FrameTree. | 578 // Crash a subframe and ensures its children are cleared from the FrameTree. |
442 // See http://crbug.com/338508. | 579 // See http://crbug.com/338508. |
443 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrashSubframe) { | 580 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrashSubframe) { |
444 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html")); | 581 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html")); |
445 NavigateToURL(shell(), main_url); | 582 NavigateToURL(shell(), main_url); |
446 | 583 |
447 StartFrameAtDataURL(); | 584 StartFrameAtDataURL(); |
(...skipping 726 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1174 params.frame_tree_node_id = child->frame_tree_node_id(); | 1311 params.frame_tree_node_id = child->frame_tree_node_id(); |
1175 child->navigator()->GetController()->LoadURLWithParams(params); | 1312 child->navigator()->GetController()->LoadURLWithParams(params); |
1176 nav_observer.Wait(); | 1313 nav_observer.Wait(); |
1177 | 1314 |
1178 // Verify that the navigation succeeded and the expected URL was loaded. | 1315 // Verify that the navigation succeeded and the expected URL was loaded. |
1179 EXPECT_TRUE(observer.last_navigation_succeeded()); | 1316 EXPECT_TRUE(observer.last_navigation_succeeded()); |
1180 EXPECT_EQ(url, observer.last_navigation_url()); | 1317 EXPECT_EQ(url, observer.last_navigation_url()); |
1181 } | 1318 } |
1182 | 1319 |
1183 } // namespace content | 1320 } // namespace content |
OLD | NEW |