blob: c7b1d8f155408b5afd26e8feb5ae567014fb5eaf [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef EXTENSIONS_BROWSER_EXTENSION_FUNCTION_DISPATCHER_H_
#define EXTENSIONS_BROWSER_EXTENSION_FUNCTION_DISPATCHER_H_
#include <map>
#include <string>
#include <vector>
#include "base/memory/weak_ptr.h"
#include "extensions/browser/extension_function.h"
#include "ipc/ipc_sender.h"
struct ExtensionHostMsg_Request_Params;
namespace content {
class BrowserContext;
class RenderFrameHost;
class WebContents;
}
namespace extensions {
class Extension;
class ExtensionAPI;
class InfoMap;
class IOThreadExtensionMessageFilter;
class ProcessMap;
class WindowController;
// A factory function for creating new ExtensionFunction instances.
typedef ExtensionFunction* (*ExtensionFunctionFactory)();
// ExtensionFunctionDispatcher receives requests to execute functions from
// Chrome extensions running in a RenderFrameHost and dispatches them to the
// appropriate handler. It lives entirely on the UI thread.
//
// ExtensionFunctionDispatcher should be a member of some class that hosts
// RenderFrameHosts and wants them to be able to display extension content.
// This class should also implement ExtensionFunctionDispatcher::Delegate.
//
// Note that a single ExtensionFunctionDispatcher does *not* correspond to a
// single RVH, a single extension, or a single URL. This is by design so that
// we can gracefully handle cases like WebContents, where the RVH, extension,
// and URL can all change over the lifetime of the tab. Instead, these items
// are all passed into each request.
class ExtensionFunctionDispatcher
: public base::SupportsWeakPtr<ExtensionFunctionDispatcher> {
public:
class Delegate {
public:
// Returns the WindowController associated with this delegate, or NULL if no
// window is associated with the delegate.
virtual WindowController* GetExtensionWindowController() const;
// Asks the delegate for any relevant WebContents associated with this
// context. For example, the WebContents in which an infobar or
// chrome-extension://<id> URL are being shown. Callers must check for a
// NULL return value (as in the case of a background page).
virtual content::WebContents* GetAssociatedWebContents() const;
// If the associated web contents is not null, returns that. Otherwise,
// returns the next most relevant visible web contents. Callers must check
// for a NULL return value (as in the case of a background page).
virtual content::WebContents* GetVisibleWebContents() const;
protected:
virtual ~Delegate() {}
};
// Dispatches an IO-thread extension function. Only used for specific
// functions that must be handled on the IO-thread.
static void DispatchOnIOThread(
InfoMap* extension_info_map,
void* profile_id,
int render_process_id,
base::WeakPtr<IOThreadExtensionMessageFilter> ipc_sender,
int routing_id,
const ExtensionHostMsg_Request_Params& params);
// Public constructor. Callers must ensure that:
// - This object outlives any RenderFrameHost's passed to created
// ExtensionFunctions.
explicit ExtensionFunctionDispatcher(
content::BrowserContext* browser_context);
~ExtensionFunctionDispatcher();
// Message handlers.
// The response is sent to the corresponding render view in an
// ExtensionMsg_Response message.
void Dispatch(const ExtensionHostMsg_Request_Params& params,
content::RenderFrameHost* render_frame_host,
int render_process_id);
// Called when an ExtensionFunction is done executing, after it has sent
// a response (if any) to the extension.
void OnExtensionFunctionCompleted(const Extension* extension,
bool is_from_service_worker);
// See the Delegate class for documentation on these methods.
// TODO(devlin): None of these belong here. We should kill
// ExtensionFunctionDispatcher::Delegate.
WindowController* GetExtensionWindowController() const;
content::WebContents* GetAssociatedWebContents() const;
content::WebContents* GetVisibleWebContents() const;
// The BrowserContext that this dispatcher is associated with.
content::BrowserContext* browser_context() { return browser_context_; }
void set_delegate(Delegate* delegate) { delegate_ = delegate; }
private:
// For a given RenderFrameHost instance, UIThreadResponseCallbackWrapper
// creates ExtensionFunction::ResponseCallback instances which send responses
// to the corresponding render view in ExtensionMsg_Response messages.
// This class tracks the lifespan of the RenderFrameHost instance, and will be
// destroyed automatically when it goes away.
class UIThreadResponseCallbackWrapper;
// Same as UIThreadResponseCallbackWrapper above, but applies to an extension
// function from an extension Service Worker.
class UIThreadWorkerResponseCallbackWrapper;
// Key used to store UIThreadWorkerResponseCallbackWrapper in the map
// |ui_thread_response_callback_wrappers_for_worker_|.
struct WorkerResponseCallbackMapKey;
// Helper to check whether an ExtensionFunction has the required permissions.
// This should be called after the function is fully initialized.
// If the check fails, |callback| is run with an access-denied error and false
// is returned. |function| must not be run in that case.
static bool CheckPermissions(
ExtensionFunction* function,
const ExtensionHostMsg_Request_Params& params,
const ExtensionFunction::ResponseCallback& callback);
// Helper to create an ExtensionFunction to handle the function given by
// |params|. Can be called on any thread.
// Does not set subclass properties, or include_incognito.
static ExtensionFunction* CreateExtensionFunction(
const ExtensionHostMsg_Request_Params& params,
const Extension* extension,
int requesting_process_id,
const ProcessMap& process_map,
ExtensionAPI* api,
void* profile_id,
const ExtensionFunction::ResponseCallback& callback);
// Helper to run the response callback with an access denied error. Can be
// called on any thread.
static void SendAccessDenied(
const ExtensionFunction::ResponseCallback& callback,
functions::HistogramValue histogram_value);
void DispatchWithCallbackInternal(
const ExtensionHostMsg_Request_Params& params,
content::RenderFrameHost* render_frame_host,
int render_process_id,
const ExtensionFunction::ResponseCallback& callback);
void RemoveWorkerCallbacksForProcess(int render_process_id);
content::BrowserContext* browser_context_;
Delegate* delegate_;
// This map doesn't own either the keys or the values. When a RenderFrameHost
// instance goes away, the corresponding entry in this map (if exists) will be
// removed.
typedef std::map<content::RenderFrameHost*,
std::unique_ptr<UIThreadResponseCallbackWrapper>>
UIThreadResponseCallbackWrapperMap;
UIThreadResponseCallbackWrapperMap ui_thread_response_callback_wrappers_;
using UIThreadWorkerResponseCallbackWrapperMap =
std::map<WorkerResponseCallbackMapKey,
std::unique_ptr<UIThreadWorkerResponseCallbackWrapper>>;
// TODO(lazyboy): The map entries are cleared upon RenderProcessHost shutown,
// we should really be clearing it on service worker shutdown.
UIThreadWorkerResponseCallbackWrapperMap
ui_thread_response_callback_wrappers_for_worker_;
};
} // namespace extensions
#endif // EXTENSIONS_BROWSER_EXTENSION_FUNCTION_DISPATCHER_H_