| OLD | NEW |
| (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_js_util.h" | |
| 6 | |
| 7 #include "base/values.h" | |
| 8 #include "extensions/renderer/api_event_handler.h" | |
| 9 #include "extensions/renderer/api_request_handler.h" | |
| 10 #include "extensions/renderer/api_signature.h" | |
| 11 #include "extensions/renderer/api_type_reference_map.h" | |
| 12 #include "extensions/renderer/declarative_event.h" | |
| 13 #include "gin/converter.h" | |
| 14 #include "gin/dictionary.h" | |
| 15 #include "gin/handle.h" | |
| 16 #include "gin/object_template_builder.h" | |
| 17 | |
| 18 namespace extensions { | |
| 19 | |
| 20 gin::WrapperInfo APIBindingJSUtil::kWrapperInfo = {gin::kEmbedderNativeGin}; | |
| 21 | |
| 22 APIBindingJSUtil::APIBindingJSUtil(APITypeReferenceMap* type_refs, | |
| 23 APIRequestHandler* request_handler, | |
| 24 APIEventHandler* event_handler, | |
| 25 const binding::RunJSFunction& run_js) | |
| 26 : type_refs_(type_refs), | |
| 27 request_handler_(request_handler), | |
| 28 event_handler_(event_handler), | |
| 29 run_js_(run_js) {} | |
| 30 | |
| 31 APIBindingJSUtil::~APIBindingJSUtil() {} | |
| 32 | |
| 33 gin::ObjectTemplateBuilder APIBindingJSUtil::GetObjectTemplateBuilder( | |
| 34 v8::Isolate* isolate) { | |
| 35 return Wrappable<APIBindingJSUtil>::GetObjectTemplateBuilder(isolate) | |
| 36 .SetMethod("sendRequest", &APIBindingJSUtil::SendRequest) | |
| 37 .SetMethod("registerEventArgumentMassager", | |
| 38 &APIBindingJSUtil::RegisterEventArgumentMassager) | |
| 39 .SetMethod("createCustomEvent", &APIBindingJSUtil::CreateCustomEvent) | |
| 40 .SetMethod("createCustomDeclarativeEvent", | |
| 41 &APIBindingJSUtil::CreateCustomDeclarativeEvent) | |
| 42 .SetMethod("invalidateEvent", &APIBindingJSUtil::InvalidateEvent) | |
| 43 .SetMethod("setLastError", &APIBindingJSUtil::SetLastError) | |
| 44 .SetMethod("clearLastError", &APIBindingJSUtil::ClearLastError) | |
| 45 .SetMethod("hasLastError", &APIBindingJSUtil::HasLastError) | |
| 46 .SetMethod("runCallbackWithLastError", | |
| 47 &APIBindingJSUtil::RunCallbackWithLastError); | |
| 48 } | |
| 49 | |
| 50 void APIBindingJSUtil::SendRequest( | |
| 51 gin::Arguments* arguments, | |
| 52 const std::string& name, | |
| 53 const std::vector<v8::Local<v8::Value>>& request_args, | |
| 54 v8::Local<v8::Value> schemas_unused, | |
| 55 v8::Local<v8::Value> options) { | |
| 56 v8::Isolate* isolate = arguments->isolate(); | |
| 57 v8::HandleScope handle_scope(isolate); | |
| 58 v8::Local<v8::Context> context = arguments->GetHolderCreationContext(); | |
| 59 | |
| 60 const APISignature* signature = type_refs_->GetAPIMethodSignature(name); | |
| 61 DCHECK(signature); | |
| 62 | |
| 63 binding::RequestThread thread = binding::RequestThread::UI; | |
| 64 v8::Local<v8::Function> custom_callback; | |
| 65 if (!options.IsEmpty() && !options->IsUndefined() && !options->IsNull()) { | |
| 66 if (!options->IsObject()) { | |
| 67 NOTREACHED(); | |
| 68 return; | |
| 69 } | |
| 70 v8::Local<v8::Object> options_obj = options.As<v8::Object>(); | |
| 71 if (!options_obj->GetPrototype()->IsNull()) { | |
| 72 NOTREACHED(); | |
| 73 return; | |
| 74 } | |
| 75 gin::Dictionary options_dict(isolate, options_obj); | |
| 76 // NOTE: We don't throw any errors here if forIOThread or customCallback are | |
| 77 // of invalid types. We could, if we wanted to be a bit more verbose. | |
| 78 bool for_io_thread = false; | |
| 79 if (options_dict.Get("forIOThread", &for_io_thread) && for_io_thread) | |
| 80 thread = binding::RequestThread::IO; | |
| 81 options_dict.Get("customCallback", &custom_callback); | |
| 82 } | |
| 83 | |
| 84 std::unique_ptr<base::ListValue> converted_arguments; | |
| 85 v8::Local<v8::Function> callback; | |
| 86 | |
| 87 // Some APIs (like fileSystem and contextMenus) don't provide arguments that | |
| 88 // match the expected schema. For now, we need to ignore these and trust the | |
| 89 // JS gives us something we expect. | |
| 90 // TODO(devlin): We should ideally always be able to validate these, meaning | |
| 91 // that we either need to make the APIs give us the expected signature, or | |
| 92 // need to have a way of indicating an internal signature. | |
| 93 CHECK(signature->ConvertArgumentsIgnoringSchema( | |
| 94 context, request_args, &converted_arguments, &callback)); | |
| 95 | |
| 96 request_handler_->StartRequest(context, name, std::move(converted_arguments), | |
| 97 callback, custom_callback, thread); | |
| 98 } | |
| 99 | |
| 100 void APIBindingJSUtil::RegisterEventArgumentMassager( | |
| 101 gin::Arguments* arguments, | |
| 102 const std::string& event_name, | |
| 103 v8::Local<v8::Function> massager) { | |
| 104 v8::Isolate* isolate = arguments->isolate(); | |
| 105 v8::HandleScope handle_scope(isolate); | |
| 106 v8::Local<v8::Context> context = arguments->GetHolderCreationContext(); | |
| 107 | |
| 108 event_handler_->RegisterArgumentMassager(context, event_name, massager); | |
| 109 } | |
| 110 | |
| 111 void APIBindingJSUtil::CreateCustomEvent(gin::Arguments* arguments, | |
| 112 v8::Local<v8::Value> v8_event_name, | |
| 113 v8::Local<v8::Value> unused_schema, | |
| 114 bool supports_filters) { | |
| 115 v8::Isolate* isolate = arguments->isolate(); | |
| 116 v8::HandleScope handle_scope(isolate); | |
| 117 v8::Local<v8::Context> context = arguments->GetHolderCreationContext(); | |
| 118 | |
| 119 std::string event_name; | |
| 120 if (!v8_event_name->IsUndefined()) { | |
| 121 if (!v8_event_name->IsString()) { | |
| 122 NOTREACHED(); | |
| 123 return; | |
| 124 } | |
| 125 event_name = gin::V8ToString(v8_event_name); | |
| 126 } | |
| 127 | |
| 128 DCHECK(!supports_filters || !event_name.empty()) | |
| 129 << "Events that support filters cannot be anonymous."; | |
| 130 | |
| 131 v8::Local<v8::Value> event; | |
| 132 if (event_name.empty()) { | |
| 133 event = event_handler_->CreateAnonymousEventInstance(context); | |
| 134 } else { | |
| 135 bool notify_on_change = true; | |
| 136 event = event_handler_->CreateEventInstance(event_name, supports_filters, | |
| 137 binding::kNoListenerMax, | |
| 138 notify_on_change, context); | |
| 139 } | |
| 140 | |
| 141 arguments->Return(event); | |
| 142 } | |
| 143 | |
| 144 void APIBindingJSUtil::CreateCustomDeclarativeEvent( | |
| 145 gin::Arguments* arguments, | |
| 146 const std::string& event_name, | |
| 147 const std::vector<std::string>& actions_list, | |
| 148 const std::vector<std::string>& conditions_list, | |
| 149 int webview_instance_id) { | |
| 150 v8::Isolate* isolate = arguments->isolate(); | |
| 151 v8::HandleScope handle_scope(isolate); | |
| 152 | |
| 153 gin::Handle<DeclarativeEvent> event = gin::CreateHandle( | |
| 154 isolate, | |
| 155 new DeclarativeEvent(event_name, type_refs_, request_handler_, | |
| 156 actions_list, conditions_list, webview_instance_id)); | |
| 157 | |
| 158 arguments->Return(event.ToV8()); | |
| 159 } | |
| 160 | |
| 161 void APIBindingJSUtil::InvalidateEvent(gin::Arguments* arguments, | |
| 162 v8::Local<v8::Object> event) { | |
| 163 v8::Isolate* isolate = arguments->isolate(); | |
| 164 v8::HandleScope handle_scope(isolate); | |
| 165 event_handler_->InvalidateCustomEvent(arguments->GetHolderCreationContext(), | |
| 166 event); | |
| 167 } | |
| 168 | |
| 169 void APIBindingJSUtil::SetLastError(gin::Arguments* arguments, | |
| 170 const std::string& error) { | |
| 171 v8::Isolate* isolate = arguments->isolate(); | |
| 172 v8::HandleScope handle_scope(isolate); | |
| 173 request_handler_->last_error()->SetError( | |
| 174 arguments->GetHolderCreationContext(), error); | |
| 175 } | |
| 176 | |
| 177 void APIBindingJSUtil::ClearLastError(gin::Arguments* arguments) { | |
| 178 v8::Isolate* isolate = arguments->isolate(); | |
| 179 v8::HandleScope handle_scope(isolate); | |
| 180 bool report_if_unchecked = false; | |
| 181 request_handler_->last_error()->ClearError( | |
| 182 arguments->GetHolderCreationContext(), report_if_unchecked); | |
| 183 } | |
| 184 | |
| 185 void APIBindingJSUtil::HasLastError(gin::Arguments* arguments) { | |
| 186 v8::Isolate* isolate = arguments->isolate(); | |
| 187 v8::HandleScope handle_scope(isolate); | |
| 188 | |
| 189 bool has_last_error = request_handler_->last_error()->HasError( | |
| 190 arguments->GetHolderCreationContext()); | |
| 191 arguments->Return(has_last_error); | |
| 192 } | |
| 193 | |
| 194 void APIBindingJSUtil::RunCallbackWithLastError( | |
| 195 gin::Arguments* arguments, | |
| 196 const std::string& error, | |
| 197 v8::Local<v8::Function> callback) { | |
| 198 v8::Isolate* isolate = arguments->isolate(); | |
| 199 v8::HandleScope handle_scope(isolate); | |
| 200 v8::Local<v8::Context> context = arguments->GetHolderCreationContext(); | |
| 201 | |
| 202 request_handler_->last_error()->SetError(context, error); | |
| 203 run_js_.Run(callback, context, 0, nullptr); | |
| 204 | |
| 205 bool report_if_unchecked = true; | |
| 206 request_handler_->last_error()->ClearError(context, report_if_unchecked); | |
| 207 } | |
| 208 | |
| 209 } // namespace extensions | |
| OLD | NEW |