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 "base/memory/ptr_util.h" | 7 #include "base/memory/ptr_util.h" |
| 8 #include "base/values.h" | 8 #include "base/values.h" |
| 9 #include "gin/arguments.h" | 9 #include "gin/arguments.h" |
| 10 | 10 |
| 11 namespace extensions { | 11 namespace extensions { |
| 12 | 12 |
| 13 namespace { | 13 namespace { |
| 14 | 14 |
| 15 // A class to help with argument parsing. Note that this uses v8::Locals and | 15 // A class to help with argument parsing. Note that this uses v8::Locals and |
| 16 // const&s because it's an implementation detail of the APISignature; this | 16 // const&s because it's an implementation detail of the APISignature; this |
| 17 // should *only* be used directly on the stack! | 17 // should *only* be used directly on the stack! |
| 18 class ArgumentParser { | 18 class ArgumentParser { |
| 19 public: | 19 public: |
| 20 ArgumentParser(const std::vector<std::unique_ptr<ArgumentSpec>>& signature, | 20 ArgumentParser(v8::Local<v8::Context> context, |
| 21 gin::Arguments* arguments, | 21 const std::vector<std::unique_ptr<ArgumentSpec>>& signature, |
| 22 const std::vector<v8::Local<v8::Value>>& arguments, | |
| 22 const ArgumentSpec::RefMap& type_refs, | 23 const ArgumentSpec::RefMap& type_refs, |
| 23 std::string* error) | 24 std::string* error) |
| 24 : context_(arguments->isolate()->GetCurrentContext()), | 25 : context_(context), |
| 25 signature_(signature), | 26 signature_(signature), |
| 26 arguments_(arguments), | 27 arguments_(arguments), |
| 27 type_refs_(type_refs), | 28 type_refs_(type_refs), |
| 28 error_(error) {} | 29 error_(error) {} |
| 29 | 30 |
| 30 // Tries to parse the arguments against the expected signature, populating a | 31 // Tries to parse the arguments against the expected signature, populating a |
| 31 // resulting list as it goes. | 32 // resulting list as it goes. |
| 32 bool ParseArguments(); | 33 bool ParseArguments(); |
| 33 | 34 |
| 34 protected: | 35 protected: |
| 35 v8::Isolate* GetIsolate() { return context_->GetIsolate(); } | 36 v8::Isolate* GetIsolate() { return context_->GetIsolate(); } |
| 36 | 37 |
| 37 private: | 38 private: |
| 39 v8::Local<v8::Value> next_argument() { | |
| 40 return current_index_ < arguments_.size() ? | |
| 41 arguments_[current_index_] : v8::Local<v8::Value>(); | |
| 42 } | |
| 43 | |
| 44 void consume_argument() { | |
|
jbroman
2016/12/23 22:37:06
nit: This doesn't look like a simple getter/setter
Devlin
2016/12/28 19:02:39
Not entirely sure I agree (it's basically just inc
| |
| 45 current_index_ = std::min(arguments_.size(), current_index_ + 1); | |
| 46 } | |
| 47 | |
| 38 // Attempts to match the next argument to the given |spec|. | 48 // Attempts to match the next argument to the given |spec|. |
| 39 // If the next argument does not match and |spec| is optional, uses a null | 49 // If the next argument does not match and |spec| is optional, uses a null |
| 40 // value. | 50 // value. |
| 41 // Returns true on success. | 51 // Returns true on success. |
| 42 bool ParseArgument(const ArgumentSpec& spec); | 52 bool ParseArgument(const ArgumentSpec& spec); |
| 43 | 53 |
| 44 // Attempts to parse the callback from the given |spec|. Returns true on | 54 // Attempts to parse the callback from the given |spec|. Returns true on |
| 45 // success. | 55 // success. |
| 46 bool ParseCallback(const ArgumentSpec& spec); | 56 bool ParseCallback(const ArgumentSpec& spec); |
| 47 | 57 |
| 48 // Adds a null value to the parsed arguments. | 58 // Adds a null value to the parsed arguments. |
| 49 virtual void AddNull() = 0; | 59 virtual void AddNull() = 0; |
| 50 // Returns a base::Value to be populated during argument matching. | 60 // Returns a base::Value to be populated during argument matching. |
| 51 virtual std::unique_ptr<base::Value>* GetBuffer() = 0; | 61 virtual std::unique_ptr<base::Value>* GetBuffer() = 0; |
| 52 // Adds a new parsed argument. | 62 // Adds a new parsed argument. |
| 53 virtual void AddParsedArgument(v8::Local<v8::Value> value) = 0; | 63 virtual void AddParsedArgument(v8::Local<v8::Value> value) = 0; |
| 54 // Adds the parsed callback. | 64 // Adds the parsed callback. |
| 55 virtual void SetCallback(v8::Local<v8::Function> callback) = 0; | 65 virtual void SetCallback(v8::Local<v8::Function> callback) = 0; |
| 56 | 66 |
| 57 v8::Local<v8::Context> context_; | 67 v8::Local<v8::Context> context_; |
| 58 const std::vector<std::unique_ptr<ArgumentSpec>>& signature_; | 68 const std::vector<std::unique_ptr<ArgumentSpec>>& signature_; |
| 59 gin::Arguments* arguments_; | 69 const std::vector<v8::Local<v8::Value>>& arguments_; |
| 60 const ArgumentSpec::RefMap& type_refs_; | 70 const ArgumentSpec::RefMap& type_refs_; |
| 61 std::string* error_; | 71 std::string* error_; |
| 72 size_t current_index_ = 0; | |
| 62 | 73 |
| 63 DISALLOW_COPY_AND_ASSIGN(ArgumentParser); | 74 DISALLOW_COPY_AND_ASSIGN(ArgumentParser); |
| 64 }; | 75 }; |
| 65 | 76 |
| 66 class V8ArgumentParser : public ArgumentParser { | 77 class V8ArgumentParser : public ArgumentParser { |
| 67 public: | 78 public: |
| 68 V8ArgumentParser(const std::vector<std::unique_ptr<ArgumentSpec>>& signature, | 79 V8ArgumentParser(v8::Local<v8::Context> context, |
| 69 gin::Arguments* arguments, | 80 const std::vector<std::unique_ptr<ArgumentSpec>>& signature, |
| 81 const std::vector<v8::Local<v8::Value>>& arguments, | |
| 70 const ArgumentSpec::RefMap& type_refs, | 82 const ArgumentSpec::RefMap& type_refs, |
| 71 std::string* error, | 83 std::string* error, |
| 72 std::vector<v8::Local<v8::Value>>* values) | 84 std::vector<v8::Local<v8::Value>>* values) |
| 73 : ArgumentParser(signature, arguments, type_refs, error), | 85 : ArgumentParser(context, signature, arguments, type_refs, error), |
| 74 values_(values) {} | 86 values_(values) {} |
| 75 | 87 |
| 76 private: | 88 private: |
| 77 void AddNull() override { values_->push_back(v8::Null(GetIsolate())); } | 89 void AddNull() override { values_->push_back(v8::Null(GetIsolate())); } |
| 78 std::unique_ptr<base::Value>* GetBuffer() override { return nullptr; } | 90 std::unique_ptr<base::Value>* GetBuffer() override { return nullptr; } |
| 79 void AddParsedArgument(v8::Local<v8::Value> value) override { | 91 void AddParsedArgument(v8::Local<v8::Value> value) override { |
| 80 values_->push_back(value); | 92 values_->push_back(value); |
| 81 } | 93 } |
| 82 void SetCallback(v8::Local<v8::Function> callback) override { | 94 void SetCallback(v8::Local<v8::Function> callback) override { |
| 83 values_->push_back(callback); | 95 values_->push_back(callback); |
| 84 } | 96 } |
| 85 | 97 |
| 86 std::vector<v8::Local<v8::Value>>* values_; | 98 std::vector<v8::Local<v8::Value>>* values_; |
| 87 | 99 |
| 88 DISALLOW_COPY_AND_ASSIGN(V8ArgumentParser); | 100 DISALLOW_COPY_AND_ASSIGN(V8ArgumentParser); |
| 89 }; | 101 }; |
| 90 | 102 |
| 91 class BaseValueArgumentParser : public ArgumentParser { | 103 class BaseValueArgumentParser : public ArgumentParser { |
| 92 public: | 104 public: |
| 93 BaseValueArgumentParser( | 105 BaseValueArgumentParser( |
| 106 v8::Local<v8::Context> context, | |
| 94 const std::vector<std::unique_ptr<ArgumentSpec>>& signature, | 107 const std::vector<std::unique_ptr<ArgumentSpec>>& signature, |
| 95 gin::Arguments* arguments, | 108 const std::vector<v8::Local<v8::Value>>& arguments, |
| 96 const ArgumentSpec::RefMap& type_refs, | 109 const ArgumentSpec::RefMap& type_refs, |
| 97 std::string* error, | 110 std::string* error, |
| 98 base::ListValue* list_value) | 111 base::ListValue* list_value) |
| 99 : ArgumentParser(signature, arguments, type_refs, error), | 112 : ArgumentParser(context, signature, arguments, type_refs, error), |
| 100 list_value_(list_value) {} | 113 list_value_(list_value) {} |
| 101 | 114 |
| 102 v8::Local<v8::Function> callback() { return callback_; } | 115 v8::Local<v8::Function> callback() { return callback_; } |
| 103 | 116 |
| 104 private: | 117 private: |
| 105 void AddNull() override { | 118 void AddNull() override { |
| 106 list_value_->Append(base::Value::CreateNullValue()); | 119 list_value_->Append(base::Value::CreateNullValue()); |
| 107 } | 120 } |
| 108 std::unique_ptr<base::Value>* GetBuffer() override { return &last_arg_; } | 121 std::unique_ptr<base::Value>* GetBuffer() override { return &last_arg_; } |
| 109 void AddParsedArgument(v8::Local<v8::Value> value) override { | 122 void AddParsedArgument(v8::Local<v8::Value> value) override { |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 136 size_t end_size = | 149 size_t end_size = |
| 137 signature_has_callback ? signature_.size() - 1 : signature_.size(); | 150 signature_has_callback ? signature_.size() - 1 : signature_.size(); |
| 138 for (size_t i = 0; i < end_size; ++i) { | 151 for (size_t i = 0; i < end_size; ++i) { |
| 139 if (!ParseArgument(*signature_[i])) | 152 if (!ParseArgument(*signature_[i])) |
| 140 return false; | 153 return false; |
| 141 } | 154 } |
| 142 | 155 |
| 143 if (signature_has_callback && !ParseCallback(*signature_.back())) | 156 if (signature_has_callback && !ParseCallback(*signature_.back())) |
| 144 return false; | 157 return false; |
| 145 | 158 |
| 146 if (!arguments_->PeekNext().IsEmpty()) | 159 if (current_index_ != arguments_.size()) |
| 147 return false; // Extra arguments aren't allowed. | 160 return false; // Extra arguments aren't allowed. |
| 148 | 161 |
| 149 return true; | 162 return true; |
| 150 } | 163 } |
| 151 | 164 |
| 152 bool ArgumentParser::ParseArgument(const ArgumentSpec& spec) { | 165 bool ArgumentParser::ParseArgument(const ArgumentSpec& spec) { |
| 153 v8::Local<v8::Value> value = arguments_->PeekNext(); | 166 v8::Local<v8::Value> value = next_argument(); |
| 154 if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) { | 167 if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) { |
| 155 if (!spec.optional()) { | 168 if (!spec.optional()) { |
| 156 *error_ = "Missing required argument: " + spec.name(); | 169 *error_ = "Missing required argument: " + spec.name(); |
| 157 return false; | 170 return false; |
| 158 } | 171 } |
| 159 // This is safe to call even if |arguments| is at the end (which can happen | 172 // This is safe to call even if |arguments| is at the end (which can happen |
| 160 // if n optional arguments are omitted at the end of the signature). | 173 // if n optional arguments are omitted at the end of the signature). |
| 161 arguments_->Skip(); | 174 consume_argument(); |
| 162 | 175 |
| 163 AddNull(); | 176 AddNull(); |
| 164 return true; | 177 return true; |
| 165 } | 178 } |
| 166 | 179 |
| 167 if (!spec.ParseArgument(context_, value, type_refs_, GetBuffer(), error_)) { | 180 if (!spec.ParseArgument(context_, value, type_refs_, GetBuffer(), error_)) { |
| 168 if (!spec.optional()) { | 181 if (!spec.optional()) { |
| 169 *error_ = "Missing required argument: " + spec.name(); | 182 *error_ = "Missing required argument: " + spec.name(); |
| 170 return false; | 183 return false; |
| 171 } | 184 } |
| 172 | 185 |
| 173 AddNull(); | 186 AddNull(); |
| 174 return true; | 187 return true; |
| 175 } | 188 } |
| 176 | 189 |
| 177 arguments_->Skip(); | 190 consume_argument(); |
| 178 AddParsedArgument(value); | 191 AddParsedArgument(value); |
| 179 return true; | 192 return true; |
| 180 } | 193 } |
| 181 | 194 |
| 182 bool ArgumentParser::ParseCallback(const ArgumentSpec& spec) { | 195 bool ArgumentParser::ParseCallback(const ArgumentSpec& spec) { |
| 183 v8::Local<v8::Value> value = arguments_->PeekNext(); | 196 v8::Local<v8::Value> value = next_argument(); |
| 184 if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) { | 197 if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) { |
| 185 if (!spec.optional()) { | 198 if (!spec.optional()) { |
| 186 *error_ = "Missing required argument: " + spec.name(); | 199 *error_ = "Missing required argument: " + spec.name(); |
| 187 return false; | 200 return false; |
| 188 } | 201 } |
| 189 arguments_->Skip(); | 202 consume_argument(); |
| 190 return true; | 203 return true; |
| 191 } | 204 } |
| 192 | 205 |
| 193 if (!value->IsFunction()) { | 206 if (!value->IsFunction()) { |
| 194 *error_ = "Argument is wrong type: " + spec.name(); | 207 *error_ = "Argument is wrong type: " + spec.name(); |
| 195 return false; | 208 return false; |
| 196 } | 209 } |
| 197 | 210 |
| 198 arguments_->Skip(); | 211 consume_argument(); |
| 199 SetCallback(value.As<v8::Function>()); | 212 SetCallback(value.As<v8::Function>()); |
| 200 return true; | 213 return true; |
| 201 } | 214 } |
| 202 | 215 |
| 203 } // namespace | 216 } // namespace |
| 204 | 217 |
| 205 APISignature::APISignature(const base::ListValue& specification) { | 218 APISignature::APISignature(const base::ListValue& specification) { |
| 206 signature_.reserve(specification.GetSize()); | 219 signature_.reserve(specification.GetSize()); |
| 207 for (const auto& value : specification) { | 220 for (const auto& value : specification) { |
| 208 const base::DictionaryValue* param = nullptr; | 221 const base::DictionaryValue* param = nullptr; |
| 209 CHECK(value->GetAsDictionary(¶m)); | 222 CHECK(value->GetAsDictionary(¶m)); |
| 210 signature_.push_back(base::MakeUnique<ArgumentSpec>(*param)); | 223 signature_.push_back(base::MakeUnique<ArgumentSpec>(*param)); |
| 211 } | 224 } |
| 212 } | 225 } |
| 213 | 226 |
| 214 APISignature::~APISignature() {} | 227 APISignature::~APISignature() {} |
| 215 | 228 |
| 216 bool APISignature::ParseArgumentsToV8(gin::Arguments* arguments, | 229 bool APISignature::ParseArgumentsToV8( |
| 217 const ArgumentSpec::RefMap& type_refs, | 230 v8::Local<v8::Context> context, |
| 218 std::vector<v8::Local<v8::Value>>* v8_out, | 231 const std::vector<v8::Local<v8::Value>>& arguments, |
| 219 std::string* error) const { | 232 const ArgumentSpec::RefMap& type_refs, |
| 233 std::vector<v8::Local<v8::Value>>* v8_out, | |
| 234 std::string* error) const { | |
| 220 DCHECK(v8_out); | 235 DCHECK(v8_out); |
| 221 std::vector<v8::Local<v8::Value>> v8_values; | 236 std::vector<v8::Local<v8::Value>> v8_values; |
| 222 V8ArgumentParser parser(signature_, arguments, type_refs, error, &v8_values); | 237 V8ArgumentParser parser( |
| 238 context, signature_, arguments, type_refs, error, &v8_values); | |
| 223 if (!parser.ParseArguments()) | 239 if (!parser.ParseArguments()) |
| 224 return false; | 240 return false; |
| 225 *v8_out = std::move(v8_values); | 241 *v8_out = std::move(v8_values); |
| 226 return true; | 242 return true; |
| 227 } | 243 } |
| 228 | 244 |
| 229 bool APISignature::ParseArgumentsToJSON( | 245 bool APISignature::ParseArgumentsToJSON( |
| 230 gin::Arguments* arguments, | 246 v8::Local<v8::Context> context, |
| 247 const std::vector<v8::Local<v8::Value>>& arguments, | |
| 231 const ArgumentSpec::RefMap& type_refs, | 248 const ArgumentSpec::RefMap& type_refs, |
| 232 std::unique_ptr<base::ListValue>* json_out, | 249 std::unique_ptr<base::ListValue>* json_out, |
| 233 v8::Local<v8::Function>* callback_out, | 250 v8::Local<v8::Function>* callback_out, |
| 234 std::string* error) const { | 251 std::string* error) const { |
| 235 DCHECK(json_out); | 252 DCHECK(json_out); |
| 236 DCHECK(callback_out); | 253 DCHECK(callback_out); |
| 237 std::unique_ptr<base::ListValue> json = base::MakeUnique<base::ListValue>(); | 254 std::unique_ptr<base::ListValue> json = base::MakeUnique<base::ListValue>(); |
| 238 BaseValueArgumentParser parser( | 255 BaseValueArgumentParser parser( |
| 239 signature_, arguments, type_refs, error, json.get()); | 256 context, signature_, arguments, type_refs, error, json.get()); |
| 240 if (!parser.ParseArguments()) | 257 if (!parser.ParseArguments()) |
| 241 return false; | 258 return false; |
| 242 *json_out = std::move(json); | 259 *json_out = std::move(json); |
| 243 *callback_out = parser.callback(); | 260 *callback_out = parser.callback(); |
| 244 return true; | 261 return true; |
| 245 } | 262 } |
| 246 | 263 |
| 247 } // namespace extensions | 264 } // namespace extensions |
| OLD | NEW |