OLD | NEW |
(Empty) | |
| 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 |
| 5 #include "extensions/renderer/chrome_setting.h" |
| 6 |
| 7 #include "base/memory/ptr_util.h" |
| 8 #include "base/strings/stringprintf.h" |
| 9 #include "base/values.h" |
| 10 #include "extensions/renderer/api_event_handler.h" |
| 11 #include "extensions/renderer/api_request_handler.h" |
| 12 #include "extensions/renderer/api_signature.h" |
| 13 #include "extensions/renderer/api_type_reference_map.h" |
| 14 #include "gin/arguments.h" |
| 15 #include "gin/handle.h" |
| 16 #include "gin/object_template_builder.h" |
| 17 |
| 18 namespace extensions { |
| 19 |
| 20 v8::Local<v8::Object> ChromeSetting::Create(v8::Local<v8::Context> context, |
| 21 const std::string& property_name, |
| 22 APIRequestHandler* request_handler, |
| 23 APIEventHandler* event_handler, |
| 24 APITypeReferenceMap* type_refs) { |
| 25 auto value_spec = base::MakeUnique<base::DictionaryValue>(); |
| 26 // Most ChromeSettings have a pref that matches the property name and are of |
| 27 // type boolean. |
| 28 base::StringPiece pref_name = property_name; |
| 29 base::StringPiece type = "boolean"; |
| 30 |
| 31 // A few of ChromeSettings are special, and have different arguments. |
| 32 base::StringPiece ref; |
| 33 if (property_name == "animationPolicy") { |
| 34 type = "string"; |
| 35 auto enum_list = base::MakeUnique<base::ListValue>(); |
| 36 enum_list->AppendString("allowed"); |
| 37 enum_list->AppendString("once"); |
| 38 enum_list->AppendString("none"); |
| 39 value_spec->Set("enum", std::move(enum_list)); |
| 40 } else if (property_name == "webRTCIPHandlingPolicy") { |
| 41 ref = "IPHandlingPolicy"; |
| 42 } else if (property_name == "spdyProxyEnabled") { |
| 43 pref_name = "spdy_proxy.enabled"; |
| 44 } else if (property_name == "dataReductionDailyContentLength") { |
| 45 type = "array"; |
| 46 pref_name = "data_reduction.daily_original_length"; |
| 47 } else if (property_name == "dataReductionDailyReceivedLength") { |
| 48 type = "array"; |
| 49 pref_name = "data_reduction.daily_received_length"; |
| 50 } else if (property_name == "dataUsageReportingEnabled") { |
| 51 pref_name = "data_usage_reporting.enabled"; |
| 52 } else if (property_name == "proxy") { |
| 53 ref = "ProxyConfig"; |
| 54 } |
| 55 |
| 56 if (!ref.empty()) |
| 57 value_spec->SetString("$ref", ref); |
| 58 else |
| 59 value_spec->SetString("type", type); |
| 60 |
| 61 // The set() call takes an object { value: { type: <t> }, ... }, where <t> |
| 62 // is the custom set() argument specified above by value_spec. |
| 63 base::DictionaryValue set_spec; |
| 64 set_spec.SetString("type", "object"); |
| 65 auto properties = base::MakeUnique<base::DictionaryValue>(); |
| 66 properties->Set("value", std::move(value_spec)); |
| 67 set_spec.Set("properties", std::move(properties)); |
| 68 |
| 69 gin::Handle<ChromeSetting> handle = gin::CreateHandle( |
| 70 context->GetIsolate(), |
| 71 new ChromeSetting(request_handler, event_handler, type_refs, |
| 72 pref_name.as_string(), set_spec)); |
| 73 return handle.ToV8().As<v8::Object>(); |
| 74 } |
| 75 |
| 76 ChromeSetting::ChromeSetting(APIRequestHandler* request_handler, |
| 77 APIEventHandler* event_handler, |
| 78 const APITypeReferenceMap* type_refs, |
| 79 const std::string& pref_name, |
| 80 const base::DictionaryValue& argument_spec) |
| 81 : request_handler_(request_handler), |
| 82 event_handler_(event_handler), |
| 83 type_refs_(type_refs), |
| 84 pref_name_(pref_name), |
| 85 argument_spec_(argument_spec) {} |
| 86 |
| 87 ChromeSetting::~ChromeSetting() = default; |
| 88 |
| 89 gin::WrapperInfo ChromeSetting::kWrapperInfo = {gin::kEmbedderNativeGin}; |
| 90 |
| 91 gin::ObjectTemplateBuilder ChromeSetting::GetObjectTemplateBuilder( |
| 92 v8::Isolate* isolate) { |
| 93 return Wrappable<ChromeSetting>::GetObjectTemplateBuilder(isolate) |
| 94 .SetMethod("get", &ChromeSetting::Get) |
| 95 .SetMethod("set", &ChromeSetting::Set) |
| 96 .SetMethod("clear", &ChromeSetting::Clear) |
| 97 .SetProperty("onChange", &ChromeSetting::GetOnChangeEvent); |
| 98 } |
| 99 |
| 100 void ChromeSetting::Get(gin::Arguments* arguments) { |
| 101 HandleFunction("get", arguments); |
| 102 } |
| 103 |
| 104 void ChromeSetting::Set(gin::Arguments* arguments) { |
| 105 v8::Isolate* isolate = arguments->isolate(); |
| 106 v8::HandleScope handle_scope(isolate); |
| 107 |
| 108 v8::Local<v8::Object> holder; |
| 109 CHECK(arguments->GetHolder(&holder)); |
| 110 v8::Local<v8::Context> context = holder->CreationContext(); |
| 111 |
| 112 v8::Local<v8::Value> value = arguments->PeekNext(); |
| 113 // The set schema included in the Schema object is generic, since it varies |
| 114 // per-setting. However, this is only ever for a single setting, so we can |
| 115 // enforce the types more thoroughly. |
| 116 std::string error; |
| 117 if (!value.IsEmpty() && !argument_spec_.ParseArgument( |
| 118 context, value, *type_refs_, nullptr, &error)) { |
| 119 arguments->ThrowTypeError("Invalid invocation"); |
| 120 return; |
| 121 } |
| 122 HandleFunction("set", arguments); |
| 123 } |
| 124 |
| 125 void ChromeSetting::Clear(gin::Arguments* arguments) { |
| 126 HandleFunction("clear", arguments); |
| 127 } |
| 128 |
| 129 v8::Local<v8::Value> ChromeSetting::GetOnChangeEvent( |
| 130 gin::Arguments* arguments) { |
| 131 v8::Isolate* isolate = arguments->isolate(); |
| 132 v8::Local<v8::Object> holder; |
| 133 CHECK(arguments->GetHolder(&holder)); |
| 134 v8::Local<v8::Context> context = holder->CreationContext(); |
| 135 v8::Local<v8::Object> wrapper = GetWrapper(isolate); |
| 136 v8::Local<v8::Private> key = v8::Private::ForApi( |
| 137 isolate, gin::StringToSymbol(isolate, "onChangeEvent")); |
| 138 v8::Local<v8::Value> event; |
| 139 if (!wrapper->GetPrivate(context, key).ToLocal(&event)) { |
| 140 NOTREACHED(); |
| 141 return v8::Local<v8::Value>(); |
| 142 } |
| 143 |
| 144 DCHECK(!event.IsEmpty()); |
| 145 if (event->IsUndefined()) { |
| 146 event = event_handler_->CreateEventInstance( |
| 147 base::StringPrintf("types.ChromeSetting.%s.onChange", |
| 148 pref_name_.c_str()), |
| 149 context); |
| 150 v8::Maybe<bool> set_result = wrapper->SetPrivate(context, key, event); |
| 151 if (!set_result.IsJust() || !set_result.FromJust()) { |
| 152 NOTREACHED(); |
| 153 return v8::Local<v8::Value>(); |
| 154 } |
| 155 } |
| 156 return event; |
| 157 } |
| 158 |
| 159 void ChromeSetting::HandleFunction(const std::string& method_name, |
| 160 gin::Arguments* arguments) { |
| 161 v8::Isolate* isolate = arguments->isolate(); |
| 162 v8::HandleScope handle_scope(isolate); |
| 163 v8::Local<v8::Object> holder; |
| 164 CHECK(arguments->GetHolder(&holder)); |
| 165 v8::Local<v8::Context> context = holder->CreationContext(); |
| 166 |
| 167 std::vector<v8::Local<v8::Value>> argument_list; |
| 168 if (arguments->Length() > 0) { |
| 169 // Just copying handles should never fail. |
| 170 CHECK(arguments->GetRemaining(&argument_list)); |
| 171 } |
| 172 |
| 173 std::string full_name = "types.ChromeSetting." + method_name; |
| 174 std::unique_ptr<base::ListValue> converted_arguments; |
| 175 v8::Local<v8::Function> callback; |
| 176 std::string error; |
| 177 if (!type_refs_->GetTypeMethodSignature(full_name)->ParseArgumentsToJSON( |
| 178 context, argument_list, *type_refs_, &converted_arguments, &callback, |
| 179 &error)) { |
| 180 arguments->ThrowTypeError("Invalid invocation"); |
| 181 return; |
| 182 } |
| 183 |
| 184 converted_arguments->Insert(0u, base::MakeUnique<base::Value>(pref_name_)); |
| 185 request_handler_->StartRequest(context, full_name, |
| 186 std::move(converted_arguments), callback, |
| 187 v8::Local<v8::Function>()); |
| 188 } |
| 189 |
| 190 } // namespace extensions |
OLD | NEW |