1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/extension_function_dispatcher.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_string_value_serializer.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h"
1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/logging.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted.h"
12a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "base/metrics/sparse_histogram.h"
13bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/process/process.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "build/build_config.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/browser/render_frame_host.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_process_host.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_view_host.h"
200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "content/public/browser/user_metrics.h"
218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "content/public/browser/web_contents.h"
228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "content/public/browser/web_contents_observer.h"
2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "content/public/common/result_codes.h"
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/api_activity_monitor.h"
25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/extension_function_registry.h"
26e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "extensions/browser/extension_message_filter.h"
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_registry.h"
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h"
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extensions_browser_client.h"
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/process_manager.h"
31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/browser/process_map.h"
32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/browser/quota_service.h"
330f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "extensions/common/extension_api.h"
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/common/extension_messages.h"
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/common/extension_set.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ipc/ipc_message.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ipc/ipc_message_macros.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using content::BrowserThread;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::RenderViewHost;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochnamespace extensions {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Notifies the ApiActivityMonitor that an extension API function has been
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// called. May be called from any thread.
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void NotifyApiFunctionCalled(const std::string& extension_id,
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             const std::string& api_name,
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             scoped_ptr<base::ListValue> args,
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             content::BrowserContext* browser_context) {
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The ApiActivityMonitor can only be accessed from the main (UI) thread. If
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // we're running on the wrong thread, re-dispatch from the main thread.
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostTask(BrowserThread::UI,
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            FROM_HERE,
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            base::Bind(&NotifyApiFunctionCalled,
57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                       extension_id,
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       api_name,
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       base::Passed(&args),
60a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                       browser_context));
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The BrowserContext may become invalid after the task above is posted.
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context))
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
67e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  ApiActivityMonitor* monitor =
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ExtensionsBrowserClient::Get()->GetApiActivityMonitor(browser_context);
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (monitor)
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    monitor->OnApiFunctionCalled(extension_id, api_name, args.Pass());
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Separate copy of ExtensionAPI used for IO thread extension functions. We need
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this because ExtensionAPI has mutable data. It should be possible to remove
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this once all the extension APIs are updated to the feature system.
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct Static {
77e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  Static() : api(ExtensionAPI::CreateWithDefaultConfiguration()) {}
78e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  scoped_ptr<ExtensionAPI> api;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::LazyInstance<Static> g_global_io_data = LAZY_INSTANCE_INITIALIZER;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Kills the specified process because it sends us a malformed message.
8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void KillBadMessageSender(base::ProcessHandle process) {
8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  NOTREACHED();
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  content::RecordAction(base::UserMetricsAction("BadMessageTerminate_EFD"));
8690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (process)
8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::KillProcess(process, content::RESULT_CODE_KILLED_BAD_MESSAGE, false);
8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void CommonResponseCallback(IPC::Sender* ipc_sender,
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                            int routing_id,
9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                            base::ProcessHandle peer_process,
9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                            int request_id,
9490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                            ExtensionFunction::ResponseType type,
9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                            const base::ListValue& results,
9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                            const std::string& error) {
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(ipc_sender);
9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (type == ExtensionFunction::BAD_MESSAGE) {
10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // The renderer has done validation before sending extension api requests.
10190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Therefore, we should never receive a request that is invalid in a way
10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // that JSON validation in the renderer should have caught. It could be an
10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // attacker trying to exploit the browser, so we crash the renderer instead.
10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LOG(ERROR) <<
10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        "Terminating renderer because of malformed extension message.";
10690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (content::RenderProcessHost::run_renderer_in_process()) {
10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // In single process mode it is better if we don't suicide but just crash.
10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      CHECK(false);
10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    } else {
11090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      KillBadMessageSender(peer_process);
11190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ipc_sender->Send(new ExtensionMsg_Response(
11790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      routing_id, request_id, type == ExtensionFunction::SUCCEEDED, results,
11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      error));
11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void IOThreadResponseCallback(
122e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const base::WeakPtr<ExtensionMessageFilter>& ipc_sender,
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    int routing_id,
12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    int request_id,
12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ExtensionFunction::ResponseType type,
12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const base::ListValue& results,
12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& error) {
128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!ipc_sender.get())
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  CommonResponseCallback(ipc_sender.get(),
132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         routing_id,
1337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                         ipc_sender->PeerHandle(),
134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         request_id,
135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         type,
136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         results,
137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         error);
13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class ExtensionFunctionDispatcher::UIThreadResponseCallbackWrapper
1438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    : public content::WebContentsObserver {
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public:
14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  UIThreadResponseCallbackWrapper(
14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      const base::WeakPtr<ExtensionFunctionDispatcher>& dispatcher,
14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      RenderViewHost* render_view_host)
1488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      : content::WebContentsObserver(
1498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)            content::WebContents::FromRenderViewHost(render_view_host)),
15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        dispatcher_(dispatcher),
1518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        render_view_host_(render_view_host),
15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        weak_ptr_factory_(this) {
15390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
15590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual ~UIThreadResponseCallbackWrapper() {
15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
15790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // content::WebContentsObserver overrides.
1598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  virtual void RenderViewDeleted(
16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      RenderViewHost* render_view_host) OVERRIDE {
161effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    DCHECK_CURRENTLY_ON(BrowserThread::UI);
1628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (render_view_host != render_view_host_)
1638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      return;
1648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (dispatcher_.get()) {
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      dispatcher_->ui_thread_response_callback_wrappers_
167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          .erase(render_view_host);
16890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    delete this;
17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ExtensionFunction::ResponseCallback CreateCallback(int request_id) {
17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return base::Bind(
17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        &UIThreadResponseCallbackWrapper::OnExtensionFunctionCompleted,
17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        weak_ptr_factory_.GetWeakPtr(),
17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        request_id);
17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
17990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
18090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) private:
18190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void OnExtensionFunctionCompleted(int request_id,
18290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                    ExtensionFunction::ResponseType type,
18390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                    const base::ListValue& results,
18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                    const std::string& error) {
18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    CommonResponseCallback(
1868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        render_view_host_, render_view_host_->GetRoutingID(),
1878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        render_view_host_->GetProcess()->GetHandle(), request_id, type,
18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        results, error);
18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::WeakPtr<ExtensionFunctionDispatcher> dispatcher_;
1928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  content::RenderViewHost* render_view_host_;
19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::WeakPtrFactory<UIThreadResponseCallbackWrapper> weak_ptr_factory_;
19490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
19590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(UIThreadResponseCallbackWrapper);
19690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
198e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochWindowController*
199e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochExtensionFunctionDispatcher::Delegate::GetExtensionWindowController() const {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)content::WebContents*
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionFunctionDispatcher::Delegate::GetAssociatedWebContents() const {
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochcontent::WebContents*
209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochExtensionFunctionDispatcher::Delegate::GetVisibleWebContents() const {
210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return GetAssociatedWebContents();
211eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionFunctionDispatcher::GetAllFunctionNames(
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<std::string>* names) {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionFunctionRegistry::GetInstance()->GetAllNames(names);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExtensionFunctionDispatcher::OverrideFunction(
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& name, ExtensionFunctionFactory factory) {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ExtensionFunctionRegistry::GetInstance()->OverrideFunction(name,
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                                    factory);
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionFunctionDispatcher::DispatchOnIOThread(
226e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    InfoMap* extension_info_map,
227e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    void* profile_id,
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int render_process_id,
229e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    base::WeakPtr<ExtensionMessageFilter> ipc_sender,
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int routing_id,
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ExtensionHostMsg_Request_Params& params) {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Extension* extension =
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extension_info_map->extensions().GetByID(params.extension_id);
23490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
23590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ExtensionFunction::ResponseCallback callback(
23690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::Bind(&IOThreadResponseCallback, ipc_sender, routing_id,
23790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 params.request_id));
23890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<ExtensionFunction> function(
240e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      CreateExtensionFunction(params,
241e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                              extension,
242e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                              render_process_id,
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              extension_info_map->process_map(),
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              g_global_io_data.Get().api.get(),
245e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                              profile_id,
246e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                              callback));
2473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!function.get())
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IOThreadExtensionFunction* function_io =
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      function->AsIOThreadExtensionFunction();
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!function_io) {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
256868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  function_io->set_ipc_sender(ipc_sender, routing_id);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  function_io->set_extension_info_map(extension_info_map);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  function->set_include_incognito(
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extension_info_map->IsIncognitoEnabled(extension->id()));
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!CheckPermissions(function.get(), extension, params, callback))
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
264e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  QuotaService* quota = extension_info_map->GetQuotaService();
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string violation_error = quota->Assess(extension->id(),
266868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                              function.get(),
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              &params.arguments,
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              base::TimeTicks::Now());
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (violation_error.empty()) {
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<base::ListValue> args(params.arguments.DeepCopy());
271e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    NotifyApiFunctionCalled(extension->id(),
272e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                            params.name,
273e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                            args.Pass(),
274e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                            static_cast<content::BrowserContext*>(profile_id));
275a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    UMA_HISTOGRAM_SPARSE_SLOWLY("Extensions.FunctionCalls",
276a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                                function->histogram_value());
277010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    function->Run()->Execute();
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    function->OnQuotaExceeded(violation_error);
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
283f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(
284f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    content::BrowserContext* browser_context,
285f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    Delegate* delegate)
286a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    : browser_context_(browser_context),
287f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      delegate_(delegate) {
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() {
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionFunctionDispatcher::Dispatch(
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ExtensionHostMsg_Request_Params& params,
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RenderViewHost* render_view_host) {
29690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  UIThreadResponseCallbackWrapperMap::const_iterator
29790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      iter = ui_thread_response_callback_wrappers_.find(render_view_host);
29890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  UIThreadResponseCallbackWrapper* callback_wrapper = NULL;
29990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (iter == ui_thread_response_callback_wrappers_.end()) {
30090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    callback_wrapper = new UIThreadResponseCallbackWrapper(AsWeakPtr(),
30190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                                           render_view_host);
30290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ui_thread_response_callback_wrappers_[render_view_host] = callback_wrapper;
30390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  } else {
30490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    callback_wrapper = iter->second;
30590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
30690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DispatchWithCallbackInternal(
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      params, render_view_host, NULL,
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      callback_wrapper->CreateCallback(params.request_id));
31090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
31190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
31290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ExtensionFunctionDispatcher::DispatchWithCallback(
31390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const ExtensionHostMsg_Request_Params& params,
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    content::RenderFrameHost* render_frame_host,
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ExtensionFunction::ResponseCallback& callback) {
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DispatchWithCallbackInternal(params, NULL, render_frame_host, callback);
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ExtensionFunctionDispatcher::DispatchWithCallbackInternal(
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ExtensionHostMsg_Request_Params& params,
32190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    RenderViewHost* render_view_host,
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    content::RenderFrameHost* render_frame_host,
32390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const ExtensionFunction::ResponseCallback& callback) {
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(render_view_host || render_frame_host);
32590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // TODO(yzshen): There is some shared logic between this method and
32690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // DispatchOnIOThread(). It is nice to deduplicate.
327e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  ProcessMap* process_map = ProcessMap::Get(browser_context_);
328a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!process_map)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
331e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const Extension* extension = registry->enabled_extensions().GetByID(
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      params.extension_id);
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!extension) {
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    extension =
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        registry->enabled_extensions().GetHostedAppByURL(params.source_url);
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int process_id = render_view_host ? render_view_host->GetProcess()->GetID() :
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                      render_frame_host->GetProcess()->GetID();
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<ExtensionFunction> function(
342a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      CreateExtensionFunction(params,
343a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                              extension,
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              process_id,
345a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                              *process_map,
346e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                              ExtensionAPI::GetSharedInstance(),
347a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                              browser_context_,
348a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                              callback));
3493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!function.get())
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UIThreadExtensionFunction* function_ui =
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      function->AsUIThreadExtensionFunction();
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!function_ui) {
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (render_view_host) {
3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    function_ui->SetRenderViewHost(render_view_host);
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    function_ui->SetRenderFrameHost(render_frame_host);
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  function_ui->set_dispatcher(AsWeakPtr());
364a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  function_ui->set_browser_context(browser_context_);
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  function->set_include_incognito(
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ExtensionsBrowserClient::Get()->CanExtensionCrossIncognito(
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          extension, browser_context_));
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!CheckPermissions(function.get(), extension, params, callback))
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ExtensionSystem* extension_system = ExtensionSystem::Get(browser_context_);
373e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  QuotaService* quota = extension_system->quota_service();
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string violation_error = quota->Assess(extension->id(),
375868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                              function.get(),
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              &params.arguments,
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              base::TimeTicks::Now());
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (violation_error.empty()) {
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<base::ListValue> args(params.arguments.DeepCopy());
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3819a3a4bc965704498ea9f22876627cda96ff9a77eBo Liu    // See crbug.com/39178.
3829a3a4bc965704498ea9f22876627cda96ff9a77eBo Liu    ExtensionsBrowserClient::Get()->PermitExternalProtocolHandler();
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    NotifyApiFunctionCalled(
3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        extension->id(), params.name, args.Pass(), browser_context_);
385a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    UMA_HISTOGRAM_SPARSE_SLOWLY("Extensions.FunctionCalls",
386a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                                function->histogram_value());
387010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    function->Run()->Execute();
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    function->OnQuotaExceeded(violation_error);
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note: do not access |this| after this point. We may have been deleted
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // if function->Run() ended up closing the tab that owns us.
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check if extension was uninstalled by management.uninstall.
3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!registry->enabled_extensions().GetByID(params.extension_id))
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We only adjust the keepalive count for UIThreadExtensionFunction for
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // now, largely for simplicity's sake. This is OK because currently, only
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the webRequest API uses IOThreadExtensionFunction, and that API is not
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // compatible with lazy background pages.
403a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  extension_system->process_manager()->IncrementLazyKeepaliveCount(extension);
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionFunctionDispatcher::OnExtensionFunctionCompleted(
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension) {
4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ExtensionSystem::Get(browser_context_)->process_manager()->
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DecrementLazyKeepaliveCount(extension);
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExtensionFunctionDispatcher::CheckPermissions(
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ExtensionFunction* function,
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension,
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ExtensionHostMsg_Request_Params& params,
41790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const ExtensionFunction::ResponseCallback& callback) {
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!function->HasPermission()) {
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Extension " << extension->id() << " does not have "
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << "permission to function: " << params.name;
42190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SendAccessDenied(callback);
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Only COMPONENT hosted apps may call extension APIs, and they are limited
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// to just the permissions they explicitly request. They should not have access
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// to extension APIs like eg chrome.runtime, chrome.windows, etc. that normally
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// are available without permission.
433a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// TODO(mpcomplete): move this to ExtensionFunction::HasPermission (or remove
434a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// it altogether).
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AllowHostedAppAPICall(const Extension& extension,
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           const GURL& source_url,
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           const std::string& function_name) {
438e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (extension.location() != Manifest::COMPONENT)
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!extension.web_extent().MatchesURL(source_url))
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Note: Not BLESSED_WEB_PAGE_CONTEXT here because these component hosted app
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // entities have traditionally been treated as blessed extensions, for better
4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // or worse.
447a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  Feature::Availability availability =
448a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      ExtensionAPI::GetSharedInstance()->IsAvailable(
449a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          function_name, &extension, Feature::BLESSED_EXTENSION_CONTEXT,
450a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          source_url);
451a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return availability.is_available();
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionFunction* ExtensionFunctionDispatcher::CreateExtensionFunction(
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ExtensionHostMsg_Request_Params& params,
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension,
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int requesting_process_id,
462e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const ProcessMap& process_map,
463e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    ExtensionAPI* api,
464e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    void* profile_id,
46590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const ExtensionFunction::ResponseCallback& callback) {
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!extension) {
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Specified extension does not exist.";
46890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SendAccessDenied(callback);
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Most hosted apps can't call APIs.
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool allowed = true;
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (extension->is_hosted_app())
47590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    allowed = AllowHostedAppAPICall(*extension, params.source_url, params.name);
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Privileged APIs can only be called from the process the extension
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // is running in.
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (allowed && api->IsPrivileged(params.name))
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    allowed = process_map.Contains(extension->id(), requesting_process_id);
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!allowed) {
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Extension API call disallowed - name:" << params.name
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               << " pid:" << requesting_process_id
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << " from URL " << params.source_url.spec();
48690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SendAccessDenied(callback);
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionFunction* function =
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ExtensionFunctionRegistry::GetInstance()->NewFunction(params.name);
492c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!function) {
493c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    LOG(ERROR) << "Unknown Extension API - " << params.name;
49490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SendAccessDenied(callback);
495c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return NULL;
496c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
497c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  function->SetArgs(&params.arguments);
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  function->set_source_url(params.source_url);
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  function->set_request_id(params.request_id);
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  function->set_has_callback(params.has_callback);
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  function->set_user_gesture(params.user_gesture);
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  function->set_extension(extension);
504e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  function->set_profile_id(profile_id);
50590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  function->set_response_callback(callback);
5065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  function->set_source_tab_id(params.source_tab_id);
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return function;
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionFunctionDispatcher::SendAccessDenied(
51390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const ExtensionFunction::ResponseCallback& callback) {
5145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::ListValue empty_list;
51590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  callback.Run(ExtensionFunction::FAILED, empty_list,
51690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)               "Access to extension API denied.");
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
518e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
519e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}  // namespace extensions
520