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