Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(23)

Side by Side Diff: extensions/renderer/api_signature.cc

Issue 2583273002: [Extensions Bindings] Allow for argument validation without conversion (Closed)
Patch Set: format Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « extensions/renderer/api_signature.h ('k') | extensions/renderer/argument_spec.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 APISignature::APISignature(const base::ListValue& specification) { 13 APISignature::APISignature(const base::ListValue& specification) {
14 signature_.reserve(specification.GetSize()); 14 signature_.reserve(specification.GetSize());
15 for (const auto& value : specification) { 15 for (const auto& value : specification) {
16 const base::DictionaryValue* param = nullptr; 16 const base::DictionaryValue* param = nullptr;
17 CHECK(value->GetAsDictionary(&param)); 17 CHECK(value->GetAsDictionary(&param));
18 signature_.push_back(base::MakeUnique<ArgumentSpec>(*param)); 18 signature_.push_back(base::MakeUnique<ArgumentSpec>(*param));
19 } 19 }
20 } 20 }
21 21
22 APISignature::~APISignature() {} 22 APISignature::~APISignature() {}
23 23
24 std::unique_ptr<base::ListValue> APISignature::ParseArguments( 24 bool APISignature::ParseArgumentsToV8(gin::Arguments* arguments,
jbroman 2016/12/22 20:01:34 Higher level thought on this (that may cancel some
Devlin 2016/12/22 22:35:04 Interesting idea! I like it a lot, for the most p
25 const ArgumentSpec::RefMap& type_refs,
26 std::vector<v8::Local<v8::Value>>* v8_out,
27 std::string* error) const {
28 return ParseArgumentsImpl(arguments, type_refs, v8_out, nullptr, nullptr,
29 error);
30 }
31
32 bool APISignature::ParseArgumentsToJSON(
25 gin::Arguments* arguments, 33 gin::Arguments* arguments,
26 const ArgumentSpec::RefMap& type_refs, 34 const ArgumentSpec::RefMap& type_refs,
35 std::unique_ptr<base::ListValue>* json_out,
27 v8::Local<v8::Function>* callback_out, 36 v8::Local<v8::Function>* callback_out,
28 std::string* error) const { 37 std::string* error) const {
29 auto results = base::MakeUnique<base::ListValue>(); 38 DCHECK(json_out);
39 DCHECK(callback_out);
40 return ParseArgumentsImpl(arguments, type_refs, nullptr, json_out,
41 callback_out, error);
42 }
43
44 bool APISignature::ParseArgumentsImpl(
45 gin::Arguments* arguments,
46 const ArgumentSpec::RefMap& type_refs,
47 std::vector<v8::Local<v8::Value>>* v8_out,
48 std::unique_ptr<base::ListValue>* json_out,
49 v8::Local<v8::Function>* callback_out,
50 std::string* error) const {
51 DCHECK(error);
52 DCHECK_EQ(!!json_out, !!callback_out);
jbroman 2016/12/22 20:01:34 I found this a little tough to read. Is this equiv
Devlin 2016/12/22 22:35:04 Moot, I think.
53 DCHECK_NE(!!v8_out, !!json_out);
54
55 std::unique_ptr<base::ListValue> json_results;
56 // Only create the base::Values and convert if we need to; otherwise just
57 // look at the v8 values.
58 if (json_out)
59 json_results = base::MakeUnique<base::ListValue>();
60 // Adding v8 values to a vector is cheap enough that we don't need to do it
61 // conditionally.
62 // TODO(devlin): This can also result in creating null values (for absent
63 // optional parameters). Is that expensive enough to warrant making this
64 // conditional?
65 std::vector<v8::Local<v8::Value>> v8_results;
30 66
31 // TODO(devlin): This is how extension APIs have always determined if a 67 // TODO(devlin): This is how extension APIs have always determined if a
32 // function has a callback, but it seems a little silly. In the long run (once 68 // function has a callback, but it seems a little silly. In the long run (once
33 // signatures are generated), it probably makes sense to indicate this 69 // signatures are generated), it probably makes sense to indicate this
34 // differently. 70 // differently.
35 bool signature_has_callback = 71 bool signature_has_callback =
36 !signature_.empty() && 72 !signature_.empty() &&
37 signature_.back()->type() == ArgumentType::FUNCTION; 73 signature_.back()->type() == ArgumentType::FUNCTION;
38 74
39 v8::Local<v8::Context> context = arguments->isolate()->GetCurrentContext(); 75 v8::Local<v8::Context> context = arguments->isolate()->GetCurrentContext();
40 76
41 size_t end_size = 77 size_t end_size =
42 signature_has_callback ? signature_.size() - 1 : signature_.size(); 78 signature_has_callback ? signature_.size() - 1 : signature_.size();
43 for (size_t i = 0; i < end_size; ++i) { 79 for (size_t i = 0; i < end_size; ++i) {
44 std::unique_ptr<base::Value> parsed = 80 if (!ParseArgument(*signature_[i], context, arguments, type_refs,
45 ParseArgument(*signature_[i], context, arguments, type_refs, error); 81 &v8_results, json_results.get(), error)) {
46 if (!parsed) 82 return false;
47 return nullptr; 83 }
48 results->Append(std::move(parsed));
49 } 84 }
50 85
51 v8::Local<v8::Function> callback_value; 86 v8::Local<v8::Function> callback_value;
52 if (signature_has_callback && 87 if (signature_has_callback &&
53 !ParseCallback(arguments, *signature_.back(), error, &callback_value)) { 88 !ParseCallback(arguments, *signature_.back(), error, &callback_value)) {
54 return nullptr; 89 return false;
55 } 90 }
56 91
57 if (!arguments->PeekNext().IsEmpty()) 92 if (!arguments->PeekNext().IsEmpty())
58 return nullptr; // Extra arguments aren't allowed. 93 return false; // Extra arguments aren't allowed.
59 94
60 *callback_out = callback_value; 95 if (json_out) {
61 return results; 96 if (!callback_value.IsEmpty())
97 *callback_out = callback_value;
98 *json_out = std::move(json_results);
99 } else {
100 DCHECK(v8_out);
101 if (!callback_value.IsEmpty())
102 v8_results.push_back(callback_value);
103 v8_out->swap(v8_results);
104 }
105
106 return true;
62 } 107 }
63 108
64 std::unique_ptr<base::Value> APISignature::ParseArgument( 109 bool APISignature::ParseArgument(const ArgumentSpec& spec,
65 const ArgumentSpec& spec, 110 v8::Local<v8::Context> context,
66 v8::Local<v8::Context> context, 111 gin::Arguments* arguments,
67 gin::Arguments* arguments, 112 const ArgumentSpec::RefMap& type_refs,
68 const ArgumentSpec::RefMap& type_refs, 113 std::vector<v8::Local<v8::Value>>* v8_out,
69 std::string* error) const { 114 base::ListValue* json_out,
115 std::string* error) const {
70 v8::Local<v8::Value> value = arguments->PeekNext(); 116 v8::Local<v8::Value> value = arguments->PeekNext();
71 if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) { 117 if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) {
72 if (!spec.optional()) { 118 if (!spec.optional()) {
73 *error = "Missing required argument: " + spec.name(); 119 *error = "Missing required argument: " + spec.name();
74 return nullptr; 120 return false;
75 } 121 }
76 // This is safe to call even if |arguments| is at the end (which can happen 122 // This is safe to call even if |arguments| is at the end (which can happen
77 // if n optional arguments are omitted at the end of the signature). 123 // if n optional arguments are omitted at the end of the signature).
78 arguments->Skip(); 124 arguments->Skip();
79 return base::Value::CreateNullValue(); 125
126 v8_out->push_back(v8::Null(context->GetIsolate()));
127 if (json_out)
128 json_out->Append(base::Value::CreateNullValue());
129 return true;
80 } 130 }
81 131
82 std::unique_ptr<base::Value> result = 132 std::unique_ptr<base::Value> json_arg;
83 spec.ConvertArgument(context, value, type_refs, error); 133 if (!spec.ParseArgument(context, value, type_refs,
84 if (!result) { 134 json_out ? &json_arg : nullptr, error)) {
85 if (!spec.optional()) { 135 if (!spec.optional()) {
86 *error = "Missing required argument: " + spec.name(); 136 *error = "Missing required argument: " + spec.name();
87 return nullptr; 137 return false;
88 } 138 }
89 return base::Value::CreateNullValue(); 139
140 v8_out->push_back(v8::Null(context->GetIsolate()));
jbroman 2016/12/22 20:01:34 It's strange that |v8_out| here is unconditionally
Devlin 2016/12/22 22:35:04 Moot, I think.
141 if (json_out)
142 json_out->Append(base::Value::CreateNullValue());
143 return true;
90 } 144 }
91 145
146 v8_out->push_back(value);
147 if (json_out)
148 json_out->Append(std::move(json_arg));
92 arguments->Skip(); 149 arguments->Skip();
93 return result; 150 return true;
94 } 151 }
95 152
96 bool APISignature::ParseCallback(gin::Arguments* arguments, 153 bool APISignature::ParseCallback(gin::Arguments* arguments,
97 const ArgumentSpec& callback_spec, 154 const ArgumentSpec& callback_spec,
98 std::string* error, 155 std::string* error,
99 v8::Local<v8::Function>* callback_out) const { 156 v8::Local<v8::Function>* callback_out) const {
100 v8::Local<v8::Value> value = arguments->PeekNext(); 157 v8::Local<v8::Value> value = arguments->PeekNext();
101 if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) { 158 if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) {
102 if (!callback_spec.optional()) { 159 if (!callback_spec.optional()) {
103 *error = "Missing required argument: " + callback_spec.name(); 160 *error = "Missing required argument: " + callback_spec.name();
104 return false; 161 return false;
105 } 162 }
106 arguments->Skip(); 163 arguments->Skip();
107 return true; 164 return true;
108 } 165 }
109 166
110 if (!value->IsFunction()) { 167 if (!value->IsFunction()) {
111 *error = "Argument is wrong type: " + callback_spec.name(); 168 *error = "Argument is wrong type: " + callback_spec.name();
112 return false; 169 return false;
113 } 170 }
114 171
115 *callback_out = value.As<v8::Function>(); 172 *callback_out = value.As<v8::Function>();
116 arguments->Skip(); 173 arguments->Skip();
117 return true; 174 return true;
118 } 175 }
119 176
120 } // namespace extensions 177 } // namespace extensions
OLDNEW
« no previous file with comments | « extensions/renderer/api_signature.h ('k') | extensions/renderer/argument_spec.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698