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

Side by Side Diff: extensions/renderer/api_signature.cc

Issue 2583273002: [Extensions Bindings] Allow for argument validation without conversion (Closed)
Patch Set: lazyboy's Created 3 years, 11 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 unified diff | Download patch
« no previous file with comments | « extensions/renderer/api_signature.h ('k') | extensions/renderer/argument_spec.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "extensions/renderer/api_signature.h" 5 #include "extensions/renderer/api_signature.h"
6 6
7 #include "base/memory/ptr_util.h" 7 #include "base/memory/ptr_util.h"
8 #include "base/values.h" 8 #include "base/values.h"
9 #include "gin/arguments.h" 9 #include "gin/arguments.h"
10 10
11 namespace extensions { 11 namespace extensions {
12 12
13 APISignature::APISignature(const base::ListValue& specification) { 13 namespace {
14 signature_.reserve(specification.GetSize()); 14
15 for (const auto& value : specification) { 15 // A class to help with argument parsing. Note that this uses v8::Locals and
16 const base::DictionaryValue* param = nullptr; 16 // const&s because it's an implementation detail of the APISignature; this
17 CHECK(value->GetAsDictionary(&param)); 17 // should *only* be used directly on the stack!
18 signature_.push_back(base::MakeUnique<ArgumentSpec>(*param)); 18 class ArgumentParser {
19 public:
20 ArgumentParser(const std::vector<std::unique_ptr<ArgumentSpec>>& signature,
21 gin::Arguments* arguments,
22 const ArgumentSpec::RefMap& type_refs,
23 std::string* error)
24 : context_(arguments->isolate()->GetCurrentContext()),
25 signature_(signature),
26 arguments_(arguments),
27 type_refs_(type_refs),
28 error_(error) {}
29
30 // Tries to parse the arguments against the expected signature.
31 bool ParseArguments();
32
33 protected:
34 v8::Isolate* GetIsolate() { return context_->GetIsolate(); }
35
36 private:
37 // Attempts to match the next argument to the given |spec|.
38 // If the next argument does not match and |spec| is optional, uses a null
39 // value.
40 // Returns true on success.
41 bool ParseArgument(const ArgumentSpec& spec);
42
43 // Attempts to parse the callback from the given |spec|. Returns true on
44 // success.
45 bool ParseCallback(const ArgumentSpec& spec);
46
47 // Adds a null value to the parsed arguments.
48 virtual void AddNull() = 0;
49 // Returns a base::Value to be populated during argument matching.
50 virtual std::unique_ptr<base::Value>* GetBuffer() = 0;
51 // Adds a new parsed argument.
52 virtual void AddParsedArgument(v8::Local<v8::Value> value) = 0;
53 // Adds the parsed callback.
54 virtual void SetCallback(v8::Local<v8::Function> callback) = 0;
55
56 v8::Local<v8::Context> context_;
57 const std::vector<std::unique_ptr<ArgumentSpec>>& signature_;
58 gin::Arguments* arguments_;
59 const ArgumentSpec::RefMap& type_refs_;
60 std::string* error_;
61
62 DISALLOW_COPY_AND_ASSIGN(ArgumentParser);
63 };
64
65 class V8ArgumentParser : public ArgumentParser {
66 public:
67 V8ArgumentParser(const std::vector<std::unique_ptr<ArgumentSpec>>& signature,
68 gin::Arguments* arguments,
69 const ArgumentSpec::RefMap& type_refs,
70 std::string* error,
71 std::vector<v8::Local<v8::Value>>* values)
72 : ArgumentParser(signature, arguments, type_refs, error),
73 values_(values) {}
74
75 private:
76 void AddNull() override { values_->push_back(v8::Null(GetIsolate())); }
77 std::unique_ptr<base::Value>* GetBuffer() override { return nullptr; }
78 void AddParsedArgument(v8::Local<v8::Value> value) override {
79 values_->push_back(value);
19 } 80 }
20 } 81 void SetCallback(v8::Local<v8::Function> callback) override {
82 values_->push_back(callback);
83 }
21 84
22 APISignature::~APISignature() {} 85 std::vector<v8::Local<v8::Value>>* values_;
23 86
24 std::unique_ptr<base::ListValue> APISignature::ParseArguments( 87 DISALLOW_COPY_AND_ASSIGN(V8ArgumentParser);
25 gin::Arguments* arguments, 88 };
26 const ArgumentSpec::RefMap& type_refs,
27 v8::Local<v8::Function>* callback_out,
28 std::string* error) const {
29 auto results = base::MakeUnique<base::ListValue>();
30 89
90 class BaseValueArgumentParser : public ArgumentParser {
91 public:
92 BaseValueArgumentParser(
93 const std::vector<std::unique_ptr<ArgumentSpec>>& signature,
94 gin::Arguments* arguments,
95 const ArgumentSpec::RefMap& type_refs,
96 std::string* error,
97 base::ListValue* list_value)
98 : ArgumentParser(signature, arguments, type_refs, error),
99 list_value_(list_value) {}
100
101 v8::Local<v8::Function> callback() { return callback_; }
102
103 private:
104 void AddNull() override {
105 list_value_->Append(base::Value::CreateNullValue());
106 }
107 std::unique_ptr<base::Value>* GetBuffer() override { return &last_arg_; }
108 void AddParsedArgument(v8::Local<v8::Value> value) override {
109 // The corresponding base::Value is expected to have been stored in
110 // |last_arg_| already.
111 DCHECK(last_arg_);
112 list_value_->Append(std::move(last_arg_));
113 last_arg_.reset();
114 }
115 void SetCallback(v8::Local<v8::Function> callback) override {
116 callback_ = callback;
117 }
118
119 base::ListValue* list_value_;
120 std::unique_ptr<base::Value> last_arg_;
121 v8::Local<v8::Function> callback_;
122
123 DISALLOW_COPY_AND_ASSIGN(BaseValueArgumentParser);
124 };
125
126 bool ArgumentParser::ParseArguments() {
31 // TODO(devlin): This is how extension APIs have always determined if a 127 // TODO(devlin): This is how extension APIs have always determined if a
32 // function has a callback, but it seems a little silly. In the long run (once 128 // function has a callback, but it seems a little silly. In the long run (once
33 // signatures are generated), it probably makes sense to indicate this 129 // signatures are generated), it probably makes sense to indicate this
34 // differently. 130 // differently.
35 bool signature_has_callback = 131 bool signature_has_callback =
36 !signature_.empty() && 132 !signature_.empty() &&
37 signature_.back()->type() == ArgumentType::FUNCTION; 133 signature_.back()->type() == ArgumentType::FUNCTION;
38 134
39 v8::Local<v8::Context> context = arguments->isolate()->GetCurrentContext();
40
41 size_t end_size = 135 size_t end_size =
42 signature_has_callback ? signature_.size() - 1 : signature_.size(); 136 signature_has_callback ? signature_.size() - 1 : signature_.size();
43 for (size_t i = 0; i < end_size; ++i) { 137 for (size_t i = 0; i < end_size; ++i) {
44 std::unique_ptr<base::Value> parsed = 138 if (!ParseArgument(*signature_[i]))
45 ParseArgument(*signature_[i], context, arguments, type_refs, error); 139 return false;
46 if (!parsed)
47 return nullptr;
48 results->Append(std::move(parsed));
49 } 140 }
50 141
51 v8::Local<v8::Function> callback_value; 142 if (signature_has_callback && !ParseCallback(*signature_.back()))
52 if (signature_has_callback && 143 return false;
53 !ParseCallback(arguments, *signature_.back(), error, &callback_value)) {
54 return nullptr;
55 }
56 144
57 if (!arguments->PeekNext().IsEmpty()) 145 if (!arguments_->PeekNext().IsEmpty())
58 return nullptr; // Extra arguments aren't allowed. 146 return false; // Extra arguments aren't allowed.
59 147
60 *callback_out = callback_value; 148 return true;
61 return results;
62 } 149 }
63 150
64 std::unique_ptr<base::Value> APISignature::ParseArgument( 151 bool ArgumentParser::ParseArgument(const ArgumentSpec& spec) {
65 const ArgumentSpec& spec, 152 v8::Local<v8::Value> value = arguments_->PeekNext();
66 v8::Local<v8::Context> context,
67 gin::Arguments* arguments,
68 const ArgumentSpec::RefMap& type_refs,
69 std::string* error) const {
70 v8::Local<v8::Value> value = arguments->PeekNext();
71 if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) { 153 if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) {
72 if (!spec.optional()) { 154 if (!spec.optional()) {
73 *error = "Missing required argument: " + spec.name(); 155 *error_ = "Missing required argument: " + spec.name();
74 return nullptr; 156 return false;
75 } 157 }
76 // This is safe to call even if |arguments| is at the end (which can happen 158 // This is safe to call even if |arguments| is at the end (which can happen
77 // if n optional arguments are omitted at the end of the signature). 159 // if n optional arguments are omitted at the end of the signature).
78 arguments->Skip(); 160 arguments_->Skip();
79 return base::Value::CreateNullValue(); 161
162 AddNull();
163 return true;
80 } 164 }
81 165
82 std::unique_ptr<base::Value> result = 166 if (!spec.ParseArgument(context_, value, type_refs_, GetBuffer(), error_)) {
83 spec.ConvertArgument(context, value, type_refs, error);
84 if (!result) {
85 if (!spec.optional()) { 167 if (!spec.optional()) {
86 *error = "Missing required argument: " + spec.name(); 168 *error_ = "Missing required argument: " + spec.name();
87 return nullptr; 169 return false;
88 } 170 }
89 return base::Value::CreateNullValue(); 171
172 AddNull();
173 return true;
90 } 174 }
91 175
92 arguments->Skip(); 176 arguments_->Skip();
93 return result; 177 AddParsedArgument(value);
178 return true;
94 } 179 }
95 180
96 bool APISignature::ParseCallback(gin::Arguments* arguments, 181 bool ArgumentParser::ParseCallback(const ArgumentSpec& spec) {
97 const ArgumentSpec& callback_spec, 182 v8::Local<v8::Value> value = arguments_->PeekNext();
98 std::string* error,
99 v8::Local<v8::Function>* callback_out) const {
100 v8::Local<v8::Value> value = arguments->PeekNext();
101 if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) { 183 if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) {
102 if (!callback_spec.optional()) { 184 if (!spec.optional()) {
103 *error = "Missing required argument: " + callback_spec.name(); 185 *error_ = "Missing required argument: " + spec.name();
104 return false; 186 return false;
105 } 187 }
106 arguments->Skip(); 188 arguments_->Skip();
107 return true; 189 return true;
108 } 190 }
109 191
110 if (!value->IsFunction()) { 192 if (!value->IsFunction()) {
111 *error = "Argument is wrong type: " + callback_spec.name(); 193 *error_ = "Argument is wrong type: " + spec.name();
112 return false; 194 return false;
113 } 195 }
114 196
115 *callback_out = value.As<v8::Function>(); 197 arguments_->Skip();
116 arguments->Skip(); 198 SetCallback(value.As<v8::Function>());
117 return true; 199 return true;
118 } 200 }
119 201
202 } // namespace
203
204 APISignature::APISignature(const base::ListValue& specification) {
205 signature_.reserve(specification.GetSize());
206 for (const auto& value : specification) {
207 const base::DictionaryValue* param = nullptr;
208 CHECK(value->GetAsDictionary(&param));
209 signature_.push_back(base::MakeUnique<ArgumentSpec>(*param));
210 }
211 }
212
213 APISignature::~APISignature() {}
214
215 bool APISignature::ParseArgumentsToV8(gin::Arguments* arguments,
216 const ArgumentSpec::RefMap& type_refs,
217 std::vector<v8::Local<v8::Value>>* v8_out,
218 std::string* error) const {
219 DCHECK(v8_out);
220 std::vector<v8::Local<v8::Value>> v8_values;
221 V8ArgumentParser parser(signature_, arguments, type_refs, error, &v8_values);
222 if (!parser.ParseArguments())
223 return false;
224 *v8_out = std::move(v8_values);
225 return true;
226 }
227
228 bool APISignature::ParseArgumentsToJSON(
229 gin::Arguments* arguments,
230 const ArgumentSpec::RefMap& type_refs,
231 std::unique_ptr<base::ListValue>* json_out,
232 v8::Local<v8::Function>* callback_out,
233 std::string* error) const {
234 DCHECK(json_out);
235 DCHECK(callback_out);
236 std::unique_ptr<base::ListValue> json = base::MakeUnique<base::ListValue>();
237 BaseValueArgumentParser parser(
238 signature_, arguments, type_refs, error, json.get());
239 if (!parser.ParseArguments())
240 return false;
241 *json_out = std::move(json);
242 *callback_out = parser.callback();
243 return true;
244 }
245
120 } // namespace extensions 246 } // namespace extensions
OLDNEW
« no previous file with comments | « extensions/renderer/api_signature.h ('k') | extensions/renderer/argument_spec.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698