OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |