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