Home | History | Annotate | Download | only in browser
      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::AddStandardScheme(kPrivilegedScheme);
     96     url::AddStandardScheme(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(), ui::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(), ui::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(), ui::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   GURL url_blank = GURL(url::kAboutBlankURL);
    376 
    377   // Same scheme and port -> same site.
    378   EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_foo, url_foo2));
    379 
    380   // Different scheme -> different site.
    381   EXPECT_FALSE(SiteInstance::IsSameWebSite(NULL, url_foo, url_foo_https));
    382 
    383   // Different port -> same site.
    384   // (Changes to document.domain make renderer ignore the port.)
    385   EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_foo, url_foo_port));
    386 
    387   // JavaScript links should be considered same site for anything.
    388   EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_javascript, url_foo));
    389   EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_javascript, url_foo_https));
    390   EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_javascript, url_foo_port));
    391 
    392   // Navigating to a blank page is considered the same site.
    393   EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_foo, url_blank));
    394   EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_foo_https, url_blank));
    395   EXPECT_TRUE(SiteInstance::IsSameWebSite(NULL, url_foo_port, url_blank));
    396 
    397   // Navigating from a blank site is not considered to be the same site.
    398   EXPECT_FALSE(SiteInstance::IsSameWebSite(NULL, url_blank, url_foo));
    399   EXPECT_FALSE(SiteInstance::IsSameWebSite(NULL, url_blank, url_foo_https));
    400   EXPECT_FALSE(SiteInstance::IsSameWebSite(NULL, url_blank, url_foo_port));
    401 
    402   DrainMessageLoops();
    403 }
    404 
    405 // Test to ensure that there is only one SiteInstance per site in a given
    406 // BrowsingInstance, when process-per-site is not in use.
    407 TEST_F(SiteInstanceTest, OneSiteInstancePerSite) {
    408   ASSERT_FALSE(base::CommandLine::ForCurrentProcess()->HasSwitch(
    409       switches::kProcessPerSite));
    410   int delete_counter = 0;
    411   scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
    412   TestBrowsingInstance* browsing_instance =
    413       new TestBrowsingInstance(browser_context.get(), &delete_counter);
    414 
    415   const GURL url_a1("http://www.google.com/1.html");
    416   scoped_refptr<SiteInstanceImpl> site_instance_a1(
    417       static_cast<SiteInstanceImpl*>(
    418           browsing_instance->GetSiteInstanceForURL(url_a1)));
    419   EXPECT_TRUE(site_instance_a1.get() != NULL);
    420 
    421   // A separate site should create a separate SiteInstance.
    422   const GURL url_b1("http://www.yahoo.com/");
    423   scoped_refptr<SiteInstanceImpl> site_instance_b1(
    424       static_cast<SiteInstanceImpl*>(
    425           browsing_instance->GetSiteInstanceForURL(url_b1)));
    426   EXPECT_NE(site_instance_a1.get(), site_instance_b1.get());
    427   EXPECT_TRUE(site_instance_a1->IsRelatedSiteInstance(site_instance_b1.get()));
    428 
    429   // Getting the new SiteInstance from the BrowsingInstance and from another
    430   // SiteInstance in the BrowsingInstance should give the same result.
    431   EXPECT_EQ(site_instance_b1.get(),
    432             site_instance_a1->GetRelatedSiteInstance(url_b1));
    433 
    434   // A second visit to the original site should return the same SiteInstance.
    435   const GURL url_a2("http://www.google.com/2.html");
    436   EXPECT_EQ(site_instance_a1.get(),
    437             browsing_instance->GetSiteInstanceForURL(url_a2));
    438   EXPECT_EQ(site_instance_a1.get(),
    439             site_instance_a1->GetRelatedSiteInstance(url_a2));
    440 
    441   // A visit to the original site in a new BrowsingInstance (same or different
    442   // browser context) should return a different SiteInstance.
    443   TestBrowsingInstance* browsing_instance2 =
    444       new TestBrowsingInstance(browser_context.get(), &delete_counter);
    445   // Ensure the new SiteInstance is ref counted so that it gets deleted.
    446   scoped_refptr<SiteInstanceImpl> site_instance_a2_2(
    447       static_cast<SiteInstanceImpl*>(
    448           browsing_instance2->GetSiteInstanceForURL(url_a2)));
    449   EXPECT_NE(site_instance_a1.get(), site_instance_a2_2.get());
    450   EXPECT_FALSE(
    451       site_instance_a1->IsRelatedSiteInstance(site_instance_a2_2.get()));
    452 
    453   // The two SiteInstances for http://google.com should not use the same process
    454   // if process-per-site is not enabled.
    455   scoped_ptr<RenderProcessHost> process_a1(site_instance_a1->GetProcess());
    456   scoped_ptr<RenderProcessHost> process_a2_2(site_instance_a2_2->GetProcess());
    457   EXPECT_NE(process_a1.get(), process_a2_2.get());
    458 
    459   // Should be able to see that we do have SiteInstances.
    460   EXPECT_TRUE(browsing_instance->HasSiteInstance(
    461       GURL("http://mail.google.com")));
    462   EXPECT_TRUE(browsing_instance2->HasSiteInstance(
    463       GURL("http://mail.google.com")));
    464   EXPECT_TRUE(browsing_instance->HasSiteInstance(
    465       GURL("http://mail.yahoo.com")));
    466 
    467   // Should be able to see that we don't have SiteInstances.
    468   EXPECT_FALSE(browsing_instance->HasSiteInstance(
    469       GURL("https://www.google.com")));
    470   EXPECT_FALSE(browsing_instance2->HasSiteInstance(
    471       GURL("http://www.yahoo.com")));
    472 
    473   // browsing_instances will be deleted when their SiteInstances are deleted.
    474   // The processes will be unregistered when the RPH scoped_ptrs go away.
    475 
    476   DrainMessageLoops();
    477 }
    478 
    479 // Test to ensure that there is only one RenderProcessHost per site for an
    480 // entire BrowserContext, if process-per-site is in use.
    481 TEST_F(SiteInstanceTest, OneSiteInstancePerSiteInBrowserContext) {
    482   base::CommandLine::ForCurrentProcess()->AppendSwitch(
    483       switches::kProcessPerSite);
    484   int delete_counter = 0;
    485   scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
    486   TestBrowsingInstance* browsing_instance =
    487       new TestBrowsingInstance(browser_context.get(), &delete_counter);
    488 
    489   const GURL url_a1("http://www.google.com/1.html");
    490   scoped_refptr<SiteInstanceImpl> site_instance_a1(
    491       static_cast<SiteInstanceImpl*>(
    492           browsing_instance->GetSiteInstanceForURL(url_a1)));
    493   EXPECT_TRUE(site_instance_a1.get() != NULL);
    494   scoped_ptr<RenderProcessHost> process_a1(site_instance_a1->GetProcess());
    495 
    496   // A separate site should create a separate SiteInstance.
    497   const GURL url_b1("http://www.yahoo.com/");
    498   scoped_refptr<SiteInstanceImpl> site_instance_b1(
    499       static_cast<SiteInstanceImpl*>(
    500           browsing_instance->GetSiteInstanceForURL(url_b1)));
    501   EXPECT_NE(site_instance_a1.get(), site_instance_b1.get());
    502   EXPECT_TRUE(site_instance_a1->IsRelatedSiteInstance(site_instance_b1.get()));
    503 
    504   // Getting the new SiteInstance from the BrowsingInstance and from another
    505   // SiteInstance in the BrowsingInstance should give the same result.
    506   EXPECT_EQ(site_instance_b1.get(),
    507             site_instance_a1->GetRelatedSiteInstance(url_b1));
    508 
    509   // A second visit to the original site should return the same SiteInstance.
    510   const GURL url_a2("http://www.google.com/2.html");
    511   EXPECT_EQ(site_instance_a1.get(),
    512             browsing_instance->GetSiteInstanceForURL(url_a2));
    513   EXPECT_EQ(site_instance_a1.get(),
    514             site_instance_a1->GetRelatedSiteInstance(url_a2));
    515 
    516   // A visit to the original site in a new BrowsingInstance (same browser
    517   // context) should return a different SiteInstance with the same process.
    518   TestBrowsingInstance* browsing_instance2 =
    519       new TestBrowsingInstance(browser_context.get(), &delete_counter);
    520   scoped_refptr<SiteInstanceImpl> site_instance_a1_2(
    521       static_cast<SiteInstanceImpl*>(
    522           browsing_instance2->GetSiteInstanceForURL(url_a1)));
    523   EXPECT_TRUE(site_instance_a1.get() != NULL);
    524   EXPECT_NE(site_instance_a1.get(), site_instance_a1_2.get());
    525   EXPECT_EQ(process_a1.get(), site_instance_a1_2->GetProcess());
    526 
    527   // A visit to the original site in a new BrowsingInstance (different browser
    528   // context) should return a different SiteInstance with a different process.
    529   scoped_ptr<TestBrowserContext> browser_context2(new TestBrowserContext());
    530   TestBrowsingInstance* browsing_instance3 =
    531       new TestBrowsingInstance(browser_context2.get(), &delete_counter);
    532   scoped_refptr<SiteInstanceImpl> site_instance_a2_3(
    533       static_cast<SiteInstanceImpl*>(
    534           browsing_instance3->GetSiteInstanceForURL(url_a2)));
    535   EXPECT_TRUE(site_instance_a2_3.get() != NULL);
    536   scoped_ptr<RenderProcessHost> process_a2_3(site_instance_a2_3->GetProcess());
    537   EXPECT_NE(site_instance_a1.get(), site_instance_a2_3.get());
    538   EXPECT_NE(process_a1.get(), process_a2_3.get());
    539 
    540   // Should be able to see that we do have SiteInstances.
    541   EXPECT_TRUE(browsing_instance->HasSiteInstance(
    542       GURL("http://mail.google.com")));  // visited before
    543   EXPECT_TRUE(browsing_instance2->HasSiteInstance(
    544       GURL("http://mail.google.com")));  // visited before
    545   EXPECT_TRUE(browsing_instance->HasSiteInstance(
    546       GURL("http://mail.yahoo.com")));  // visited before
    547 
    548   // Should be able to see that we don't have SiteInstances.
    549   EXPECT_FALSE(browsing_instance2->HasSiteInstance(
    550       GURL("http://www.yahoo.com")));  // different BI, same browser context
    551   EXPECT_FALSE(browsing_instance->HasSiteInstance(
    552       GURL("https://www.google.com")));  // not visited before
    553   EXPECT_FALSE(browsing_instance3->HasSiteInstance(
    554       GURL("http://www.yahoo.com")));  // different BI, different context
    555 
    556   // browsing_instances will be deleted when their SiteInstances are deleted.
    557   // The processes will be unregistered when the RPH scoped_ptrs go away.
    558 
    559   DrainMessageLoops();
    560 }
    561 
    562 static SiteInstanceImpl* CreateSiteInstance(BrowserContext* browser_context,
    563                                             const GURL& url) {
    564   return static_cast<SiteInstanceImpl*>(
    565       SiteInstance::CreateForURL(browser_context, url));
    566 }
    567 
    568 // Test to ensure that pages that require certain privileges are grouped
    569 // in processes with similar pages.
    570 TEST_F(SiteInstanceTest, ProcessSharingByType) {
    571   // This test shouldn't run with --site-per-process or
    572   // --enable-strict-site-isolation modes, since they don't allow render
    573   // process reuse, which this test explicitly exercises.
    574   const base::CommandLine& command_line =
    575       *base::CommandLine::ForCurrentProcess();
    576   if (command_line.HasSwitch(switches::kSitePerProcess) ||
    577       command_line.HasSwitch(switches::kEnableStrictSiteIsolation))
    578     return;
    579 
    580   // On Android by default the number of renderer hosts is unlimited and process
    581   // sharing doesn't happen. We set the override so that the test can run
    582   // everywhere.
    583   RenderProcessHost::SetMaxRendererProcessCount(kMaxRendererProcessCount);
    584 
    585   ChildProcessSecurityPolicyImpl* policy =
    586       ChildProcessSecurityPolicyImpl::GetInstance();
    587 
    588   // Make a bunch of mock renderers so that we hit the limit.
    589   scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
    590   ScopedVector<MockRenderProcessHost> hosts;
    591   for (size_t i = 0; i < kMaxRendererProcessCount; ++i)
    592     hosts.push_back(new MockRenderProcessHost(browser_context.get()));
    593 
    594   // Create some extension instances and make sure they share a process.
    595   scoped_refptr<SiteInstanceImpl> extension1_instance(
    596       CreateSiteInstance(browser_context.get(),
    597           GURL(kPrivilegedScheme + std::string("://foo/bar"))));
    598   set_privileged_process_id(extension1_instance->GetProcess()->GetID());
    599 
    600   scoped_refptr<SiteInstanceImpl> extension2_instance(
    601       CreateSiteInstance(browser_context.get(),
    602           GURL(kPrivilegedScheme + std::string("://baz/bar"))));
    603 
    604   scoped_ptr<RenderProcessHost> extension_host(
    605       extension1_instance->GetProcess());
    606   EXPECT_EQ(extension1_instance->GetProcess(),
    607             extension2_instance->GetProcess());
    608 
    609   // Create some WebUI instances and make sure they share a process.
    610   scoped_refptr<SiteInstanceImpl> webui1_instance(CreateSiteInstance(
    611       browser_context.get(), GURL(kChromeUIScheme + std::string("://newtab"))));
    612   policy->GrantWebUIBindings(webui1_instance->GetProcess()->GetID());
    613 
    614   scoped_refptr<SiteInstanceImpl> webui2_instance(
    615       CreateSiteInstance(browser_context.get(),
    616                          GURL(kChromeUIScheme + std::string("://history"))));
    617 
    618   scoped_ptr<RenderProcessHost> dom_host(webui1_instance->GetProcess());
    619   EXPECT_EQ(webui1_instance->GetProcess(), webui2_instance->GetProcess());
    620 
    621   // Make sure none of differing privilege processes are mixed.
    622   EXPECT_NE(extension1_instance->GetProcess(), webui1_instance->GetProcess());
    623 
    624   for (size_t i = 0; i < kMaxRendererProcessCount; ++i) {
    625     EXPECT_NE(extension1_instance->GetProcess(), hosts[i]);
    626     EXPECT_NE(webui1_instance->GetProcess(), hosts[i]);
    627   }
    628 
    629   DrainMessageLoops();
    630 
    631   // Disable the process limit override.
    632   RenderProcessHost::SetMaxRendererProcessCount(0u);
    633 }
    634 
    635 // Test to ensure that HasWrongProcessForURL behaves properly for different
    636 // types of URLs.
    637 TEST_F(SiteInstanceTest, HasWrongProcessForURL) {
    638   scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
    639   scoped_ptr<RenderProcessHost> host;
    640   scoped_refptr<SiteInstanceImpl> instance(static_cast<SiteInstanceImpl*>(
    641       SiteInstance::Create(browser_context.get())));
    642 
    643   EXPECT_FALSE(instance->HasSite());
    644   EXPECT_TRUE(instance->GetSiteURL().is_empty());
    645 
    646   instance->SetSite(GURL("http://evernote.com/"));
    647   EXPECT_TRUE(instance->HasSite());
    648 
    649   // Check prior to "assigning" a process to the instance, which is expected
    650   // to return false due to not being attached to any process yet.
    651   EXPECT_FALSE(instance->HasWrongProcessForURL(GURL("http://google.com")));
    652 
    653   // The call to GetProcess actually creates a new real process, which works
    654   // fine, but might be a cause for problems in different contexts.
    655   host.reset(instance->GetProcess());
    656   EXPECT_TRUE(host.get() != NULL);
    657   EXPECT_TRUE(instance->HasProcess());
    658 
    659   EXPECT_FALSE(instance->HasWrongProcessForURL(GURL("http://evernote.com")));
    660   EXPECT_FALSE(instance->HasWrongProcessForURL(
    661       GURL("javascript:alert(document.location.href);")));
    662 
    663   EXPECT_TRUE(instance->HasWrongProcessForURL(GURL("chrome://settings")));
    664 
    665   // Test that WebUI SiteInstances reject normal web URLs.
    666   const GURL webui_url("chrome://settings");
    667   scoped_refptr<SiteInstanceImpl> webui_instance(static_cast<SiteInstanceImpl*>(
    668       SiteInstance::Create(browser_context.get())));
    669   webui_instance->SetSite(webui_url);
    670   scoped_ptr<RenderProcessHost> webui_host(webui_instance->GetProcess());
    671 
    672   // Simulate granting WebUI bindings for the process.
    673   ChildProcessSecurityPolicyImpl::GetInstance()->GrantWebUIBindings(
    674       webui_host->GetID());
    675 
    676   EXPECT_TRUE(webui_instance->HasProcess());
    677   EXPECT_FALSE(webui_instance->HasWrongProcessForURL(webui_url));
    678   EXPECT_TRUE(webui_instance->HasWrongProcessForURL(GURL("http://google.com")));
    679 
    680   // WebUI uses process-per-site, so another instance will use the same process
    681   // even if we haven't called GetProcess yet.  Make sure HasWrongProcessForURL
    682   // doesn't crash (http://crbug.com/137070).
    683   scoped_refptr<SiteInstanceImpl> webui_instance2(
    684       static_cast<SiteInstanceImpl*>(
    685           SiteInstance::Create(browser_context.get())));
    686   webui_instance2->SetSite(webui_url);
    687   EXPECT_FALSE(webui_instance2->HasWrongProcessForURL(webui_url));
    688   EXPECT_TRUE(
    689       webui_instance2->HasWrongProcessForURL(GURL("http://google.com")));
    690 
    691   DrainMessageLoops();
    692 }
    693 
    694 // Test to ensure that HasWrongProcessForURL behaves properly even when
    695 // --site-per-process is used (http://crbug.com/160671).
    696 TEST_F(SiteInstanceTest, HasWrongProcessForURLInSitePerProcess) {
    697   base::CommandLine::ForCurrentProcess()->AppendSwitch(
    698       switches::kSitePerProcess);
    699 
    700   scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
    701   scoped_ptr<RenderProcessHost> host;
    702   scoped_refptr<SiteInstanceImpl> instance(static_cast<SiteInstanceImpl*>(
    703       SiteInstance::Create(browser_context.get())));
    704 
    705   instance->SetSite(GURL("http://evernote.com/"));
    706   EXPECT_TRUE(instance->HasSite());
    707 
    708   // Check prior to "assigning" a process to the instance, which is expected
    709   // to return false due to not being attached to any process yet.
    710   EXPECT_FALSE(instance->HasWrongProcessForURL(GURL("http://google.com")));
    711 
    712   // The call to GetProcess actually creates a new real process, which works
    713   // fine, but might be a cause for problems in different contexts.
    714   host.reset(instance->GetProcess());
    715   EXPECT_TRUE(host.get() != NULL);
    716   EXPECT_TRUE(instance->HasProcess());
    717 
    718   EXPECT_FALSE(instance->HasWrongProcessForURL(GURL("http://evernote.com")));
    719   EXPECT_FALSE(instance->HasWrongProcessForURL(
    720       GURL("javascript:alert(document.location.href);")));
    721 
    722   EXPECT_TRUE(instance->HasWrongProcessForURL(GURL("chrome://settings")));
    723 
    724   DrainMessageLoops();
    725 }
    726 
    727 // Test that we do not reuse a process in process-per-site mode if it has the
    728 // wrong bindings for its URL.  http://crbug.com/174059.
    729 TEST_F(SiteInstanceTest, ProcessPerSiteWithWrongBindings) {
    730   scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
    731   scoped_ptr<RenderProcessHost> host;
    732   scoped_ptr<RenderProcessHost> host2;
    733   scoped_refptr<SiteInstanceImpl> instance(static_cast<SiteInstanceImpl*>(
    734       SiteInstance::Create(browser_context.get())));
    735 
    736   EXPECT_FALSE(instance->HasSite());
    737   EXPECT_TRUE(instance->GetSiteURL().is_empty());
    738 
    739   // Simulate navigating to a WebUI URL in a process that does not have WebUI
    740   // bindings.  This already requires bypassing security checks.
    741   const GURL webui_url("chrome://settings");
    742   instance->SetSite(webui_url);
    743   EXPECT_TRUE(instance->HasSite());
    744 
    745   // The call to GetProcess actually creates a new real process.
    746   host.reset(instance->GetProcess());
    747   EXPECT_TRUE(host.get() != NULL);
    748   EXPECT_TRUE(instance->HasProcess());
    749 
    750   // Without bindings, this should look like the wrong process.
    751   EXPECT_TRUE(instance->HasWrongProcessForURL(webui_url));
    752 
    753   // WebUI uses process-per-site, so another instance would normally use the
    754   // same process.  Make sure it doesn't use the same process if the bindings
    755   // are missing.
    756   scoped_refptr<SiteInstanceImpl> instance2(
    757       static_cast<SiteInstanceImpl*>(
    758           SiteInstance::Create(browser_context.get())));
    759   instance2->SetSite(webui_url);
    760   host2.reset(instance2->GetProcess());
    761   EXPECT_TRUE(host2.get() != NULL);
    762   EXPECT_TRUE(instance2->HasProcess());
    763   EXPECT_NE(host.get(), host2.get());
    764 
    765   DrainMessageLoops();
    766 }
    767 
    768 // Test that we do not register processes with empty sites for process-per-site
    769 // mode.
    770 TEST_F(SiteInstanceTest, NoProcessPerSiteForEmptySite) {
    771   base::CommandLine::ForCurrentProcess()->AppendSwitch(
    772       switches::kProcessPerSite);
    773   scoped_ptr<TestBrowserContext> browser_context(new TestBrowserContext());
    774   scoped_ptr<RenderProcessHost> host;
    775   scoped_refptr<SiteInstanceImpl> instance(static_cast<SiteInstanceImpl*>(
    776       SiteInstance::Create(browser_context.get())));
    777 
    778   instance->SetSite(GURL());
    779   EXPECT_TRUE(instance->HasSite());
    780   EXPECT_TRUE(instance->GetSiteURL().is_empty());
    781   host.reset(instance->GetProcess());
    782 
    783   EXPECT_FALSE(RenderProcessHostImpl::GetProcessHostForSite(
    784       browser_context.get(), GURL()));
    785 
    786   DrainMessageLoops();
    787 }
    788 
    789 }  // namespace content
    790