Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / extensions / extension_function_dispatcher.cc
blobd305729da54220fe5bfa8bcb2e9fa1c5696ec228
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.
5 #include "chrome/browser/extensions/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/extensions/activity_log/activity_action_constants.h"
16 #include "chrome/browser/extensions/activity_log/activity_log.h"
17 #include "chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h"
18 #include "chrome/browser/extensions/extension_function_registry.h"
19 #include "chrome/browser/extensions/extension_service.h"
20 #include "chrome/browser/extensions/extension_system.h"
21 #include "chrome/browser/extensions/extension_util.h"
22 #include "chrome/browser/extensions/extension_web_ui.h"
23 #include "chrome/browser/external_protocol/external_protocol_handler.h"
24 #include "chrome/browser/renderer_host/chrome_render_message_filter.h"
25 #include "chrome/common/extensions/extension_messages.h"
26 #include "chrome/common/url_constants.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/render_frame_host.h"
29 #include "content/public/browser/render_process_host.h"
30 #include "content/public/browser/render_view_host.h"
31 #include "content/public/browser/user_metrics.h"
32 #include "content/public/browser/web_contents.h"
33 #include "content/public/browser/web_contents_observer.h"
34 #include "content/public/common/result_codes.h"
35 #include "extensions/browser/process_map.h"
36 #include "extensions/browser/quota_service.h"
37 #include "extensions/common/extension_api.h"
38 #include "extensions/common/extension_set.h"
39 #include "ipc/ipc_message.h"
40 #include "ipc/ipc_message_macros.h"
41 #include "webkit/common/resource_type.h"
43 using extensions::Extension;
44 using extensions::ExtensionAPI;
45 using extensions::ExtensionSystem;
46 using extensions::Feature;
47 using content::RenderViewHost;
49 namespace {
51 void LogSuccess(const std::string& extension_id,
52 const std::string& api_name,
53 scoped_ptr<base::ListValue> args,
54 content::BrowserContext* browser_context) {
55 // The ActivityLog can only be accessed from the main (UI) thread. If we're
56 // running on the wrong thread, re-dispatch from the main thread.
57 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
58 BrowserThread::PostTask(BrowserThread::UI,
59 FROM_HERE,
60 base::Bind(&LogSuccess,
61 extension_id,
62 api_name,
63 base::Passed(&args),
64 browser_context));
65 } else {
66 extensions::ActivityLog* activity_log =
67 extensions::ActivityLog::GetInstance(browser_context);
68 scoped_refptr<extensions::Action> action =
69 new extensions::Action(extension_id,
70 base::Time::Now(),
71 extensions::Action::ACTION_API_CALL,
72 api_name);
73 action->set_args(args.Pass());
74 activity_log->LogAction(action);
78 // Separate copy of ExtensionAPI used for IO thread extension functions. We need
79 // this because ExtensionAPI has mutable data. It should be possible to remove
80 // this once all the extension APIs are updated to the feature system.
81 struct Static {
82 Static()
83 : api(extensions::ExtensionAPI::CreateWithDefaultConfiguration()) {
85 scoped_ptr<extensions::ExtensionAPI> api;
87 base::LazyInstance<Static> g_global_io_data = LAZY_INSTANCE_INITIALIZER;
89 // Kills the specified process because it sends us a malformed message.
90 void KillBadMessageSender(base::ProcessHandle process) {
91 NOTREACHED();
92 content::RecordAction(base::UserMetricsAction("BadMessageTerminate_EFD"));
93 if (process)
94 base::KillProcess(process, content::RESULT_CODE_KILLED_BAD_MESSAGE, false);
97 void CommonResponseCallback(IPC::Sender* ipc_sender,
98 int routing_id,
99 base::ProcessHandle peer_process,
100 int request_id,
101 ExtensionFunction::ResponseType type,
102 const base::ListValue& results,
103 const std::string& error) {
104 DCHECK(ipc_sender);
106 if (type == ExtensionFunction::BAD_MESSAGE) {
107 // The renderer has done validation before sending extension api requests.
108 // Therefore, we should never receive a request that is invalid in a way
109 // that JSON validation in the renderer should have caught. It could be an
110 // attacker trying to exploit the browser, so we crash the renderer instead.
111 LOG(ERROR) <<
112 "Terminating renderer because of malformed extension message.";
113 if (content::RenderProcessHost::run_renderer_in_process()) {
114 // In single process mode it is better if we don't suicide but just crash.
115 CHECK(false);
116 } else {
117 KillBadMessageSender(peer_process);
120 return;
123 ipc_sender->Send(new ExtensionMsg_Response(
124 routing_id, request_id, type == ExtensionFunction::SUCCEEDED, results,
125 error));
128 void IOThreadResponseCallback(
129 const base::WeakPtr<ChromeRenderMessageFilter>& ipc_sender,
130 int routing_id,
131 int request_id,
132 ExtensionFunction::ResponseType type,
133 const base::ListValue& results,
134 const std::string& error) {
135 if (!ipc_sender.get())
136 return;
138 CommonResponseCallback(ipc_sender.get(),
139 routing_id,
140 ipc_sender->PeerHandle(),
141 request_id,
142 type,
143 results,
144 error);
147 } // namespace
149 class ExtensionFunctionDispatcher::UIThreadResponseCallbackWrapper
150 : public content::WebContentsObserver {
151 public:
152 UIThreadResponseCallbackWrapper(
153 const base::WeakPtr<ExtensionFunctionDispatcher>& dispatcher,
154 RenderViewHost* render_view_host)
155 : content::WebContentsObserver(
156 content::WebContents::FromRenderViewHost(render_view_host)),
157 dispatcher_(dispatcher),
158 render_view_host_(render_view_host),
159 weak_ptr_factory_(this) {
162 virtual ~UIThreadResponseCallbackWrapper() {
165 // content::WebContentsObserver overrides.
166 virtual void RenderViewDeleted(
167 RenderViewHost* render_view_host) OVERRIDE {
168 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
169 if (render_view_host != render_view_host_)
170 return;
172 if (dispatcher_.get()) {
173 dispatcher_->ui_thread_response_callback_wrappers_
174 .erase(render_view_host);
177 delete this;
180 ExtensionFunction::ResponseCallback CreateCallback(int request_id) {
181 return base::Bind(
182 &UIThreadResponseCallbackWrapper::OnExtensionFunctionCompleted,
183 weak_ptr_factory_.GetWeakPtr(),
184 request_id);
187 private:
188 void OnExtensionFunctionCompleted(int request_id,
189 ExtensionFunction::ResponseType type,
190 const base::ListValue& results,
191 const std::string& error) {
192 CommonResponseCallback(
193 render_view_host_, render_view_host_->GetRoutingID(),
194 render_view_host_->GetProcess()->GetHandle(), request_id, type,
195 results, error);
198 base::WeakPtr<ExtensionFunctionDispatcher> dispatcher_;
199 content::RenderViewHost* render_view_host_;
200 base::WeakPtrFactory<UIThreadResponseCallbackWrapper> weak_ptr_factory_;
202 DISALLOW_COPY_AND_ASSIGN(UIThreadResponseCallbackWrapper);
205 extensions::WindowController*
206 ExtensionFunctionDispatcher::Delegate::GetExtensionWindowController()
207 const {
208 return NULL;
211 content::WebContents*
212 ExtensionFunctionDispatcher::Delegate::GetAssociatedWebContents() const {
213 return NULL;
216 content::WebContents*
217 ExtensionFunctionDispatcher::Delegate::GetVisibleWebContents() const {
218 return GetAssociatedWebContents();
221 void ExtensionFunctionDispatcher::GetAllFunctionNames(
222 std::vector<std::string>* names) {
223 ExtensionFunctionRegistry::GetInstance()->GetAllNames(names);
226 bool ExtensionFunctionDispatcher::OverrideFunction(
227 const std::string& name, ExtensionFunctionFactory factory) {
228 return ExtensionFunctionRegistry::GetInstance()->OverrideFunction(name,
229 factory);
232 void ExtensionFunctionDispatcher::ResetFunctions() {
233 ExtensionFunctionRegistry::GetInstance()->ResetFunctions();
236 // static
237 void ExtensionFunctionDispatcher::DispatchOnIOThread(
238 extensions::InfoMap* extension_info_map,
239 void* browser_context,
240 int render_process_id,
241 base::WeakPtr<ChromeRenderMessageFilter> ipc_sender,
242 int routing_id,
243 const ExtensionHostMsg_Request_Params& params) {
244 const Extension* extension =
245 extension_info_map->extensions().GetByID(params.extension_id);
247 ExtensionFunction::ResponseCallback callback(
248 base::Bind(&IOThreadResponseCallback, ipc_sender, routing_id,
249 params.request_id));
251 scoped_refptr<ExtensionFunction> function(
252 CreateExtensionFunction(params, extension, render_process_id,
253 extension_info_map->process_map(),
254 g_global_io_data.Get().api.get(),
255 browser_context, callback));
256 scoped_ptr<base::ListValue> args(params.arguments.DeepCopy());
258 if (!function.get())
259 return;
261 IOThreadExtensionFunction* function_io =
262 function->AsIOThreadExtensionFunction();
263 if (!function_io) {
264 NOTREACHED();
265 return;
267 function_io->set_ipc_sender(ipc_sender, routing_id);
268 function_io->set_extension_info_map(extension_info_map);
269 function->set_include_incognito(
270 extension_info_map->IsIncognitoEnabled(extension->id()));
272 if (!CheckPermissions(function.get(), extension, params, callback))
273 return;
275 extensions::QuotaService* quota = extension_info_map->GetQuotaService();
276 std::string violation_error = quota->Assess(extension->id(),
277 function.get(),
278 &params.arguments,
279 base::TimeTicks::Now());
280 if (violation_error.empty()) {
281 LogSuccess(extension->id(),
282 params.name,
283 args.Pass(),
284 static_cast<content::BrowserContext*>(browser_context));
285 function->Run();
286 } else {
287 function->OnQuotaExceeded(violation_error);
291 ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(
292 content::BrowserContext* browser_context,
293 Delegate* delegate)
294 : browser_context_(browser_context),
295 delegate_(delegate) {
298 ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() {
301 void ExtensionFunctionDispatcher::Dispatch(
302 const ExtensionHostMsg_Request_Params& params,
303 RenderViewHost* render_view_host) {
304 UIThreadResponseCallbackWrapperMap::const_iterator
305 iter = ui_thread_response_callback_wrappers_.find(render_view_host);
306 UIThreadResponseCallbackWrapper* callback_wrapper = NULL;
307 if (iter == ui_thread_response_callback_wrappers_.end()) {
308 callback_wrapper = new UIThreadResponseCallbackWrapper(AsWeakPtr(),
309 render_view_host);
310 ui_thread_response_callback_wrappers_[render_view_host] = callback_wrapper;
311 } else {
312 callback_wrapper = iter->second;
315 DispatchWithCallbackInternal(
316 params, render_view_host, NULL,
317 callback_wrapper->CreateCallback(params.request_id));
320 void ExtensionFunctionDispatcher::DispatchWithCallback(
321 const ExtensionHostMsg_Request_Params& params,
322 content::RenderFrameHost* render_frame_host,
323 const ExtensionFunction::ResponseCallback& callback) {
324 DispatchWithCallbackInternal(params, NULL, render_frame_host, callback);
327 void ExtensionFunctionDispatcher::DispatchWithCallbackInternal(
328 const ExtensionHostMsg_Request_Params& params,
329 RenderViewHost* render_view_host,
330 content::RenderFrameHost* render_frame_host,
331 const ExtensionFunction::ResponseCallback& callback) {
332 DCHECK(render_view_host || render_frame_host);
333 // TODO(yzshen): There is some shared logic between this method and
334 // DispatchOnIOThread(). It is nice to deduplicate.
335 ExtensionSystem* extension_system =
336 ExtensionSystem::GetForBrowserContext(browser_context_);
337 ExtensionService* service = extension_system->extension_service();
338 extensions::ProcessMap* process_map =
339 extensions::ProcessMap::Get(browser_context_);
340 if (!process_map)
341 return;
343 const Extension* extension = service->extensions()->GetByID(
344 params.extension_id);
345 if (!extension)
346 extension = service->extensions()->GetHostedAppByURL(params.source_url);
348 int process_id = render_view_host ? render_view_host->GetProcess()->GetID() :
349 render_frame_host->GetProcess()->GetID();
350 scoped_refptr<ExtensionFunction> function(
351 CreateExtensionFunction(params,
352 extension,
353 process_id,
354 *process_map,
355 extensions::ExtensionAPI::GetSharedInstance(),
356 browser_context_,
357 callback));
358 scoped_ptr<base::ListValue> args(params.arguments.DeepCopy());
360 if (!function.get())
361 return;
363 UIThreadExtensionFunction* function_ui =
364 function->AsUIThreadExtensionFunction();
365 if (!function_ui) {
366 NOTREACHED();
367 return;
369 if (render_view_host) {
370 function_ui->SetRenderViewHost(render_view_host);
371 } else {
372 function_ui->SetRenderFrameHost(render_frame_host);
374 function_ui->set_dispatcher(AsWeakPtr());
375 function_ui->set_context(browser_context_);
376 function->set_include_incognito(extension_util::CanCrossIncognito(extension,
377 service));
379 if (!CheckPermissions(function.get(), extension, params, callback))
380 return;
382 extensions::QuotaService* quota = service->quota_service();
383 std::string violation_error = quota->Assess(extension->id(),
384 function.get(),
385 &params.arguments,
386 base::TimeTicks::Now());
387 if (violation_error.empty()) {
388 // See crbug.com/39178.
389 ExternalProtocolHandler::PermitLaunchUrl();
390 LogSuccess(extension->id(), params.name, args.Pass(), browser_context_);
391 function->Run();
392 } else {
393 function->OnQuotaExceeded(violation_error);
396 // Note: do not access |this| after this point. We may have been deleted
397 // if function->Run() ended up closing the tab that owns us.
399 // Check if extension was uninstalled by management.uninstall.
400 if (!service->extensions()->GetByID(params.extension_id))
401 return;
403 // We only adjust the keepalive count for UIThreadExtensionFunction for
404 // now, largely for simplicity's sake. This is OK because currently, only
405 // the webRequest API uses IOThreadExtensionFunction, and that API is not
406 // compatible with lazy background pages.
407 extension_system->process_manager()->IncrementLazyKeepaliveCount(extension);
410 void ExtensionFunctionDispatcher::OnExtensionFunctionCompleted(
411 const Extension* extension) {
412 ExtensionSystem::GetForBrowserContext(browser_context_)->process_manager()->
413 DecrementLazyKeepaliveCount(extension);
416 // static
417 bool ExtensionFunctionDispatcher::CheckPermissions(
418 ExtensionFunction* function,
419 const Extension* extension,
420 const ExtensionHostMsg_Request_Params& params,
421 const ExtensionFunction::ResponseCallback& callback) {
422 if (!function->HasPermission()) {
423 LOG(ERROR) << "Extension " << extension->id() << " does not have "
424 << "permission to function: " << params.name;
425 SendAccessDenied(callback);
426 return false;
428 return true;
431 namespace {
433 // Only COMPONENT hosted apps may call extension APIs, and they are limited
434 // to just the permissions they explicitly request. They should not have access
435 // to extension APIs like eg chrome.runtime, chrome.windows, etc. that normally
436 // are available without permission.
437 // TODO(mpcomplete): move this to ExtensionFunction::HasPermission (or remove
438 // it altogether).
439 bool AllowHostedAppAPICall(const Extension& extension,
440 const GURL& source_url,
441 const std::string& function_name) {
442 if (extension.location() != extensions::Manifest::COMPONENT)
443 return false;
445 if (!extension.web_extent().MatchesURL(source_url))
446 return false;
448 // Note: Not BLESSED_WEB_PAGE_CONTEXT here because these component hosted app
449 // entities have traditionally been treated as blessed extensions, for better
450 // or worse.
451 Feature::Availability availability =
452 ExtensionAPI::GetSharedInstance()->IsAvailable(
453 function_name, &extension, Feature::BLESSED_EXTENSION_CONTEXT,
454 source_url);
455 return availability.is_available();
458 } // namespace
461 // static
462 ExtensionFunction* ExtensionFunctionDispatcher::CreateExtensionFunction(
463 const ExtensionHostMsg_Request_Params& params,
464 const Extension* extension,
465 int requesting_process_id,
466 const extensions::ProcessMap& process_map,
467 extensions::ExtensionAPI* api,
468 void* profile,
469 const ExtensionFunction::ResponseCallback& callback) {
470 if (!extension) {
471 LOG(ERROR) << "Specified extension does not exist.";
472 SendAccessDenied(callback);
473 return NULL;
476 // Most hosted apps can't call APIs.
477 bool allowed = true;
478 if (extension->is_hosted_app())
479 allowed = AllowHostedAppAPICall(*extension, params.source_url, params.name);
481 // Privileged APIs can only be called from the process the extension
482 // is running in.
483 if (allowed && api->IsPrivileged(params.name))
484 allowed = process_map.Contains(extension->id(), requesting_process_id);
486 if (!allowed) {
487 LOG(ERROR) << "Extension API call disallowed - name:" << params.name
488 << " pid:" << requesting_process_id
489 << " from URL " << params.source_url.spec();
490 SendAccessDenied(callback);
491 return NULL;
494 ExtensionFunction* function =
495 ExtensionFunctionRegistry::GetInstance()->NewFunction(params.name);
496 if (!function) {
497 LOG(ERROR) << "Unknown Extension API - " << params.name;
498 SendAccessDenied(callback);
499 return NULL;
502 function->SetArgs(&params.arguments);
503 function->set_source_url(params.source_url);
504 function->set_request_id(params.request_id);
505 function->set_has_callback(params.has_callback);
506 function->set_user_gesture(params.user_gesture);
507 function->set_extension(extension);
508 function->set_profile_id(profile);
509 function->set_response_callback(callback);
511 return function;
514 // static
515 void ExtensionFunctionDispatcher::SendAccessDenied(
516 const ExtensionFunction::ResponseCallback& callback) {
517 base::ListValue empty_list;
518 callback.Run(ExtensionFunction::FAILED, empty_list,
519 "Access to extension API denied.");