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 |