Bluetooth: replace "profiles" with "uuids"
[chromium-blink-merge.git] / extensions / browser / extension_function_dispatcher.cc
blob3e29582c0455cfcfde1ede00b1e2dd6508469172
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
3 // found in the LICENSE file.
5 #include "extensions/browser/extension_function_dispatcher.h"
7 #include "base/bind.h"
8 #include "base/json/json_string_value_serializer.h"
9 #include "base/lazy_instance.h"
10 #include "base/logging.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/process/process.h"
13 #include "base/values.h"
14 #include "build/build_config.h"
15 #include "chrome/browser/renderer_host/chrome_render_message_filter.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/render_frame_host.h"
18 #include "content/public/browser/render_process_host.h"
19 #include "content/public/browser/render_view_host.h"
20 #include "content/public/browser/user_metrics.h"
21 #include "content/public/browser/web_contents.h"
22 #include "content/public/browser/web_contents_observer.h"
23 #include "content/public/common/result_codes.h"
24 #include "extensions/browser/api_activity_monitor.h"
25 #include "extensions/browser/extension_function_registry.h"
26 #include "extensions/browser/extension_registry.h"
27 #include "extensions/browser/extension_system.h"
28 #include "extensions/browser/extensions_browser_client.h"
29 #include "extensions/browser/process_manager.h"
30 #include "extensions/browser/process_map.h"
31 #include "extensions/browser/quota_service.h"
32 #include "extensions/common/extension_api.h"
33 #include "extensions/common/extension_messages.h"
34 #include "extensions/common/extension_set.h"
35 #include "ipc/ipc_message.h"
36 #include "ipc/ipc_message_macros.h"
38 using extensions::Extension;
39 using extensions::ExtensionAPI;
40 using extensions::ExtensionsBrowserClient;
41 using extensions::ExtensionSystem;
42 using extensions::Feature;
43 using content::BrowserThread;
44 using content::RenderViewHost;
46 namespace {
48 // Notifies the ApiActivityMonitor that an extension API function has been
49 // called. May be called from any thread.
50 void NotifyApiFunctionCalled(const std::string& extension_id,
51 const std::string& api_name,
52 scoped_ptr<base::ListValue> args,
53 content::BrowserContext* browser_context) {
54 // The ApiActivityMonitor can only be accessed from the main (UI) thread. If
55 // we're running on the wrong thread, re-dispatch from the main thread.
56 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
57 BrowserThread::PostTask(BrowserThread::UI,
58 FROM_HERE,
59 base::Bind(&NotifyApiFunctionCalled,
60 extension_id,
61 api_name,
62 base::Passed(&args),
63 browser_context));
64 return;
66 // The BrowserContext may become invalid after the task above is posted.
67 if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context))
68 return;
70 extensions::ApiActivityMonitor* monitor =
71 ExtensionsBrowserClient::Get()->GetApiActivityMonitor(browser_context);
72 if (monitor)
73 monitor->OnApiFunctionCalled(extension_id, api_name, args.Pass());
76 // Separate copy of ExtensionAPI used for IO thread extension functions. We need
77 // this because ExtensionAPI has mutable data. It should be possible to remove
78 // this once all the extension APIs are updated to the feature system.
79 struct Static {
80 Static()
81 : api(extensions::ExtensionAPI::CreateWithDefaultConfiguration()) {
83 scoped_ptr<extensions::ExtensionAPI> api;
85 base::LazyInstance<Static> g_global_io_data = LAZY_INSTANCE_INITIALIZER;
87 // Kills the specified process because it sends us a malformed message.
88 void KillBadMessageSender(base::ProcessHandle process) {
89 NOTREACHED();
90 content::RecordAction(base::UserMetricsAction("BadMessageTerminate_EFD"));
91 if (process)
92 base::KillProcess(process, content::RESULT_CODE_KILLED_BAD_MESSAGE, false);
95 void CommonResponseCallback(IPC::Sender* ipc_sender,
96 int routing_id,
97 base::ProcessHandle peer_process,
98 int request_id,
99 ExtensionFunction::ResponseType type,
100 const base::ListValue& results,
101 const std::string& error) {
102 DCHECK(ipc_sender);
104 if (type == ExtensionFunction::BAD_MESSAGE) {
105 // The renderer has done validation before sending extension api requests.
106 // Therefore, we should never receive a request that is invalid in a way
107 // that JSON validation in the renderer should have caught. It could be an
108 // attacker trying to exploit the browser, so we crash the renderer instead.
109 LOG(ERROR) <<
110 "Terminating renderer because of malformed extension message.";
111 if (content::RenderProcessHost::run_renderer_in_process()) {
112 // In single process mode it is better if we don't suicide but just crash.
113 CHECK(false);
114 } else {
115 KillBadMessageSender(peer_process);
118 return;
121 ipc_sender->Send(new ExtensionMsg_Response(
122 routing_id, request_id, type == ExtensionFunction::SUCCEEDED, results,
123 error));
126 void IOThreadResponseCallback(
127 const base::WeakPtr<ChromeRenderMessageFilter>& ipc_sender,
128 int routing_id,
129 int request_id,
130 ExtensionFunction::ResponseType type,
131 const base::ListValue& results,
132 const std::string& error) {
133 if (!ipc_sender.get())
134 return;
136 CommonResponseCallback(ipc_sender.get(),
137 routing_id,
138 ipc_sender->PeerHandle(),
139 request_id,
140 type,
141 results,
142 error);
145 } // namespace
147 class ExtensionFunctionDispatcher::UIThreadResponseCallbackWrapper
148 : public content::WebContentsObserver {
149 public:
150 UIThreadResponseCallbackWrapper(
151 const base::WeakPtr<ExtensionFunctionDispatcher>& dispatcher,
152 RenderViewHost* render_view_host)
153 : content::WebContentsObserver(
154 content::WebContents::FromRenderViewHost(render_view_host)),
155 dispatcher_(dispatcher),
156 render_view_host_(render_view_host),
157 weak_ptr_factory_(this) {
160 virtual ~UIThreadResponseCallbackWrapper() {
163 // content::WebContentsObserver overrides.
164 virtual void RenderViewDeleted(
165 RenderViewHost* render_view_host) OVERRIDE {
166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
167 if (render_view_host != render_view_host_)
168 return;
170 if (dispatcher_.get()) {
171 dispatcher_->ui_thread_response_callback_wrappers_
172 .erase(render_view_host);
175 delete this;
178 ExtensionFunction::ResponseCallback CreateCallback(int request_id) {
179 return base::Bind(
180 &UIThreadResponseCallbackWrapper::OnExtensionFunctionCompleted,
181 weak_ptr_factory_.GetWeakPtr(),
182 request_id);
185 private:
186 void OnExtensionFunctionCompleted(int request_id,
187 ExtensionFunction::ResponseType type,
188 const base::ListValue& results,
189 const std::string& error) {
190 CommonResponseCallback(
191 render_view_host_, render_view_host_->GetRoutingID(),
192 render_view_host_->GetProcess()->GetHandle(), request_id, type,
193 results, error);
196 base::WeakPtr<ExtensionFunctionDispatcher> dispatcher_;
197 content::RenderViewHost* render_view_host_;
198 base::WeakPtrFactory<UIThreadResponseCallbackWrapper> weak_ptr_factory_;
200 DISALLOW_COPY_AND_ASSIGN(UIThreadResponseCallbackWrapper);
203 extensions::WindowController*
204 ExtensionFunctionDispatcher::Delegate::GetExtensionWindowController()
205 const {
206 return NULL;
209 content::WebContents*
210 ExtensionFunctionDispatcher::Delegate::GetAssociatedWebContents() const {
211 return NULL;
214 content::WebContents*
215 ExtensionFunctionDispatcher::Delegate::GetVisibleWebContents() const {
216 return GetAssociatedWebContents();
219 void ExtensionFunctionDispatcher::GetAllFunctionNames(
220 std::vector<std::string>* names) {
221 ExtensionFunctionRegistry::GetInstance()->GetAllNames(names);
224 bool ExtensionFunctionDispatcher::OverrideFunction(
225 const std::string& name, ExtensionFunctionFactory factory) {
226 return ExtensionFunctionRegistry::GetInstance()->OverrideFunction(name,
227 factory);
230 // static
231 void ExtensionFunctionDispatcher::DispatchOnIOThread(
232 extensions::InfoMap* extension_info_map,
233 void* browser_context,
234 int render_process_id,
235 base::WeakPtr<ChromeRenderMessageFilter> ipc_sender,
236 int routing_id,
237 const ExtensionHostMsg_Request_Params& params) {
238 const Extension* extension =
239 extension_info_map->extensions().GetByID(params.extension_id);
241 ExtensionFunction::ResponseCallback callback(
242 base::Bind(&IOThreadResponseCallback, ipc_sender, routing_id,
243 params.request_id));
245 scoped_refptr<ExtensionFunction> function(
246 CreateExtensionFunction(params, extension, render_process_id,
247 extension_info_map->process_map(),
248 g_global_io_data.Get().api.get(),
249 browser_context, callback));
250 if (!function.get())
251 return;
253 IOThreadExtensionFunction* function_io =
254 function->AsIOThreadExtensionFunction();
255 if (!function_io) {
256 NOTREACHED();
257 return;
259 function_io->set_ipc_sender(ipc_sender, routing_id);
260 function_io->set_extension_info_map(extension_info_map);
261 function->set_include_incognito(
262 extension_info_map->IsIncognitoEnabled(extension->id()));
264 if (!CheckPermissions(function.get(), extension, params, callback))
265 return;
267 extensions::QuotaService* quota = extension_info_map->GetQuotaService();
268 std::string violation_error = quota->Assess(extension->id(),
269 function.get(),
270 &params.arguments,
271 base::TimeTicks::Now());
272 if (violation_error.empty()) {
273 scoped_ptr<base::ListValue> args(params.arguments.DeepCopy());
274 NotifyApiFunctionCalled(
275 extension->id(),
276 params.name,
277 args.Pass(),
278 static_cast<content::BrowserContext*>(browser_context));
279 function->Run();
280 } else {
281 function->OnQuotaExceeded(violation_error);
285 ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(
286 content::BrowserContext* browser_context,
287 Delegate* delegate)
288 : browser_context_(browser_context),
289 delegate_(delegate) {
292 ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() {
295 void ExtensionFunctionDispatcher::Dispatch(
296 const ExtensionHostMsg_Request_Params& params,
297 RenderViewHost* render_view_host) {
298 UIThreadResponseCallbackWrapperMap::const_iterator
299 iter = ui_thread_response_callback_wrappers_.find(render_view_host);
300 UIThreadResponseCallbackWrapper* callback_wrapper = NULL;
301 if (iter == ui_thread_response_callback_wrappers_.end()) {
302 callback_wrapper = new UIThreadResponseCallbackWrapper(AsWeakPtr(),
303 render_view_host);
304 ui_thread_response_callback_wrappers_[render_view_host] = callback_wrapper;
305 } else {
306 callback_wrapper = iter->second;
309 DispatchWithCallbackInternal(
310 params, render_view_host, NULL,
311 callback_wrapper->CreateCallback(params.request_id));
314 void ExtensionFunctionDispatcher::DispatchWithCallback(
315 const ExtensionHostMsg_Request_Params& params,
316 content::RenderFrameHost* render_frame_host,
317 const ExtensionFunction::ResponseCallback& callback) {
318 DispatchWithCallbackInternal(params, NULL, render_frame_host, callback);
321 void ExtensionFunctionDispatcher::DispatchWithCallbackInternal(
322 const ExtensionHostMsg_Request_Params& params,
323 RenderViewHost* render_view_host,
324 content::RenderFrameHost* render_frame_host,
325 const ExtensionFunction::ResponseCallback& callback) {
326 DCHECK(render_view_host || render_frame_host);
327 // TODO(yzshen): There is some shared logic between this method and
328 // DispatchOnIOThread(). It is nice to deduplicate.
329 extensions::ProcessMap* process_map =
330 extensions::ProcessMap::Get(browser_context_);
331 if (!process_map)
332 return;
334 extensions::ExtensionRegistry* registry =
335 extensions::ExtensionRegistry::Get(browser_context_);
336 const Extension* extension = registry->enabled_extensions().GetByID(
337 params.extension_id);
338 if (!extension) {
339 extension =
340 registry->enabled_extensions().GetHostedAppByURL(params.source_url);
343 int process_id = render_view_host ? render_view_host->GetProcess()->GetID() :
344 render_frame_host->GetProcess()->GetID();
345 scoped_refptr<ExtensionFunction> function(
346 CreateExtensionFunction(params,
347 extension,
348 process_id,
349 *process_map,
350 extensions::ExtensionAPI::GetSharedInstance(),
351 browser_context_,
352 callback));
353 if (!function.get())
354 return;
356 UIThreadExtensionFunction* function_ui =
357 function->AsUIThreadExtensionFunction();
358 if (!function_ui) {
359 NOTREACHED();
360 return;
362 if (render_view_host) {
363 function_ui->SetRenderViewHost(render_view_host);
364 } else {
365 function_ui->SetRenderFrameHost(render_frame_host);
367 function_ui->set_dispatcher(AsWeakPtr());
368 function_ui->set_browser_context(browser_context_);
369 function->set_include_incognito(
370 ExtensionsBrowserClient::Get()->CanExtensionCrossIncognito(
371 extension, browser_context_));
373 if (!CheckPermissions(function.get(), extension, params, callback))
374 return;
376 ExtensionSystem* extension_system = ExtensionSystem::Get(browser_context_);
377 extensions::QuotaService* quota = extension_system->quota_service();
378 std::string violation_error = quota->Assess(extension->id(),
379 function.get(),
380 &params.arguments,
381 base::TimeTicks::Now());
382 if (violation_error.empty()) {
383 scoped_ptr<base::ListValue> args(params.arguments.DeepCopy());
385 // See crbug.com/39178.
386 ExtensionsBrowserClient::Get()->PermitExternalProtocolHandler();
387 NotifyApiFunctionCalled(
388 extension->id(), params.name, args.Pass(), browser_context_);
389 function->Run();
390 } else {
391 function->OnQuotaExceeded(violation_error);
394 // Note: do not access |this| after this point. We may have been deleted
395 // if function->Run() ended up closing the tab that owns us.
397 // Check if extension was uninstalled by management.uninstall.
398 if (!registry->enabled_extensions().GetByID(params.extension_id))
399 return;
401 // We only adjust the keepalive count for UIThreadExtensionFunction for
402 // now, largely for simplicity's sake. This is OK because currently, only
403 // the webRequest API uses IOThreadExtensionFunction, and that API is not
404 // compatible with lazy background pages.
405 extension_system->process_manager()->IncrementLazyKeepaliveCount(extension);
408 void ExtensionFunctionDispatcher::OnExtensionFunctionCompleted(
409 const Extension* extension) {
410 ExtensionSystem::Get(browser_context_)->process_manager()->
411 DecrementLazyKeepaliveCount(extension);
414 // static
415 bool ExtensionFunctionDispatcher::CheckPermissions(
416 ExtensionFunction* function,
417 const Extension* extension,
418 const ExtensionHostMsg_Request_Params& params,
419 const ExtensionFunction::ResponseCallback& callback) {
420 if (!function->HasPermission()) {
421 LOG(ERROR) << "Extension " << extension->id() << " does not have "
422 << "permission to function: " << params.name;
423 SendAccessDenied(callback);
424 return false;
426 return true;
429 namespace {
431 // Only COMPONENT hosted apps may call extension APIs, and they are limited
432 // to just the permissions they explicitly request. They should not have access
433 // to extension APIs like eg chrome.runtime, chrome.windows, etc. that normally
434 // are available without permission.
435 // TODO(mpcomplete): move this to ExtensionFunction::HasPermission (or remove
436 // it altogether).
437 bool AllowHostedAppAPICall(const Extension& extension,
438 const GURL& source_url,
439 const std::string& function_name) {
440 if (extension.location() != extensions::Manifest::COMPONENT)
441 return false;
443 if (!extension.web_extent().MatchesURL(source_url))
444 return false;
446 // Note: Not BLESSED_WEB_PAGE_CONTEXT here because these component hosted app
447 // entities have traditionally been treated as blessed extensions, for better
448 // or worse.
449 Feature::Availability availability =
450 ExtensionAPI::GetSharedInstance()->IsAvailable(
451 function_name, &extension, Feature::BLESSED_EXTENSION_CONTEXT,
452 source_url);
453 return availability.is_available();
456 } // namespace
459 // static
460 ExtensionFunction* ExtensionFunctionDispatcher::CreateExtensionFunction(
461 const ExtensionHostMsg_Request_Params& params,
462 const Extension* extension,
463 int requesting_process_id,
464 const extensions::ProcessMap& process_map,
465 extensions::ExtensionAPI* api,
466 void* profile,
467 const ExtensionFunction::ResponseCallback& callback) {
468 if (!extension) {
469 LOG(ERROR) << "Specified extension does not exist.";
470 SendAccessDenied(callback);
471 return NULL;
474 // Most hosted apps can't call APIs.
475 bool allowed = true;
476 if (extension->is_hosted_app())
477 allowed = AllowHostedAppAPICall(*extension, params.source_url, params.name);
479 // Privileged APIs can only be called from the process the extension
480 // is running in.
481 if (allowed && api->IsPrivileged(params.name))
482 allowed = process_map.Contains(extension->id(), requesting_process_id);
484 if (!allowed) {
485 LOG(ERROR) << "Extension API call disallowed - name:" << params.name
486 << " pid:" << requesting_process_id
487 << " from URL " << params.source_url.spec();
488 SendAccessDenied(callback);
489 return NULL;
492 ExtensionFunction* function =
493 ExtensionFunctionRegistry::GetInstance()->NewFunction(params.name);
494 if (!function) {
495 LOG(ERROR) << "Unknown Extension API - " << params.name;
496 SendAccessDenied(callback);
497 return NULL;
500 function->SetArgs(&params.arguments);
501 function->set_source_url(params.source_url);
502 function->set_request_id(params.request_id);
503 function->set_has_callback(params.has_callback);
504 function->set_user_gesture(params.user_gesture);
505 function->set_extension(extension);
506 function->set_profile_id(profile);
507 function->set_response_callback(callback);
508 function->set_source_tab_id(params.source_tab_id);
510 return function;
513 // static
514 void ExtensionFunctionDispatcher::SendAccessDenied(
515 const ExtensionFunction::ResponseCallback& callback) {
516 base::ListValue empty_list;
517 callback.Run(ExtensionFunction::FAILED, empty_list,
518 "Access to extension API denied.");