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. 4 5 #include "base/command_line.h" 6 #include "base/compiler_specific.h" 7 #include "base/memory/scoped_vector.h" 8 #include "base/strings/string16.h" 9 #include "content/browser/browser_thread_impl.h" 10 #include "content/browser/browsing_instance.h" 11 #include "content/browser/child_process_security_policy_impl.h" 12 #include "content/browser/frame_host/navigation_entry_impl.h" 13 #include "content/browser/renderer_host/render_process_host_impl.h" 14 #include "content/browser/renderer_host/render_view_host_impl.h" 15 #include "content/browser/site_instance_impl.h" 16 #include "content/browser/web_contents/web_contents_impl.h" 17 #include "content/browser/webui/web_ui_controller_factory_registry.h" 18 #include "content/public/common/content_client.h" 19 #include "content/public/common/content_constants.h" 20 #include "content/public/common/content_switches.h" 21 #include "content/public/common/url_constants.h" 22 #include "content/public/common/url_utils.h" 23 #include "content/public/test/mock_render_process_host.h" 24 #include "content/public/test/test_browser_context.h" 25 #include "content/public/test/test_browser_thread.h" 26 #include "content/test/test_content_browser_client.h" 27 #include "content/test/test_content_client.h" 28 #include "content/test/test_render_view_host.h" 29 #include "testing/gtest/include/gtest/gtest.h" 30 #include "url/url_util.h" 31 32 namespace content { 33 namespace { 34 35 const char kPrivilegedScheme[] = "privileged"; 36 37 class SiteInstanceTestWebUIControllerFactory : public WebUIControllerFactory { 38 public: 39 virtual WebUIController* CreateWebUIControllerForURL( 40 WebUI* web_ui, const GURL& url) const OVERRIDE { 41 return NULL; 42 } 43 virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context, 44 const GURL& url) const OVERRIDE { 45 return WebUI::kNoWebUI; 46 } 47 virtual bool UseWebUIForURL(BrowserContext* browser_context, 48 const GURL& url) const OVERRIDE { 49 return HasWebUIScheme(url); 50 } 51 virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context, 52 const GURL& url) const OVERRIDE { 53 return HasWebUIScheme(url); 54 } 55 }; 56 57 class SiteInstanceTestBrowserClient : public TestContentBrowserClient { 58 public: 59 SiteInstanceTestBrowserClient() 60 : privileged_process_id_(-1) { 61 WebUIControllerFactory::RegisterFactory(&factory_); 62 } 63 64 virtual ~SiteInstanceTestBrowserClient() { 65 WebUIControllerFactory::UnregisterFactoryForTesting(&factory_); 66 } 67 68 virtual bool IsSuitableHost(RenderProcessHost* process_host, 69 const GURL& site_url) OVERRIDE { 70 return (privileged_process_id_ == process_host->GetID()) == 71 site_url.SchemeIs(kPrivilegedScheme); 72 } 73 74 void set_privileged_process_id(int process_id) { 75 privileged_process_id_ = process_id; 76 } 77 78 private: 79 SiteInstanceTestWebUIControllerFactory factory_; 80 int privileged_process_id_; 81 }; 82 83 class SiteInstanceTest : public testing::Test { 84 public: 85 SiteInstanceTest() 86 : ui_thread_(BrowserThread::UI, &message_loop_), 87 file_user_blocking_thread_(BrowserThread::FILE_USER_BLOCKING, 88 &message_loop_), 89 io_thread_(BrowserThread::IO, &message_loop_), 90 old_browser_client_(NULL) { 91 } 92 93 virtual void SetUp() { 94 old_browser_client_ = SetBrowserClientForTesting(&browser_client_); 95 url_util::AddStandardScheme(kPrivilegedScheme); 96 url_util::AddStandardScheme(chrome::kChromeUIScheme); 97 98 SiteInstanceImpl::set_render_process_host_factory(&rph_factory_); 99 } 100 101 virtual void TearDown() { 102 // Ensure that no RenderProcessHosts are left over after the tests. 103 EXPECT_TRUE(RenderProcessHost::AllHostsIterator().IsAtEnd()); 104 105 SetBrowserClientForTesting(old_browser_client_); 106 SiteInstanceImpl::set_render_process_host_factory(NULL); 107 108 // http://crbug.com/143565 found SiteInstanceTest leaking an 109 // AppCacheDatabase. This happens because some part of the test indirectly 110 // calls StoragePartitionImplMap::PostCreateInitialization(), which posts 111 // a task to the IO thread to create the AppCacheDatabase. Since the 112 // message loop is not running, the AppCacheDatabase ends up getting 113 // created when DrainMessageLoops() gets called at the end of a test case. 114 // Immediately after, the test case ends and the AppCacheDatabase gets 115 // scheduled for deletion. Here, call DrainMessageLoops() again so the 116 // AppCacheDatabase actually gets deleted. 117 DrainMessageLoops(); 118 } 119 120 void set_privileged_process_id(int process_id) { 121 browser_client_.set_privileged_process_id(process_id); 122 } 123 124 void DrainMessageLoops() { 125 // We don't just do this in TearDown() because we create TestBrowserContext 126 // objects in each test, which will be destructed before 127 // TearDown() is called. 128 base::MessageLoop::current()->RunUntilIdle(); 129 message_loop_.RunUntilIdle(); 130 } 131 132 private: 133 base::MessageLoopForUI message_loop_; 134 TestBrowserThread ui_thread_; 135 TestBrowserThread file_user_blocking_thread_; 136 TestBrowserThread io_thread_; 137 138 SiteInstanceTestBrowserClient browser_client_; 139 ContentBrowserClient* old_browser_client_; 140 MockRenderProcessHostFactory rph_factory_; 141 }; 142 143 // Subclass of BrowsingInstance that updates a counter when deleted and 144 // returns TestSiteInstances from GetSiteInstanceForURL. 145 class TestBrowsingInstance : public BrowsingInstance { 146 public: 147 TestBrowsingInstance(BrowserContext* browser_context, int* delete_counter) 148 : BrowsingInstance(browser_context), 149 delete_counter_(delete_counter) { 150 } 151 152 // Make a few methods public for tests. 153 using BrowsingInstance::browser_context; 154 using BrowsingInstance::HasSiteInstance; 155 using BrowsingInstance::GetSiteInstanceForURL; 156 using BrowsingInstance::RegisterSiteInstance; 157 using BrowsingInstance::UnregisterSiteInstance; 158 159 private: 160 virtual ~TestBrowsingInstance() { 161 (*delete_counter_)++; 162 } 163 164 int* delete_counter_; 165 }; 166 167 // Subclass of SiteInstanceImpl that updates a counter when deleted. 168 class TestSiteInstance : public SiteInstanceImpl { 169 public: 170 static TestSiteInstance* CreateTestSiteInstance( 171 BrowserContext* browser_context, 172 int* site_delete_counter, 173 int* browsing_delete_counter) { 174 TestBrowsingInstance* browsing_instance = 175 new TestBrowsingInstance(browser_context, browsing_delete_counter); 176 return new TestSiteInstance(browsing_instance, site_delete_counter); 177 } 178 179 private: 180 TestSiteInstance(BrowsingInstance* browsing_instance, int* delete_counter) 181 : SiteInstanceImpl(browsing_instance), delete_counter_(delete_counter) {} 182 virtual ~TestSiteInstance() { 183 (*delete_counter_)++; 184 } 185 186 int* delete_counter_; 187 }; 188 189 } // namespace 190 191 // Test to ensure no memory leaks for SiteInstance objects. 192 TEST_F(SiteInstanceTest, SiteInstanceDestructor) { 193 // The existence of this object will cause WebContentsImpl to create our 194 // test one instead of the real one. 195 RenderViewHostTestEnabler rvh_test_enabler; 196 int site_delete_counter = 0; 197 int browsing_delete_counter = 0; 198 const GURL url("test:foo"); 199 200 // Ensure that instances are deleted when their NavigationEntries are gone. 201 TestSiteInstance* instance = 202 TestSiteInstance::CreateTestSiteInstance(NULL, &site_delete_counter, 203 &browsing_delete_counter); 204 EXPECT_EQ(0, site_delete_counter); 205 206 NavigationEntryImpl* e1 = new NavigationEntryImpl( 207 instance, 0, url, Referrer(), base::string16(), PAGE_TRANSITION_LINK, 208 false); 209 210 // Redundantly setting e1's SiteInstance shouldn't affect the ref count. 211 e1->set_site_instance(instance); 212 EXPECT_EQ(0, site_delete_counter); 213 214 // Add a second reference 215 NavigationEntryImpl* e2 = new NavigationEntryImpl( 216 instance, 0, url, Referrer(), base::string16(), PAGE_TRANSITION_LINK, 217 false); 218 219 // Now delete both entries and be sure the SiteInstance goes away. 220 delete e1; 221 EXPECT_EQ(0, site_delete_counter); 222 EXPECT_EQ(0, browsing_delete_counter); 223 delete e2; 224 EXPECT_EQ(1, site_delete_counter); 225 // instance is now deleted 226 EXPECT_EQ(1, browsing_delete_counter); 227 // browsing_instance is now deleted 228 229 // Ensure that instances are deleted when their RenderViewHosts are gone. 230 scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext()); 231 instance = 232 TestSiteInstance::CreateTestSiteInstance(browser_context.get(), 233 &site_delete_counter, 234 &browsing_delete_counter); 235 { 236 scoped_ptr<WebContentsImpl> web_contents(static_cast<WebContentsImpl*>( 237 WebContents::Create(WebContents::CreateParams( 238 browser_context.get(), instance)))); 239 EXPECT_EQ(1, site_delete_counter); 240 EXPECT_EQ(1, browsing_delete_counter); 241 } 242 243 // Make sure that we flush any messages related to the above WebContentsImpl 244 // destruction. 245 DrainMessageLoops(); 246 247 EXPECT_EQ(2, site_delete_counter); 248 EXPECT_EQ(2, browsing_delete_counter); 249 // contents is now deleted, along with instance and browsing_instance 250 } 251 252 // Test that NavigationEntries with SiteInstances can be cloned, but that their 253 // SiteInstances can be changed afterwards. Also tests that the ref counts are 254 // updated properly after the change. 255 TEST_F(SiteInstanceTest, CloneNavigationEntry) { 256 int site_delete_counter1 = 0; 257 int site_delete_counter2 = 0; 258 int browsing_delete_counter = 0; 259 const GURL url("test:foo"); 260 261 SiteInstanceImpl* instance1 = 262 TestSiteInstance::CreateTestSiteInstance(NULL, &site_delete_counter1, 263 &browsing_delete_counter); 264 SiteInstanceImpl* instance2 = 265 TestSiteInstance::CreateTestSiteInstance(NULL, &site_delete_counter2, 266 &browsing_delete_counter); 267 268 NavigationEntryImpl* e1 = new NavigationEntryImpl( 269 instance1, 0, url, Referrer(), base::string16(), PAGE_TRANSITION_LINK, 270 false); 271 // Clone the entry 272 NavigationEntryImpl* e2 = new NavigationEntryImpl(*e1); 273 274 // Should be able to change the SiteInstance of the cloned entry. 275 e2->set_site_instance(instance2); 276 277 // The first SiteInstance should go away after deleting e1, since e2 should 278 // no longer be referencing it. 279 delete e1; 280 EXPECT_EQ(1, site_delete_counter1); 281 EXPECT_EQ(0, site_delete_counter2); 282 283 // The second SiteInstance should go away after deleting e2. 284 delete e2; 285 EXPECT_EQ(1, site_delete_counter1); 286 EXPECT_EQ(1, site_delete_counter2); 287 288 // Both BrowsingInstances are also now deleted 289 EXPECT_EQ(2, browsing_delete_counter); 290 291 DrainMessageLoops(); 292 } 293 294 // Test to ensure GetProcess returns and creates processes correctly. 295 TEST_F(SiteInstanceTest, GetProcess) { 296 // Ensure that GetProcess returns a process. 297 scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext()); 298 scoped_ptr<RenderProcessHost> host1; 299 scoped_refptr<SiteInstanceImpl> instance(static_cast<SiteInstanceImpl*>( 300 SiteInstance::Create(browser_context.get()))); 301 host1.reset(instance->GetProcess()); 302 EXPECT_TRUE(host1.get() != NULL); 303 304 // Ensure that GetProcess creates a new process. 305 scoped_refptr<SiteInstanceImpl> instance2(static_cast<SiteInstanceImpl*>( 306 SiteInstance::Create(browser_context.get()))); 307 scoped_ptr<RenderProcessHost> host2(instance2->GetProcess()); 308 EXPECT_TRUE(host2.get() != NULL); 309 EXPECT_NE(host1.get(), host2.get()); 310 311 DrainMessageLoops(); 312 } 313 314 // Test to ensure SetSite and site() work properly. 315 TEST_F(SiteInstanceTest, SetSite) { 316 scoped_refptr<SiteInstanceImpl> instance(static_cast<SiteInstanceImpl*>( 317 SiteInstance::Create(NULL))); 318 EXPECT_FALSE(instance->HasSite()); 319 EXPECT_TRUE(instance->GetSiteURL().is_empty()); 320 321 instance->SetSite(GURL("http://www.google.com/index.html")); 322 EXPECT_EQ(GURL("http://google.com"), instance->GetSiteURL()); 323 324 EXPECT_TRUE(instance->HasSite()); 325 326 DrainMessageLoops(); 327 } 328 329 // Test to ensure GetSiteForURL properly returns sites for URLs. 330 TEST_F(SiteInstanceTest, GetSiteForURL) { 331 // Pages are irrelevant. 332 GURL test_url = GURL("http://www.google.com/index.html"); 333 EXPECT_EQ(GURL("http://google.com"), 334 SiteInstanceImpl::GetSiteForURL(NULL, test_url)); 335 336 // Ports are irrlevant. 337 test_url = GURL("https://www.google.com:8080"); 338 EXPECT_EQ(GURL("https://google.com"), 339 SiteInstanceImpl::GetSiteForURL(NULL, test_url)); 340 341 // Javascript URLs have no site. 342 test_url = GURL("javascript:foo();"); 343 EXPECT_EQ(GURL(), SiteInstanceImpl::GetSiteForURL(NULL, test_url)); 344 345 test_url = GURL("http://foo/a.html"); 346 EXPECT_EQ(GURL("http://foo"), SiteInstanceImpl::GetSiteForURL( 347 NULL, test_url)); 348 349 test_url = GURL("file:///C:/Downloads/"); 350 EXPECT_EQ(GURL(), SiteInstanceImpl::GetSiteForURL(NULL, test_url)); 351 352 std::string guest_url(kGuestScheme); 353 guest_url.append("://abc123"); 354 test_url = GURL(guest_url); 355 EXPECT_EQ(test_url, SiteInstanceImpl::GetSiteForURL(NULL, test_url)); 356 357 // TODO(creis): Do we want to special case file URLs to ensure they have 358 // either no site or a special "file://" site? We currently return 359 // "file://home/" as the site, which seems broken. 360 // test_url = GURL("file://home/"); 361 // EXPECT_EQ(GURL(), SiteInstanceImpl::GetSiteForURL(NULL, test_url)); 362 363 DrainMessageLoops(); 364 } 365 366 // Test of distinguishing URLs from different sites. Most of this logic is 367 // tested in RegistryControlledDomainTest. This test focuses on URLs with 368 // different schemes or ports. 369 TEST_F(SiteInstanceTest, IsSameWebSite) { 370 GURL url_foo = GURL("http://foo/a.html"); 371 GURL url_foo2 = GURL("http://foo/b.html"); 372 GURL url_foo_https = GURL("https://foo/a.html"); 373 GURL url_foo_port = GURL("http://foo:8080/a.html"); 374 GURL url_javascript = GURL("javascript:alert(1);"); 375 376 // Same scheme and port -> same site. 377 EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_foo, url_foo2)); 378 379 // Different scheme -> different site. 380 EXPECT_FALSE(SiteInstance::IsSameWebSite(NULL, url_foo, url_foo_https)); 381 382 // Different port -> same site. 383 // (Changes to document.domain make renderer ignore the port.) 384 EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_foo, url_foo_port)); 385 386 // JavaScript links should be considered same site for anything. 387 EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_javascript, url_foo)); 388 EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_javascript, url_foo_https)); 389 EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_javascript, url_foo_port)); 390 391 DrainMessageLoops(); 392 } 393 394 // Test to ensure that there is only one SiteInstance per site in a given 395 // BrowsingInstance, when process-per-site is not in use. 396 TEST_F(SiteInstanceTest, OneSiteInstancePerSite) { 397 ASSERT_FALSE(CommandLine::ForCurrentProcess()->HasSwitch( 398 switches::kProcessPerSite)); 399 int delete_counter = 0; 400 scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext()); 401 TestBrowsingInstance* browsing_instance = 402 new TestBrowsingInstance(browser_context.get(), &delete_counter); 403 404 const GURL url_a1("http://www.google.com/1.html"); 405 scoped_refptr<SiteInstanceImpl> site_instance_a1( 406 static_cast<SiteInstanceImpl*>( 407 browsing_instance->GetSiteInstanceForURL(url_a1))); 408 EXPECT_TRUE(site_instance_a1.get() != NULL); 409 410 // A separate site should create a separate SiteInstance. 411 const GURL url_b1("http://www.yahoo.com/"); 412 scoped_refptr<SiteInstanceImpl> site_instance_b1( 413 static_cast<SiteInstanceImpl*>( 414 browsing_instance->GetSiteInstanceForURL(url_b1))); 415 EXPECT_NE(site_instance_a1.get(), site_instance_b1.get()); 416 EXPECT_TRUE(site_instance_a1->IsRelatedSiteInstance(site_instance_b1.get())); 417 418 // Getting the new SiteInstance from the BrowsingInstance and from another 419 // SiteInstance in the BrowsingInstance should give the same result. 420 EXPECT_EQ(site_instance_b1.get(), 421 site_instance_a1->GetRelatedSiteInstance(url_b1)); 422 423 // A second visit to the original site should return the same SiteInstance. 424 const GURL url_a2("http://www.google.com/2.html"); 425 EXPECT_EQ(site_instance_a1.get(), 426 browsing_instance->GetSiteInstanceForURL(url_a2)); 427 EXPECT_EQ(site_instance_a1.get(), 428 site_instance_a1->GetRelatedSiteInstance(url_a2)); 429 430 // A visit to the original site in a new BrowsingInstance (same or different 431 // browser context) should return a different SiteInstance. 432 TestBrowsingInstance* browsing_instance2 = 433 new TestBrowsingInstance(browser_context.get(), &delete_counter); 434 // Ensure the new SiteInstance is ref counted so that it gets deleted. 435 scoped_refptr<SiteInstanceImpl> site_instance_a2_2( 436 static_cast<SiteInstanceImpl*>( 437 browsing_instance2->GetSiteInstanceForURL(url_a2))); 438 EXPECT_NE(site_instance_a1.get(), site_instance_a2_2.get()); 439 EXPECT_FALSE( 440 site_instance_a1->IsRelatedSiteInstance(site_instance_a2_2.get())); 441 442 // The two SiteInstances for http://google.com should not use the same process 443 // if process-per-site is not enabled. 444 scoped_ptr<RenderProcessHost> process_a1(site_instance_a1->GetProcess()); 445 scoped_ptr<RenderProcessHost> process_a2_2(site_instance_a2_2->GetProcess()); 446 EXPECT_NE(process_a1.get(), process_a2_2.get()); 447 448 // Should be able to see that we do have SiteInstances. 449 EXPECT_TRUE(browsing_instance->HasSiteInstance( 450 GURL("http://mail.google.com"))); 451 EXPECT_TRUE(browsing_instance2->HasSiteInstance( 452 GURL("http://mail.google.com"))); 453 EXPECT_TRUE(browsing_instance->HasSiteInstance( 454 GURL("http://mail.yahoo.com"))); 455 456 // Should be able to see that we don't have SiteInstances. 457 EXPECT_FALSE(browsing_instance->HasSiteInstance( 458 GURL("https://www.google.com"))); 459 EXPECT_FALSE(browsing_instance2->HasSiteInstance( 460 GURL("http://www.yahoo.com"))); 461 462 // browsing_instances will be deleted when their SiteInstances are deleted. 463 // The processes will be unregistered when the RPH scoped_ptrs go away. 464 465 DrainMessageLoops(); 466 } 467 468 // Test to ensure that there is only one RenderProcessHost per site for an 469 // entire BrowserContext, if process-per-site is in use. 470 TEST_F(SiteInstanceTest, OneSiteInstancePerSiteInBrowserContext) { 471 CommandLine::ForCurrentProcess()->AppendSwitch( 472 switches::kProcessPerSite); 473 int delete_counter = 0; 474 scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext()); 475 TestBrowsingInstance* browsing_instance = 476 new TestBrowsingInstance(browser_context.get(), &delete_counter); 477 478 const GURL url_a1("http://www.google.com/1.html"); 479 scoped_refptr<SiteInstanceImpl> site_instance_a1( 480 static_cast<SiteInstanceImpl*>( 481 browsing_instance->GetSiteInstanceForURL(url_a1))); 482 EXPECT_TRUE(site_instance_a1.get() != NULL); 483 scoped_ptr<RenderProcessHost> process_a1(site_instance_a1->GetProcess()); 484 485 // A separate site should create a separate SiteInstance. 486 const GURL url_b1("http://www.yahoo.com/"); 487 scoped_refptr<SiteInstanceImpl> site_instance_b1( 488 static_cast<SiteInstanceImpl*>( 489 browsing_instance->GetSiteInstanceForURL(url_b1))); 490 EXPECT_NE(site_instance_a1.get(), site_instance_b1.get()); 491 EXPECT_TRUE(site_instance_a1->IsRelatedSiteInstance(site_instance_b1.get())); 492 493 // Getting the new SiteInstance from the BrowsingInstance and from another 494 // SiteInstance in the BrowsingInstance should give the same result. 495 EXPECT_EQ(site_instance_b1.get(), 496 site_instance_a1->GetRelatedSiteInstance(url_b1)); 497 498 // A second visit to the original site should return the same SiteInstance. 499 const GURL url_a2("http://www.google.com/2.html"); 500 EXPECT_EQ(site_instance_a1.get(), 501 browsing_instance->GetSiteInstanceForURL(url_a2)); 502 EXPECT_EQ(site_instance_a1.get(), 503 site_instance_a1->GetRelatedSiteInstance(url_a2)); 504 505 // A visit to the original site in a new BrowsingInstance (same browser 506 // context) should return a different SiteInstance with the same process. 507 TestBrowsingInstance* browsing_instance2 = 508 new TestBrowsingInstance(browser_context.get(), &delete_counter); 509 scoped_refptr<SiteInstanceImpl> site_instance_a1_2( 510 static_cast<SiteInstanceImpl*>( 511 browsing_instance2->GetSiteInstanceForURL(url_a1))); 512 EXPECT_TRUE(site_instance_a1.get() != NULL); 513 EXPECT_NE(site_instance_a1.get(), site_instance_a1_2.get()); 514 EXPECT_EQ(process_a1.get(), site_instance_a1_2->GetProcess()); 515 516 // A visit to the original site in a new BrowsingInstance (different browser 517 // context) should return a different SiteInstance with a different process. 518 scoped_ptr<TestBrowserContext> browser_context2(new TestBrowserContext()); 519 TestBrowsingInstance* browsing_instance3 = 520 new TestBrowsingInstance(browser_context2.get(), &delete_counter); 521 scoped_refptr<SiteInstanceImpl> site_instance_a2_3( 522 static_cast<SiteInstanceImpl*>( 523 browsing_instance3->GetSiteInstanceForURL(url_a2))); 524 EXPECT_TRUE(site_instance_a2_3.get() != NULL); 525 scoped_ptr<RenderProcessHost> process_a2_3(site_instance_a2_3->GetProcess()); 526 EXPECT_NE(site_instance_a1.get(), site_instance_a2_3.get()); 527 EXPECT_NE(process_a1.get(), process_a2_3.get()); 528 529 // Should be able to see that we do have SiteInstances. 530 EXPECT_TRUE(browsing_instance->HasSiteInstance( 531 GURL("http://mail.google.com"))); // visited before 532 EXPECT_TRUE(browsing_instance2->HasSiteInstance( 533 GURL("http://mail.google.com"))); // visited before 534 EXPECT_TRUE(browsing_instance->HasSiteInstance( 535 GURL("http://mail.yahoo.com"))); // visited before 536 537 // Should be able to see that we don't have SiteInstances. 538 EXPECT_FALSE(browsing_instance2->HasSiteInstance( 539 GURL("http://www.yahoo.com"))); // different BI, same browser context 540 EXPECT_FALSE(browsing_instance->HasSiteInstance( 541 GURL("https://www.google.com"))); // not visited before 542 EXPECT_FALSE(browsing_instance3->HasSiteInstance( 543 GURL("http://www.yahoo.com"))); // different BI, different context 544 545 // browsing_instances will be deleted when their SiteInstances are deleted. 546 // The processes will be unregistered when the RPH scoped_ptrs go away. 547 548 DrainMessageLoops(); 549 } 550 551 static SiteInstanceImpl* CreateSiteInstance(BrowserContext* browser_context, 552 const GURL& url) { 553 return static_cast<SiteInstanceImpl*>( 554 SiteInstance::CreateForURL(browser_context, url)); 555 } 556 557 // Test to ensure that pages that require certain privileges are grouped 558 // in processes with similar pages. 559 TEST_F(SiteInstanceTest, ProcessSharingByType) { 560 ChildProcessSecurityPolicyImpl* policy = 561 ChildProcessSecurityPolicyImpl::GetInstance(); 562 563 // Make a bunch of mock renderers so that we hit the limit. 564 scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext()); 565 ScopedVector<MockRenderProcessHost> hosts; 566 for (size_t i = 0; i < kMaxRendererProcessCount; ++i) 567 hosts.push_back(new MockRenderProcessHost(browser_context.get())); 568 569 // Create some extension instances and make sure they share a process. 570 scoped_refptr<SiteInstanceImpl> extension1_instance( 571 CreateSiteInstance(browser_context.get(), 572 GURL(kPrivilegedScheme + std::string("://foo/bar")))); 573 set_privileged_process_id(extension1_instance->GetProcess()->GetID()); 574 575 scoped_refptr<SiteInstanceImpl> extension2_instance( 576 CreateSiteInstance(browser_context.get(), 577 GURL(kPrivilegedScheme + std::string("://baz/bar")))); 578 579 scoped_ptr<RenderProcessHost> extension_host( 580 extension1_instance->GetProcess()); 581 EXPECT_EQ(extension1_instance->GetProcess(), 582 extension2_instance->GetProcess()); 583 584 // Create some WebUI instances and make sure they share a process. 585 scoped_refptr<SiteInstanceImpl> webui1_instance(CreateSiteInstance( 586 browser_context.get(), 587 GURL(chrome::kChromeUIScheme + std::string("://newtab")))); 588 policy->GrantWebUIBindings(webui1_instance->GetProcess()->GetID()); 589 590 scoped_refptr<SiteInstanceImpl> webui2_instance(CreateSiteInstance( 591 browser_context.get(), 592 GURL(chrome::kChromeUIScheme + std::string("://history")))); 593 594 scoped_ptr<RenderProcessHost> dom_host(webui1_instance->GetProcess()); 595 EXPECT_EQ(webui1_instance->GetProcess(), webui2_instance->GetProcess()); 596 597 // Make sure none of differing privilege processes are mixed. 598 EXPECT_NE(extension1_instance->GetProcess(), webui1_instance->GetProcess()); 599 600 for (size_t i = 0; i < kMaxRendererProcessCount; ++i) { 601 EXPECT_NE(extension1_instance->GetProcess(), hosts[i]); 602 EXPECT_NE(webui1_instance->GetProcess(), hosts[i]); 603 } 604 605 DrainMessageLoops(); 606 } 607 608 // Test to ensure that HasWrongProcessForURL behaves properly for different 609 // types of URLs. 610 TEST_F(SiteInstanceTest, HasWrongProcessForURL) { 611 scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext()); 612 scoped_ptr<RenderProcessHost> host; 613 scoped_refptr<SiteInstanceImpl> instance(static_cast<SiteInstanceImpl*>( 614 SiteInstance::Create(browser_context.get()))); 615 616 EXPECT_FALSE(instance->HasSite()); 617 EXPECT_TRUE(instance->GetSiteURL().is_empty()); 618 619 instance->SetSite(GURL("http://evernote.com/")); 620 EXPECT_TRUE(instance->HasSite()); 621 622 // Check prior to "assigning" a process to the instance, which is expected 623 // to return false due to not being attached to any process yet. 624 EXPECT_FALSE(instance->HasWrongProcessForURL(GURL("http://google.com"))); 625 626 // The call to GetProcess actually creates a new real process, which works 627 // fine, but might be a cause for problems in different contexts. 628 host.reset(instance->GetProcess()); 629 EXPECT_TRUE(host.get() != NULL); 630 EXPECT_TRUE(instance->HasProcess()); 631 632 EXPECT_FALSE(instance->HasWrongProcessForURL(GURL("http://evernote.com"))); 633 EXPECT_FALSE(instance->HasWrongProcessForURL( 634 GURL("javascript:alert(document.location.href);"))); 635 636 EXPECT_TRUE(instance->HasWrongProcessForURL(GURL("chrome://settings"))); 637 638 // Test that WebUI SiteInstances reject normal web URLs. 639 const GURL webui_url("chrome://settings"); 640 scoped_refptr<SiteInstanceImpl> webui_instance(static_cast<SiteInstanceImpl*>( 641 SiteInstance::Create(browser_context.get()))); 642 webui_instance->SetSite(webui_url); 643 scoped_ptr<RenderProcessHost> webui_host(webui_instance->GetProcess()); 644 645 // Simulate granting WebUI bindings for the process. 646 ChildProcessSecurityPolicyImpl::GetInstance()->GrantWebUIBindings( 647 webui_host->GetID()); 648 649 EXPECT_TRUE(webui_instance->HasProcess()); 650 EXPECT_FALSE(webui_instance->HasWrongProcessForURL(webui_url)); 651 EXPECT_TRUE(webui_instance->HasWrongProcessForURL(GURL("http://google.com"))); 652 653 // WebUI uses process-per-site, so another instance will use the same process 654 // even if we haven't called GetProcess yet. Make sure HasWrongProcessForURL 655 // doesn't crash (http://crbug.com/137070). 656 scoped_refptr<SiteInstanceImpl> webui_instance2( 657 static_cast<SiteInstanceImpl*>( 658 SiteInstance::Create(browser_context.get()))); 659 webui_instance2->SetSite(webui_url); 660 EXPECT_FALSE(webui_instance2->HasWrongProcessForURL(webui_url)); 661 EXPECT_TRUE( 662 webui_instance2->HasWrongProcessForURL(GURL("http://google.com"))); 663 664 DrainMessageLoops(); 665 } 666 667 // Test to ensure that HasWrongProcessForURL behaves properly even when 668 // --site-per-process is used (http://crbug.com/160671). 669 TEST_F(SiteInstanceTest, HasWrongProcessForURLInSitePerProcess) { 670 CommandLine::ForCurrentProcess()->AppendSwitch( 671 switches::kSitePerProcess); 672 673 scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext()); 674 scoped_ptr<RenderProcessHost> host; 675 scoped_refptr<SiteInstanceImpl> instance(static_cast<SiteInstanceImpl*>( 676 SiteInstance::Create(browser_context.get()))); 677 678 instance->SetSite(GURL("http://evernote.com/")); 679 EXPECT_TRUE(instance->HasSite()); 680 681 // Check prior to "assigning" a process to the instance, which is expected 682 // to return false due to not being attached to any process yet. 683 EXPECT_FALSE(instance->HasWrongProcessForURL(GURL("http://google.com"))); 684 685 // The call to GetProcess actually creates a new real process, which works 686 // fine, but might be a cause for problems in different contexts. 687 host.reset(instance->GetProcess()); 688 EXPECT_TRUE(host.get() != NULL); 689 EXPECT_TRUE(instance->HasProcess()); 690 691 EXPECT_FALSE(instance->HasWrongProcessForURL(GURL("http://evernote.com"))); 692 EXPECT_FALSE(instance->HasWrongProcessForURL( 693 GURL("javascript:alert(document.location.href);"))); 694 695 EXPECT_TRUE(instance->HasWrongProcessForURL(GURL("chrome://settings"))); 696 697 DrainMessageLoops(); 698 } 699 700 // Test that we do not reuse a process in process-per-site mode if it has the 701 // wrong bindings for its URL. http://crbug.com/174059. 702 TEST_F(SiteInstanceTest, ProcessPerSiteWithWrongBindings) { 703 scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext()); 704 scoped_ptr<RenderProcessHost> host; 705 scoped_ptr<RenderProcessHost> host2; 706 scoped_refptr<SiteInstanceImpl> instance(static_cast<SiteInstanceImpl*>( 707 SiteInstance::Create(browser_context.get()))); 708 709 EXPECT_FALSE(instance->HasSite()); 710 EXPECT_TRUE(instance->GetSiteURL().is_empty()); 711 712 // Simulate navigating to a WebUI URL in a process that does not have WebUI 713 // bindings. This already requires bypassing security checks. 714 const GURL webui_url("chrome://settings"); 715 instance->SetSite(webui_url); 716 EXPECT_TRUE(instance->HasSite()); 717 718 // The call to GetProcess actually creates a new real process. 719 host.reset(instance->GetProcess()); 720 EXPECT_TRUE(host.get() != NULL); 721 EXPECT_TRUE(instance->HasProcess()); 722 723 // Without bindings, this should look like the wrong process. 724 EXPECT_TRUE(instance->HasWrongProcessForURL(webui_url)); 725 726 // WebUI uses process-per-site, so another instance would normally use the 727 // same process. Make sure it doesn't use the same process if the bindings 728 // are missing. 729 scoped_refptr<SiteInstanceImpl> instance2( 730 static_cast<SiteInstanceImpl*>( 731 SiteInstance::Create(browser_context.get()))); 732 instance2->SetSite(webui_url); 733 host2.reset(instance2->GetProcess()); 734 EXPECT_TRUE(host2.get() != NULL); 735 EXPECT_TRUE(instance2->HasProcess()); 736 EXPECT_NE(host.get(), host2.get()); 737 738 DrainMessageLoops(); 739 } 740 741 // Test that we do not register processes with empty sites for process-per-site 742 // mode. 743 TEST_F(SiteInstanceTest, NoProcessPerSiteForEmptySite) { 744 CommandLine::ForCurrentProcess()->AppendSwitch( 745 switches::kProcessPerSite); 746 scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext()); 747 scoped_ptr<RenderProcessHost> host; 748 scoped_refptr<SiteInstanceImpl> instance(static_cast<SiteInstanceImpl*>( 749 SiteInstance::Create(browser_context.get()))); 750 751 instance->SetSite(GURL()); 752 EXPECT_TRUE(instance->HasSite()); 753 EXPECT_TRUE(instance->GetSiteURL().is_empty()); 754 host.reset(instance->GetProcess()); 755 756 EXPECT_FALSE(RenderProcessHostImpl::GetProcessHostForSite( 757 browser_context.get(), GURL())); 758 759 DrainMessageLoops(); 760 } 761 762 } // namespace content 763