Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / browser / site_instance_impl_unittest.cc
blobdd7c36096d5289813f7467d32a0cc8541b7eb097
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/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"
32 namespace content {
33 namespace {
35 const char kPrivilegedScheme[] = "privileged";
37 class SiteInstanceTestWebUIControllerFactory : public WebUIControllerFactory {
38 public:
39 WebUIController* CreateWebUIControllerForURL(WebUI* web_ui,
40 const GURL& url) const override {
41 return NULL;
43 WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
44 const GURL& url) const override {
45 return WebUI::kNoWebUI;
47 bool UseWebUIForURL(BrowserContext* browser_context,
48 const GURL& url) const override {
49 return HasWebUIScheme(url);
51 bool UseWebUIBindingsForURL(BrowserContext* browser_context,
52 const GURL& url) const override {
53 return HasWebUIScheme(url);
57 class SiteInstanceTestBrowserClient : public TestContentBrowserClient {
58 public:
59 SiteInstanceTestBrowserClient()
60 : privileged_process_id_(-1) {
61 WebUIControllerFactory::RegisterFactory(&factory_);
64 ~SiteInstanceTestBrowserClient() override {
65 WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
68 bool IsSuitableHost(RenderProcessHost* process_host,
69 const GURL& site_url) override {
70 return (privileged_process_id_ == process_host->GetID()) ==
71 site_url.SchemeIs(kPrivilegedScheme);
74 void set_privileged_process_id(int process_id) {
75 privileged_process_id_ = process_id;
78 private:
79 SiteInstanceTestWebUIControllerFactory factory_;
80 int privileged_process_id_;
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) {
93 void SetUp() override {
94 old_browser_client_ = SetBrowserClientForTesting(&browser_client_);
95 url::AddStandardScheme(kPrivilegedScheme);
96 url::AddStandardScheme(kChromeUIScheme);
98 SiteInstanceImpl::set_render_process_host_factory(&rph_factory_);
101 void TearDown() override {
102 // Ensure that no RenderProcessHosts are left over after the tests.
103 EXPECT_TRUE(RenderProcessHost::AllHostsIterator().IsAtEnd());
105 SetBrowserClientForTesting(old_browser_client_);
106 SiteInstanceImpl::set_render_process_host_factory(NULL);
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();
120 void set_privileged_process_id(int process_id) {
121 browser_client_.set_privileged_process_id(process_id);
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();
132 private:
133 base::MessageLoopForUI message_loop_;
134 TestBrowserThread ui_thread_;
135 TestBrowserThread file_user_blocking_thread_;
136 TestBrowserThread io_thread_;
138 SiteInstanceTestBrowserClient browser_client_;
139 ContentBrowserClient* old_browser_client_;
140 MockRenderProcessHostFactory rph_factory_;
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) {
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;
159 private:
160 ~TestBrowsingInstance() override { (*delete_counter_)++; }
162 int* delete_counter_;
165 // Subclass of SiteInstanceImpl that updates a counter when deleted.
166 class TestSiteInstance : public SiteInstanceImpl {
167 public:
168 static TestSiteInstance* CreateTestSiteInstance(
169 BrowserContext* browser_context,
170 int* site_delete_counter,
171 int* browsing_delete_counter) {
172 TestBrowsingInstance* browsing_instance =
173 new TestBrowsingInstance(browser_context, browsing_delete_counter);
174 return new TestSiteInstance(browsing_instance, site_delete_counter);
177 private:
178 TestSiteInstance(BrowsingInstance* browsing_instance, int* delete_counter)
179 : SiteInstanceImpl(browsing_instance), delete_counter_(delete_counter) {}
180 ~TestSiteInstance() override { (*delete_counter_)++; }
182 int* delete_counter_;
185 } // namespace
187 // Test to ensure no memory leaks for SiteInstance objects.
188 TEST_F(SiteInstanceTest, SiteInstanceDestructor) {
189 // The existence of this object will cause WebContentsImpl to create our
190 // test one instead of the real one.
191 RenderViewHostTestEnabler rvh_test_enabler;
192 int site_delete_counter = 0;
193 int browsing_delete_counter = 0;
194 const GURL url("test:foo");
196 // Ensure that instances are deleted when their NavigationEntries are gone.
197 TestSiteInstance* instance =
198 TestSiteInstance::CreateTestSiteInstance(NULL, &site_delete_counter,
199 &browsing_delete_counter);
200 EXPECT_EQ(0, site_delete_counter);
202 NavigationEntryImpl* e1 = new NavigationEntryImpl(
203 instance, 0, url, Referrer(), base::string16(), ui::PAGE_TRANSITION_LINK,
204 false);
206 // Redundantly setting e1's SiteInstance shouldn't affect the ref count.
207 e1->set_site_instance(instance);
208 EXPECT_EQ(0, site_delete_counter);
210 // Add a second reference
211 NavigationEntryImpl* e2 = new NavigationEntryImpl(
212 instance, 0, url, Referrer(), base::string16(), ui::PAGE_TRANSITION_LINK,
213 false);
215 // Now delete both entries and be sure the SiteInstance goes away.
216 delete e1;
217 EXPECT_EQ(0, site_delete_counter);
218 EXPECT_EQ(0, browsing_delete_counter);
219 delete e2;
220 EXPECT_EQ(1, site_delete_counter);
221 // instance is now deleted
222 EXPECT_EQ(1, browsing_delete_counter);
223 // browsing_instance is now deleted
225 // Ensure that instances are deleted when their RenderViewHosts are gone.
226 scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
227 instance =
228 TestSiteInstance::CreateTestSiteInstance(browser_context.get(),
229 &site_delete_counter,
230 &browsing_delete_counter);
232 scoped_ptr<WebContentsImpl> web_contents(static_cast<WebContentsImpl*>(
233 WebContents::Create(WebContents::CreateParams(
234 browser_context.get(), instance))));
235 EXPECT_EQ(1, site_delete_counter);
236 EXPECT_EQ(1, browsing_delete_counter);
239 // Make sure that we flush any messages related to the above WebContentsImpl
240 // destruction.
241 DrainMessageLoops();
243 EXPECT_EQ(2, site_delete_counter);
244 EXPECT_EQ(2, browsing_delete_counter);
245 // contents is now deleted, along with instance and browsing_instance
248 // Test that NavigationEntries with SiteInstances can be cloned, but that their
249 // SiteInstances can be changed afterwards. Also tests that the ref counts are
250 // updated properly after the change.
251 TEST_F(SiteInstanceTest, CloneNavigationEntry) {
252 int site_delete_counter1 = 0;
253 int site_delete_counter2 = 0;
254 int browsing_delete_counter = 0;
255 const GURL url("test:foo");
257 SiteInstanceImpl* instance1 =
258 TestSiteInstance::CreateTestSiteInstance(NULL, &site_delete_counter1,
259 &browsing_delete_counter);
260 SiteInstanceImpl* instance2 =
261 TestSiteInstance::CreateTestSiteInstance(NULL, &site_delete_counter2,
262 &browsing_delete_counter);
264 NavigationEntryImpl* e1 = new NavigationEntryImpl(
265 instance1, 0, url, Referrer(), base::string16(), ui::PAGE_TRANSITION_LINK,
266 false);
267 // Clone the entry
268 NavigationEntryImpl* e2 = e1->Clone();
270 // Should be able to change the SiteInstance of the cloned entry.
271 e2->set_site_instance(instance2);
273 // The first SiteInstance should go away after deleting e1, since e2 should
274 // no longer be referencing it.
275 delete e1;
276 EXPECT_EQ(1, site_delete_counter1);
277 EXPECT_EQ(0, site_delete_counter2);
279 // The second SiteInstance should go away after deleting e2.
280 delete e2;
281 EXPECT_EQ(1, site_delete_counter1);
282 EXPECT_EQ(1, site_delete_counter2);
284 // Both BrowsingInstances are also now deleted
285 EXPECT_EQ(2, browsing_delete_counter);
287 DrainMessageLoops();
290 // Test to ensure GetProcess returns and creates processes correctly.
291 TEST_F(SiteInstanceTest, GetProcess) {
292 // Ensure that GetProcess returns a process.
293 scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
294 scoped_ptr<RenderProcessHost> host1;
295 scoped_refptr<SiteInstanceImpl> instance(static_cast<SiteInstanceImpl*>(
296 SiteInstance::Create(browser_context.get())));
297 host1.reset(instance->GetProcess());
298 EXPECT_TRUE(host1.get() != NULL);
300 // Ensure that GetProcess creates a new process.
301 scoped_refptr<SiteInstanceImpl> instance2(static_cast<SiteInstanceImpl*>(
302 SiteInstance::Create(browser_context.get())));
303 scoped_ptr<RenderProcessHost> host2(instance2->GetProcess());
304 EXPECT_TRUE(host2.get() != NULL);
305 EXPECT_NE(host1.get(), host2.get());
307 DrainMessageLoops();
310 // Test to ensure SetSite and site() work properly.
311 TEST_F(SiteInstanceTest, SetSite) {
312 scoped_refptr<SiteInstanceImpl> instance(static_cast<SiteInstanceImpl*>(
313 SiteInstance::Create(NULL)));
314 EXPECT_FALSE(instance->HasSite());
315 EXPECT_TRUE(instance->GetSiteURL().is_empty());
317 instance->SetSite(GURL("http://www.google.com/index.html"));
318 EXPECT_EQ(GURL("http://google.com"), instance->GetSiteURL());
320 EXPECT_TRUE(instance->HasSite());
322 DrainMessageLoops();
325 // Test to ensure GetSiteForURL properly returns sites for URLs.
326 TEST_F(SiteInstanceTest, GetSiteForURL) {
327 // Pages are irrelevant.
328 GURL test_url = GURL("http://www.google.com/index.html");
329 GURL site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
330 EXPECT_EQ(GURL("http://google.com"), site_url);
331 EXPECT_EQ("http", site_url.scheme());
332 EXPECT_EQ("google.com", site_url.host());
334 // Ports are irrlevant.
335 test_url = GURL("https://www.google.com:8080");
336 site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
337 EXPECT_EQ(GURL("https://google.com"), site_url);
339 // Hostnames without TLDs are ok.
340 test_url = GURL("http://foo/a.html");
341 site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
342 EXPECT_EQ(GURL("http://foo"), site_url);
343 EXPECT_EQ("foo", site_url.host());
345 // File URLs should include the scheme.
346 test_url = GURL("file:///C:/Downloads/");
347 site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
348 EXPECT_EQ(GURL("file:"), site_url);
349 EXPECT_EQ("file", site_url.scheme());
350 EXPECT_FALSE(site_url.has_host());
352 // Some file URLs have hosts in the path.
353 test_url = GURL("file://server/path");
354 site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
355 EXPECT_EQ(GURL("file://server"), site_url);
356 EXPECT_EQ("server", site_url.host());
358 // Data URLs should include the scheme.
359 test_url = GURL("data:text/html,foo");
360 site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
361 EXPECT_EQ(GURL("data:"), site_url);
362 EXPECT_EQ("data", site_url.scheme());
363 EXPECT_FALSE(site_url.has_host());
365 // Javascript URLs should include the scheme.
366 test_url = GURL("javascript:foo();");
367 site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
368 EXPECT_EQ(GURL("javascript:"), site_url);
369 EXPECT_EQ("javascript", site_url.scheme());
370 EXPECT_FALSE(site_url.has_host());
372 // Guest URLs are special and need to have the path in the site as well,
373 // since it affects the StoragePartition configuration.
374 std::string guest_url(kGuestScheme);
375 guest_url.append("://abc123/path");
376 test_url = GURL(guest_url);
377 site_url = SiteInstanceImpl::GetSiteForURL(NULL, test_url);
378 EXPECT_EQ(test_url, site_url);
380 DrainMessageLoops();
383 // Test of distinguishing URLs from different sites. Most of this logic is
384 // tested in RegistryControlledDomainTest. This test focuses on URLs with
385 // different schemes or ports.
386 TEST_F(SiteInstanceTest, IsSameWebSite) {
387 GURL url_foo = GURL("http://foo/a.html");
388 GURL url_foo2 = GURL("http://foo/b.html");
389 GURL url_foo_https = GURL("https://foo/a.html");
390 GURL url_foo_port = GURL("http://foo:8080/a.html");
391 GURL url_javascript = GURL("javascript:alert(1);");
392 GURL url_blank = GURL(url::kAboutBlankURL);
394 // Same scheme and port -> same site.
395 EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_foo, url_foo2));
397 // Different scheme -> different site.
398 EXPECT_FALSE(SiteInstance::IsSameWebSite(NULL, url_foo, url_foo_https));
400 // Different port -> same site.
401 // (Changes to document.domain make renderer ignore the port.)
402 EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_foo, url_foo_port));
404 // JavaScript links should be considered same site for anything.
405 EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_javascript, url_foo));
406 EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_javascript, url_foo_https));
407 EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_javascript, url_foo_port));
409 // Navigating to a blank page is considered the same site.
410 EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_foo, url_blank));
411 EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_foo_https, url_blank));
412 EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_foo_port, url_blank));
414 // Navigating from a blank site is not considered to be the same site.
415 EXPECT_FALSE(SiteInstance::IsSameWebSite(NULL, url_blank, url_foo));
416 EXPECT_FALSE(SiteInstance::IsSameWebSite(NULL, url_blank, url_foo_https));
417 EXPECT_FALSE(SiteInstance::IsSameWebSite(NULL, url_blank, url_foo_port));
419 DrainMessageLoops();
422 // Test to ensure that there is only one SiteInstance per site in a given
423 // BrowsingInstance, when process-per-site is not in use.
424 TEST_F(SiteInstanceTest, OneSiteInstancePerSite) {
425 ASSERT_FALSE(base::CommandLine::ForCurrentProcess()->HasSwitch(
426 switches::kProcessPerSite));
427 int delete_counter = 0;
428 scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
429 TestBrowsingInstance* browsing_instance =
430 new TestBrowsingInstance(browser_context.get(), &delete_counter);
432 const GURL url_a1("http://www.google.com/1.html");
433 scoped_refptr<SiteInstanceImpl> site_instance_a1(
434 static_cast<SiteInstanceImpl*>(
435 browsing_instance->GetSiteInstanceForURL(url_a1)));
436 EXPECT_TRUE(site_instance_a1.get() != NULL);
438 // A separate site should create a separate SiteInstance.
439 const GURL url_b1("http://www.yahoo.com/");
440 scoped_refptr<SiteInstanceImpl> site_instance_b1(
441 static_cast<SiteInstanceImpl*>(
442 browsing_instance->GetSiteInstanceForURL(url_b1)));
443 EXPECT_NE(site_instance_a1.get(), site_instance_b1.get());
444 EXPECT_TRUE(site_instance_a1->IsRelatedSiteInstance(site_instance_b1.get()));
446 // Getting the new SiteInstance from the BrowsingInstance and from another
447 // SiteInstance in the BrowsingInstance should give the same result.
448 EXPECT_EQ(site_instance_b1.get(),
449 site_instance_a1->GetRelatedSiteInstance(url_b1));
451 // A second visit to the original site should return the same SiteInstance.
452 const GURL url_a2("http://www.google.com/2.html");
453 EXPECT_EQ(site_instance_a1.get(),
454 browsing_instance->GetSiteInstanceForURL(url_a2));
455 EXPECT_EQ(site_instance_a1.get(),
456 site_instance_a1->GetRelatedSiteInstance(url_a2));
458 // A visit to the original site in a new BrowsingInstance (same or different
459 // browser context) should return a different SiteInstance.
460 TestBrowsingInstance* browsing_instance2 =
461 new TestBrowsingInstance(browser_context.get(), &delete_counter);
462 // Ensure the new SiteInstance is ref counted so that it gets deleted.
463 scoped_refptr<SiteInstanceImpl> site_instance_a2_2(
464 static_cast<SiteInstanceImpl*>(
465 browsing_instance2->GetSiteInstanceForURL(url_a2)));
466 EXPECT_NE(site_instance_a1.get(), site_instance_a2_2.get());
467 EXPECT_FALSE(
468 site_instance_a1->IsRelatedSiteInstance(site_instance_a2_2.get()));
470 // The two SiteInstances for http://google.com should not use the same process
471 // if process-per-site is not enabled.
472 scoped_ptr<RenderProcessHost> process_a1(site_instance_a1->GetProcess());
473 scoped_ptr<RenderProcessHost> process_a2_2(site_instance_a2_2->GetProcess());
474 EXPECT_NE(process_a1.get(), process_a2_2.get());
476 // Should be able to see that we do have SiteInstances.
477 EXPECT_TRUE(browsing_instance->HasSiteInstance(
478 GURL("http://mail.google.com")));
479 EXPECT_TRUE(browsing_instance2->HasSiteInstance(
480 GURL("http://mail.google.com")));
481 EXPECT_TRUE(browsing_instance->HasSiteInstance(
482 GURL("http://mail.yahoo.com")));
484 // Should be able to see that we don't have SiteInstances.
485 EXPECT_FALSE(browsing_instance->HasSiteInstance(
486 GURL("https://www.google.com")));
487 EXPECT_FALSE(browsing_instance2->HasSiteInstance(
488 GURL("http://www.yahoo.com")));
490 // browsing_instances will be deleted when their SiteInstances are deleted.
491 // The processes will be unregistered when the RPH scoped_ptrs go away.
493 DrainMessageLoops();
496 // Test to ensure that there is only one RenderProcessHost per site for an
497 // entire BrowserContext, if process-per-site is in use.
498 TEST_F(SiteInstanceTest, OneSiteInstancePerSiteInBrowserContext) {
499 base::CommandLine::ForCurrentProcess()->AppendSwitch(
500 switches::kProcessPerSite);
501 int delete_counter = 0;
502 scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
503 TestBrowsingInstance* browsing_instance =
504 new TestBrowsingInstance(browser_context.get(), &delete_counter);
506 const GURL url_a1("http://www.google.com/1.html");
507 scoped_refptr<SiteInstanceImpl> site_instance_a1(
508 static_cast<SiteInstanceImpl*>(
509 browsing_instance->GetSiteInstanceForURL(url_a1)));
510 EXPECT_TRUE(site_instance_a1.get() != NULL);
511 scoped_ptr<RenderProcessHost> process_a1(site_instance_a1->GetProcess());
513 // A separate site should create a separate SiteInstance.
514 const GURL url_b1("http://www.yahoo.com/");
515 scoped_refptr<SiteInstanceImpl> site_instance_b1(
516 static_cast<SiteInstanceImpl*>(
517 browsing_instance->GetSiteInstanceForURL(url_b1)));
518 EXPECT_NE(site_instance_a1.get(), site_instance_b1.get());
519 EXPECT_TRUE(site_instance_a1->IsRelatedSiteInstance(site_instance_b1.get()));
521 // Getting the new SiteInstance from the BrowsingInstance and from another
522 // SiteInstance in the BrowsingInstance should give the same result.
523 EXPECT_EQ(site_instance_b1.get(),
524 site_instance_a1->GetRelatedSiteInstance(url_b1));
526 // A second visit to the original site should return the same SiteInstance.
527 const GURL url_a2("http://www.google.com/2.html");
528 EXPECT_EQ(site_instance_a1.get(),
529 browsing_instance->GetSiteInstanceForURL(url_a2));
530 EXPECT_EQ(site_instance_a1.get(),
531 site_instance_a1->GetRelatedSiteInstance(url_a2));
533 // A visit to the original site in a new BrowsingInstance (same browser
534 // context) should return a different SiteInstance with the same process.
535 TestBrowsingInstance* browsing_instance2 =
536 new TestBrowsingInstance(browser_context.get(), &delete_counter);
537 scoped_refptr<SiteInstanceImpl> site_instance_a1_2(
538 static_cast<SiteInstanceImpl*>(
539 browsing_instance2->GetSiteInstanceForURL(url_a1)));
540 EXPECT_TRUE(site_instance_a1.get() != NULL);
541 EXPECT_NE(site_instance_a1.get(), site_instance_a1_2.get());
542 EXPECT_EQ(process_a1.get(), site_instance_a1_2->GetProcess());
544 // A visit to the original site in a new BrowsingInstance (different browser
545 // context) should return a different SiteInstance with a different process.
546 scoped_ptr<TestBrowserContext> browser_context2(new TestBrowserContext());
547 TestBrowsingInstance* browsing_instance3 =
548 new TestBrowsingInstance(browser_context2.get(), &delete_counter);
549 scoped_refptr<SiteInstanceImpl> site_instance_a2_3(
550 static_cast<SiteInstanceImpl*>(
551 browsing_instance3->GetSiteInstanceForURL(url_a2)));
552 EXPECT_TRUE(site_instance_a2_3.get() != NULL);
553 scoped_ptr<RenderProcessHost> process_a2_3(site_instance_a2_3->GetProcess());
554 EXPECT_NE(site_instance_a1.get(), site_instance_a2_3.get());
555 EXPECT_NE(process_a1.get(), process_a2_3.get());
557 // Should be able to see that we do have SiteInstances.
558 EXPECT_TRUE(browsing_instance->HasSiteInstance(
559 GURL("http://mail.google.com"))); // visited before
560 EXPECT_TRUE(browsing_instance2->HasSiteInstance(
561 GURL("http://mail.google.com"))); // visited before
562 EXPECT_TRUE(browsing_instance->HasSiteInstance(
563 GURL("http://mail.yahoo.com"))); // visited before
565 // Should be able to see that we don't have SiteInstances.
566 EXPECT_FALSE(browsing_instance2->HasSiteInstance(
567 GURL("http://www.yahoo.com"))); // different BI, same browser context
568 EXPECT_FALSE(browsing_instance->HasSiteInstance(
569 GURL("https://www.google.com"))); // not visited before
570 EXPECT_FALSE(browsing_instance3->HasSiteInstance(
571 GURL("http://www.yahoo.com"))); // different BI, different context
573 // browsing_instances will be deleted when their SiteInstances are deleted.
574 // The processes will be unregistered when the RPH scoped_ptrs go away.
576 DrainMessageLoops();
579 static SiteInstanceImpl* CreateSiteInstance(BrowserContext* browser_context,
580 const GURL& url) {
581 return static_cast<SiteInstanceImpl*>(
582 SiteInstance::CreateForURL(browser_context, url));
585 // Test to ensure that pages that require certain privileges are grouped
586 // in processes with similar pages.
587 TEST_F(SiteInstanceTest, ProcessSharingByType) {
588 // This test shouldn't run with --site-per-process or
589 // --enable-strict-site-isolation modes, since they don't allow render
590 // process reuse, which this test explicitly exercises.
591 const base::CommandLine& command_line =
592 *base::CommandLine::ForCurrentProcess();
593 if (command_line.HasSwitch(switches::kSitePerProcess) ||
594 command_line.HasSwitch(switches::kEnableStrictSiteIsolation))
595 return;
597 // On Android by default the number of renderer hosts is unlimited and process
598 // sharing doesn't happen. We set the override so that the test can run
599 // everywhere.
600 RenderProcessHost::SetMaxRendererProcessCount(kMaxRendererProcessCount);
602 ChildProcessSecurityPolicyImpl* policy =
603 ChildProcessSecurityPolicyImpl::GetInstance();
605 // Make a bunch of mock renderers so that we hit the limit.
606 scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
607 ScopedVector<MockRenderProcessHost> hosts;
608 for (size_t i = 0; i < kMaxRendererProcessCount; ++i)
609 hosts.push_back(new MockRenderProcessHost(browser_context.get()));
611 // Create some extension instances and make sure they share a process.
612 scoped_refptr<SiteInstanceImpl> extension1_instance(
613 CreateSiteInstance(browser_context.get(),
614 GURL(kPrivilegedScheme + std::string("://foo/bar"))));
615 set_privileged_process_id(extension1_instance->GetProcess()->GetID());
617 scoped_refptr<SiteInstanceImpl> extension2_instance(
618 CreateSiteInstance(browser_context.get(),
619 GURL(kPrivilegedScheme + std::string("://baz/bar"))));
621 scoped_ptr<RenderProcessHost> extension_host(
622 extension1_instance->GetProcess());
623 EXPECT_EQ(extension1_instance->GetProcess(),
624 extension2_instance->GetProcess());
626 // Create some WebUI instances and make sure they share a process.
627 scoped_refptr<SiteInstanceImpl> webui1_instance(CreateSiteInstance(
628 browser_context.get(), GURL(kChromeUIScheme + std::string("://newtab"))));
629 policy->GrantWebUIBindings(webui1_instance->GetProcess()->GetID());
631 scoped_refptr<SiteInstanceImpl> webui2_instance(
632 CreateSiteInstance(browser_context.get(),
633 GURL(kChromeUIScheme + std::string("://history"))));
635 scoped_ptr<RenderProcessHost> dom_host(webui1_instance->GetProcess());
636 EXPECT_EQ(webui1_instance->GetProcess(), webui2_instance->GetProcess());
638 // Make sure none of differing privilege processes are mixed.
639 EXPECT_NE(extension1_instance->GetProcess(), webui1_instance->GetProcess());
641 for (size_t i = 0; i < kMaxRendererProcessCount; ++i) {
642 EXPECT_NE(extension1_instance->GetProcess(), hosts[i]);
643 EXPECT_NE(webui1_instance->GetProcess(), hosts[i]);
646 DrainMessageLoops();
648 // Disable the process limit override.
649 RenderProcessHost::SetMaxRendererProcessCount(0u);
652 // Test to ensure that HasWrongProcessForURL behaves properly for different
653 // types of URLs.
654 TEST_F(SiteInstanceTest, HasWrongProcessForURL) {
655 scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
656 scoped_ptr<RenderProcessHost> host;
657 scoped_refptr<SiteInstanceImpl> instance(static_cast<SiteInstanceImpl*>(
658 SiteInstance::Create(browser_context.get())));
660 EXPECT_FALSE(instance->HasSite());
661 EXPECT_TRUE(instance->GetSiteURL().is_empty());
663 instance->SetSite(GURL("http://evernote.com/"));
664 EXPECT_TRUE(instance->HasSite());
666 // Check prior to "assigning" a process to the instance, which is expected
667 // to return false due to not being attached to any process yet.
668 EXPECT_FALSE(instance->HasWrongProcessForURL(GURL("http://google.com")));
670 // The call to GetProcess actually creates a new real process, which works
671 // fine, but might be a cause for problems in different contexts.
672 host.reset(instance->GetProcess());
673 EXPECT_TRUE(host.get() != NULL);
674 EXPECT_TRUE(instance->HasProcess());
676 EXPECT_FALSE(instance->HasWrongProcessForURL(GURL("http://evernote.com")));
677 EXPECT_FALSE(instance->HasWrongProcessForURL(
678 GURL("javascript:alert(document.location.href);")));
680 EXPECT_TRUE(instance->HasWrongProcessForURL(GURL("chrome://settings")));
682 // Test that WebUI SiteInstances reject normal web URLs.
683 const GURL webui_url("chrome://settings");
684 scoped_refptr<SiteInstanceImpl> webui_instance(static_cast<SiteInstanceImpl*>(
685 SiteInstance::Create(browser_context.get())));
686 webui_instance->SetSite(webui_url);
687 scoped_ptr<RenderProcessHost> webui_host(webui_instance->GetProcess());
689 // Simulate granting WebUI bindings for the process.
690 ChildProcessSecurityPolicyImpl::GetInstance()->GrantWebUIBindings(
691 webui_host->GetID());
693 EXPECT_TRUE(webui_instance->HasProcess());
694 EXPECT_FALSE(webui_instance->HasWrongProcessForURL(webui_url));
695 EXPECT_TRUE(webui_instance->HasWrongProcessForURL(GURL("http://google.com")));
697 // WebUI uses process-per-site, so another instance will use the same process
698 // even if we haven't called GetProcess yet. Make sure HasWrongProcessForURL
699 // doesn't crash (http://crbug.com/137070).
700 scoped_refptr<SiteInstanceImpl> webui_instance2(
701 static_cast<SiteInstanceImpl*>(
702 SiteInstance::Create(browser_context.get())));
703 webui_instance2->SetSite(webui_url);
704 EXPECT_FALSE(webui_instance2->HasWrongProcessForURL(webui_url));
705 EXPECT_TRUE(
706 webui_instance2->HasWrongProcessForURL(GURL("http://google.com")));
708 DrainMessageLoops();
711 // Test to ensure that HasWrongProcessForURL behaves properly even when
712 // --site-per-process is used (http://crbug.com/160671).
713 TEST_F(SiteInstanceTest, HasWrongProcessForURLInSitePerProcess) {
714 base::CommandLine::ForCurrentProcess()->AppendSwitch(
715 switches::kSitePerProcess);
717 scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
718 scoped_ptr<RenderProcessHost> host;
719 scoped_refptr<SiteInstanceImpl> instance(static_cast<SiteInstanceImpl*>(
720 SiteInstance::Create(browser_context.get())));
722 instance->SetSite(GURL("http://evernote.com/"));
723 EXPECT_TRUE(instance->HasSite());
725 // Check prior to "assigning" a process to the instance, which is expected
726 // to return false due to not being attached to any process yet.
727 EXPECT_FALSE(instance->HasWrongProcessForURL(GURL("http://google.com")));
729 // The call to GetProcess actually creates a new real process, which works
730 // fine, but might be a cause for problems in different contexts.
731 host.reset(instance->GetProcess());
732 EXPECT_TRUE(host.get() != NULL);
733 EXPECT_TRUE(instance->HasProcess());
735 EXPECT_FALSE(instance->HasWrongProcessForURL(GURL("http://evernote.com")));
736 EXPECT_FALSE(instance->HasWrongProcessForURL(
737 GURL("javascript:alert(document.location.href);")));
739 EXPECT_TRUE(instance->HasWrongProcessForURL(GURL("chrome://settings")));
741 DrainMessageLoops();
744 // Test that we do not reuse a process in process-per-site mode if it has the
745 // wrong bindings for its URL. http://crbug.com/174059.
746 TEST_F(SiteInstanceTest, ProcessPerSiteWithWrongBindings) {
747 scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
748 scoped_ptr<RenderProcessHost> host;
749 scoped_ptr<RenderProcessHost> host2;
750 scoped_refptr<SiteInstanceImpl> instance(static_cast<SiteInstanceImpl*>(
751 SiteInstance::Create(browser_context.get())));
753 EXPECT_FALSE(instance->HasSite());
754 EXPECT_TRUE(instance->GetSiteURL().is_empty());
756 // Simulate navigating to a WebUI URL in a process that does not have WebUI
757 // bindings. This already requires bypassing security checks.
758 const GURL webui_url("chrome://settings");
759 instance->SetSite(webui_url);
760 EXPECT_TRUE(instance->HasSite());
762 // The call to GetProcess actually creates a new real process.
763 host.reset(instance->GetProcess());
764 EXPECT_TRUE(host.get() != NULL);
765 EXPECT_TRUE(instance->HasProcess());
767 // Without bindings, this should look like the wrong process.
768 EXPECT_TRUE(instance->HasWrongProcessForURL(webui_url));
770 // WebUI uses process-per-site, so another instance would normally use the
771 // same process. Make sure it doesn't use the same process if the bindings
772 // are missing.
773 scoped_refptr<SiteInstanceImpl> instance2(
774 static_cast<SiteInstanceImpl*>(
775 SiteInstance::Create(browser_context.get())));
776 instance2->SetSite(webui_url);
777 host2.reset(instance2->GetProcess());
778 EXPECT_TRUE(host2.get() != NULL);
779 EXPECT_TRUE(instance2->HasProcess());
780 EXPECT_NE(host.get(), host2.get());
782 DrainMessageLoops();
785 // Test that we do not register processes with empty sites for process-per-site
786 // mode.
787 TEST_F(SiteInstanceTest, NoProcessPerSiteForEmptySite) {
788 base::CommandLine::ForCurrentProcess()->AppendSwitch(
789 switches::kProcessPerSite);
790 scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
791 scoped_ptr<RenderProcessHost> host;
792 scoped_refptr<SiteInstanceImpl> instance(static_cast<SiteInstanceImpl*>(
793 SiteInstance::Create(browser_context.get())));
795 instance->SetSite(GURL());
796 EXPECT_TRUE(instance->HasSite());
797 EXPECT_TRUE(instance->GetSiteURL().is_empty());
798 host.reset(instance->GetProcess());
800 EXPECT_FALSE(RenderProcessHostImpl::GetProcessHostForSite(
801 browser_context.get(), GURL()));
803 DrainMessageLoops();
806 } // namespace content