diff options
author | mpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-26 22:48:12 +0000 |
---|---|---|
committer | mpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-26 22:48:12 +0000 |
commit | a2aef2ea9d7d923a9c1c768eadd1092ce46b64bf (patch) | |
tree | 5f78f3f4cf0ea1d08ee4eafa0e22118d8486440f /chrome/browser/extensions | |
parent | 5bd4938ab9c427e324933fa3689d2de7bfc4e315 (diff) | |
download | chromium_src-a2aef2ea9d7d923a9c1c768eadd1092ce46b64bf.zip chromium_src-a2aef2ea9d7d923a9c1c768eadd1092ce46b64bf.tar.gz chromium_src-a2aef2ea9d7d923a9c1c768eadd1092ce46b64bf.tar.bz2 |
Split UI-specific bits off ExtensionFunction into a separate class.
This is a precursor to another patch I'm working on, which will add
ExtensionFunctions that can run on the IO thread. The webRequest API will use
this.
I've also done a bit of other cleanup:
- moved almost everything off of {Async,Sync}ExtensionFunction, up into the
base class, since none of it was specific to either of those.
- store Extension directly on ExtensionFunction, rather than needing to look it
up, since it is now refcounted.
BUG=no
TEST=no
Review URL: http://codereview.chromium.org/7073001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@86919 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/extensions')
9 files changed, 224 insertions, 164 deletions
diff --git a/chrome/browser/extensions/extension_bookmark_manager_api.cc b/chrome/browser/extensions/extension_bookmark_manager_api.cc index 6d89d373..d3445fa 100644 --- a/chrome/browser/extensions/extension_bookmark_manager_api.cc +++ b/chrome/browser/extensions/extension_bookmark_manager_api.cc @@ -15,6 +15,7 @@ #include "chrome/browser/extensions/extension_bookmark_helpers.h" #include "chrome/browser/extensions/extension_bookmarks_module_constants.h" #include "chrome/browser/extensions/extension_event_router.h" +#include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/extensions/extension_web_ui.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/chrome_url_data_manager.h" diff --git a/chrome/browser/extensions/extension_bookmarks_module.cc b/chrome/browser/extensions/extension_bookmarks_module.cc index f17ab59..1358ee6 100644 --- a/chrome/browser/extensions/extension_bookmarks_module.cc +++ b/chrome/browser/extensions/extension_bookmarks_module.cc @@ -23,6 +23,7 @@ #include "chrome/browser/extensions/extension_bookmark_helpers.h" #include "chrome/browser/extensions/extension_bookmarks_module_constants.h" #include "chrome/browser/extensions/extension_event_router.h" +#include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/extensions/extensions_quota_service.h" #include "chrome/browser/importer/importer_data_types.h" #include "chrome/browser/importer/importer_host.h" diff --git a/chrome/browser/extensions/extension_debugger_api.h b/chrome/browser/extensions/extension_debugger_api.h index 5fd9d00..6d1642e 100644 --- a/chrome/browser/extensions/extension_debugger_api.h +++ b/chrome/browser/extensions/extension_debugger_api.h @@ -17,6 +17,7 @@ class DictionaryValue; class ExtensionDevToolsClientHost; +class TabContents; class DebuggerFunction : public AsyncExtensionFunction { protected: diff --git a/chrome/browser/extensions/extension_function.cc b/chrome/browser/extensions/extension_function.cc index f390d72..def3edb 100644 --- a/chrome/browser/extensions/extension_function.cc +++ b/chrome/browser/extensions/extension_function.cc @@ -17,15 +17,20 @@ #include "content/common/notification_type.h" #include "content/common/result_codes.h" -ExtensionFunction::RenderViewHostTracker::RenderViewHostTracker( - ExtensionFunction* function) +// static +void ExtensionFunctionDeleteTraits::Destruct(const ExtensionFunction* x) { + x->Destruct(); +} + +UIThreadExtensionFunction::RenderViewHostTracker::RenderViewHostTracker( + UIThreadExtensionFunction* function) : function_(function) { registrar_.Add(this, NotificationType::RENDER_VIEW_HOST_DELETED, Source<RenderViewHost>(function->render_view_host())); } -void ExtensionFunction::RenderViewHostTracker::Observe( +void UIThreadExtensionFunction::RenderViewHostTracker::Observe( NotificationType type, const NotificationSource& source, const NotificationDetails& details) { @@ -37,43 +42,23 @@ void ExtensionFunction::RenderViewHostTracker::Observe( ExtensionFunction::ExtensionFunction() : request_id_(-1), - profile_(NULL), + profile_id_(0), has_callback_(false), include_incognito_(false), - user_gesture_(false) { + user_gesture_(false), + args_(NULL), + bad_message_(false) { } ExtensionFunction::~ExtensionFunction() { } -void ExtensionFunction::SetRenderViewHost(RenderViewHost* render_view_host) { - render_view_host_ = render_view_host; - tracker_.reset(render_view_host ? new RenderViewHostTracker(this) : NULL); -} - -const Extension* ExtensionFunction::GetExtension() { - ExtensionService* service = profile_->GetExtensionService(); - DCHECK(service); - return service->GetExtensionById(extension_id_, false); -} - -Browser* ExtensionFunction::GetCurrentBrowser() { - return dispatcher()->GetCurrentBrowser(render_view_host_, include_incognito_); -} - -AsyncExtensionFunction::AsyncExtensionFunction() - : args_(NULL), bad_message_(false) { -} - -AsyncExtensionFunction::~AsyncExtensionFunction() { -} - -void AsyncExtensionFunction::SetArgs(const ListValue* args) { +void ExtensionFunction::SetArgs(const ListValue* args) { DCHECK(!args_.get()); // Should only be called once. args_.reset(args->DeepCopy()); } -const std::string AsyncExtensionFunction::GetResult() { +const std::string ExtensionFunction::GetResult() { std::string json; // Some functions might not need to return any results. if (result_.get()) @@ -81,16 +66,42 @@ const std::string AsyncExtensionFunction::GetResult() { return json; } -const std::string AsyncExtensionFunction::GetError() { +const std::string ExtensionFunction::GetError() { return error_; } -void AsyncExtensionFunction::Run() { +void ExtensionFunction::Run() { if (!RunImpl()) SendResponse(false); } -void AsyncExtensionFunction::SendResponse(bool success) { +bool ExtensionFunction::HasOptionalArgument(size_t index) { + Value* value; + return args_->Get(index, &value) && !value->IsType(Value::TYPE_NULL); +} + +UIThreadExtensionFunction::UIThreadExtensionFunction() + : profile_(NULL) { +} + +UIThreadExtensionFunction::~UIThreadExtensionFunction() { +} + +void UIThreadExtensionFunction::Destruct() const { + BrowserThread::DeleteOnUIThread::Destruct(this); +} + +void UIThreadExtensionFunction::SetRenderViewHost( + RenderViewHost* render_view_host) { + render_view_host_ = render_view_host; + tracker_.reset(render_view_host ? new RenderViewHostTracker(this) : NULL); +} + +Browser* UIThreadExtensionFunction::GetCurrentBrowser() { + return dispatcher()->GetCurrentBrowser(render_view_host_, include_incognito_); +} + +void UIThreadExtensionFunction::SendResponse(bool success) { if (!render_view_host_ || !dispatcher()) return; if (bad_message_) { @@ -103,7 +114,7 @@ void AsyncExtensionFunction::SendResponse(bool success) { GetResult(), GetError())); } -void AsyncExtensionFunction::HandleBadMessage() { +void UIThreadExtensionFunction::HandleBadMessage() { LOG(ERROR) << "bad extension message " << name_ << " : terminating renderer."; if (RenderProcessHost::run_renderer_in_process()) { // In single process mode it is better if we don't suicide but just crash. @@ -111,14 +122,17 @@ void AsyncExtensionFunction::HandleBadMessage() { } else { NOTREACHED(); UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_EFD")); - base::KillProcess(render_view_host_->process()->GetHandle(), - ResultCodes::KILLED_BAD_MESSAGE, false); + if (render_view_host_) { + base::KillProcess(render_view_host_->process()->GetHandle(), + ResultCodes::KILLED_BAD_MESSAGE, false); + } } } -bool AsyncExtensionFunction::HasOptionalArgument(size_t index) { - Value* value; - return args_->Get(index, &value) && !value->IsType(Value::TYPE_NULL); +AsyncExtensionFunction::AsyncExtensionFunction() { +} + +AsyncExtensionFunction::~AsyncExtensionFunction() { } SyncExtensionFunction::SyncExtensionFunction() { diff --git a/chrome/browser/extensions/extension_function.h b/chrome/browser/extensions/extension_function.h index aed4dda..6e28775 100644 --- a/chrome/browser/extensions/extension_function.h +++ b/chrome/browser/extensions/extension_function.h @@ -11,15 +11,19 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" -#include "chrome/browser/extensions/extension_function_dispatcher.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/common/extensions/extension.h" #include "content/browser/browser_thread.h" #include "content/common/notification_observer.h" #include "content/common/notification_registrar.h" +class Browser; +class ExtensionFunction; class ExtensionFunctionDispatcher; +class UIThreadExtensionFunction; class ListValue; -class Profile; class QuotaLimitHeuristic; +class RenderViewHost; class Value; #define EXTENSION_FUNCTION_VALIDATE(test) do { \ @@ -38,56 +42,59 @@ class Value; #define DECLARE_EXTENSION_FUNCTION_NAME(name) \ public: static const char* function_name() { return name; } +// Traits that describe how ExtensionFunction should be deleted. This just calls +// the virtual "Destruct" method on ExtensionFunction, allowing derived classes +// to override the behavior. +struct ExtensionFunctionDeleteTraits { + public: + static void Destruct(const ExtensionFunction* x); +}; + // Abstract base class for extension functions the ExtensionFunctionDispatcher // knows how to dispatch to. class ExtensionFunction : public base::RefCountedThreadSafe<ExtensionFunction, - BrowserThread::DeleteOnUIThread> { + ExtensionFunctionDeleteTraits> { public: ExtensionFunction(); - virtual ~ExtensionFunction(); - - // Specifies the name of the function. - void set_name(const std::string& name) { name_ = name; } - const std::string name() const { return name_; } - - // Set the profile which contains the extension that has originated this - // function call. - void set_profile(Profile* profile) { profile_ = profile; } - Profile* profile() const { return profile_; } - - // Set the id of this function call's extension. - void set_extension_id(std::string extension_id) { - extension_id_ = extension_id; + virtual UIThreadExtensionFunction* AsUIThreadExtensionFunction() { + return NULL; } - std::string extension_id() const { return extension_id_; } - void SetRenderViewHost(RenderViewHost* render_view_host); - RenderViewHost* render_view_host() const { return render_view_host_; } + // Execute the API. Clients should initialize the ExtensionFunction using + // SetArgs(), set_request_id(), and the other setters before calling this + // method. Derived classes should be ready to return GetResult() and + // GetError() before returning from this function. + // Note that once Run() returns, dispatcher() can be NULL, so be sure to + // NULL-check. + virtual void Run(); + + // Returns a quota limit heuristic suitable for this function. + // No quota limiting by default. + virtual void GetQuotaLimitHeuristics( + std::list<QuotaLimitHeuristic*>* heuristics) const {} // Specifies the raw arguments to the function, as a JSON value. - virtual void SetArgs(const ListValue* args) = 0; + virtual void SetArgs(const ListValue* args); // Retrieves the results of the function as a JSON-encoded string (may // be empty). - virtual const std::string GetResult() = 0; + virtual const std::string GetResult(); // Retrieves any error string from the function. - virtual const std::string GetError() = 0; + virtual const std::string GetError(); - // Returns a quota limit heuristic suitable for this function. - // No quota limiting by default. - virtual void GetQuotaLimitHeuristics( - std::list<QuotaLimitHeuristic*>* heuristics) const {} + // Specifies the name of the function. + void set_name(const std::string& name) { name_ = name; } + const std::string& name() const { return name_; } - void set_dispatcher( - const base::WeakPtr<ExtensionFunctionDispatcher>& dispatcher) { - dispatcher_ = dispatcher; - } - ExtensionFunctionDispatcher* dispatcher() const { - return dispatcher_.get(); - } + void set_profile_id(ProfileId profile_id) { profile_id_ = profile_id; } + ProfileId profile_id() const { return profile_id_; } + + void set_extension(const Extension* extension) { extension_ = extension; } + const Extension* GetExtension() const { return extension_.get(); } + const std::string& extension_id() const { return extension_->id(); } void set_request_id(int request_id) { request_id_ = request_id; } int request_id() { return request_id_; } @@ -104,19 +111,110 @@ class ExtensionFunction void set_user_gesture(bool user_gesture) { user_gesture_ = user_gesture; } bool user_gesture() const { return user_gesture_; } - // Execute the API. Clients should call set_raw_args() and - // set_request_id() before calling this method. Derived classes should be - // ready to return raw_result() and error() before returning from this - // function. - virtual void Run() = 0; + protected: + friend struct ExtensionFunctionDeleteTraits; + + virtual ~ExtensionFunction(); + + // Helper method for ExtensionFunctionDeleteTraits. Deletes this object. + virtual void Destruct() const = 0; + + // Derived classes should implement this method to do their work and return + // success/failure. + virtual bool RunImpl() = 0; + + // Sends the result back to the extension. + virtual void SendResponse(bool success) = 0; + + // Called when we receive an extension api request that is invalid in a way + // that JSON validation in the renderer should have caught. This should never + // happen and could be an attacker trying to exploit the browser, so we crash + // the renderer instead. + virtual void HandleBadMessage() = 0; + + // Return true if the argument to this function at |index| was provided and + // is non-null. + bool HasOptionalArgument(size_t index); + + // Id of this request, used to map the response back to the caller. + int request_id_; + + // The ID of the Profile of this function's extension. + ProfileId profile_id_; + + // The extension that called this function. + scoped_refptr<const Extension> extension_; + + // The name of this function. + std::string name_; + + // The URL of the frame which is making this request + GURL source_url_; + + // True if the js caller provides a callback function to receive the response + // of this call. + bool has_callback_; + + // True if this callback should include information from incognito contexts + // even if our profile_ is non-incognito. Note that in the case of a "split" + // mode extension, this will always be false, and we will limit access to + // data from within the same profile_ (either incognito or not). + bool include_incognito_; + + // True if the call was made in response of user gesture. + bool user_gesture_; + + // The arguments to the API. Only non-null if argument were specified. + scoped_ptr<ListValue> args_; + + // The result of the API. This should be populated by the derived class before + // SendResponse() is called. + scoped_ptr<Value> result_; + + // Any detailed error from the API. This should be populated by the derived + // class before Run() returns. + std::string error_; + + // Any class that gets a malformed message should set this to true before + // returning. The calling renderer process will be killed. + bool bad_message_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionFunction); +}; + +// Extension functions that run on the UI thread. Most functions fall into +// this category. +class UIThreadExtensionFunction : public ExtensionFunction { + public: + UIThreadExtensionFunction(); + + virtual UIThreadExtensionFunction* AsUIThreadExtensionFunction() OVERRIDE { + return this; + } + + // Set the profile which contains the extension that has originated this + // function call. + void set_profile(Profile* profile) { profile_ = profile; } + Profile* profile() const { return profile_; } + + void SetRenderViewHost(RenderViewHost* render_view_host); + RenderViewHost* render_view_host() const { return render_view_host_; } + + void set_dispatcher( + const base::WeakPtr<ExtensionFunctionDispatcher>& dispatcher) { + dispatcher_ = dispatcher; + } + ExtensionFunctionDispatcher* dispatcher() const { + return dispatcher_.get(); + } protected: - friend class base::RefCountedThreadSafe<ExtensionFunction>; + template<BrowserThread::ID id> friend struct BrowserThread::DeleteOnThread; + friend class DeleteTask<UIThreadExtensionFunction>; + + virtual ~UIThreadExtensionFunction(); - // Gets the extension that called this function. This can return NULL for - // async functions, for example if the extension is unloaded while the - // function is running. - const Extension* GetExtension(); + virtual void SendResponse(bool success); // Gets the "current" browser, if any. // @@ -142,34 +240,9 @@ class ExtensionFunction // The RenderViewHost we will send responses too. RenderViewHost* render_view_host_; - // Id of this request, used to map the response back to the caller. - int request_id_; - // The Profile of this function's extension. Profile* profile_; - // The id of this function's extension. - std::string extension_id_; - - // The name of this function. - std::string name_; - - // The URL of the frame which is making this request - GURL source_url_; - - // True if the js caller provides a callback function to receive the response - // of this call. - bool has_callback_; - - // True if this callback should include information from incognito contexts - // even if our profile_ is non-incognito. Note that in the case of a "split" - // mode extension, this will always be false, and we will limit access to - // data from within the same profile_ (either incognito or not). - bool include_incognito_; - - // True if the call was made in response of user gesture. - bool user_gesture_; - private: // Helper class to track the lifetime of ExtensionFunction's RenderViewHost // pointer and NULL it out when it dies. We use this separate class (instead @@ -179,71 +252,31 @@ class ExtensionFunction // method. class RenderViewHostTracker : public NotificationObserver { public: - explicit RenderViewHostTracker(ExtensionFunction* extension_function); + explicit RenderViewHostTracker(UIThreadExtensionFunction* function); private: virtual void Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details); - ExtensionFunction* function_; + UIThreadExtensionFunction* function_; NotificationRegistrar registrar_; }; + virtual void HandleBadMessage(); + + virtual void Destruct() const; + scoped_ptr<RenderViewHostTracker> tracker_; - DISALLOW_COPY_AND_ASSIGN(ExtensionFunction); }; // Base class for an extension function that runs asynchronously *relative to // the browser's UI thread*. -// Note that once Run() returns, dispatcher() can be NULL, so be sure to -// NULL-check. -// TODO(aa) Remove this extra level of inheritance once the browser stops -// parsing JSON (and instead uses custom serialization of Value objects). -class AsyncExtensionFunction : public ExtensionFunction { +class AsyncExtensionFunction : public UIThreadExtensionFunction { public: AsyncExtensionFunction(); - virtual void SetArgs(const ListValue* args); - virtual const std::string GetResult(); - virtual const std::string GetError(); - virtual void Run(); - - // Derived classes should implement this method to do their work and return - // success/failure. - virtual bool RunImpl() = 0; - protected: virtual ~AsyncExtensionFunction(); - - void SendResponse(bool success); - - // Return true if the argument to this function at |index| was provided and - // is non-null. - bool HasOptionalArgument(size_t index); - - // The arguments to the API. Only non-null if argument were specified. - scoped_ptr<ListValue> args_; - - // The result of the API. This should be populated by the derived class before - // SendResponse() is called. - scoped_ptr<Value> result_; - - // Any detailed error from the API. This should be populated by the derived - // class before Run() returns. - std::string error_; - - // Any class that gets a malformed message should set this to true before - // returning. The calling renderer process will be killed. - bool bad_message_; - - private: - // Called when we receive an extension api request that is invalid in a way - // that JSON validation in the renderer should have caught. This should never - // happen and could be an attacker trying to exploit the browser, so we crash - // the renderer instead. - void HandleBadMessage(); - - DISALLOW_COPY_AND_ASSIGN(AsyncExtensionFunction); }; // A SyncExtensionFunction is an ExtensionFunction that runs synchronously @@ -253,15 +286,11 @@ class AsyncExtensionFunction : public ExtensionFunction { // // This kind of function is convenient for implementing simple APIs that just // need to interact with things on the browser UI thread. -class SyncExtensionFunction : public AsyncExtensionFunction { +class SyncExtensionFunction : public UIThreadExtensionFunction { public: SyncExtensionFunction(); - // Derived classes should implement this method to do their work and return - // success/failure. - virtual bool RunImpl() = 0; - - virtual void Run(); + virtual void Run() OVERRIDE; protected: virtual ~SyncExtensionFunction(); diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc index 2329ae7..a19b839 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.cc +++ b/chrome/browser/extensions/extension_function_dispatcher.cc @@ -479,10 +479,18 @@ void ExtensionFunctionDispatcher::Dispatch( scoped_refptr<ExtensionFunction> function( FactoryRegistry::GetInstance()->NewFunction(params.name)); - function->SetRenderViewHost(render_view_host); - function->set_dispatcher(AsWeakPtr()); - function->set_profile(profile_); - function->set_extension_id(extension->id()); + UIThreadExtensionFunction* function_ui = + function->AsUIThreadExtensionFunction(); + if (!function_ui) { + NOTREACHED(); + return; + } + function_ui->SetRenderViewHost(render_view_host); + function_ui->set_dispatcher(AsWeakPtr()); + function_ui->set_profile(profile_); + + function->set_profile_id(profile_->GetRuntimeId()); + function->set_extension(extension); function->SetArgs(¶ms.arguments); function->set_source_url(params.source_url); function->set_request_id(params.request_id); diff --git a/chrome/browser/extensions/extension_test_api.cc b/chrome/browser/extensions/extension_test_api.cc index 2309feb..e5bc60f 100644 --- a/chrome/browser/extensions/extension_test_api.cc +++ b/chrome/browser/extensions/extension_test_api.cc @@ -8,6 +8,7 @@ #include "base/memory/singleton.h" #include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/extensions/extensions_quota_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" diff --git a/chrome/browser/extensions/extension_webstore_private_api.cc b/chrome/browser/extensions/extension_webstore_private_api.cc index a38d867..4cbdb93 100644 --- a/chrome/browser/extensions/extension_webstore_private_api.cc +++ b/chrome/browser/extensions/extension_webstore_private_api.cc @@ -12,6 +12,7 @@ #include "base/values.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/crx_installer.h" +#include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/extensions/extension_install_dialog.h" #include "chrome/browser/extensions/extension_prefs.h" #include "chrome/browser/extensions/extension_service.h" diff --git a/chrome/browser/extensions/extensions_quota_service_unittest.cc b/chrome/browser/extensions/extensions_quota_service_unittest.cc index 63eedb1..39cd64e3 100644 --- a/chrome/browser/extensions/extensions_quota_service_unittest.cc +++ b/chrome/browser/extensions/extensions_quota_service_unittest.cc @@ -56,6 +56,10 @@ class MockFunction : public ExtensionFunction { virtual const std::string GetError() { return std::string(); } virtual const std::string GetResult() { return std::string(); } virtual void Run() {} + virtual void Destruct() const { delete this; } + virtual bool RunImpl() { return true; } + virtual void SendResponse(bool) { } + virtual void HandleBadMessage() { } }; class TimedLimitMockFunction : public MockFunction { |