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_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