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

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

Issue 2847853002: [Extensions Bindings] Add errors to signature parsing (Closed)
Patch Set: 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 *error_ = api_errors::TooManyArguments();
jbroman 2017/04/27 19:37:20 Can this happen when the previous check for too ma
Devlin 2017/05/01 22:22:09 Added. // This can potentially happen even if
174 return false; // Extra arguments aren't allowed. 185 return false; // Extra arguments aren't allowed.
186 }
175 187
176 return true; 188 return true;
177 } 189 }
178 190
179 bool ArgumentParser::ParseArgument(const ArgumentSpec& spec) { 191 bool ArgumentParser::ParseArgument(const ArgumentSpec& spec) {
180 v8::Local<v8::Value> value = next_argument(); 192 v8::Local<v8::Value> value = next_argument();
181 if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) { 193 if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) {
182 if (!spec.optional()) { 194 if (!spec.optional()) {
183 *error_ = "Missing required argument: " + spec.name(); 195 *error_ = api_errors::MissingRequiredArgument(spec.name().c_str());
lazyboy 2017/04/27 20:55:03 Here and line 209, remove c_str().
Devlin 2017/05/01 22:22:09 MissingRequiredArgument() takes a const char* (and
lazyboy 2017/05/01 23:14:21 I think I mistakenly read it as *error_ = some_str
184 return false; 196 return false;
185 } 197 }
186 // This is safe to call even if |arguments| is at the end (which can happen 198 // 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). 199 // if n optional arguments are omitted at the end of the signature).
188 ConsumeArgument(); 200 ConsumeArgument();
189 201
190 AddNull(); 202 AddNull();
191 return true; 203 return true;
192 } 204 }
193 205
194 if (!spec.ParseArgument(context_, value, type_refs_, GetBuffer(), error_)) { 206 if (!spec.ParseArgument(context_, value, type_refs_, GetBuffer(),
207 &parse_error_)) {
195 if (!spec.optional()) { 208 if (!spec.optional()) {
196 *error_ = "Missing required argument: " + spec.name(); 209 *error_ = api_errors::ArgumentError(spec.name(), parse_error_);
197 return false; 210 return false;
198 } 211 }
199 212
200 AddNull(); 213 AddNull();
201 return true; 214 return true;
202 } 215 }
203 216
204 ConsumeArgument(); 217 ConsumeArgument();
205 AddParsedArgument(value); 218 AddParsedArgument(value);
206 return true; 219 return true;
207 } 220 }
208 221
209 bool ArgumentParser::ParseCallback(const ArgumentSpec& spec) { 222 bool ArgumentParser::ParseCallback(const ArgumentSpec& spec) {
210 v8::Local<v8::Value> value = next_argument(); 223 v8::Local<v8::Value> value = next_argument();
211 if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) { 224 if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) {
212 if (!spec.optional()) { 225 if (!spec.optional()) {
213 *error_ = "Missing required argument: " + spec.name(); 226 *error_ = api_errors::MissingRequiredArgument(spec.name().c_str());
214 return false; 227 return false;
215 } 228 }
216 ConsumeArgument(); 229 ConsumeArgument();
217 AddNullCallback(); 230 AddNullCallback();
218 return true; 231 return true;
219 } 232 }
220 233
221 if (!value->IsFunction()) { 234 if (!spec.ParseArgument(context_, value, type_refs_, nullptr,
222 *error_ = "Argument is wrong type: " + spec.name(); 235 &parse_error_)) {
236 *error_ = api_errors::ArgumentError(spec.name(), parse_error_);
223 return false; 237 return false;
224 } 238 }
225 239
226 ConsumeArgument(); 240 ConsumeArgument();
227 SetCallback(value.As<v8::Function>()); 241 SetCallback(value.As<v8::Function>());
228 return true; 242 return true;
229 } 243 }
230 244
231 } // namespace 245 } // namespace
232 246
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
313 return false; 327 return false;
314 json->Append(std::move(converted)); 328 json->Append(std::move(converted));
315 } 329 }
316 330
317 *json_out = std::move(json); 331 *json_out = std::move(json);
318 *callback_out = callback; 332 *callback_out = callback;
319 return true; 333 return true;
320 } 334 }
321 335
322 } // namespace extensions 336 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698