Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(322)

Side by Side Diff: chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc

Issue 434023004: Move more extensions code from ChromeContentBrowserClient to ChromeContentBrowserClientExtensionsPa… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: put back a #include Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/extensions/chrome_content_browser_client_extensions_part.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/chrome_content_browser_client_extensions_par t.h" 5 #include "chrome/browser/extensions/chrome_content_browser_client_extensions_par t.h"
6 6
7 #include <set>
8
7 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/extensions/browser_permissions_policy_delegate.h"
8 #include "chrome/browser/extensions/extension_service.h" 12 #include "chrome/browser/extensions/extension_service.h"
9 #include "chrome/browser/extensions/extension_web_ui.h" 13 #include "chrome/browser/extensions/extension_web_ui.h"
10 #include "chrome/browser/extensions/extension_webkit_preferences.h" 14 #include "chrome/browser/extensions/extension_webkit_preferences.h"
11 #include "chrome/browser/profiles/profile.h" 15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/profiles/profile_io_data.h"
17 #include "chrome/browser/profiles/profile_manager.h"
18 #include "chrome/common/chrome_constants.h"
19 #include "chrome/common/extensions/extension_constants.h"
20 #include "chrome/common/extensions/extension_process_policy.h"
21 #include "chrome/common/extensions/manifest_handlers/app_isolation_info.h"
12 #include "content/public/browser/browser_thread.h" 22 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/browser_url_handler.h" 23 #include "content/public/browser/browser_url_handler.h"
14 #include "content/public/browser/render_process_host.h" 24 #include "content/public/browser/render_process_host.h"
15 #include "content/public/browser/render_view_host.h" 25 #include "content/public/browser/render_view_host.h"
16 #include "content/public/browser/site_instance.h" 26 #include "content/public/browser/site_instance.h"
17 #include "content/public/browser/web_contents.h" 27 #include "content/public/browser/web_contents.h"
28 #include "extensions/browser/extension_host.h"
18 #include "extensions/browser/extension_registry.h" 29 #include "extensions/browser/extension_registry.h"
19 #include "extensions/browser/extension_system.h" 30 #include "extensions/browser/extension_system.h"
20 #include "extensions/browser/info_map.h" 31 #include "extensions/browser/info_map.h"
21 #include "extensions/browser/view_type_utils.h" 32 #include "extensions/browser/view_type_utils.h"
22 #include "extensions/common/constants.h" 33 #include "extensions/common/constants.h"
34 #include "extensions/common/manifest_handlers/background_info.h"
35 #include "extensions/common/manifest_handlers/web_accessible_resources_info.h"
23 #include "extensions/common/switches.h" 36 #include "extensions/common/switches.h"
24 37
25 // TODO(thestig): Remove ifdefs when extensions no longer build on mobile. 38 // TODO(thestig): Remove ifdefs when extensions no longer build on mobile.
26 #if defined(ENABLE_EXTENSIONS) 39 #if defined(ENABLE_EXTENSIONS)
27 #include "chrome/browser/extensions/api/web_request/web_request_api.h" 40 #include "chrome/browser/extensions/api/web_request/web_request_api.h"
28 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h" 41 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
29 #include "chrome/browser/renderer_host/chrome_extension_message_filter.h" 42 #include "chrome/browser/renderer_host/chrome_extension_message_filter.h"
30 #include "chrome/browser/sync_file_system/local/sync_file_system_backend.h" 43 #include "chrome/browser/sync_file_system/local/sync_file_system_backend.h"
31 #include "extensions/browser/extension_message_filter.h" 44 #include "extensions/browser/extension_message_filter.h"
32 #endif 45 #endif
33 46
34 using content::BrowserThread; 47 using content::BrowserThread;
35 using content::BrowserURLHandler; 48 using content::BrowserURLHandler;
36 using content::RenderViewHost; 49 using content::RenderViewHost;
37 using content::SiteInstance; 50 using content::SiteInstance;
38 using content::WebContents; 51 using content::WebContents;
39 using content::WebPreferences; 52 using content::WebPreferences;
40 53
41 namespace extensions { 54 namespace extensions {
42 55
56 namespace {
57
58 // Used by the GetPrivilegeRequiredByUrl() and GetProcessPrivilege() functions
59 // below. Extension, and isolated apps require different privileges to be
60 // granted to their RenderProcessHosts. This classification allows us to make
61 // sure URLs are served by hosts with the right set of privileges.
62 enum RenderProcessHostPrivilege {
63 PRIV_NORMAL,
64 PRIV_HOSTED,
65 PRIV_ISOLATED,
66 PRIV_EXTENSION,
67 };
68
69 RenderProcessHostPrivilege GetPrivilegeRequiredByUrl(
70 const GURL& url,
71 ExtensionService* service) {
72 // Default to a normal renderer cause it is lower privileged. This should only
73 // occur if the URL on a site instance is either malformed, or uninitialized.
74 // If it is malformed, then there is no need for better privileges anyways.
75 // If it is uninitialized, but eventually settles on being an a scheme other
76 // than normal webrenderer, the navigation logic will correct us out of band
77 // anyways.
78 if (!url.is_valid())
79 return PRIV_NORMAL;
80
81 if (!url.SchemeIs(kExtensionScheme))
82 return PRIV_NORMAL;
83
84 const Extension* extension = service->extensions()->GetByID(url.host());
85 if (extension && AppIsolationInfo::HasIsolatedStorage(extension))
86 return PRIV_ISOLATED;
87 if (extension && extension->is_hosted_app())
88 return PRIV_HOSTED;
89 return PRIV_EXTENSION;
90 }
91
92 RenderProcessHostPrivilege GetProcessPrivilege(
93 content::RenderProcessHost* process_host,
94 ProcessMap* process_map,
95 ExtensionService* service) {
96 std::set<std::string> extension_ids =
97 process_map->GetExtensionsInProcess(process_host->GetID());
98 if (extension_ids.empty())
99 return PRIV_NORMAL;
100
101 for (std::set<std::string>::iterator iter = extension_ids.begin();
102 iter != extension_ids.end(); ++iter) {
103 const Extension* extension = service->GetExtensionById(*iter, false);
104 if (extension && AppIsolationInfo::HasIsolatedStorage(extension))
105 return PRIV_ISOLATED;
106 if (extension && extension->is_hosted_app())
107 return PRIV_HOSTED;
108 }
109
110 return PRIV_EXTENSION;
111 }
112
113 } // namespace
114
43 ChromeContentBrowserClientExtensionsPart:: 115 ChromeContentBrowserClientExtensionsPart::
44 ChromeContentBrowserClientExtensionsPart() { 116 ChromeContentBrowserClientExtensionsPart() {
117 permissions_policy_delegate_.reset(new BrowserPermissionsPolicyDelegate());
45 } 118 }
46 119
47 ChromeContentBrowserClientExtensionsPart:: 120 ChromeContentBrowserClientExtensionsPart::
48 ~ChromeContentBrowserClientExtensionsPart() { 121 ~ChromeContentBrowserClientExtensionsPart() {
49 } 122 }
50 123
124 // static
125 GURL ChromeContentBrowserClientExtensionsPart::GetEffectiveURL(
126 Profile* profile, const GURL& url) {
127 // If the input |url| is part of an installed app, the effective URL is an
128 // extension URL with the ID of that extension as the host. This has the
129 // effect of grouping apps together in a common SiteInstance.
130 ExtensionService* extension_service =
131 ExtensionSystem::Get(profile)->extension_service();
132 if (!extension_service)
133 return url;
134
135 const Extension* extension =
136 extension_service->extensions()->GetHostedAppByURL(url);
137 if (!extension)
138 return url;
139
140 // Bookmark apps do not use the hosted app process model, and should be
141 // treated as normal URLs.
142 if (extension->from_bookmark())
143 return url;
144
145 // If the URL is part of an extension's web extent, convert it to an
146 // extension URL.
147 return extension->GetResourceURL(url.path());
148 }
149
150 // static
151 bool ChromeContentBrowserClientExtensionsPart::ShouldUseProcessPerSite(
152 Profile* profile, const GURL& effective_url) {
153 if (!effective_url.SchemeIs(kExtensionScheme))
154 return false;
155
156 ExtensionService* extension_service =
157 ExtensionSystem::Get(profile)->extension_service();
158 if (!extension_service)
159 return false;
160
161 const Extension* extension =
162 extension_service->extensions()->GetExtensionOrAppByURL(effective_url);
163 if (!extension)
164 return false;
165
166 // If the URL is part of a hosted app that does not have the background
167 // permission, or that does not allow JavaScript access to the background
168 // page, we want to give each instance its own process to improve
169 // responsiveness.
170 if (extension->GetType() == Manifest::TYPE_HOSTED_APP) {
171 if (!extension->permissions_data()->HasAPIPermission(
172 APIPermission::kBackground) ||
173 !BackgroundInfo::AllowJSAccess(extension)) {
174 return false;
175 }
176 }
177
178 // Hosted apps that have script access to their background page must use
179 // process per site, since all instances can make synchronous calls to the
180 // background window. Other extensions should use process per site as well.
181 return true;
182 }
183
184 // static
185 bool ChromeContentBrowserClientExtensionsPart::CanCommitURL(
186 content::RenderProcessHost* process_host, const GURL& url) {
187 // We need to let most extension URLs commit in any process, since this can
188 // be allowed due to web_accessible_resources. Most hosted app URLs may also
189 // load in any process (e.g., in an iframe). However, the Chrome Web Store
190 // cannot be loaded in iframes and should never be requested outside its
191 // process.
192 Profile* profile =
193 Profile::FromBrowserContext(process_host->GetBrowserContext());
194 ExtensionService* service =
195 ExtensionSystem::Get(profile)->extension_service();
196 if (!service)
197 return true;
198
199 const Extension* new_extension =
200 service->extensions()->GetExtensionOrAppByURL(url);
201 if (new_extension &&
202 new_extension->is_hosted_app() &&
203 new_extension->id() == extension_misc::kWebStoreAppId &&
204 !ProcessMap::Get(profile)->Contains(
205 new_extension->id(), process_host->GetID())) {
206 return false;
207 }
208 return true;
209 }
210
211 // static
212 bool ChromeContentBrowserClientExtensionsPart::IsSuitableHost(
213 Profile* profile,
214 content::RenderProcessHost* process_host,
215 const GURL& site_url) {
216 DCHECK(profile);
217
218 ExtensionService* service =
219 ExtensionSystem::Get(profile)->extension_service();
220 ProcessMap* process_map = ProcessMap::Get(profile);
221
222 // These may be NULL during tests. In that case, just assume any site can
223 // share any host.
224 if (!service || !process_map)
225 return true;
226
227 // Otherwise, just make sure the process privilege matches the privilege
228 // required by the site.
229 RenderProcessHostPrivilege privilege_required =
230 GetPrivilegeRequiredByUrl(site_url, service);
231 return GetProcessPrivilege(process_host, process_map, service) ==
232 privilege_required;
233 }
234
235 // static
236 bool
237 ChromeContentBrowserClientExtensionsPart::ShouldTryToUseExistingProcessHost(
238 Profile* profile, const GURL& url) {
239 // This function is trying to limit the amount of processes used by extensions
240 // with background pages. It uses a globally set percentage of processes to
241 // run such extensions and if the limit is exceeded, it returns true, to
242 // indicate to the content module to group extensions together.
243 ExtensionService* service = profile ?
244 ExtensionSystem::Get(profile)->extension_service() : NULL;
245 if (!service)
246 return false;
247
248 // We have to have a valid extension with background page to proceed.
249 const Extension* extension =
250 service->extensions()->GetExtensionOrAppByURL(url);
251 if (!extension)
252 return false;
253 if (!BackgroundInfo::HasBackgroundPage(extension))
254 return false;
255
256 std::set<int> process_ids;
257 size_t max_process_count =
258 content::RenderProcessHost::GetMaxRendererProcessCount();
259
260 // Go through all profiles to ensure we have total count of extension
261 // processes containing background pages, otherwise one profile can
262 // starve the other.
263 std::vector<Profile*> profiles = g_browser_process->profile_manager()->
264 GetLoadedProfiles();
265 for (size_t i = 0; i < profiles.size(); ++i) {
266 ProcessManager* epm = ExtensionSystem::Get(profiles[i])->process_manager();
267 for (ProcessManager::const_iterator iter = epm->background_hosts().begin();
268 iter != epm->background_hosts().end(); ++iter) {
269 const ExtensionHost* host = *iter;
270 process_ids.insert(host->render_process_host()->GetID());
271 }
272 }
273
274 return (process_ids.size() >
275 (max_process_count * chrome::kMaxShareOfExtensionProcesses));
276 }
277
278 // static
279 bool ChromeContentBrowserClientExtensionsPart::
280 ShouldSwapBrowsingInstancesForNavigation(SiteInstance* site_instance,
281 const GURL& current_url,
282 const GURL& new_url) {
283 // If we don't have an ExtensionService, then rely on the SiteInstance logic
284 // in RenderFrameHostManager to decide when to swap.
285 Profile* profile =
286 Profile::FromBrowserContext(site_instance->GetBrowserContext());
287 ExtensionService* service =
288 ExtensionSystem::Get(profile)->extension_service();
289 if (!service)
290 return false;
291
292 // We must use a new BrowsingInstance (forcing a process swap and disabling
293 // scripting by existing tabs) if one of the URLs is an extension and the
294 // other is not the exact same extension.
295 //
296 // We ignore hosted apps here so that other tabs in their BrowsingInstance can
297 // use postMessage with them. (The exception is the Chrome Web Store, which
298 // is a hosted app that requires its own BrowsingInstance.) Navigations
299 // to/from a hosted app will still trigger a SiteInstance swap in
300 // RenderFrameHostManager.
301 const Extension* current_extension =
302 service->extensions()->GetExtensionOrAppByURL(current_url);
303 if (current_extension &&
304 current_extension->is_hosted_app() &&
305 current_extension->id() != extension_misc::kWebStoreAppId)
306 current_extension = NULL;
307
308 const Extension* new_extension =
309 service->extensions()->GetExtensionOrAppByURL(new_url);
310 if (new_extension &&
311 new_extension->is_hosted_app() &&
312 new_extension->id() != extension_misc::kWebStoreAppId)
313 new_extension = NULL;
314
315 // First do a process check. We should force a BrowsingInstance swap if the
316 // current process doesn't know about new_extension, even if current_extension
317 // is somehow the same as new_extension.
318 ProcessMap* process_map = ProcessMap::Get(profile);
319 if (new_extension &&
320 site_instance->HasProcess() &&
321 !process_map->Contains(
322 new_extension->id(), site_instance->GetProcess()->GetID()))
323 return true;
324
325 // Otherwise, swap BrowsingInstances if current_extension and new_extension
326 // differ.
327 return current_extension != new_extension;
328 }
329
330 // static
331 bool ChromeContentBrowserClientExtensionsPart::ShouldSwapProcessesForRedirect(
332 content::ResourceContext* resource_context,
333 const GURL& current_url,
334 const GURL& new_url) {
335 ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context);
336 return CrossesExtensionProcessBoundary(
337 io_data->GetExtensionInfoMap()->extensions(),
338 current_url, new_url, false);
339 }
340
341 // static
342 std::string ChromeContentBrowserClientExtensionsPart::GetWorkerProcessTitle(
343 const GURL& url, content::ResourceContext* context) {
344 // Check if it's an extension-created worker, in which case we want to use
345 // the name of the extension.
346 ProfileIOData* io_data = ProfileIOData::FromResourceContext(context);
347 const Extension* extension =
348 io_data->GetExtensionInfoMap()->extensions().GetByID(url.host());
349 return extension ? extension->name() : std::string();
350 }
351
352 // static
353 bool ChromeContentBrowserClientExtensionsPart::ShouldAllowOpenURL(
354 content::SiteInstance* site_instance,
355 const GURL& from_url,
356 const GURL& to_url,
357 bool* result) {
358 DCHECK(result);
359
360 // Do not allow pages from the web or other extensions navigate to
361 // non-web-accessible extension resources.
362 if (to_url.SchemeIs(kExtensionScheme) &&
363 (from_url.SchemeIsHTTPOrHTTPS() || from_url.SchemeIs(kExtensionScheme))) {
364 Profile* profile = Profile::FromBrowserContext(
365 site_instance->GetProcess()->GetBrowserContext());
366 ExtensionService* service =
367 ExtensionSystem::Get(profile)->extension_service();
368 if (!service) {
369 *result = true;
370 return true;
371 }
372 const Extension* extension =
373 service->extensions()->GetExtensionOrAppByURL(to_url);
374 if (!extension) {
375 *result = true;
376 return true;
377 }
378 const Extension* from_extension =
379 service->extensions()->GetExtensionOrAppByURL(
380 site_instance->GetSiteURL());
381 if (from_extension && from_extension->id() == extension->id()) {
382 *result = true;
383 return true;
384 }
385
386 if (!WebAccessibleResourcesInfo::IsResourceWebAccessible(
387 extension, to_url.path())) {
388 *result = false;
389 return true;
390 }
391 }
392 return false;
393 }
394
395 // static
396 void ChromeContentBrowserClientExtensionsPart::SetSigninProcess(
397 content::SiteInstance* site_instance) {
398 Profile* profile =
399 Profile::FromBrowserContext(site_instance->GetBrowserContext());
400 DCHECK(profile);
401 BrowserThread::PostTask(
402 BrowserThread::IO,
403 FROM_HERE,
404 base::Bind(&InfoMap::SetSigninProcess,
405 ExtensionSystem::Get(profile)->info_map(),
406 site_instance->GetProcess()->GetID()));
407 }
408
51 void ChromeContentBrowserClientExtensionsPart::RenderProcessWillLaunch( 409 void ChromeContentBrowserClientExtensionsPart::RenderProcessWillLaunch(
52 content::RenderProcessHost* host) { 410 content::RenderProcessHost* host) {
53 #if defined(ENABLE_EXTENSIONS) 411 #if defined(ENABLE_EXTENSIONS)
54 int id = host->GetID(); 412 int id = host->GetID();
55 Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext()); 413 Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
56 414
57 host->AddFilter(new ChromeExtensionMessageFilter(id, profile)); 415 host->AddFilter(new ChromeExtensionMessageFilter(id, profile));
58 host->AddFilter(new ExtensionMessageFilter(id, profile)); 416 host->AddFilter(new ExtensionMessageFilter(id, profile));
59 SendExtensionWebRequestStatusToHost(host); 417 SendExtensionWebRequestStatusToHost(host);
60 #endif 418 #endif
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 content::RenderProcessHost* process, 572 content::RenderProcessHost* process,
215 Profile* profile) { 573 Profile* profile) {
216 if (!process) 574 if (!process)
217 return; 575 return;
218 DCHECK(profile); 576 DCHECK(profile);
219 if (ProcessMap::Get(profile)->Contains(process->GetID())) 577 if (ProcessMap::Get(profile)->Contains(process->GetID()))
220 command_line->AppendSwitch(switches::kExtensionProcess); 578 command_line->AppendSwitch(switches::kExtensionProcess);
221 } 579 }
222 580
223 } // namespace extensions 581 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/browser/extensions/chrome_content_browser_client_extensions_part.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698