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

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

Issue 2847853002: [Extensions Bindings] Add errors to signature parsing (Closed)
Patch Set: Rebase Created 3 years, 7 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
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 <algorithm> 7 #include <algorithm>
8 8
9 #include "base/memory/ptr_util.h" 9 #include "base/memory/ptr_util.h"
10 #include "base/values.h" 10 #include "base/values.h"
11 #include "content/public/child/v8_value_converter.h" 11 #include "content/public/child/v8_value_converter.h"
12 #include "extensions/renderer/api_invocation_errors.h"
12 #include "extensions/renderer/argument_spec.h" 13 #include "extensions/renderer/argument_spec.h"
13 #include "gin/arguments.h" 14 #include "gin/arguments.h"
14 15
15 namespace extensions { 16 namespace extensions {
16 17
17 namespace { 18 namespace {
18 19
19 bool HasCallback(const std::vector<std::unique_ptr<ArgumentSpec>>& signature) { 20 bool HasCallback(const std::vector<std::unique_ptr<ArgumentSpec>>& signature) {
20 // TODO(devlin): This is how extension APIs have always determined if a 21 // TODO(devlin): This is how extension APIs have always determined if a
21 // function has a callback, but it seems a little silly. In the long run (once 22 // function has a callback, but it seems a little silly. In the long run (once
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
77 // Adds the parsed callback. 78 // Adds the parsed callback.
78 virtual void SetCallback(v8::Local<v8::Function> callback) = 0; 79 virtual void SetCallback(v8::Local<v8::Function> callback) = 0;
79 80
80 v8::Local<v8::Context> context_; 81 v8::Local<v8::Context> context_;
81 const std::vector<std::unique_ptr<ArgumentSpec>>& signature_; 82 const std::vector<std::unique_ptr<ArgumentSpec>>& signature_;
82 const std::vector<v8::Local<v8::Value>>& arguments_; 83 const std::vector<v8::Local<v8::Value>>& arguments_;
83 const APITypeReferenceMap& type_refs_; 84 const APITypeReferenceMap& type_refs_;
84 std::string* error_; 85 std::string* error_;
85 size_t current_index_ = 0; 86 size_t current_index_ = 0;
86 87
88 // An error to pass while parsing arguments to avoid having to allocate a new
89 // std::string on the stack multiple times.
90 std::string parse_error_;
91
87 DISALLOW_COPY_AND_ASSIGN(ArgumentParser); 92 DISALLOW_COPY_AND_ASSIGN(ArgumentParser);
88 }; 93 };
89 94
90 class V8ArgumentParser : public ArgumentParser { 95 class V8ArgumentParser : public ArgumentParser {
91 public: 96 public:
92 V8ArgumentParser(v8::Local<v8::Context> context, 97 V8ArgumentParser(v8::Local<v8::Context> context,
93 const std::vector<std::unique_ptr<ArgumentSpec>>& signature, 98 const std::vector<std::unique_ptr<ArgumentSpec>>& signature,
94 const std::vector<v8::Local<v8::Value>>& arguments, 99 const std::vector<v8::Local<v8::Value>>& arguments,
95 const APITypeReferenceMap& type_refs, 100 const APITypeReferenceMap& type_refs,
96 std::string* error, 101 std::string* error,
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 } 156 }
152 157
153 base::ListValue* list_value_; 158 base::ListValue* list_value_;
154 std::unique_ptr<base::Value> last_arg_; 159 std::unique_ptr<base::Value> last_arg_;
155 v8::Local<v8::Function> callback_; 160 v8::Local<v8::Function> callback_;
156 161
157 DISALLOW_COPY_AND_ASSIGN(BaseValueArgumentParser); 162 DISALLOW_COPY_AND_ASSIGN(BaseValueArgumentParser);
158 }; 163 };
159 164
160 bool ArgumentParser::ParseArguments() { 165 bool ArgumentParser::ParseArguments() {
166 if (arguments_.size() > signature_.size()) {
167 *error_ = api_errors::TooManyArguments();
168 return false;
169 }
170
161 bool signature_has_callback = HasCallback(signature_); 171 bool signature_has_callback = HasCallback(signature_);
162 172
163 size_t end_size = 173 size_t end_size =
164 signature_has_callback ? signature_.size() - 1 : signature_.size(); 174 signature_has_callback ? signature_.size() - 1 : signature_.size();
165 for (size_t i = 0; i < end_size; ++i) { 175 for (size_t i = 0; i < end_size; ++i) {
166 if (!ParseArgument(*signature_[i])) 176 if (!ParseArgument(*signature_[i]))
167 return false; 177 return false;
168 } 178 }
169 179
170 if (signature_has_callback && !ParseCallback(*signature_.back())) 180 if (signature_has_callback && !ParseCallback(*signature_.back()))
171 return false; 181 return false;
172 182
173 if (current_index_ != arguments_.size()) 183 if (current_index_ != arguments_.size()) {
184 // This can potentially happen even if the check above for too many
185 // arguments succeeds when optional parameters are omitted. For instance,
186 // if the signature expects (optional int, function callback) and the caller
187 // provides (function callback, object random), the first size check and
188 // callback spec would succeed, but we wouldn't consume all the arguments.
189 *error_ = api_errors::TooManyArguments();
174 return false; // Extra arguments aren't allowed. 190 return false; // Extra arguments aren't allowed.
191 }
175 192
176 return true; 193 return true;
177 } 194 }
178 195
179 bool ArgumentParser::ParseArgument(const ArgumentSpec& spec) { 196 bool ArgumentParser::ParseArgument(const ArgumentSpec& spec) {
180 v8::Local<v8::Value> value = next_argument(); 197 v8::Local<v8::Value> value = next_argument();
181 if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) { 198 if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) {
182 if (!spec.optional()) { 199 if (!spec.optional()) {
183 *error_ = "Missing required argument: " + spec.name(); 200 *error_ = api_errors::MissingRequiredArgument(spec.name().c_str());
184 return false; 201 return false;
185 } 202 }
186 // This is safe to call even if |arguments| is at the end (which can happen 203 // This is safe to call even if |arguments| is at the end (which can happen
187 // if n optional arguments are omitted at the end of the signature). 204 // if n optional arguments are omitted at the end of the signature).
188 ConsumeArgument(); 205 ConsumeArgument();
189 206
190 AddNull(); 207 AddNull();
191 return true; 208 return true;
192 } 209 }
193 210
194 if (!spec.ParseArgument(context_, value, type_refs_, GetBuffer(), error_)) { 211 if (!spec.ParseArgument(context_, value, type_refs_, GetBuffer(),
212 &parse_error_)) {
195 if (!spec.optional()) { 213 if (!spec.optional()) {
196 *error_ = "Missing required argument: " + spec.name(); 214 *error_ = api_errors::ArgumentError(spec.name(), parse_error_);
197 return false; 215 return false;
198 } 216 }
199 217
200 AddNull(); 218 AddNull();
201 return true; 219 return true;
202 } 220 }
203 221
204 ConsumeArgument(); 222 ConsumeArgument();
205 AddParsedArgument(value); 223 AddParsedArgument(value);
206 return true; 224 return true;
207 } 225 }
208 226
209 bool ArgumentParser::ParseCallback(const ArgumentSpec& spec) { 227 bool ArgumentParser::ParseCallback(const ArgumentSpec& spec) {
210 v8::Local<v8::Value> value = next_argument(); 228 v8::Local<v8::Value> value = next_argument();
211 if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) { 229 if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) {
212 if (!spec.optional()) { 230 if (!spec.optional()) {
213 *error_ = "Missing required argument: " + spec.name(); 231 *error_ = api_errors::MissingRequiredArgument(spec.name().c_str());
214 return false; 232 return false;
215 } 233 }
216 ConsumeArgument(); 234 ConsumeArgument();
217 AddNullCallback(); 235 AddNullCallback();
218 return true; 236 return true;
219 } 237 }
220 238
221 if (!value->IsFunction()) { 239 if (!spec.ParseArgument(context_, value, type_refs_, nullptr,
222 *error_ = "Argument is wrong type: " + spec.name(); 240 &parse_error_)) {
241 *error_ = api_errors::ArgumentError(spec.name(), parse_error_);
223 return false; 242 return false;
224 } 243 }
225 244
226 ConsumeArgument(); 245 ConsumeArgument();
227 SetCallback(value.As<v8::Function>()); 246 SetCallback(value.As<v8::Function>());
228 return true; 247 return true;
229 } 248 }
230 249
231 } // namespace 250 } // namespace
232 251
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
313 return false; 332 return false;
314 json->Append(std::move(converted)); 333 json->Append(std::move(converted));
315 } 334 }
316 335
317 *json_out = std::move(json); 336 *json_out = std::move(json);
318 *callback_out = callback; 337 *callback_out = callback;
319 return true; 338 return true;
320 } 339 }
321 340
322 } // namespace extensions 341 } // namespace extensions
OLDNEW
« no previous file with comments | « extensions/renderer/api_invocation_errors_unittest.cc ('k') | extensions/renderer/api_signature_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698