blob: 26565a1f47d04200151daf1974b320f613764d0d [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]eaa7dd182010-12-14 11:09:007#include "chrome/browser/extensions/extension_service.h"
[email protected]1d8a3d1f2011-02-19 07:11:528#include "chrome/browser/renderer_host/browser_render_process_host.h"
[email protected]7e3abea42011-02-18 00:51:109#include "chrome/common/url_constants.h"
[email protected]39365212011-02-24 01:01:0010#include "content/browser/browsing_instance.h"
[email protected]1fd1a502011-03-30 16:55:5611#include "content/browser/content_browser_client.h"
[email protected]67fc0392011-02-25 02:56:5712#include "content/browser/webui/web_ui_factory.h"
[email protected]7f070d42011-03-09 20:25:3213#include "content/common/notification_service.h"
[email protected]1fd1a502011-03-30 16:55:5614#include "content/common/content_client.h"
initial.commit09911bf2008-07-26 23:55:2915#include "net/base/registry_controlled_domain.h"
16
[email protected]2ee0418e2009-06-26 21:00:4317// We treat javascript:, about:crash, about:hang, and about:shorthang as the
18// same site as any URL since they are actually modifiers on existing pages.
19static bool IsURLSameAsAnySiteInstance(const GURL& url) {
20 if (!url.is_valid())
21 return false;
22 return url.SchemeIs(chrome::kJavaScriptScheme) ||
23 url.spec() == chrome::kAboutCrashURL ||
[email protected]a8f024392011-01-13 21:50:1624 url.spec() == chrome::kAboutKillURL ||
[email protected]2ee0418e2009-06-26 21:00:4325 url.spec() == chrome::kAboutHangURL ||
26 url.spec() == chrome::kAboutShorthangURL;
27}
28
[email protected]4566f132009-03-12 01:55:1329SiteInstance::SiteInstance(BrowsingInstance* browsing_instance)
30 : browsing_instance_(browsing_instance),
31 render_process_host_factory_(NULL),
32 process_(NULL),
33 max_page_id_(-1),
34 has_site_(false) {
35 DCHECK(browsing_instance);
36
[email protected]5be94df2009-05-22 18:41:3237 registrar_.Add(this, NotificationType::RENDERER_PROCESS_TERMINATED,
38 NotificationService::AllSources());
[email protected]4566f132009-03-12 01:55:1339}
40
initial.commit09911bf2008-07-26 23:55:2941SiteInstance::~SiteInstance() {
42 // Now that no one is referencing us, we can safely remove ourselves from
43 // the BrowsingInstance. Any future visits to a page from this site
44 // (within the same BrowsingInstance) can safely create a new SiteInstance.
45 if (has_site_)
46 browsing_instance_->UnregisterSiteInstance(this);
47}
48
[email protected]5ab79b02010-04-26 16:47:1149bool SiteInstance::HasProcess() const {
50 return (process_ != NULL);
51}
52
initial.commit09911bf2008-07-26 23:55:2953RenderProcessHost* SiteInstance::GetProcess() {
[email protected]08c8ec7e2010-07-11 17:14:4854 // TODO(erikkay) It would be nice to ensure that the renderer type had been
55 // properly set before we get here. The default tab creation case winds up
56 // with no site set at this point, so it will default to TYPE_NORMAL. This
57 // may not be correct, so we'll wind up potentially creating a process that
58 // we then throw away, or worse sharing a process with the wrong process type.
59 // See crbug.com/43448.
60
initial.commit09911bf2008-07-26 23:55:2961 // Create a new process if ours went away or was reused.
[email protected]4566f132009-03-12 01:55:1362 if (!process_) {
initial.commit09911bf2008-07-26 23:55:2963 // See if we should reuse an old process
64 if (RenderProcessHost::ShouldTryToUseExistingProcessHost())
[email protected]4566f132009-03-12 01:55:1365 process_ = RenderProcessHost::GetExistingProcessHost(
[email protected]1dfa9502009-06-15 20:28:0966 browsing_instance_->profile(), GetRendererType());
initial.commit09911bf2008-07-26 23:55:2967
68 // Otherwise (or if that fails), create a new one.
[email protected]4566f132009-03-12 01:55:1369 if (!process_) {
[email protected]a6df5112009-01-21 23:50:1570 if (render_process_host_factory_) {
[email protected]4566f132009-03-12 01:55:1371 process_ = render_process_host_factory_->CreateRenderProcessHost(
[email protected]a6df5112009-01-21 23:50:1572 browsing_instance_->profile());
73 } else {
[email protected]4566f132009-03-12 01:55:1374 process_ = new BrowserRenderProcessHost(browsing_instance_->profile());
[email protected]a6df5112009-01-21 23:50:1575 }
76 }
initial.commit09911bf2008-07-26 23:55:2977
initial.commit09911bf2008-07-26 23:55:2978 // Make sure the process starts at the right max_page_id
[email protected]4566f132009-03-12 01:55:1379 process_->UpdateMaxPageID(max_page_id_);
initial.commit09911bf2008-07-26 23:55:2980 }
[email protected]4566f132009-03-12 01:55:1381 DCHECK(process_);
initial.commit09911bf2008-07-26 23:55:2982
[email protected]4566f132009-03-12 01:55:1383 return process_;
initial.commit09911bf2008-07-26 23:55:2984}
85
86void SiteInstance::SetSite(const GURL& url) {
87 // A SiteInstance's site should not change.
88 // TODO(creis): When following links or script navigations, we can currently
89 // render pages from other sites in this SiteInstance. This will eventually
90 // be fixed, but until then, we should still not set the site of a
91 // SiteInstance more than once.
92 DCHECK(!has_site_);
93
94 // Remember that this SiteInstance has been used to load a URL, even if the
95 // URL is invalid.
96 has_site_ = true;
[email protected]3a8eecb2010-04-22 23:56:3097 site_ = GetSiteForURL(browsing_instance_->profile(), url);
initial.commit09911bf2008-07-26 23:55:2998
99 // Now that we have a site, register it with the BrowsingInstance. This
100 // ensures that we won't create another SiteInstance for this site within
101 // the same BrowsingInstance, because all same-site pages within a
102 // BrowsingInstance can script each other.
103 browsing_instance_->RegisterSiteInstance(this);
104}
105
106bool SiteInstance::HasRelatedSiteInstance(const GURL& url) {
107 return browsing_instance_->HasSiteInstance(url);
108}
109
110SiteInstance* SiteInstance::GetRelatedSiteInstance(const GURL& url) {
111 return browsing_instance_->GetSiteInstanceForURL(url);
112}
113
114/*static*/
115SiteInstance* SiteInstance::CreateSiteInstance(Profile* profile) {
116 return new SiteInstance(new BrowsingInstance(profile));
117}
118
119/*static*/
[email protected]d8a96622009-05-07 19:21:16120SiteInstance* SiteInstance::CreateSiteInstanceForURL(Profile* profile,
121 const GURL& url) {
[email protected]633fbc42009-05-07 23:39:47122 // This BrowsingInstance may be deleted if it returns an existing
123 // SiteInstance.
124 scoped_refptr<BrowsingInstance> instance(new BrowsingInstance(profile));
125 return instance->GetSiteInstanceForURL(url);
[email protected]d8a96622009-05-07 19:21:16126}
127
128/*static*/
[email protected]3a8eecb2010-04-22 23:56:30129GURL SiteInstance::GetSiteForURL(Profile* profile, const GURL& real_url) {
130 GURL url = GetEffectiveURL(profile, real_url);
131
initial.commit09911bf2008-07-26 23:55:29132 // URLs with no host should have an empty site.
133 GURL site;
134
135 // TODO(creis): For many protocols, we should just treat the scheme as the
[email protected]76a010b2008-12-07 23:48:03136 // site, since there is no host. e.g., file:, about:, chrome:
initial.commit09911bf2008-07-26 23:55:29137
138 // If the url has a host, then determine the site.
139 if (url.has_host()) {
[email protected]6705b232008-11-26 00:16:51140 // Only keep the scheme and registered domain as given by GetOrigin. This
141 // may also include a port, which we need to drop.
initial.commit09911bf2008-07-26 23:55:29142 site = url.GetOrigin();
143
[email protected]6705b232008-11-26 00:16:51144 // Remove port, if any.
145 if (site.has_port()) {
146 GURL::Replacements rep;
147 rep.ClearPort();
148 site = site.ReplaceComponents(rep);
149 }
150
initial.commit09911bf2008-07-26 23:55:29151 // If this URL has a registered domain, we only want to remember that part.
152 std::string domain =
[email protected]8ac1a752008-07-31 19:40:37153 net::RegistryControlledDomainService::GetDomainAndRegistry(url);
initial.commit09911bf2008-07-26 23:55:29154 if (!domain.empty()) {
155 GURL::Replacements rep;
156 rep.SetHostStr(domain);
157 site = site.ReplaceComponents(rep);
158 }
159 }
160 return site;
161}
162
163/*static*/
[email protected]3a8eecb2010-04-22 23:56:30164bool SiteInstance::IsSameWebSite(Profile* profile,
165 const GURL& real_url1, const GURL& real_url2) {
166 GURL url1 = GetEffectiveURL(profile, real_url1);
167 GURL url2 = GetEffectiveURL(profile, real_url2);
168
initial.commit09911bf2008-07-26 23:55:29169 // We infer web site boundaries based on the registered domain name of the
[email protected]6705b232008-11-26 00:16:51170 // top-level page and the scheme. We do not pay attention to the port if
171 // one is present, because pages served from different ports can still
172 // access each other if they change their document.domain variable.
initial.commit09911bf2008-07-26 23:55:29173
[email protected]2ee0418e2009-06-26 21:00:43174 // Some special URLs will match the site instance of any other URL. This is
175 // done before checking both of them for validity, since we want these URLs
176 // to have the same site instance as even an invalid one.
177 if (IsURLSameAsAnySiteInstance(url1) || IsURLSameAsAnySiteInstance(url2))
initial.commit09911bf2008-07-26 23:55:29178 return true;
179
180 // If either URL is invalid, they aren't part of the same site.
[email protected]2ee0418e2009-06-26 21:00:43181 if (!url1.is_valid() || !url2.is_valid())
initial.commit09911bf2008-07-26 23:55:29182 return false;
initial.commit09911bf2008-07-26 23:55:29183
[email protected]6705b232008-11-26 00:16:51184 // If the schemes differ, they aren't part of the same site.
[email protected]2ee0418e2009-06-26 21:00:43185 if (url1.scheme() != url2.scheme())
initial.commit09911bf2008-07-26 23:55:29186 return false;
initial.commit09911bf2008-07-26 23:55:29187
[email protected]8ac1a752008-07-31 19:40:37188 return net::RegistryControlledDomainService::SameDomainOrHost(url1, url2);
initial.commit09911bf2008-07-26 23:55:29189}
[email protected]4566f132009-03-12 01:55:13190
[email protected]3a8eecb2010-04-22 23:56:30191/*static*/
192GURL SiteInstance::GetEffectiveURL(Profile* profile, const GURL& url) {
[email protected]eaa7dd182010-12-14 11:09:00193 if (!profile || !profile->GetExtensionService())
[email protected]3a8eecb2010-04-22 23:56:30194 return url;
195
[email protected]9adb9692010-10-29 23:14:02196 const Extension* extension =
[email protected]eaa7dd182010-12-14 11:09:00197 profile->GetExtensionService()->GetExtensionByWebExtent(url);
[email protected]3a8eecb2010-04-22 23:56:30198 if (extension) {
199 // If the URL is part of an extension's web extent, convert it to an
200 // extension URL.
201 return extension->GetResourceURL(url.path());
202 } else {
203 return url;
204 }
205}
206
[email protected]08c8ec7e2010-07-11 17:14:48207/*static*/
208RenderProcessHost::Type SiteInstance::RendererTypeForURL(const GURL& url) {
209 if (!url.is_valid())
[email protected]1dfa9502009-06-15 20:28:09210 return RenderProcessHost::TYPE_NORMAL;
211
[email protected]08c8ec7e2010-07-11 17:14:48212 if (url.SchemeIs(chrome::kExtensionScheme))
[email protected]1dfa9502009-06-15 20:28:09213 return RenderProcessHost::TYPE_EXTENSION;
214
[email protected]80a8fad2011-01-29 04:02:38215 // TODO(erikkay) creis recommends using UseWebUIForURL instead.
[email protected]1fd1a502011-03-30 16:55:56216 if (content::WebUIFactory::Get()->HasWebUIScheme(url))
[email protected]d0980792011-02-13 19:41:40217 return RenderProcessHost::TYPE_WEBUI;
[email protected]1dfa9502009-06-15 20:28:09218
219 return RenderProcessHost::TYPE_NORMAL;
220}
221
[email protected]08c8ec7e2010-07-11 17:14:48222RenderProcessHost::Type SiteInstance::GetRendererType() {
223 // We may not have a site at this point, which generally means this is a
224 // normal navigation.
225 if (!has_site_)
226 return RenderProcessHost::TYPE_NORMAL;
227
228 return RendererTypeForURL(site_);
229}
230
[email protected]4566f132009-03-12 01:55:13231void SiteInstance::Observe(NotificationType type,
232 const NotificationSource& source,
233 const NotificationDetails& details) {
234 DCHECK(type == NotificationType::RENDERER_PROCESS_TERMINATED);
235 RenderProcessHost* rph = Source<RenderProcessHost>(source).ptr();
236 if (rph == process_)
237 process_ = NULL;
238}