Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(196)

Unified Diff: extensions/renderer/bindings/argument_spec.cc

Issue 2947223003: [Extensions Bindings] Consider argument type more in signature parsing (Closed)
Patch Set: rebase Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: extensions/renderer/bindings/argument_spec.cc
diff --git a/extensions/renderer/bindings/argument_spec.cc b/extensions/renderer/bindings/argument_spec.cc
index cd105bff336f5b4285611f25b0bf4edec412c4d1..0c4e3bad3d64f4cf835fd6b34dab19933df8bc45 100644
--- a/extensions/renderer/bindings/argument_spec.cc
+++ b/extensions/renderer/bindings/argument_spec.cc
@@ -205,76 +205,122 @@ void ArgumentSpec::InitializeType(const base::DictionaryValue* dict) {
ArgumentSpec::~ArgumentSpec() {}
-bool ArgumentSpec::ParseArgument(v8::Local<v8::Context> context,
- v8::Local<v8::Value> value,
+bool ArgumentSpec::IsCorrectType(v8::Local<v8::Value> value,
const APITypeReferenceMap& refs,
- std::unique_ptr<base::Value>* out_value,
std::string* error) const {
- if (type_ == ArgumentType::FUNCTION) {
- if (!value->IsFunction()) {
- *error = GetInvalidTypeError(value);
- return false;
- }
+ bool is_valid_type = false;
- if (out_value) {
- // Certain APIs (contextMenus) have functions as parameters other than the
- // callback (contextMenus uses it for an onclick listener). Our generated
- // types have adapted to consider functions "objects" and serialize them
- // as dictionaries.
- // TODO(devlin): It'd be awfully nice to get rid of this eccentricity.
- *out_value = base::MakeUnique<base::DictionaryValue>();
+ switch (type_) {
+ case ArgumentType::INTEGER:
+ is_valid_type = value->IsInt32();
+ break;
+ case ArgumentType::DOUBLE:
+ is_valid_type = value->IsNumber();
+ break;
+ case ArgumentType::BOOLEAN:
+ is_valid_type = value->IsBoolean();
+ break;
+ case ArgumentType::STRING:
+ is_valid_type = value->IsString();
+ break;
+ case ArgumentType::OBJECT:
+ // Don't allow functions or arrays (even though they are technically
+ // objects). This is to make it easier to match otherwise-ambiguous
+ // signatures. For instance, if an API method has an optional object
+ // parameter and then an optional callback, we wouldn't necessarily be
+ // able to match the arguments if we allowed functions as objects.
+ // TODO(devlin): What about other subclasses of Object, like Map and Set?
+ is_valid_type =
+ value->IsObject() && !value->IsFunction() && !value->IsArray();
+ break;
+ case ArgumentType::LIST:
+ is_valid_type = value->IsArray();
+ break;
+ case ArgumentType::BINARY:
+ is_valid_type = value->IsArrayBuffer() || value->IsArrayBufferView();
+ break;
+ case ArgumentType::FUNCTION:
+ is_valid_type = value->IsFunction();
+ break;
+ case ArgumentType::ANY:
+ is_valid_type = true;
+ break;
+ case ArgumentType::REF: {
+ DCHECK(ref_);
+ const ArgumentSpec* reference = refs.GetSpec(ref_.value());
+ DCHECK(reference) << ref_.value();
+ is_valid_type = reference->IsCorrectType(value, refs, error);
+ break;
}
- return true;
+ case ArgumentType::CHOICES:
+ for (const auto& choice : choices_) {
+ if (choice->IsCorrectType(value, refs, error)) {
+ is_valid_type = true;
+ break;
+ }
+ }
+ break;
}
- if (type_ == ArgumentType::REF) {
- DCHECK(ref_);
- const ArgumentSpec* reference = refs.GetSpec(ref_.value());
- DCHECK(reference) << ref_.value();
- return reference->ParseArgument(context, value, refs, out_value, error);
- }
+ if (!is_valid_type)
+ *error = GetInvalidTypeError(value);
+ return is_valid_type;
+}
- if (type_ == ArgumentType::CHOICES) {
- for (const auto& choice : choices_) {
- if (choice->ParseArgument(context, value, refs, out_value, error))
- return true;
- }
- *error = api_errors::InvalidChoice();
+bool ArgumentSpec::ParseArgument(v8::Local<v8::Context> context,
+ v8::Local<v8::Value> value,
+ const APITypeReferenceMap& refs,
+ std::unique_ptr<base::Value>* out_value,
+ std::string* error) const {
+ // Note: for top-level arguments (i.e., those passed directly to the function,
+ // as opposed to a property on an object, or the item of an array), we will
+ // have already checked the type. Doing so again should be nearly free, but
+ // if we do find this to be an issue, we could avoid the second call.
+ if (!IsCorrectType(value, refs, error))
return false;
- }
- if (IsFundamentalType())
- return ParseArgumentToFundamental(context, value, out_value, error);
- if (type_ == ArgumentType::OBJECT) {
- // Don't allow functions or arrays (even though they are technically
- // objects). This is to make it easier to match otherwise-ambiguous
- // signatures. For instance, if an API method has an optional object
- // parameter and then an optional callback, we wouldn't necessarily be able
- // to match the arguments if we allowed functions as objects.
- if (!value->IsObject() || value->IsFunction() || value->IsArray()) {
- *error = GetInvalidTypeError(value);
- return false;
- }
- v8::Local<v8::Object> object = value.As<v8::Object>();
- return ParseArgumentToObject(context, object, refs, out_value, error);
- }
- if (type_ == ArgumentType::LIST) {
- if (!value->IsArray()) {
- *error = GetInvalidTypeError(value);
- return false;
+ switch (type_) {
+ case ArgumentType::INTEGER:
+ case ArgumentType::DOUBLE:
+ case ArgumentType::BOOLEAN:
+ case ArgumentType::STRING:
+ return ParseArgumentToFundamental(context, value, out_value, error);
+ case ArgumentType::OBJECT:
+ return ParseArgumentToObject(context, value.As<v8::Object>(), refs,
+ out_value, error);
+ case ArgumentType::LIST:
+ return ParseArgumentToArray(context, value.As<v8::Array>(), refs,
+ out_value, error);
+ case ArgumentType::BINARY:
+ return ParseArgumentToAny(context, value, out_value, error);
+ case ArgumentType::FUNCTION:
+ if (out_value) {
+ // Certain APIs (contextMenus) have functions as parameters other than
+ // the callback (contextMenus uses it for an onclick listener). Our
+ // generated types have adapted to consider functions "objects" and
+ // serialize them as dictionaries.
+ // TODO(devlin): It'd be awfully nice to get rid of this eccentricity.
+ *out_value = base::MakeUnique<base::DictionaryValue>();
+ }
+ return true;
+ case ArgumentType::REF: {
+ DCHECK(ref_);
+ const ArgumentSpec* reference = refs.GetSpec(ref_.value());
+ DCHECK(reference) << ref_.value();
+ return reference->ParseArgument(context, value, refs, out_value, error);
}
- v8::Local<v8::Array> array = value.As<v8::Array>();
- return ParseArgumentToArray(context, array, refs, out_value, error);
- }
- if (type_ == ArgumentType::BINARY) {
- if (!value->IsArrayBuffer() && !value->IsArrayBufferView()) {
- *error = GetInvalidTypeError(value);
+ case ArgumentType::CHOICES: {
+ for (const auto& choice : choices_) {
+ if (choice->ParseArgument(context, value, refs, out_value, error))
+ return true;
+ }
+ *error = api_errors::InvalidChoice();
return false;
}
- return ParseArgumentToAny(context, value, out_value, error);
+ case ArgumentType::ANY:
+ return ParseArgumentToAny(context, value, out_value, error);
}
- if (type_ == ArgumentType::ANY)
- return ParseArgumentToAny(context, value, out_value, error);
+
NOTREACHED();
return false;
}
@@ -328,24 +374,14 @@ const std::string& ArgumentSpec::GetTypeName() const {
return type_name_;
}
-bool ArgumentSpec::IsFundamentalType() const {
- return type_ == ArgumentType::INTEGER || type_ == ArgumentType::DOUBLE ||
- type_ == ArgumentType::BOOLEAN || type_ == ArgumentType::STRING;
-}
-
bool ArgumentSpec::ParseArgumentToFundamental(
v8::Local<v8::Context> context,
v8::Local<v8::Value> value,
std::unique_ptr<base::Value>* out_value,
std::string* error) const {
- DCHECK(IsFundamentalType());
-
switch (type_) {
case ArgumentType::INTEGER: {
- if (!value->IsInt32()) {
- *error = GetInvalidTypeError(value);
- return false;
- }
+ DCHECK(value->IsInt32());
int int_val = value.As<v8::Int32>()->Value();
if (!CheckFundamentalBounds(int_val, minimum_, maximum_, error))
return false;
@@ -354,10 +390,7 @@ bool ArgumentSpec::ParseArgumentToFundamental(
return true;
}
case ArgumentType::DOUBLE: {
- if (!value->IsNumber()) {
- *error = GetInvalidTypeError(value);
- return false;
- }
+ DCHECK(value->IsNumber());
double double_val = value.As<v8::Number>()->Value();
if (!CheckFundamentalBounds(double_val, minimum_, maximum_, error))
return false;
@@ -366,10 +399,7 @@ bool ArgumentSpec::ParseArgumentToFundamental(
return true;
}
case ArgumentType::STRING: {
- if (!value->IsString()) {
- *error = GetInvalidTypeError(value);
- return false;
- }
+ DCHECK(value->IsString());
v8::Local<v8::String> v8_string = value.As<v8::String>();
size_t length = static_cast<size_t>(v8_string->Length());
@@ -404,10 +434,7 @@ bool ArgumentSpec::ParseArgumentToFundamental(
return true;
}
case ArgumentType::BOOLEAN: {
- if (!value->IsBoolean()) {
- *error = GetInvalidTypeError(value);
- return false;
- }
+ DCHECK(value->IsBoolean());
if (out_value) {
*out_value =
base::MakeUnique<base::Value>(value.As<v8::Boolean>()->Value());
« no previous file with comments | « extensions/renderer/bindings/argument_spec.h ('k') | extensions/renderer/bindings/argument_spec_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698