Chromium Code Reviews| 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 |