| OLD | NEW |
| 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/js_extension_bindings_system.h" | 5 #include "extensions/renderer/js_extension_bindings_system.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/strings/string_split.h" | 8 #include "base/strings/string_split.h" |
| 9 #include "content/public/child/v8_value_converter.h" | 9 #include "content/public/child/v8_value_converter.h" |
| 10 #include "content/public/common/content_switches.h" | 10 #include "content/public/common/content_switches.h" |
| 11 #include "extensions/common/extension.h" | 11 #include "extensions/common/extension.h" |
| 12 #include "extensions/common/extension_api.h" |
| 12 #include "extensions/common/extension_urls.h" | 13 #include "extensions/common/extension_urls.h" |
| 13 #include "extensions/common/extensions_client.h" | 14 #include "extensions/common/extensions_client.h" |
| 14 #include "extensions/common/features/feature.h" | 15 #include "extensions/common/features/feature.h" |
| 15 #include "extensions/common/features/feature_provider.h" | 16 #include "extensions/common/features/feature_provider.h" |
| 16 #include "extensions/common/manifest_constants.h" | 17 #include "extensions/common/manifest_constants.h" |
| 17 #include "extensions/common/manifest_handlers/externally_connectable.h" | 18 #include "extensions/common/manifest_handlers/externally_connectable.h" |
| 18 #include "extensions/renderer/binding_generating_native_handler.h" | 19 #include "extensions/renderer/binding_generating_native_handler.h" |
| 19 #include "extensions/renderer/renderer_extension_registry.h" | 20 #include "extensions/renderer/renderer_extension_registry.h" |
| 20 #include "extensions/renderer/resource_bundle_source_map.h" | 21 #include "extensions/renderer/resource_bundle_source_map.h" |
| 21 #include "extensions/renderer/script_context.h" | 22 #include "extensions/renderer/script_context.h" |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 171 // TODO(kalman): Make the bindings registration have zero overhead then run | 172 // TODO(kalman): Make the bindings registration have zero overhead then run |
| 172 // the same code regardless of context type. | 173 // the same code regardless of context type. |
| 173 switch (context->context_type()) { | 174 switch (context->context_type()) { |
| 174 case Feature::UNSPECIFIED_CONTEXT: | 175 case Feature::UNSPECIFIED_CONTEXT: |
| 175 case Feature::WEB_PAGE_CONTEXT: | 176 case Feature::WEB_PAGE_CONTEXT: |
| 176 case Feature::BLESSED_WEB_PAGE_CONTEXT: | 177 case Feature::BLESSED_WEB_PAGE_CONTEXT: |
| 177 // Hard-code registration of any APIs that are exposed to webpage-like | 178 // Hard-code registration of any APIs that are exposed to webpage-like |
| 178 // contexts, because it's too expensive to run the full bindings code. | 179 // contexts, because it's too expensive to run the full bindings code. |
| 179 // All of the same permission checks will still apply. | 180 // All of the same permission checks will still apply. |
| 180 if (context->GetAvailability("app").is_available()) | 181 if (context->GetAvailability("app").is_available()) |
| 181 RegisterBinding("app", context); | 182 RegisterBinding("app", "app", context); |
| 182 if (context->GetAvailability("webstore").is_available()) | 183 if (context->GetAvailability("webstore").is_available()) |
| 183 RegisterBinding("webstore", context); | 184 RegisterBinding("webstore", "webstore", context); |
| 184 if (context->GetAvailability("dashboardPrivate").is_available()) | 185 if (context->GetAvailability("dashboardPrivate").is_available()) |
| 185 RegisterBinding("dashboardPrivate", context); | 186 RegisterBinding("dashboardPrivate", "dashboardPrivate", context); |
| 186 if (IsRuntimeAvailableToContext(context)) | 187 if (IsRuntimeAvailableToContext(context)) |
| 187 RegisterBinding("runtime", context); | 188 RegisterBinding("runtime", "runtime", context); |
| 188 break; | 189 break; |
| 189 | 190 |
| 190 case Feature::SERVICE_WORKER_CONTEXT: | 191 case Feature::SERVICE_WORKER_CONTEXT: |
| 191 DCHECK(ExtensionsClient::Get() | 192 DCHECK(ExtensionsClient::Get() |
| 192 ->ExtensionAPIEnabledInExtensionServiceWorkers()); | 193 ->ExtensionAPIEnabledInExtensionServiceWorkers()); |
| 193 // Intentional fallthrough. | 194 // Intentional fallthrough. |
| 194 case Feature::BLESSED_EXTENSION_CONTEXT: | 195 case Feature::BLESSED_EXTENSION_CONTEXT: |
| 195 case Feature::UNBLESSED_EXTENSION_CONTEXT: | 196 case Feature::UNBLESSED_EXTENSION_CONTEXT: |
| 196 case Feature::CONTENT_SCRIPT_CONTEXT: | 197 case Feature::CONTENT_SCRIPT_CONTEXT: |
| 197 case Feature::WEBUI_CONTEXT: { | 198 case Feature::WEBUI_CONTEXT: { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 210 if (api_feature_provider->GetParent(map_entry.second.get()) != nullptr) | 211 if (api_feature_provider->GetParent(map_entry.second.get()) != nullptr) |
| 211 continue; | 212 continue; |
| 212 | 213 |
| 213 // Skip chrome.test if this isn't a test. | 214 // Skip chrome.test if this isn't a test. |
| 214 if (map_entry.first == "test" && | 215 if (map_entry.first == "test" && |
| 215 !base::CommandLine::ForCurrentProcess()->HasSwitch( | 216 !base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 216 ::switches::kTestType)) { | 217 ::switches::kTestType)) { |
| 217 continue; | 218 continue; |
| 218 } | 219 } |
| 219 | 220 |
| 220 if (context->IsAnyFeatureAvailableToContext(*map_entry.second)) { | 221 if (context->IsAnyFeatureAvailableToContext( |
| 222 *map_entry.second, CheckAliasStatus::NOT_ALLOWED)) { |
| 223 // Check if the API feature is indeed an alias. If it is, the API |
| 224 // should use source API bindings as its own. |
| 225 const std::string& source = map_entry.second->source(); |
| 221 // TODO(lazyboy): RegisterBinding() uses |source_map_|, any thread | 226 // TODO(lazyboy): RegisterBinding() uses |source_map_|, any thread |
| 222 // safety issue? | 227 // safety issue? |
| 223 RegisterBinding(map_entry.first, context); | 228 RegisterBinding(source.empty() ? map_entry.first : source, |
| 229 map_entry.first, context); |
| 224 } | 230 } |
| 225 } | 231 } |
| 226 break; | 232 break; |
| 227 } | 233 } |
| 228 } | 234 } |
| 229 } | 235 } |
| 230 | 236 |
| 231 void JsExtensionBindingsSystem::HandleResponse(int request_id, | 237 void JsExtensionBindingsSystem::HandleResponse(int request_id, |
| 232 bool success, | 238 bool success, |
| 233 const base::ListValue& response, | 239 const base::ListValue& response, |
| (...skipping 25 matching lines...) Expand all Loading... |
| 259 arguments.push_back( | 265 arguments.push_back( |
| 260 converter->ToV8Value(filtering_info, context->v8_context())); | 266 converter->ToV8Value(filtering_info, context->v8_context())); |
| 261 } | 267 } |
| 262 } | 268 } |
| 263 | 269 |
| 264 context->module_system()->CallModuleMethodSafe( | 270 context->module_system()->CallModuleMethodSafe( |
| 265 kEventBindings, kEventDispatchFunction, arguments.size(), | 271 kEventBindings, kEventDispatchFunction, arguments.size(), |
| 266 arguments.data()); | 272 arguments.data()); |
| 267 } | 273 } |
| 268 | 274 |
| 269 void JsExtensionBindingsSystem::RegisterBinding(const std::string& api_name, | 275 void JsExtensionBindingsSystem::RegisterBinding( |
| 270 ScriptContext* context) { | 276 const std::string& api_name, |
| 277 const std::string& api_bind_name, |
| 278 ScriptContext* context) { |
| 271 std::string bind_name; | 279 std::string bind_name; |
| 272 v8::Local<v8::Object> bind_object = | 280 v8::Local<v8::Object> bind_object = |
| 273 GetOrCreateBindObjectIfAvailable(api_name, &bind_name, context); | 281 GetOrCreateBindObjectIfAvailable(api_bind_name, &bind_name, context); |
| 274 | 282 |
| 275 // Empty if the bind object failed to be created, probably because the | 283 // Empty if the bind object failed to be created, probably because the |
| 276 // extension overrode chrome with a non-object, e.g. window.chrome = true. | 284 // extension overrode chrome with a non-object, e.g. window.chrome = true. |
| 277 if (bind_object.IsEmpty()) | 285 if (bind_object.IsEmpty()) |
| 278 return; | 286 return; |
| 279 | 287 |
| 280 v8::Local<v8::String> v8_bind_name = | 288 v8::Local<v8::String> v8_bind_name = |
| 281 v8::String::NewFromUtf8(context->isolate(), bind_name.c_str()); | 289 v8::String::NewFromUtf8(context->isolate(), bind_name.c_str()); |
| 282 if (bind_object->HasRealNamedProperty(v8_bind_name)) { | 290 if (bind_object->HasRealNamedProperty(v8_bind_name)) { |
| 283 // The bind object may already have the property if the API has been | 291 // The bind object may already have the property if the API has been |
| 284 // registered before (or if the extension has put something there already, | 292 // registered before (or if the extension has put something there already, |
| 285 // but, whatevs). | 293 // but, whatevs). |
| 286 // | 294 // |
| 287 // In the former case, we need to re-register the bindings for the APIs | 295 // In the former case, we need to re-register the bindings for the APIs |
| 288 // which the extension now has permissions for (if any), but not touch any | 296 // which the extension now has permissions for (if any), but not touch any |
| 289 // others so that we don't destroy state such as event listeners. | 297 // others so that we don't destroy state such as event listeners. |
| 290 // | 298 // |
| 291 // TODO(kalman): Only register available APIs to make this all moot. | 299 // TODO(kalman): Only register available APIs to make this all moot. |
| 292 if (bind_object->HasRealNamedCallbackProperty(v8_bind_name)) | 300 if (bind_object->HasRealNamedCallbackProperty(v8_bind_name)) |
| 293 return; // lazy binding still there, nothing to do | 301 return; // lazy binding still there, nothing to do |
| 294 if (bind_object->Get(v8_bind_name)->IsObject()) | 302 if (bind_object->Get(v8_bind_name)->IsObject()) |
| 295 return; // binding has already been fully installed | 303 return; // binding has already been fully installed |
| 296 } | 304 } |
| 297 | 305 |
| 298 ModuleSystem* module_system = context->module_system(); | 306 ModuleSystem* module_system = context->module_system(); |
| 299 if (!source_map_->Contains(api_name)) { | 307 if (!source_map_->Contains(api_name)) { |
| 300 module_system->RegisterNativeHandler( | 308 module_system->RegisterNativeHandler( |
| 301 api_name, | 309 api_bind_name, |
| 302 std::unique_ptr<NativeHandler>( | 310 std::unique_ptr<NativeHandler>( |
| 303 new BindingGeneratingNativeHandler(context, api_name, "binding"))); | 311 new BindingGeneratingNativeHandler(context, api_name, "binding"))); |
| 304 module_system->SetNativeLazyField(bind_object, bind_name, api_name, | 312 module_system->SetNativeLazyField(bind_object, bind_name, api_bind_name, |
| 305 "binding"); | 313 "binding"); |
| 306 } else { | 314 } else { |
| 307 module_system->SetLazyField(bind_object, bind_name, api_name, "binding"); | 315 module_system->SetLazyField(bind_object, bind_name, api_name, "binding"); |
| 308 } | 316 } |
| 309 } | 317 } |
| 310 | 318 |
| 311 } // namespace extensions | 319 } // namespace extensions |
| OLD | NEW |