chrome_setting.cc 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. // Copyright 2017 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. #include "extensions/renderer/chrome_setting.h"
  5. #include "base/strings/stringprintf.h"
  6. #include "base/values.h"
  7. #include "extensions/renderer/bindings/api_binding_util.h"
  8. #include "extensions/renderer/bindings/api_event_handler.h"
  9. #include "extensions/renderer/bindings/api_invocation_errors.h"
  10. #include "extensions/renderer/bindings/api_request_handler.h"
  11. #include "extensions/renderer/bindings/api_signature.h"
  12. #include "extensions/renderer/bindings/api_type_reference_map.h"
  13. #include "extensions/renderer/bindings/binding_access_checker.h"
  14. #include "gin/arguments.h"
  15. #include "gin/handle.h"
  16. #include "gin/object_template_builder.h"
  17. #include "v8/include/v8-object.h"
  18. namespace extensions {
  19. v8::Local<v8::Object> ChromeSetting::Create(
  20. v8::Isolate* isolate,
  21. const std::string& property_name,
  22. const base::ListValue* property_values,
  23. APIRequestHandler* request_handler,
  24. APIEventHandler* event_handler,
  25. APITypeReferenceMap* type_refs,
  26. const BindingAccessChecker* access_checker) {
  27. const base::Value::List& property_values_list = property_values->GetList();
  28. CHECK_GE(property_values_list.size(), 2u);
  29. const std::string& pref_name = property_values_list[0u].GetString();
  30. const base::Value& value_spec = property_values_list[1u];
  31. CHECK(value_spec.is_dict());
  32. gin::Handle<ChromeSetting> handle = gin::CreateHandle(
  33. isolate,
  34. new ChromeSetting(request_handler, event_handler, type_refs,
  35. access_checker, pref_name,
  36. static_cast<const base::DictionaryValue&>(value_spec)));
  37. return handle.ToV8().As<v8::Object>();
  38. }
  39. ChromeSetting::ChromeSetting(APIRequestHandler* request_handler,
  40. APIEventHandler* event_handler,
  41. const APITypeReferenceMap* type_refs,
  42. const BindingAccessChecker* access_checker,
  43. const std::string& pref_name,
  44. const base::DictionaryValue& set_value_spec)
  45. : request_handler_(request_handler),
  46. event_handler_(event_handler),
  47. type_refs_(type_refs),
  48. access_checker_(access_checker),
  49. pref_name_(pref_name),
  50. argument_spec_(ArgumentType::OBJECT) {
  51. // The set() call takes an object { value: { type: <t> }, ... }, where <t>
  52. // is the custom set() argument specified above by value_spec.
  53. ArgumentSpec::PropertiesMap properties;
  54. {
  55. auto scope_spec = std::make_unique<ArgumentSpec>(ArgumentType::REF);
  56. scope_spec->set_ref("types.ChromeSettingScope");
  57. scope_spec->set_optional(true);
  58. properties["scope"] = std::move(scope_spec);
  59. }
  60. properties["value"] = std::make_unique<ArgumentSpec>(set_value_spec);
  61. argument_spec_.set_properties(std::move(properties));
  62. }
  63. ChromeSetting::~ChromeSetting() = default;
  64. gin::WrapperInfo ChromeSetting::kWrapperInfo = {gin::kEmbedderNativeGin};
  65. gin::ObjectTemplateBuilder ChromeSetting::GetObjectTemplateBuilder(
  66. v8::Isolate* isolate) {
  67. return Wrappable<ChromeSetting>::GetObjectTemplateBuilder(isolate)
  68. .SetMethod("get", &ChromeSetting::Get)
  69. .SetMethod("set", &ChromeSetting::Set)
  70. .SetMethod("clear", &ChromeSetting::Clear)
  71. .SetProperty("onChange", &ChromeSetting::GetOnChangeEvent);
  72. }
  73. const char* ChromeSetting::GetTypeName() {
  74. return "ChromeSetting";
  75. }
  76. void ChromeSetting::Get(gin::Arguments* arguments) {
  77. HandleFunction("get", arguments);
  78. }
  79. void ChromeSetting::Set(gin::Arguments* arguments) {
  80. v8::Isolate* isolate = arguments->isolate();
  81. v8::HandleScope handle_scope(isolate);
  82. v8::Local<v8::Context> context = arguments->GetHolderCreationContext();
  83. if (!binding::IsContextValidOrThrowError(context))
  84. return;
  85. v8::Local<v8::Value> value = arguments->PeekNext();
  86. // The set schema included in the Schema object is generic, since it varies
  87. // per-setting. However, this is only ever for a single setting, so we can
  88. // enforce the types more thoroughly.
  89. std::string error;
  90. if (!value.IsEmpty() &&
  91. !argument_spec_.ParseArgument(context, value, *type_refs_, nullptr,
  92. nullptr, &error)) {
  93. arguments->ThrowTypeError("Invalid invocation");
  94. return;
  95. }
  96. HandleFunction("set", arguments);
  97. }
  98. void ChromeSetting::Clear(gin::Arguments* arguments) {
  99. HandleFunction("clear", arguments);
  100. }
  101. v8::Local<v8::Value> ChromeSetting::GetOnChangeEvent(
  102. gin::Arguments* arguments) {
  103. v8::Isolate* isolate = arguments->isolate();
  104. v8::Local<v8::Context> context = arguments->GetHolderCreationContext();
  105. v8::Local<v8::Object> wrapper = GetWrapper(isolate).ToLocalChecked();
  106. if (!binding::IsContextValidOrThrowError(context))
  107. return v8::Undefined(isolate);
  108. v8::Local<v8::Private> key = v8::Private::ForApi(
  109. isolate, gin::StringToSymbol(isolate, "onChangeEvent"));
  110. v8::Local<v8::Value> event;
  111. if (!wrapper->GetPrivate(context, key).ToLocal(&event)) {
  112. NOTREACHED();
  113. return v8::Local<v8::Value>();
  114. }
  115. DCHECK(!event.IsEmpty());
  116. if (event->IsUndefined()) {
  117. bool supports_filters = false;
  118. bool supports_lazy_listeners = true;
  119. event = event_handler_->CreateEventInstance(
  120. base::StringPrintf("types.ChromeSetting.%s.onChange",
  121. pref_name_.c_str()),
  122. supports_filters, supports_lazy_listeners, binding::kNoListenerMax,
  123. true, context);
  124. v8::Maybe<bool> set_result = wrapper->SetPrivate(context, key, event);
  125. if (!set_result.IsJust() || !set_result.FromJust()) {
  126. NOTREACHED();
  127. return v8::Local<v8::Value>();
  128. }
  129. }
  130. return event;
  131. }
  132. void ChromeSetting::HandleFunction(const std::string& method_name,
  133. gin::Arguments* arguments) {
  134. v8::Isolate* isolate = arguments->isolate();
  135. v8::HandleScope handle_scope(isolate);
  136. v8::Local<v8::Context> context = arguments->GetHolderCreationContext();
  137. if (!binding::IsContextValidOrThrowError(context))
  138. return;
  139. std::vector<v8::Local<v8::Value>> argument_list = arguments->GetAll();
  140. std::string full_name = "types.ChromeSetting." + method_name;
  141. if (!access_checker_->HasAccessOrThrowError(context, full_name))
  142. return;
  143. std::unique_ptr<base::ListValue> converted_arguments;
  144. v8::Local<v8::Function> callback;
  145. std::string error;
  146. const APISignature* signature = type_refs_->GetTypeMethodSignature(full_name);
  147. APISignature::JSONParseResult parse_result =
  148. signature->ParseArgumentsToJSON(context, argument_list, *type_refs_);
  149. if (!parse_result.succeeded()) {
  150. arguments->ThrowTypeError(api_errors::InvocationError(
  151. full_name, signature->GetExpectedSignature(), *parse_result.error));
  152. return;
  153. }
  154. parse_result.arguments_list->GetList().Insert(
  155. parse_result.arguments_list->GetList().begin(), base::Value(pref_name_));
  156. v8::Local<v8::Promise> promise = request_handler_->StartRequest(
  157. context, full_name, std::move(parse_result.arguments_list),
  158. parse_result.async_type, parse_result.callback, v8::Local<v8::Function>(),
  159. binding::ResultModifierFunction());
  160. if (!promise.IsEmpty())
  161. arguments->Return(promise);
  162. }
  163. } // namespace extensions