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

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

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