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

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

Issue 2947463002: [Extensions Bindings] Add a bindings/ subdirectory under renderer (Closed)
Patch Set: . Created 3 years, 6 months 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_binding.h ('k') | extensions/renderer/api_binding_bridge.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "extensions/renderer/api_binding.h"
6
7 #include <algorithm>
8
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/values.h"
15 #include "extensions/common/extension_api.h"
16 #include "extensions/renderer/api_binding_hooks.h"
17 #include "extensions/renderer/api_binding_types.h"
18 #include "extensions/renderer/api_event_handler.h"
19 #include "extensions/renderer/api_invocation_errors.h"
20 #include "extensions/renderer/api_request_handler.h"
21 #include "extensions/renderer/api_signature.h"
22 #include "extensions/renderer/api_type_reference_map.h"
23 #include "extensions/renderer/binding_access_checker.h"
24 #include "extensions/renderer/declarative_event.h"
25 #include "extensions/renderer/v8_helpers.h"
26 #include "gin/arguments.h"
27 #include "gin/handle.h"
28 #include "gin/per_context_data.h"
29 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
30
31 namespace extensions {
32
33 namespace {
34
35 // Returns the name of the enum value for use in JavaScript; JS enum entries use
36 // SCREAMING_STYLE.
37 std::string GetJSEnumEntryName(const std::string& original) {
38 // The webstorePrivate API has an empty enum value for a result.
39 // TODO(devlin): Work with the webstore team to see if we can move them off
40 // this - they also already have a "success" result that they can use.
41 // See crbug.com/709120.
42 if (original.empty())
43 return original;
44
45 std::string result;
46 // If the original starts with a digit, prefix it with an underscore.
47 if (base::IsAsciiDigit(original[0]))
48 result.push_back('_');
49 // Given 'myEnum-Foo':
50 for (size_t i = 0; i < original.size(); ++i) {
51 // Add an underscore between camelcased items:
52 // 'myEnum-Foo' -> 'mY_Enum-Foo'
53 if (i > 0 && base::IsAsciiLower(original[i - 1]) &&
54 base::IsAsciiUpper(original[i])) {
55 result.push_back('_');
56 result.push_back(original[i]);
57 } else if (original[i] == '-') { // 'mY_Enum-Foo' -> 'mY_Enum_Foo'
58 result.push_back('_');
59 } else { // 'mY_Enum_Foo' -> 'MY_ENUM_FOO'
60 result.push_back(base::ToUpperASCII(original[i]));
61 }
62 }
63 return result;
64 }
65
66 bool IsContextValid(v8::Local<v8::Context> context) {
67 // If the given context has been disposed, the per-context data has been
68 // deleted, and the context is no longer valid. The APIBinding (which owns
69 // various necessary pieces) should outlive all contexts, so if the context
70 // is valid, associated callbacks should be safe.
71 return gin::PerContextData::From(context) != nullptr;
72 }
73
74 void CallbackHelper(const v8::FunctionCallbackInfo<v8::Value>& info) {
75 gin::Arguments args(info);
76 if (!IsContextValid(args.isolate()->GetCurrentContext()))
77 return;
78
79 v8::Local<v8::External> external;
80 CHECK(args.GetData(&external));
81 auto* callback = static_cast<APIBinding::HandlerCallback*>(external->Value());
82
83 callback->Run(&args);
84 }
85
86 } // namespace
87
88 struct APIBinding::MethodData {
89 MethodData(std::string full_name,
90 const APISignature* signature,
91 binding::RequestThread thread)
92 : full_name(std::move(full_name)), signature(signature), thread(thread) {}
93
94 // The fully-qualified name of this api (e.g. runtime.sendMessage instead of
95 // sendMessage).
96 const std::string full_name;
97 // The expected API signature.
98 const APISignature* signature;
99 // Thread to invoke the method on.
100 const binding::RequestThread thread;
101 // The callback used by the v8 function.
102 APIBinding::HandlerCallback callback;
103 };
104
105 // TODO(devlin): Maybe separate EventData into two classes? Rules, actions, and
106 // conditions should never be present on vanilla events.
107 struct APIBinding::EventData {
108 EventData(std::string exposed_name,
109 std::string full_name,
110 bool supports_filters,
111 bool supports_rules,
112 int max_listeners,
113 bool notify_on_change,
114 std::vector<std::string> actions,
115 std::vector<std::string> conditions,
116 APIBinding* binding)
117 : exposed_name(std::move(exposed_name)),
118 full_name(std::move(full_name)),
119 supports_filters(supports_filters),
120 supports_rules(supports_rules),
121 max_listeners(max_listeners),
122 notify_on_change(notify_on_change),
123 actions(std::move(actions)),
124 conditions(std::move(conditions)),
125 binding(binding) {}
126
127 // The name of the event on the API object (e.g. onCreated).
128 std::string exposed_name;
129
130 // The fully-specified name of the event (e.g. tabs.onCreated).
131 std::string full_name;
132
133 // Whether the event supports filters.
134 bool supports_filters;
135
136 // Whether the event supports rules.
137 bool supports_rules;
138
139 // The maximum number of listeners this event supports.
140 int max_listeners;
141
142 // Whether to notify the browser of listener changes.
143 bool notify_on_change;
144
145 // The associated actions and conditions for declarative events.
146 std::vector<std::string> actions;
147 std::vector<std::string> conditions;
148
149 // The associated APIBinding. This raw pointer is safe because the
150 // EventData is only accessed from the callbacks associated with the
151 // APIBinding, and both the APIBinding and APIEventHandler are owned by the
152 // same object (the APIBindingsSystem).
153 APIBinding* binding;
154 };
155
156 struct APIBinding::CustomPropertyData {
157 CustomPropertyData(const std::string& type_name,
158 const std::string& property_name,
159 const base::ListValue* property_values,
160 const CreateCustomType& create_custom_type)
161 : type_name(type_name),
162 property_name(property_name),
163 property_values(property_values),
164 create_custom_type(create_custom_type) {}
165
166 // The type of the property, e.g. 'storage.StorageArea'.
167 std::string type_name;
168 // The name of the property on the object, e.g. 'local' for
169 // chrome.storage.local.
170 std::string property_name;
171 // Values curried into this particular type from the schema.
172 const base::ListValue* property_values;
173
174 CreateCustomType create_custom_type;
175 };
176
177 APIBinding::APIBinding(const std::string& api_name,
178 const base::ListValue* function_definitions,
179 const base::ListValue* type_definitions,
180 const base::ListValue* event_definitions,
181 const base::DictionaryValue* property_definitions,
182 const CreateCustomType& create_custom_type,
183 std::unique_ptr<APIBindingHooks> binding_hooks,
184 APITypeReferenceMap* type_refs,
185 APIRequestHandler* request_handler,
186 APIEventHandler* event_handler,
187 BindingAccessChecker* access_checker)
188 : api_name_(api_name),
189 property_definitions_(property_definitions),
190 create_custom_type_(create_custom_type),
191 binding_hooks_(std::move(binding_hooks)),
192 type_refs_(type_refs),
193 request_handler_(request_handler),
194 event_handler_(event_handler),
195 access_checker_(access_checker),
196 weak_factory_(this) {
197 // TODO(devlin): It might make sense to instantiate the object_template_
198 // directly here, which would avoid the need to hold on to
199 // |property_definitions_| and |enums_|. However, there are *some* cases where
200 // we don't immediately stamp out an API from the template following
201 // construction.
202
203 if (function_definitions) {
204 for (const auto& func : *function_definitions) {
205 const base::DictionaryValue* func_dict = nullptr;
206 CHECK(func.GetAsDictionary(&func_dict));
207 std::string name;
208 CHECK(func_dict->GetString("name", &name));
209
210 const base::ListValue* params = nullptr;
211 CHECK(func_dict->GetList("parameters", &params));
212
213 bool for_io_thread = false;
214 func_dict->GetBoolean("forIOThread", &for_io_thread);
215
216 auto signature = base::MakeUnique<APISignature>(*params);
217 std::string full_name =
218 base::StringPrintf("%s.%s", api_name_.c_str(), name.c_str());
219 methods_[name] = base::MakeUnique<MethodData>(
220 full_name, signature.get(),
221 for_io_thread ? binding::RequestThread::IO
222 : binding::RequestThread::UI);
223 type_refs->AddAPIMethodSignature(full_name, std::move(signature));
224 }
225 }
226
227 if (type_definitions) {
228 for (const auto& type : *type_definitions) {
229 const base::DictionaryValue* type_dict = nullptr;
230 CHECK(type.GetAsDictionary(&type_dict));
231 std::string id;
232 CHECK(type_dict->GetString("id", &id));
233 auto argument_spec = base::MakeUnique<ArgumentSpec>(*type_dict);
234 const std::set<std::string>& enum_values = argument_spec->enum_values();
235 if (!enum_values.empty()) {
236 // Type names may be prefixed by the api name. If so, remove the prefix.
237 base::Optional<std::string> stripped_id;
238 if (base::StartsWith(id, api_name_, base::CompareCase::SENSITIVE))
239 stripped_id = id.substr(api_name_.size() + 1); // +1 for trailing '.'
240 std::vector<EnumEntry>& entries =
241 enums_[stripped_id ? *stripped_id : id];
242 entries.reserve(enum_values.size());
243 for (const auto& enum_value : enum_values) {
244 entries.push_back(
245 std::make_pair(enum_value, GetJSEnumEntryName(enum_value)));
246 }
247 }
248 type_refs->AddSpec(id, std::move(argument_spec));
249 // Some types, like storage.StorageArea, have functions associated with
250 // them. Cache the function signatures in the type map.
251 const base::ListValue* type_functions = nullptr;
252 if (type_dict->GetList("functions", &type_functions)) {
253 for (const auto& func : *type_functions) {
254 const base::DictionaryValue* func_dict = nullptr;
255 CHECK(func.GetAsDictionary(&func_dict));
256 std::string function_name;
257 CHECK(func_dict->GetString("name", &function_name));
258
259 const base::ListValue* params = nullptr;
260 CHECK(func_dict->GetList("parameters", &params));
261 type_refs->AddTypeMethodSignature(
262 base::StringPrintf("%s.%s", id.c_str(), function_name.c_str()),
263 base::MakeUnique<APISignature>(*params));
264 }
265 }
266 }
267 }
268
269 if (event_definitions) {
270 events_.reserve(event_definitions->GetSize());
271 for (const auto& event : *event_definitions) {
272 const base::DictionaryValue* event_dict = nullptr;
273 CHECK(event.GetAsDictionary(&event_dict));
274 std::string name;
275 CHECK(event_dict->GetString("name", &name));
276 std::string full_name =
277 base::StringPrintf("%s.%s", api_name_.c_str(), name.c_str());
278 const base::ListValue* filters = nullptr;
279 bool supports_filters =
280 event_dict->GetList("filters", &filters) && !filters->empty();
281
282 std::vector<std::string> rule_actions;
283 std::vector<std::string> rule_conditions;
284 const base::DictionaryValue* options = nullptr;
285 bool supports_rules = false;
286 bool notify_on_change = true;
287 int max_listeners = binding::kNoListenerMax;
288 if (event_dict->GetDictionary("options", &options)) {
289 bool temp_supports_filters = false;
290 // TODO(devlin): For some reason, schemas indicate supporting filters
291 // either through having a 'filters' property *or* through having
292 // a 'supportsFilters' property. We should clean that up.
293 supports_filters |=
294 (options->GetBoolean("supportsFilters", &temp_supports_filters) &&
295 temp_supports_filters);
296 if (options->GetBoolean("supportsRules", &supports_rules) &&
297 supports_rules) {
298 bool supports_listeners = false;
299 DCHECK(options->GetBoolean("supportsListeners", &supports_listeners));
300 DCHECK(!supports_listeners)
301 << "Events cannot support rules and listeners.";
302 auto get_values = [options](base::StringPiece name,
303 std::vector<std::string>* out_value) {
304 const base::ListValue* list = nullptr;
305 CHECK(options->GetList(name, &list));
306 for (const auto& entry : *list) {
307 DCHECK(entry.is_string());
308 out_value->push_back(entry.GetString());
309 }
310 };
311 get_values("actions", &rule_actions);
312 get_values("conditions", &rule_conditions);
313 }
314
315 options->GetInteger("maxListeners", &max_listeners);
316 bool unmanaged = false;
317 if (options->GetBoolean("unmanaged", &unmanaged))
318 notify_on_change = !unmanaged;
319 }
320
321 events_.push_back(base::MakeUnique<EventData>(
322 std::move(name), std::move(full_name), supports_filters,
323 supports_rules, max_listeners, notify_on_change,
324 std::move(rule_actions), std::move(rule_conditions), this));
325 }
326 }
327 }
328
329 APIBinding::~APIBinding() {}
330
331 v8::Local<v8::Object> APIBinding::CreateInstance(
332 v8::Local<v8::Context> context) {
333 DCHECK(IsContextValid(context));
334 v8::Isolate* isolate = context->GetIsolate();
335 if (object_template_.IsEmpty())
336 InitializeTemplate(isolate);
337 DCHECK(!object_template_.IsEmpty());
338
339 v8::Local<v8::Object> object =
340 object_template_.Get(isolate)->NewInstance(context).ToLocalChecked();
341
342 // The object created from the template includes all methods, but some may
343 // be unavailable in this context. Iterate over them and delete any that
344 // aren't available.
345 // TODO(devlin): Ideally, we'd only do this check on the methods that are
346 // conditionally exposed. Or, we could have multiple templates for different
347 // configurations, assuming there are a small number of possibilities.
348 for (const auto& key_value : methods_) {
349 if (!access_checker_->HasAccess(context, key_value.second->full_name)) {
350 v8::Maybe<bool> success = object->Delete(
351 context, gin::StringToSymbol(isolate, key_value.first));
352 CHECK(success.IsJust());
353 CHECK(success.FromJust());
354 }
355 }
356 for (const auto& event : events_) {
357 if (!access_checker_->HasAccess(context, event->full_name)) {
358 v8::Maybe<bool> success = object->Delete(
359 context, gin::StringToSymbol(isolate, event->exposed_name));
360 CHECK(success.IsJust());
361 CHECK(success.FromJust());
362 }
363 }
364
365 return object;
366 }
367
368 void APIBinding::InitializeTemplate(v8::Isolate* isolate) {
369 DCHECK(object_template_.IsEmpty());
370 v8::Local<v8::ObjectTemplate> object_template =
371 v8::ObjectTemplate::New(isolate);
372
373 for (const auto& key_value : methods_) {
374 MethodData& method = *key_value.second;
375 DCHECK(method.callback.is_null());
376 method.callback =
377 base::Bind(&APIBinding::HandleCall, weak_factory_.GetWeakPtr(),
378 method.full_name, method.signature, method.thread);
379
380 object_template->Set(
381 gin::StringToSymbol(isolate, key_value.first),
382 v8::FunctionTemplate::New(isolate, &CallbackHelper,
383 v8::External::New(isolate, &method.callback),
384 v8::Local<v8::Signature>(), 0,
385 v8::ConstructorBehavior::kThrow));
386 }
387
388 for (const auto& event : events_) {
389 object_template->SetLazyDataProperty(
390 gin::StringToSymbol(isolate, event->exposed_name),
391 &APIBinding::GetEventObject, v8::External::New(isolate, event.get()));
392 }
393
394 for (const auto& entry : enums_) {
395 v8::Local<v8::ObjectTemplate> enum_object =
396 v8::ObjectTemplate::New(isolate);
397 for (const auto& enum_entry : entry.second) {
398 enum_object->Set(gin::StringToSymbol(isolate, enum_entry.second),
399 gin::StringToSymbol(isolate, enum_entry.first));
400 }
401 object_template->Set(isolate, entry.first.c_str(), enum_object);
402 }
403
404 if (property_definitions_) {
405 DecorateTemplateWithProperties(isolate, object_template,
406 *property_definitions_);
407 }
408
409 // Allow custom bindings a chance to tweak the template, such as to add
410 // additional properties or types.
411 binding_hooks_->InitializeTemplate(isolate, object_template, *type_refs_);
412
413 object_template_.Set(isolate, object_template);
414 }
415
416 void APIBinding::DecorateTemplateWithProperties(
417 v8::Isolate* isolate,
418 v8::Local<v8::ObjectTemplate> object_template,
419 const base::DictionaryValue& properties) {
420 static const char kValueKey[] = "value";
421 for (base::DictionaryValue::Iterator iter(properties); !iter.IsAtEnd();
422 iter.Advance()) {
423 const base::DictionaryValue* dict = nullptr;
424 CHECK(iter.value().GetAsDictionary(&dict));
425 bool optional = false;
426 if (dict->GetBoolean("optional", &optional)) {
427 // TODO(devlin): What does optional even mean here? It's only used, it
428 // seems, for lastError and inIncognitoContext, which are both handled
429 // with custom bindings. Investigate, and remove.
430 continue;
431 }
432
433 v8::Local<v8::String> v8_key = gin::StringToSymbol(isolate, iter.key());
434 std::string ref;
435 if (dict->GetString("$ref", &ref)) {
436 const base::ListValue* property_values = nullptr;
437 CHECK(dict->GetList("value", &property_values));
438 auto property_data = base::MakeUnique<CustomPropertyData>(
439 ref, iter.key(), property_values, create_custom_type_);
440 object_template->SetLazyDataProperty(
441 v8_key, &APIBinding::GetCustomPropertyObject,
442 v8::External::New(isolate, property_data.get()));
443 custom_properties_.push_back(std::move(property_data));
444 continue;
445 }
446
447 std::string type;
448 CHECK(dict->GetString("type", &type));
449 if (type != "object" && !dict->HasKey(kValueKey)) {
450 // TODO(devlin): What does a fundamental property not having a value mean?
451 // It doesn't seem useful, and looks like it's only used by runtime.id,
452 // which is set by custom bindings. Investigate, and remove.
453 continue;
454 }
455 if (type == "integer") {
456 int val = 0;
457 CHECK(dict->GetInteger(kValueKey, &val));
458 object_template->Set(v8_key, v8::Integer::New(isolate, val));
459 } else if (type == "boolean") {
460 bool val = false;
461 CHECK(dict->GetBoolean(kValueKey, &val));
462 object_template->Set(v8_key, v8::Boolean::New(isolate, val));
463 } else if (type == "string") {
464 std::string val;
465 CHECK(dict->GetString(kValueKey, &val)) << iter.key();
466 object_template->Set(v8_key, gin::StringToSymbol(isolate, val));
467 } else if (type == "object" || !ref.empty()) {
468 v8::Local<v8::ObjectTemplate> property_template =
469 v8::ObjectTemplate::New(isolate);
470 const base::DictionaryValue* property_dict = nullptr;
471 CHECK(dict->GetDictionary("properties", &property_dict));
472 DecorateTemplateWithProperties(isolate, property_template,
473 *property_dict);
474 object_template->Set(v8_key, property_template);
475 }
476 }
477 }
478
479 // static
480 void APIBinding::GetEventObject(
481 v8::Local<v8::Name> property,
482 const v8::PropertyCallbackInfo<v8::Value>& info) {
483 v8::Isolate* isolate = info.GetIsolate();
484 v8::HandleScope handle_scope(isolate);
485 v8::Local<v8::Context> context = info.Holder()->CreationContext();
486 if (!IsContextValid(context))
487 return;
488
489 CHECK(info.Data()->IsExternal());
490 auto* event_data =
491 static_cast<EventData*>(info.Data().As<v8::External>()->Value());
492 v8::Local<v8::Value> retval;
493 if (event_data->binding->binding_hooks_->CreateCustomEvent(
494 context, event_data->full_name, &retval)) {
495 // A custom event was created; our work is done.
496 } else if (event_data->supports_rules) {
497 gin::Handle<DeclarativeEvent> event = gin::CreateHandle(
498 isolate, new DeclarativeEvent(
499 event_data->full_name, event_data->binding->type_refs_,
500 event_data->binding->request_handler_, event_data->actions,
501 event_data->conditions, 0));
502 retval = event.ToV8();
503 } else {
504 retval = event_data->binding->event_handler_->CreateEventInstance(
505 event_data->full_name, event_data->supports_filters,
506 event_data->max_listeners, event_data->notify_on_change, context);
507 }
508 info.GetReturnValue().Set(retval);
509 }
510
511 void APIBinding::GetCustomPropertyObject(
512 v8::Local<v8::Name> property_name,
513 const v8::PropertyCallbackInfo<v8::Value>& info) {
514 v8::Isolate* isolate = info.GetIsolate();
515 v8::HandleScope handle_scope(isolate);
516 v8::Local<v8::Context> context = info.Holder()->CreationContext();
517 if (!IsContextValid(context))
518 return;
519
520 v8::Context::Scope context_scope(context);
521 CHECK(info.Data()->IsExternal());
522 auto* property_data =
523 static_cast<CustomPropertyData*>(info.Data().As<v8::External>()->Value());
524
525 v8::Local<v8::Object> property = property_data->create_custom_type.Run(
526 isolate, property_data->type_name, property_data->property_name,
527 property_data->property_values);
528 if (property.IsEmpty())
529 return;
530
531 info.GetReturnValue().Set(property);
532 }
533
534 void APIBinding::HandleCall(const std::string& name,
535 const APISignature* signature,
536 const binding::RequestThread thread,
537 gin::Arguments* arguments) {
538 std::string error;
539 v8::Isolate* isolate = arguments->isolate();
540 v8::HandleScope handle_scope(isolate);
541
542 // Since this is called synchronously from the JS entry point,
543 // GetCurrentContext() should always be correct.
544 v8::Local<v8::Context> context = isolate->GetCurrentContext();
545
546 if (!access_checker_->HasAccessOrThrowError(context, name)) {
547 // TODO(devlin): Do we need handle this for events as well? I'm not sure the
548 // currrent system does (though perhaps it should). Investigate.
549 return;
550 }
551
552 std::vector<v8::Local<v8::Value>> argument_list = arguments->GetAll();
553
554 bool invalid_invocation = false;
555 v8::Local<v8::Function> custom_callback;
556 bool updated_args = false;
557 {
558 v8::TryCatch try_catch(isolate);
559 APIBindingHooks::RequestResult hooks_result = binding_hooks_->RunHooks(
560 name, context, signature, &argument_list, *type_refs_);
561
562 switch (hooks_result.code) {
563 case APIBindingHooks::RequestResult::INVALID_INVOCATION:
564 invalid_invocation = true;
565 error = std::move(hooks_result.error);
566 // Throw a type error below so that it's not caught by our try-catch.
567 break;
568 case APIBindingHooks::RequestResult::THROWN:
569 DCHECK(try_catch.HasCaught());
570 try_catch.ReThrow();
571 return;
572 case APIBindingHooks::RequestResult::HANDLED:
573 if (!hooks_result.return_value.IsEmpty())
574 arguments->Return(hooks_result.return_value);
575 return; // Our work here is done.
576 case APIBindingHooks::RequestResult::ARGUMENTS_UPDATED:
577 updated_args = true; // Intentional fall-through.
578 case APIBindingHooks::RequestResult::NOT_HANDLED:
579 break; // Handle in the default manner.
580 }
581 custom_callback = hooks_result.custom_callback;
582 }
583
584 if (invalid_invocation) {
585 arguments->ThrowTypeError(api_errors::InvocationError(
586 name, signature->GetExpectedSignature(), error));
587 return;
588 }
589
590 std::unique_ptr<base::ListValue> converted_arguments;
591 v8::Local<v8::Function> callback;
592 {
593 v8::TryCatch try_catch(isolate);
594
595 // If custom hooks updated the arguments post-validation, we just trust the
596 // values the hooks provide and convert them directly. This is because some
597 // APIs have one set of values they use for validation, and a second they
598 // use in the implementation of the function (see, e.g.
599 // fileSystem.getDisplayPath).
600 // TODO(devlin): That's unfortunate. Not only does it require special casing
601 // here, but it also means we can't auto-generate the params for the
602 // function on the browser side.
603 if (updated_args) {
604 bool success = signature->ConvertArgumentsIgnoringSchema(
605 context, argument_list, &converted_arguments, &callback);
606 if (!success) {
607 // Converted arguments passed to us by our bindings should never fail.
608 NOTREACHED();
609 return;
610 }
611 } else {
612 invalid_invocation = !signature->ParseArgumentsToJSON(
613 context, argument_list, *type_refs_, &converted_arguments, &callback,
614 &error);
615 }
616
617 if (try_catch.HasCaught()) {
618 DCHECK(!converted_arguments);
619 try_catch.ReThrow();
620 return;
621 }
622 }
623 if (invalid_invocation) {
624 arguments->ThrowTypeError(api_errors::InvocationError(
625 name, signature->GetExpectedSignature(), error));
626 return;
627 }
628
629 request_handler_->StartRequest(context, name, std::move(converted_arguments),
630 callback, custom_callback, thread);
631 }
632
633 } // namespace extensions
OLDNEW
« no previous file with comments | « extensions/renderer/api_binding.h ('k') | extensions/renderer/api_binding_bridge.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698