#include "extensions/browser/extension_function.h"
#include "base/logging.h"
-#include "base/metrics/sparse_histogram.h"
-#include "chrome/browser/extensions/extension_function_dispatcher.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/renderer_host/chrome_render_message_filter.h"
-#include "chrome/common/extensions/extension_messages.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
+#include "extensions/browser/extension_function_dispatcher.h"
+#include "extensions/browser/extension_message_filter.h"
+#include "extensions/common/error_utils.h"
#include "extensions/common/extension_api.h"
+#include "extensions/common/extension_messages.h"
using content::BrowserThread;
using content::RenderViewHost;
using content::WebContents;
+using extensions::ErrorUtils;
using extensions::ExtensionAPI;
using extensions::Feature;
+namespace {
+
+class ArgumentListResponseValue
+ : public ExtensionFunction::ResponseValueObject {
+ public:
+ ArgumentListResponseValue(const std::string& function_name,
+ const char* title,
+ ExtensionFunction* function,
+ scoped_ptr<base::ListValue> result)
+ : function_name_(function_name), title_(title) {
+ if (function->GetResultList()) {
+ DCHECK_EQ(function->GetResultList(), result.get())
+ << "The result set on this function (" << function_name_ << ") "
+ << "either by calling SetResult() or directly modifying |result_| is "
+ << "different to the one passed to " << title_ << "(). "
+ << "The best way to fix this problem is to exclusively use " << title_
+ << "(). SetResult() and |result_| are deprecated.";
+ } else {
+ function->SetResultList(result.Pass());
+ }
+ // It would be nice to DCHECK(error.empty()) but some legacy extension
+ // function implementations... I'm looking at chrome.input.ime... do this
+ // for some reason.
+ }
+
+ virtual ~ArgumentListResponseValue() {}
+
+ virtual bool Apply() OVERRIDE { return true; }
+
+ private:
+ std::string function_name_;
+ const char* title_;
+};
+
+class ErrorResponseValue : public ExtensionFunction::ResponseValueObject {
+ public:
+ ErrorResponseValue(ExtensionFunction* function, const std::string& error) {
+ // It would be nice to DCHECK(!error.empty()) but too many legacy extension
+ // function implementations don't set error but signal failure.
+ function->SetError(error);
+ }
+
+ virtual ~ErrorResponseValue() {}
+
+ virtual bool Apply() OVERRIDE { return false; }
+};
+
+class BadMessageResponseValue : public ExtensionFunction::ResponseValueObject {
+ public:
+ explicit BadMessageResponseValue(ExtensionFunction* function) {
+ function->set_bad_message(true);
+ NOTREACHED() << function->name() << ": bad message";
+ }
+
+ virtual ~BadMessageResponseValue() {}
+
+ virtual bool Apply() OVERRIDE { return false; }
+};
+
+class RespondNowAction : public ExtensionFunction::ResponseActionObject {
+ public:
+ typedef base::Callback<void(bool)> SendResponseCallback;
+ RespondNowAction(ExtensionFunction::ResponseValue result,
+ const SendResponseCallback& send_response)
+ : result_(result.Pass()), send_response_(send_response) {}
+ virtual ~RespondNowAction() {}
+
+ virtual void Execute() OVERRIDE { send_response_.Run(result_->Apply()); }
+
+ private:
+ ExtensionFunction::ResponseValue result_;
+ SendResponseCallback send_response_;
+};
+
+class RespondLaterAction : public ExtensionFunction::ResponseActionObject {
+ public:
+ virtual ~RespondLaterAction() {}
+
+ virtual void Execute() OVERRIDE {}
+};
+
+} // namespace
+
// static
void ExtensionFunctionDeleteTraits::Destruct(const ExtensionFunction* x) {
x->Destruct();
function_->SetRenderFrameHost(NULL);
}
+ virtual bool OnMessageReceived(
+ const IPC::Message& message,
+ content::RenderFrameHost* render_frame_host) OVERRIDE {
+ DCHECK(render_frame_host);
+ if (render_frame_host == function_->render_frame_host())
+ return function_->OnMessageReceived(message);
+ else
+ return false;
+ }
+
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
return function_->OnMessageReceived(message);
}
user_gesture_(false),
bad_message_(false),
histogram_value_(extensions::functions::UNKNOWN),
- source_tab_id_(-1) {
+ source_tab_id_(-1),
+ source_context_type_(Feature::UNSPECIFIED_CONTEXT) {
}
ExtensionFunction::~ExtensionFunction() {
bool ExtensionFunction::HasPermission() {
Feature::Availability availability =
ExtensionAPI::GetSharedInstance()->IsAvailable(
- name_, extension_, Feature::BLESSED_EXTENSION_CONTEXT, source_url());
+ name_, extension_, source_context_type_, source_url());
return availability.is_available();
}
results_->Append(result);
}
-const base::ListValue* ExtensionFunction::GetResultList() {
+void ExtensionFunction::SetResultList(scoped_ptr<base::ListValue> results) {
+ results_ = results.Pass();
+}
+
+const base::ListValue* ExtensionFunction::GetResultList() const {
return results_.get();
}
-const std::string ExtensionFunction::GetError() {
+std::string ExtensionFunction::GetError() const {
return error_;
}
error_ = error;
}
-void ExtensionFunction::Run() {
- UMA_HISTOGRAM_SPARSE_SLOWLY("Extensions.FunctionCalls", histogram_value());
+ExtensionFunction::ResponseValue ExtensionFunction::NoArguments() {
+ return ResponseValue(new ArgumentListResponseValue(
+ name(), "NoArguments", this, make_scoped_ptr(new base::ListValue())));
+}
+
+ExtensionFunction::ResponseValue ExtensionFunction::OneArgument(
+ base::Value* arg) {
+ scoped_ptr<base::ListValue> args(new base::ListValue());
+ args->Append(arg);
+ return ResponseValue(
+ new ArgumentListResponseValue(name(), "OneArgument", this, args.Pass()));
+}
+
+ExtensionFunction::ResponseValue ExtensionFunction::TwoArguments(
+ base::Value* arg1,
+ base::Value* arg2) {
+ scoped_ptr<base::ListValue> args(new base::ListValue());
+ args->Append(arg1);
+ args->Append(arg2);
+ return ResponseValue(
+ new ArgumentListResponseValue(name(), "TwoArguments", this, args.Pass()));
+}
+
+ExtensionFunction::ResponseValue ExtensionFunction::ArgumentList(
+ scoped_ptr<base::ListValue> args) {
+ return ResponseValue(
+ new ArgumentListResponseValue(name(), "ArgumentList", this, args.Pass()));
+}
+
+ExtensionFunction::ResponseValue ExtensionFunction::Error(
+ const std::string& error) {
+ return ResponseValue(new ErrorResponseValue(this, error));
+}
+
+ExtensionFunction::ResponseValue ExtensionFunction::Error(
+ const std::string& format,
+ const std::string& s1) {
+ return ResponseValue(
+ new ErrorResponseValue(this, ErrorUtils::FormatErrorMessage(format, s1)));
+}
+
+ExtensionFunction::ResponseValue ExtensionFunction::Error(
+ const std::string& format,
+ const std::string& s1,
+ const std::string& s2) {
+ return ResponseValue(new ErrorResponseValue(
+ this, ErrorUtils::FormatErrorMessage(format, s1, s2)));
+}
+
+ExtensionFunction::ResponseValue ExtensionFunction::Error(
+ const std::string& format,
+ const std::string& s1,
+ const std::string& s2,
+ const std::string& s3) {
+ return ResponseValue(new ErrorResponseValue(
+ this, ErrorUtils::FormatErrorMessage(format, s1, s2, s3)));
+}
+
+ExtensionFunction::ResponseValue ExtensionFunction::BadMessage() {
+ return ResponseValue(new BadMessageResponseValue(this));
+}
+
+ExtensionFunction::ResponseAction ExtensionFunction::RespondNow(
+ ResponseValue result) {
+ return ResponseAction(new RespondNowAction(
+ result.Pass(), base::Bind(&ExtensionFunction::SendResponse, this)));
+}
+
+ExtensionFunction::ResponseAction ExtensionFunction::RespondLater() {
+ return ResponseAction(new RespondLaterAction());
+}
+
+// static
+ExtensionFunction::ResponseAction ExtensionFunction::ValidationFailure(
+ ExtensionFunction* function) {
+ return function->RespondNow(function->BadMessage());
+}
- if (!RunImpl())
- SendResponse(false);
+void ExtensionFunction::Respond(ResponseValue result) {
+ SendResponse(result->Apply());
}
bool ExtensionFunction::ShouldSkipQuotaLimiting() const {
response_callback_.Run(type, *results_, GetError());
}
+void ExtensionFunction::OnRespondingLater(ResponseValue value) {
+ SendResponse(value->Apply());
+}
+
UIThreadExtensionFunction::UIThreadExtensionFunction()
: render_view_host_(NULL),
render_frame_host_(NULL),
UIThreadExtensionFunction::~UIThreadExtensionFunction() {
if (dispatcher() && render_view_host())
- dispatcher()->OnExtensionFunctionCompleted(GetExtension());
+ dispatcher()->OnExtensionFunctionCompleted(extension());
}
UIThreadExtensionFunction*
delegate_->OnSendResponse(this, success, bad_message_);
else
SendResponseImpl(success);
+
+ if (!transferred_blob_uuids_.empty()) {
+ DCHECK(!delegate_) << "Blob transfer not supported with test delegate.";
+ GetIPCSender()->Send(
+ new ExtensionMsg_TransferBlobs(transferred_blob_uuids_));
+ }
+}
+
+void UIThreadExtensionFunction::SetTransferredBlobUUIDs(
+ const std::vector<std::string>& blob_uuids) {
+ DCHECK(transferred_blob_uuids_.empty()); // Should only be called once.
+ transferred_blob_uuids_ = blob_uuids;
}
void UIThreadExtensionFunction::WriteToConsole(
content::ConsoleMessageLevel level,
const std::string& message) {
- if (render_view_host_) {
- render_view_host_->Send(new ExtensionMsg_AddMessageToConsole(
- render_view_host_->GetRoutingID(), level, message));
- } else {
- render_frame_host_->Send(new ExtensionMsg_AddMessageToConsole(
- render_frame_host_->GetRoutingID(), level, message));
- }
+ GetIPCSender()->Send(
+ new ExtensionMsg_AddMessageToConsole(GetRoutingID(), level, message));
+}
+
+IPC::Sender* UIThreadExtensionFunction::GetIPCSender() {
+ if (render_view_host_)
+ return render_view_host_;
+ else
+ return render_frame_host_;
+}
+
+int UIThreadExtensionFunction::GetRoutingID() {
+ if (render_view_host_)
+ return render_view_host_->GetRoutingID();
+ else
+ return render_frame_host_->GetRoutingID();
}
IOThreadExtensionFunction::IOThreadExtensionFunction()
AsyncExtensionFunction::~AsyncExtensionFunction() {
}
+ExtensionFunction::ResponseAction AsyncExtensionFunction::Run() {
+ return RunAsync() ? RespondLater() : RespondNow(Error(error_));
+}
+
+// static
+bool AsyncExtensionFunction::ValidationFailure(
+ AsyncExtensionFunction* function) {
+ return false;
+}
+
SyncExtensionFunction::SyncExtensionFunction() {
}
SyncExtensionFunction::~SyncExtensionFunction() {
}
-void SyncExtensionFunction::Run() {
- SendResponse(RunImpl());
+ExtensionFunction::ResponseAction SyncExtensionFunction::Run() {
+ return RespondNow(RunSync() ? ArgumentList(results_.Pass()) : Error(error_));
+}
+
+// static
+bool SyncExtensionFunction::ValidationFailure(SyncExtensionFunction* function) {
+ return false;
}
SyncIOThreadExtensionFunction::SyncIOThreadExtensionFunction() {
SyncIOThreadExtensionFunction::~SyncIOThreadExtensionFunction() {
}
-void SyncIOThreadExtensionFunction::Run() {
- SendResponse(RunImpl());
+ExtensionFunction::ResponseAction SyncIOThreadExtensionFunction::Run() {
+ return RespondNow(RunSync() ? ArgumentList(results_.Pass()) : Error(error_));
+}
+
+// static
+bool SyncIOThreadExtensionFunction::ValidationFailure(
+ SyncIOThreadExtensionFunction* function) {
+ return false;
}