blob: f96e3b2a6d7671d4e1e5d0d85e0a74fcf432a6c6 [file] [log] [blame]
[email protected]80a8fad2011-01-29 04:02:381// Copyright (c) 2011 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]1d8a3d1f2011-02-19 07:11:525#include "content/browser/site_instance.h"
initial.commit09911bf2008-07-26 23:55:296
[email protected]39365212011-02-24 01:01:007#include "content/browser/browsing_instance.h"
[email protected]1fd1a502011-03-30 16:55:568#include "content/browser/content_browser_client.h"
[email protected]05fcf982011-04-19 00:44:149#include "content/browser/renderer_host/browser_render_process_host.h"
[email protected]67fc0392011-02-25 02:56:5710#include "content/browser/webui/web_ui_factory.h"
[email protected]1fd1a502011-03-30 16:55:5611#include "content/common/content_client.h"
[email protected]0f012df82011-05-19 14:15:2912#include "content/common/notification_service.h"
13#include "content/common/url_constants.h"
initial.commit09911bf2008-07-26 23:55:2914#include "net/base/registry_controlled_domain.h"
15
[email protected]2ee0418e2009-06-26 21:00:4316static bool IsURLSameAsAnySiteInstance(const GURL& url) {
17 if (!url.is_valid())
18 return false;
[email protected]0f012df82011-05-19 14:15:2919
20 // We treat javascript: and about:crash as the same site as any URL since they
21 // are actually modifiers on existing pages.
22 if (url.SchemeIs(chrome::kJavaScriptScheme) ||
23 url.spec() == chrome::kAboutCrashURL) {
24 return true;
25 }
26
27 return
28 content::GetContentClient()->browser()->IsURLSameAsAnySiteInstance(url);
[email protected]2ee0418e2009-06-26 21:00:4329}
30
[email protected]992db4c2011-05-12 15:37:1531int32 SiteInstance::next_site_instance_id_ = 1;
32
[email protected]4566f132009-03-12 01:55:1333SiteInstance::SiteInstance(BrowsingInstance* browsing_instance)
[email protected]992db4c2011-05-12 15:37:1534 : id_(next_site_instance_id_++),
35 browsing_instance_(browsing_instance),
[email protected]4566f132009-03-12 01:55:1336 render_process_host_factory_(NULL),
37 process_(NULL),
38 max_page_id_(-1),
39 has_site_(false) {
40 DCHECK(browsing_instance);
41
[email protected]5be94df2009-05-22 18:41:3242 registrar_.Add(this, NotificationType::RENDERER_PROCESS_TERMINATED,
43 NotificationService::AllSources());
[email protected]4566f132009-03-12 01:55:1344}
45
initial.commit09911bf2008-07-26 23:55:2946SiteInstance::~SiteInstance() {
47 // Now that no one is referencing us, we can safely remove ourselves from
48 // the BrowsingInstance. Any future visits to a page from this site
49 // (within the same BrowsingInstance) can safely create a new SiteInstance.
50 if (has_site_)
51 browsing_instance_->UnregisterSiteInstance(this);
52}
53
[email protected]5ab79b02010-04-26 16:47:1154bool SiteInstance::HasProcess() const {
55 return (process_ != NULL);
56}
57
initial.commit09911bf2008-07-26 23:55:2958RenderProcessHost* SiteInstance::GetProcess() {
[email protected]08c8ec7e2010-07-11 17:14:4859 // TODO(erikkay) It would be nice to ensure that the renderer type had been
60 // properly set before we get here. The default tab creation case winds up
61 // with no site set at this point, so it will default to TYPE_NORMAL. This
62 // may not be correct, so we'll wind up potentially creating a process that
63 // we then throw away, or worse sharing a process with the wrong process type.
64 // See crbug.com/43448.
65
initial.commit09911bf2008-07-26 23:55:2966 // Create a new process if ours went away or was reused.
[email protected]4566f132009-03-12 01:55:1367 if (!process_) {
initial.commit09911bf2008-07-26 23:55:2968 // See if we should reuse an old process
69 if (RenderProcessHost::ShouldTryToUseExistingProcessHost())
[email protected]4566f132009-03-12 01:55:1370 process_ = RenderProcessHost::GetExistingProcessHost(
[email protected]1dfa9502009-06-15 20:28:0971 browsing_instance_->profile(), GetRendererType());
initial.commit09911bf2008-07-26 23:55:2972
73 // Otherwise (or if that fails), create a new one.
[email protected]4566f132009-03-12 01:55:1374 if (!process_) {
[email protected]a6df5112009-01-21 23:50:1575 if (render_process_host_factory_) {
[email protected]4566f132009-03-12 01:55:1376 process_ = render_process_host_factory_->CreateRenderProcessHost(
[email protected]a6df5112009-01-21 23:50:1577 browsing_instance_->profile());
78 } else {
[email protected]4566f132009-03-12 01:55:1379 process_ = new BrowserRenderProcessHost(browsing_instance_->profile());
[email protected]a6df5112009-01-21 23:50:1580 }
81 }
initial.commit09911bf2008-07-26 23:55:2982
initial.commit09911bf2008-07-26 23:55:2983 // Make sure the process starts at the right max_page_id
[email protected]4566f132009-03-12 01:55:1384 process_->UpdateMaxPageID(max_page_id_);
initial.commit09911bf2008-07-26 23:55:2985 }
[email protected]4566f132009-03-12 01:55:1386 DCHECK(process_);
initial.commit09911bf2008-07-26 23:55:2987
[email protected]4566f132009-03-12 01:55:1388 return process_;
initial.commit09911bf2008-07-26 23:55:2989}
90
91void SiteInstance::SetSite(const GURL& url) {
92 // A SiteInstance's site should not change.
93 // TODO(creis): When following links or script navigations, we can currently
94 // render pages from other sites in this SiteInstance. This will eventually
95 // be fixed, but until then, we should still not set the site of a
96 // SiteInstance more than once.
97 DCHECK(!has_site_);
98
99 // Remember that this SiteInstance has been used to load a URL, even if the
100 // URL is invalid.
101 has_site_ = true;
[email protected]3a8eecb2010-04-22 23:56:30102 site_ = GetSiteForURL(browsing_instance_->profile(), url);
initial.commit09911bf2008-07-26 23:55:29103
104 // Now that we have a site, register it with the BrowsingInstance. This
105 // ensures that we won't create another SiteInstance for this site within
106 // the same BrowsingInstance, because all same-site pages within a
107 // BrowsingInstance can script each other.
108 browsing_instance_->RegisterSiteInstance(this);
109}
110
111bool SiteInstance::HasRelatedSiteInstance(const GURL& url) {
112 return browsing_instance_->HasSiteInstance(url);
113}
114
115SiteInstance* SiteInstance::GetRelatedSiteInstance(const GURL& url) {
116 return browsing_instance_->GetSiteInstanceForURL(url);
117}
118
119/*static*/
120SiteInstance* SiteInstance::CreateSiteInstance(Profile* profile) {
121 return new SiteInstance(new BrowsingInstance(profile));
122}
123
124/*static*/
[email protected]d8a96622009-05-07 19:21:16125SiteInstance* SiteInstance::CreateSiteInstanceForURL(Profile* profile,
126 const GURL& url) {
[email protected]633fbc42009-05-07 23:39:47127 // This BrowsingInstance may be deleted if it returns an existing
128 // SiteInstance.
129 scoped_refptr<BrowsingInstance> instance(new BrowsingInstance(profile));
130 return instance->GetSiteInstanceForURL(url);
[email protected]d8a96622009-05-07 19:21:16131}
132
133/*static*/
[email protected]3a8eecb2010-04-22 23:56:30134GURL SiteInstance::GetSiteForURL(Profile* profile, const GURL& real_url) {
135 GURL url = GetEffectiveURL(profile, real_url);
136
initial.commit09911bf2008-07-26 23:55:29137 // URLs with no host should have an empty site.
138 GURL site;
139
140 // TODO(creis): For many protocols, we should just treat the scheme as the
[email protected]76a010b2008-12-07 23:48:03141 // site, since there is no host. e.g., file:, about:, chrome:
initial.commit09911bf2008-07-26 23:55:29142
143 // If the url has a host, then determine the site.
144 if (url.has_host()) {
[email protected]6705b232008-11-26 00:16:51145 // Only keep the scheme and registered domain as given by GetOrigin. This
146 // may also include a port, which we need to drop.
initial.commit09911bf2008-07-26 23:55:29147 site = url.GetOrigin();
148
[email protected]6705b232008-11-26 00:16:51149 // Remove port, if any.
150 if (site.has_port()) {
151 GURL::Replacements rep;
152 rep.ClearPort();
153 site = site.ReplaceComponents(rep);
154 }
155
initial.commit09911bf2008-07-26 23:55:29156 // If this URL has a registered domain, we only want to remember that part.
157 std::string domain =
[email protected]8ac1a752008-07-31 19:40:37158 net::RegistryControlledDomainService::GetDomainAndRegistry(url);
initial.commit09911bf2008-07-26 23:55:29159 if (!domain.empty()) {
160 GURL::Replacements rep;
161 rep.SetHostStr(domain);
162 site = site.ReplaceComponents(rep);
163 }
164 }
165 return site;
166}
167
168/*static*/
[email protected]3a8eecb2010-04-22 23:56:30169bool SiteInstance::IsSameWebSite(Profile* profile,
170 const GURL& real_url1, const GURL& real_url2) {
171 GURL url1 = GetEffectiveURL(profile, real_url1);
172 GURL url2 = GetEffectiveURL(profile, real_url2);
173
initial.commit09911bf2008-07-26 23:55:29174 // We infer web site boundaries based on the registered domain name of the
[email protected]6705b232008-11-26 00:16:51175 // top-level page and the scheme. We do not pay attention to the port if
176 // one is present, because pages served from different ports can still
177 // access each other if they change their document.domain variable.
initial.commit09911bf2008-07-26 23:55:29178
[email protected]2ee0418e2009-06-26 21:00:43179 // Some special URLs will match the site instance of any other URL. This is
180 // done before checking both of them for validity, since we want these URLs
181 // to have the same site instance as even an invalid one.
182 if (IsURLSameAsAnySiteInstance(url1) || IsURLSameAsAnySiteInstance(url2))
initial.commit09911bf2008-07-26 23:55:29183 return true;
184
185 // If either URL is invalid, they aren't part of the same site.
[email protected]2ee0418e2009-06-26 21:00:43186 if (!url1.is_valid() || !url2.is_valid())
initial.commit09911bf2008-07-26 23:55:29187 return false;
initial.commit09911bf2008-07-26 23:55:29188
[email protected]6705b232008-11-26 00:16:51189 // If the schemes differ, they aren't part of the same site.
[email protected]2ee0418e2009-06-26 21:00:43190 if (url1.scheme() != url2.scheme())
initial.commit09911bf2008-07-26 23:55:29191 return false;
initial.commit09911bf2008-07-26 23:55:29192
[email protected]8ac1a752008-07-31 19:40:37193 return net::RegistryControlledDomainService::SameDomainOrHost(url1, url2);
initial.commit09911bf2008-07-26 23:55:29194}
[email protected]4566f132009-03-12 01:55:13195
[email protected]3a8eecb2010-04-22 23:56:30196/*static*/
197GURL SiteInstance::GetEffectiveURL(Profile* profile, const GURL& url) {
[email protected]36fb2c7c2011-04-04 15:49:08198 return content::GetContentClient()->browser()->GetEffectiveURL(profile, url);
[email protected]3a8eecb2010-04-22 23:56:30199}
200
[email protected]08c8ec7e2010-07-11 17:14:48201/*static*/
202RenderProcessHost::Type SiteInstance::RendererTypeForURL(const GURL& url) {
203 if (!url.is_valid())
[email protected]1dfa9502009-06-15 20:28:09204 return RenderProcessHost::TYPE_NORMAL;
205
[email protected]08c8ec7e2010-07-11 17:14:48206 if (url.SchemeIs(chrome::kExtensionScheme))
[email protected]1dfa9502009-06-15 20:28:09207 return RenderProcessHost::TYPE_EXTENSION;
208
[email protected]80a8fad2011-01-29 04:02:38209 // TODO(erikkay) creis recommends using UseWebUIForURL instead.
[email protected]1fd1a502011-03-30 16:55:56210 if (content::WebUIFactory::Get()->HasWebUIScheme(url))
[email protected]d0980792011-02-13 19:41:40211 return RenderProcessHost::TYPE_WEBUI;
[email protected]1dfa9502009-06-15 20:28:09212
213 return RenderProcessHost::TYPE_NORMAL;
214}
215
[email protected]08c8ec7e2010-07-11 17:14:48216RenderProcessHost::Type SiteInstance::GetRendererType() {
217 // We may not have a site at this point, which generally means this is a
218 // normal navigation.
219 if (!has_site_)
220 return RenderProcessHost::TYPE_NORMAL;
221
222 return RendererTypeForURL(site_);
223}
224
[email protected]4566f132009-03-12 01:55:13225void SiteInstance::Observe(NotificationType type,
226 const NotificationSource& source,
227 const NotificationDetails& details) {
228 DCHECK(type == NotificationType::RENDERER_PROCESS_TERMINATED);
229 RenderProcessHost* rph = Source<RenderProcessHost>(source).ptr();
230 if (rph == process_)
231 process_ = NULL;
232}