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