diff options
| author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-08-24 12:15:48 +0200 |
|---|---|---|
| committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-08-28 13:30:04 +0000 |
| commit | b014812705fc80bff0a5c120dfcef88f349816dc (patch) | |
| tree | 25a2e2d9fa285f1add86aa333389a839f81a39ae /chromium/extensions/browser | |
| parent | 9f4560b1027ae06fdb497023cdcaf91b8511fa74 (diff) | |
| download | qtwebengine-chromium-b014812705fc80bff0a5c120dfcef88f349816dc.tar.gz | |
BASELINE: Update Chromium to 68.0.3440.125
Change-Id: I23f19369e01f688e496f5bf179abb521ad73874f
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/extensions/browser')
158 files changed, 2592 insertions, 1386 deletions
diff --git a/chromium/extensions/browser/BUILD.gn b/chromium/extensions/browser/BUILD.gn index e1dcd075672..40b145b62c4 100644 --- a/chromium/extensions/browser/BUILD.gn +++ b/chromium/extensions/browser/BUILD.gn @@ -127,6 +127,8 @@ jumbo_source_set("browser_sources") { "extension_file_task_runner.h", "extension_function.cc", "extension_function.h", + "extension_function_constants.cc", + "extension_function_constants.h", "extension_function_dispatcher.cc", "extension_function_dispatcher.h", "extension_function_registry.cc", @@ -276,6 +278,8 @@ jumbo_source_set("browser_sources") { "load_monitoring_extension_host_queue.h", "management_policy.cc", "management_policy.h", + "media_capture_util.cc", + "media_capture_util.h", "mojo/interface_registration.cc", "mojo/interface_registration.h", "mojo/keep_alive_impl.cc", @@ -476,6 +480,7 @@ source_set("browser_tests") { } if (is_chromeos) { sources += [ + "api/cec_private/cec_private_apitest.cc", "api/media_perception_private/media_perception_private_apitest.cc", "api/virtual_keyboard/virtual_keyboard_apitest.cc", ] diff --git a/chromium/extensions/browser/api/BUILD.gn b/chromium/extensions/browser/api/BUILD.gn index 691e452964b..8045a127f65 100644 --- a/chromium/extensions/browser/api/BUILD.gn +++ b/chromium/extensions/browser/api/BUILD.gn @@ -131,6 +131,7 @@ source_set("api") { ] public_deps += [ + "//extensions/browser/api/cec_private", "//extensions/browser/api/clipboard", "//extensions/browser/api/diagnostics", "//extensions/browser/api/networking_config", diff --git a/chromium/extensions/browser/api/alarms/alarm_manager.cc b/chromium/extensions/browser/api/alarms/alarm_manager.cc index f6f9171c524..2440e0c75e7 100644 --- a/chromium/extensions/browser/api/alarms/alarm_manager.cc +++ b/chromium/extensions/browser/api/alarms/alarm_manager.cc @@ -11,7 +11,6 @@ #include "base/bind.h" #include "base/json/json_writer.h" #include "base/lazy_instance.h" -#include "base/message_loop/message_loop.h" #include "base/time/clock.h" #include "base/time/default_clock.h" #include "base/time/time.h" diff --git a/chromium/extensions/browser/api/alarms/alarms_api_unittest.cc b/chromium/extensions/browser/api/alarms/alarms_api_unittest.cc index 0d2d2dd5558..c15047feba3 100644 --- a/chromium/extensions/browser/api/alarms/alarms_api_unittest.cc +++ b/chromium/extensions/browser/api/alarms/alarms_api_unittest.cc @@ -7,7 +7,6 @@ #include <stddef.h> #include "base/json/json_reader.h" -#include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/test/simple_test_clock.h" #include "base/values.h" diff --git a/chromium/extensions/browser/api/bluetooth/bluetooth_apitest.cc b/chromium/extensions/browser/api/bluetooth/bluetooth_apitest.cc index 1db964d9590..a5f23ca635e 100644 --- a/chromium/extensions/browser/api/bluetooth/bluetooth_apitest.cc +++ b/chromium/extensions/browser/api/bluetooth/bluetooth_apitest.cc @@ -41,12 +41,12 @@ namespace { static const char* kAdapterAddress = "A1:A2:A3:A4:A5:A6"; static const char* kName = "whatsinaname"; -class BluetoothApiTest : public ExtensionApiTest { +class BluetoothApiTest : public extensions::ExtensionApiTest { public: BluetoothApiTest() {} void SetUpOnMainThread() override { - ExtensionApiTest::SetUpOnMainThread(); + extensions::ExtensionApiTest::SetUpOnMainThread(); empty_extension_ = extensions::ExtensionBuilder("Test").Build(); SetUpMockAdapter(); } diff --git a/chromium/extensions/browser/api/bluetooth_socket/bluetooth_socket_api.cc b/chromium/extensions/browser/api/bluetooth_socket/bluetooth_socket_api.cc index cb2a3e454a7..69134a8a2a8 100644 --- a/chromium/extensions/browser/api/bluetooth_socket/bluetooth_socket_api.cc +++ b/chromium/extensions/browser/api/bluetooth_socket/bluetooth_socket_api.cc @@ -545,13 +545,13 @@ BluetoothSocketSendFunction::~BluetoothSocketSendFunction() {} ExtensionFunction::ResponseAction BluetoothSocketSendFunction::Run() { DCHECK_CURRENTLY_ON(work_thread_id()); - auto params = bluetooth_socket::Send::Params::Create(*args_); - EXTENSION_FUNCTION_VALIDATE(params.get()); + params_ = bluetooth_socket::Send::Params::Create(*args_); + EXTENSION_FUNCTION_VALIDATE(params_.get()); - io_buffer_size_ = params->data.size(); - io_buffer_ = new net::WrappedIOBuffer(params->data.data()); + io_buffer_size_ = params_->data.size(); + io_buffer_ = new net::WrappedIOBuffer(params_->data.data()); - BluetoothApiSocket* socket = GetSocket(params->socket_id); + BluetoothApiSocket* socket = GetSocket(params_->socket_id); if (!socket) return RespondNow(Error(kSocketNotFoundError)); diff --git a/chromium/extensions/browser/api/bluetooth_socket/bluetooth_socket_api.h b/chromium/extensions/browser/api/bluetooth_socket/bluetooth_socket_api.h index 8178739413d..bbab919aacb 100644 --- a/chromium/extensions/browser/api/bluetooth_socket/bluetooth_socket_api.h +++ b/chromium/extensions/browser/api/bluetooth_socket/bluetooth_socket_api.h @@ -294,6 +294,7 @@ class BluetoothSocketSendFunction : public BluetoothSocketAsyncApiFunction { void OnError(BluetoothApiSocket::ErrorReason reason, const std::string& message); + std::unique_ptr<bluetooth_socket::Send::Params> params_; scoped_refptr<net::IOBuffer> io_buffer_; size_t io_buffer_size_; diff --git a/chromium/extensions/browser/api/bluetooth_socket/bluetooth_socket_api_unittest.cc b/chromium/extensions/browser/api/bluetooth_socket/bluetooth_socket_api_unittest.cc index 990505568ba..e755a3f612e 100644 --- a/chromium/extensions/browser/api/bluetooth_socket/bluetooth_socket_api_unittest.cc +++ b/chromium/extensions/browser/api/bluetooth_socket/bluetooth_socket_api_unittest.cc @@ -41,7 +41,7 @@ TEST_F(BluetoothSocketApiUnittest, CreateThenClose) { .Set("name", "bluetooth app") .Set("version", "1.0") .Set("bluetooth", - DictionaryBuilder().SetBoolean("socket", true).Build()) + DictionaryBuilder().Set("socket", true).Build()) .Set("app", DictionaryBuilder() .Set("background", diff --git a/chromium/extensions/browser/api/cast_channel/cast_channel_apitest.cc b/chromium/extensions/browser/api/cast_channel/cast_channel_apitest.cc index 5e7e35ec1c0..39f14f846cf 100644 --- a/chromium/extensions/browser/api/cast_channel/cast_channel_apitest.cc +++ b/chromium/extensions/browser/api/cast_channel/cast_channel_apitest.cc @@ -84,12 +84,12 @@ ACTION_TEMPLATE(InvokeCompletionCallback, } // namespace -class CastChannelAPITest : public ExtensionApiTest { +class CastChannelAPITest : public extensions::ExtensionApiTest { public: CastChannelAPITest() : ip_endpoint_(CreateIPEndPointForTest()) {} void SetUpCommandLine(base::CommandLine* command_line) override { - ExtensionApiTest::SetUpCommandLine(command_line); + extensions::ExtensionApiTest::SetUpCommandLine(command_line); command_line->AppendSwitchASCII( extensions::switches::kWhitelistedExtensionID, kTestExtensionId); } @@ -98,7 +98,7 @@ class CastChannelAPITest : public ExtensionApiTest { // Stub out DualMediaSinkService so it does not interfere with the test. media_router::DualMediaSinkService::SetInstanceForTest( new media_router::NoopDualMediaSinkService()); - ExtensionApiTest::SetUp(); + extensions::ExtensionApiTest::SetUp(); } void SetUpMockCastSocket() { diff --git a/chromium/extensions/browser/api/cec_private/BUILD.gn b/chromium/extensions/browser/api/cec_private/BUILD.gn new file mode 100644 index 00000000000..eea3c3439b2 --- /dev/null +++ b/chromium/extensions/browser/api/cec_private/BUILD.gn @@ -0,0 +1,23 @@ +# Copyright 2018 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//extensions/buildflags/buildflags.gni") + +assert(enable_extensions, + "Cannot depend on extensions because enable_extensions=false.") + +source_set("cec_private") { + sources = [ + "cec_private_api.cc", + "cec_private_api.h", + ] + + deps = [ + "//extensions/common/api", + ] + + public_deps = [ + "//extensions/browser:browser_sources", + ] +} diff --git a/chromium/extensions/browser/api/cec_private/cec_private_api.cc b/chromium/extensions/browser/api/cec_private/cec_private_api.cc new file mode 100644 index 00000000000..936a7895ef4 --- /dev/null +++ b/chromium/extensions/browser/api/cec_private/cec_private_api.cc @@ -0,0 +1,118 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/browser/api/cec_private/cec_private_api.h" + +#include <vector> + +#include "base/bind.h" +#include "base/logging.h" +#include "chromeos/dbus/cec_service_client.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "extensions/common/api/cec_private.h" +#include "extensions/common/manifest_handlers/kiosk_mode_info.h" + +namespace { + +const char kKioskOnlyError[] = + "Only kiosk enabled extensions are allowed to use this function."; + +extensions::api::cec_private::DisplayCecPowerState +ConvertCecServiceClientPowerState( + chromeos::CecServiceClient::PowerState power_state) { + switch (power_state) { + case chromeos::CecServiceClient::PowerState::kError: + return extensions::api::cec_private::DISPLAY_CEC_POWER_STATE_ERROR; + case chromeos::CecServiceClient::PowerState::kAdapterNotConfigured: + return extensions::api::cec_private:: + DISPLAY_CEC_POWER_STATE_ADAPTERNOTCONFIGURED; + case chromeos::CecServiceClient::PowerState::kNoDevice: + return extensions::api::cec_private::DISPLAY_CEC_POWER_STATE_NODEVICE; + case chromeos::CecServiceClient::PowerState::kOn: + return extensions::api::cec_private::DISPLAY_CEC_POWER_STATE_ON; + case chromeos::CecServiceClient::PowerState::kStandBy: + return extensions::api::cec_private::DISPLAY_CEC_POWER_STATE_STANDBY; + case chromeos::CecServiceClient::PowerState::kTransitioningToOn: + return extensions::api::cec_private:: + DISPLAY_CEC_POWER_STATE_TRANSITIONINGTOON; + case chromeos::CecServiceClient::PowerState::kTransitioningToStandBy: + return extensions::api::cec_private:: + DISPLAY_CEC_POWER_STATE_TRANSITIONINGTOSTANDBY; + case chromeos::CecServiceClient::PowerState::kUnknown: + return extensions::api::cec_private::DISPLAY_CEC_POWER_STATE_UNKNOWN; + } + + NOTREACHED(); + return extensions::api::cec_private::DISPLAY_CEC_POWER_STATE_UNKNOWN; +} + +} // namespace + +namespace extensions { +namespace api { + +CecPrivateFunction::CecPrivateFunction() = default; + +CecPrivateFunction::~CecPrivateFunction() = default; + +// Only allow calls from kiosk mode extensions. +bool CecPrivateFunction::PreRunValidation(std::string* error) { + if (!UIThreadExtensionFunction::PreRunValidation(error)) + return false; + + if (KioskModeInfo::IsKioskEnabled(extension())) + return true; + + *error = kKioskOnlyError; + return false; +} + +CecPrivateSendStandByFunction::CecPrivateSendStandByFunction() = default; + +CecPrivateSendStandByFunction::~CecPrivateSendStandByFunction() = default; + +ExtensionFunction::ResponseAction CecPrivateSendStandByFunction::Run() { + chromeos::DBusThreadManager::Get()->GetCecServiceClient()->SendStandBy(); + return RespondNow(NoArguments()); +} + +CecPrivateSendWakeUpFunction::CecPrivateSendWakeUpFunction() = default; + +CecPrivateSendWakeUpFunction::~CecPrivateSendWakeUpFunction() = default; + +ExtensionFunction::ResponseAction CecPrivateSendWakeUpFunction::Run() { + chromeos::DBusThreadManager::Get()->GetCecServiceClient()->SendWakeUp(); + return RespondNow(NoArguments()); +} + +CecPrivateQueryDisplayCecPowerStateFunction:: + CecPrivateQueryDisplayCecPowerStateFunction() = default; + +CecPrivateQueryDisplayCecPowerStateFunction:: + ~CecPrivateQueryDisplayCecPowerStateFunction() = default; + +ExtensionFunction::ResponseAction +CecPrivateQueryDisplayCecPowerStateFunction::Run() { + chromeos::DBusThreadManager::Get() + ->GetCecServiceClient() + ->QueryDisplayCecPowerState(base::BindOnce( + &CecPrivateQueryDisplayCecPowerStateFunction::HandlePowerStates, + this)); + return RespondLater(); +} + +void CecPrivateQueryDisplayCecPowerStateFunction::HandlePowerStates( + const std::vector<chromeos::CecServiceClient::PowerState>& power_states) { + std::vector<cec_private::DisplayCecPowerState> result_power_states; + + for (const chromeos::CecServiceClient::PowerState& state : power_states) { + result_power_states.push_back(ConvertCecServiceClientPowerState(state)); + } + + Respond(ArgumentList(cec_private::QueryDisplayCecPowerState::Results::Create( + result_power_states))); +} + +} // namespace api +} // namespace extensions diff --git a/chromium/extensions/browser/api/cec_private/cec_private_api.h b/chromium/extensions/browser/api/cec_private/cec_private_api.h new file mode 100644 index 00000000000..6a2029b5cda --- /dev/null +++ b/chromium/extensions/browser/api/cec_private/cec_private_api.h @@ -0,0 +1,75 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_BROWSER_API_CEC_PRIVATE_CEC_PRIVATE_API_H_ +#define EXTENSIONS_BROWSER_API_CEC_PRIVATE_CEC_PRIVATE_API_H_ + +#include <vector> + +#include "chromeos/dbus/cec_service_client.h" +#include "extensions/browser/extension_function.h" +#include "extensions/browser/extension_function_histogram_value.h" + +namespace extensions { +namespace api { + +class CecPrivateFunction : public UIThreadExtensionFunction { + public: + CecPrivateFunction(); + + protected: + ~CecPrivateFunction() override; + bool PreRunValidation(std::string* error) override; + + private: + DISALLOW_COPY_AND_ASSIGN(CecPrivateFunction); +}; + +class CecPrivateSendStandByFunction : public CecPrivateFunction { + public: + CecPrivateSendStandByFunction(); + DECLARE_EXTENSION_FUNCTION("cecPrivate.sendStandBy", CECPRIVATE_SENDSTANDBY) + + protected: + ~CecPrivateSendStandByFunction() override; + ResponseAction Run() override; + + private: + DISALLOW_COPY_AND_ASSIGN(CecPrivateSendStandByFunction); +}; + +class CecPrivateSendWakeUpFunction : public CecPrivateFunction { + public: + CecPrivateSendWakeUpFunction(); + DECLARE_EXTENSION_FUNCTION("cecPrivate.sendWakeUp", CECPRIVATE_SENDWAKEUP) + + protected: + ~CecPrivateSendWakeUpFunction() override; + ResponseAction Run() override; + + private: + DISALLOW_COPY_AND_ASSIGN(CecPrivateSendWakeUpFunction); +}; + +class CecPrivateQueryDisplayCecPowerStateFunction : public CecPrivateFunction { + public: + CecPrivateQueryDisplayCecPowerStateFunction(); + DECLARE_EXTENSION_FUNCTION("cecPrivate.queryDisplayCecPowerState", + CECPRIVATE_QUERYDISPLAYCECPOWERSTATE) + + protected: + ~CecPrivateQueryDisplayCecPowerStateFunction() override; + ResponseAction Run() override; + + private: + void HandlePowerStates( + const std::vector<chromeos::CecServiceClient::PowerState>& power_states); + + DISALLOW_COPY_AND_ASSIGN(CecPrivateQueryDisplayCecPowerStateFunction); +}; + +} // namespace api +} // namespace extensions + +#endif // EXTENSIONS_BROWSER_API_CEC_PRIVATE_CEC_PRIVATE_API_H_ diff --git a/chromium/extensions/browser/api/cec_private/cec_private_apitest.cc b/chromium/extensions/browser/api/cec_private/cec_private_apitest.cc new file mode 100644 index 00000000000..23c4b31c164 --- /dev/null +++ b/chromium/extensions/browser/api/cec_private/cec_private_apitest.cc @@ -0,0 +1,76 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/macros.h" +#include "chromeos/dbus/cec_service_client.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/fake_cec_service_client.h" +#include "extensions/common/features/feature_session_type.h" +#include "extensions/common/switches.h" +#include "extensions/shell/test/shell_apitest.h" +#include "extensions/test/extension_test_message_listener.h" +#include "extensions/test/result_catcher.h" + +namespace extensions { + +namespace { + +constexpr char kTestAppId[] = "jabiebdnficieldhmegebckfhpfidfla"; + +class CecPrivateKioskApiTest : public ShellApiTest { + public: + CecPrivateKioskApiTest() + : session_type_( + ScopedCurrentFeatureSessionType(FeatureSessionType::KIOSK)) {} + ~CecPrivateKioskApiTest() override = default; + + void SetUpOnMainThread() override { + cec_ = static_cast<chromeos::FakeCecServiceClient*>( + chromeos::DBusThreadManager::Get()->GetCecServiceClient()); + } + + void SetUpCommandLine(base::CommandLine* command_line) override { + command_line->AppendSwitchASCII( + extensions::switches::kWhitelistedExtensionID, kTestAppId); + ShellApiTest::SetUpCommandLine(command_line); + } + + protected: + chromeos::FakeCecServiceClient* cec_ = nullptr; + + private: + std::unique_ptr<base::AutoReset<FeatureSessionType>> session_type_; + DISALLOW_COPY_AND_ASSIGN(CecPrivateKioskApiTest); +}; + +using CecPrivateNonKioskApiTest = ShellApiTest; + +} // namespace + +IN_PROC_BROWSER_TEST_F(CecPrivateKioskApiTest, TestAllApiFunctions) { + cec_->set_tv_power_states({chromeos::CecServiceClient::PowerState::kOn, + chromeos::CecServiceClient::PowerState::kOn}); + extensions::ResultCatcher catcher; + ExtensionTestMessageListener standby_call_count("standby_call_count", true); + ExtensionTestMessageListener wakeup_call_count("wakeup_call_count", true); + + ASSERT_TRUE(LoadApp("api_test/cec_private/api")); + + ASSERT_TRUE(standby_call_count.WaitUntilSatisfied()) + << standby_call_count.message(); + standby_call_count.Reply(cec_->stand_by_call_count()); + + ASSERT_TRUE(wakeup_call_count.WaitUntilSatisfied()) + << wakeup_call_count.message(); + wakeup_call_count.Reply(cec_->wake_up_call_count()); + + ASSERT_TRUE(catcher.GetNextResult()) << catcher.message(); +} + +IN_PROC_BROWSER_TEST_F(CecPrivateNonKioskApiTest, TestCecPrivateNotAvailable) { + ASSERT_TRUE(RunAppTest("api_test/cec_private/non_kiosk_api_not_available")) + << message_; +} + +} // namespace extensions diff --git a/chromium/extensions/browser/api/declarative/declarative_rule_unittest.cc b/chromium/extensions/browser/api/declarative/declarative_rule_unittest.cc index c7e869c200f..8cb2cb86ab2 100644 --- a/chromium/extensions/browser/api/declarative/declarative_rule_unittest.cc +++ b/chromium/extensions/browser/api/declarative/declarative_rule_unittest.cc @@ -5,7 +5,6 @@ #include "extensions/browser/api/declarative/declarative_rule.h" #include "base/bind.h" -#include "base/message_loop/message_loop.h" #include "base/test/values_test_util.h" #include "base/values.h" #include "components/url_matcher/url_matcher_constants.h" diff --git a/chromium/extensions/browser/api/declarative/rules_registry.cc b/chromium/extensions/browser/api/declarative/rules_registry.cc index 9066bfb0f49..b84cc3a1701 100644 --- a/chromium/extensions/browser/api/declarative/rules_registry.cc +++ b/chromium/extensions/browser/api/declarative/rules_registry.cc @@ -8,7 +8,6 @@ #include "base/bind.h" #include "base/logging.h" -#include "base/message_loop/message_loop.h" #include "base/metrics/histogram_macros.h" #include "base/stl_util.h" #include "base/strings/stringprintf.h" @@ -88,7 +87,7 @@ RulesRegistry::RulesRegistry(content::BrowserContext* browser_context, ready_(/*signaled=*/!cache_delegate), // Immediately ready if no cache // delegate to wait for. last_generated_rule_identifier_id_(0), - weak_ptr_factory_(browser_context_ ? this : NULL) { + weak_ptr_factory_(this) { if (cache_delegate) { cache_delegate_ = cache_delegate->GetWeakPtr(); cache_delegate->Init(this); diff --git a/chromium/extensions/browser/api/declarative_net_request/indexed_rule.cc b/chromium/extensions/browser/api/declarative_net_request/indexed_rule.cc index 9849a407b01..47e5d21b76d 100644 --- a/chromium/extensions/browser/api/declarative_net_request/indexed_rule.cc +++ b/chromium/extensions/browser/api/declarative_net_request/indexed_rule.cc @@ -155,6 +155,8 @@ flat_rule::ElementType GetElementType(dnr_api::ResourceType resource_type) { switch (resource_type) { case dnr_api::RESOURCE_TYPE_NONE: return flat_rule::ElementType_NONE; + case dnr_api::RESOURCE_TYPE_MAIN_FRAME: + return flat_rule::ElementType_MAIN_FRAME; case dnr_api::RESOURCE_TYPE_SUB_FRAME: return flat_rule::ElementType_SUBDOCUMENT; case dnr_api::RESOURCE_TYPE_STYLESHEET: @@ -171,6 +173,8 @@ flat_rule::ElementType GetElementType(dnr_api::ResourceType resource_type) { return flat_rule::ElementType_XMLHTTPREQUEST; case dnr_api::RESOURCE_TYPE_PING: return flat_rule::ElementType_PING; + case dnr_api::RESOURCE_TYPE_CSP_REPORT: + return flat_rule::ElementType_CSP_REPORT; case dnr_api::RESOURCE_TYPE_MEDIA: return flat_rule::ElementType_MEDIA; case dnr_api::RESOURCE_TYPE_WEBSOCKET: @@ -214,10 +218,12 @@ ParseResult ComputeElementTypes(const dnr_api::RuleCondition& condition, if (include_element_type_mask & exclude_element_type_mask) return ParseResult::ERROR_RESOURCE_TYPE_DUPLICATED; - *element_types = - include_element_type_mask - ? include_element_type_mask - : (flat_rule::ElementType_ANY & ~exclude_element_type_mask); + if (include_element_type_mask != flat_rule::ElementType_NONE) + *element_types = include_element_type_mask; + else if (exclude_element_type_mask != flat_rule::ElementType_NONE) + *element_types = flat_rule::ElementType_ANY & ~exclude_element_type_mask; + else + *element_types = url_pattern_index::kDefaultFlatElementTypesMask; return ParseResult::SUCCESS; } diff --git a/chromium/extensions/browser/api/declarative_net_request/indexed_rule_unittest.cc b/chromium/extensions/browser/api/declarative_net_request/indexed_rule_unittest.cc index 334d50b51cd..7fe106ecdab 100644 --- a/chromium/extensions/browser/api/declarative_net_request/indexed_rule_unittest.cc +++ b/chromium/extensions/browser/api/declarative_net_request/indexed_rule_unittest.cc @@ -156,7 +156,8 @@ TEST_F(IndexedRuleTest, ResourceTypesParsing) { // Only valid if |expected_result| is SUCCESS. const uint16_t expected_element_types; } cases[] = { - {nullptr, nullptr, ParseResult::SUCCESS, flat_rule::ElementType_ANY}, + {nullptr, nullptr, ParseResult::SUCCESS, + flat_rule::ElementType_ANY & ~flat_rule::ElementType_MAIN_FRAME}, {nullptr, std::make_unique<ResourceTypeVec>( ResourceTypeVec({dnr_api::RESOURCE_TYPE_SCRIPT})), @@ -174,12 +175,13 @@ TEST_F(IndexedRuleTest, ResourceTypesParsing) { flat_rule::ElementType_NONE}, {nullptr, std::make_unique<ResourceTypeVec>(ResourceTypeVec( - {dnr_api::RESOURCE_TYPE_SUB_FRAME, dnr_api::RESOURCE_TYPE_STYLESHEET, - dnr_api::RESOURCE_TYPE_SCRIPT, dnr_api::RESOURCE_TYPE_IMAGE, - dnr_api::RESOURCE_TYPE_FONT, dnr_api::RESOURCE_TYPE_OBJECT, + {dnr_api::RESOURCE_TYPE_MAIN_FRAME, dnr_api::RESOURCE_TYPE_SUB_FRAME, + dnr_api::RESOURCE_TYPE_STYLESHEET, dnr_api::RESOURCE_TYPE_SCRIPT, + dnr_api::RESOURCE_TYPE_IMAGE, dnr_api::RESOURCE_TYPE_FONT, + dnr_api::RESOURCE_TYPE_OBJECT, dnr_api::RESOURCE_TYPE_XMLHTTPREQUEST, dnr_api::RESOURCE_TYPE_PING, - dnr_api::RESOURCE_TYPE_MEDIA, dnr_api::RESOURCE_TYPE_WEBSOCKET, - dnr_api::RESOURCE_TYPE_OTHER})), + dnr_api::RESOURCE_TYPE_CSP_REPORT, dnr_api::RESOURCE_TYPE_MEDIA, + dnr_api::RESOURCE_TYPE_WEBSOCKET, dnr_api::RESOURCE_TYPE_OTHER})), ParseResult::ERROR_NO_APPLICABLE_RESOURCE_TYPES, flat_rule::ElementType_NONE}, {std::make_unique<ResourceTypeVec>(ResourceTypeVec()), diff --git a/chromium/extensions/browser/api/declarative_net_request/ruleset_manager.cc b/chromium/extensions/browser/api/declarative_net_request/ruleset_manager.cc index 3090523b810..ba24ab6fb70 100644 --- a/chromium/extensions/browser/api/declarative_net_request/ruleset_manager.cc +++ b/chromium/extensions/browser/api/declarative_net_request/ruleset_manager.cc @@ -34,11 +34,11 @@ flat_rule::ElementType GetElementType(content::ResourceType type) { case content::RESOURCE_TYPE_LAST_TYPE: case content::RESOURCE_TYPE_PREFETCH: case content::RESOURCE_TYPE_SUB_RESOURCE: - // TODO(crbug.com/696822): Add support for main frame and csp report to - // url_pattern_index. These are supported by the Web Request API. + return flat_rule::ElementType_OTHER; case content::RESOURCE_TYPE_MAIN_FRAME: + return flat_rule::ElementType_MAIN_FRAME; case content::RESOURCE_TYPE_CSP_REPORT: - return flat_rule::ElementType_OTHER; + return flat_rule::ElementType_CSP_REPORT; case content::RESOURCE_TYPE_SCRIPT: case content::RESOURCE_TYPE_WORKER: case content::RESOURCE_TYPE_SHARED_WORKER: @@ -152,79 +152,76 @@ void RulesetManager::RemoveRuleset(const ExtensionId& extension_id) { ClearRendererCacheOnNavigation(); } -bool RulesetManager::ShouldBlockRequest(const WebRequestInfo& request, - bool is_incognito_context) const { +RulesetManager::Action RulesetManager::EvaluateRequest( + const WebRequestInfo& request, + bool is_incognito_context, + GURL* redirect_url) const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(redirect_url); if (!ShouldEvaluateRequest(request)) - return false; - - if (test_observer_) - test_observer_->OnShouldBlockRequest(request, is_incognito_context); + return Action::NONE; SCOPED_UMA_HISTOGRAM_TIMER( - "Extensions.DeclarativeNetRequest.ShouldBlockRequestTime.AllExtensions"); + "Extensions.DeclarativeNetRequest.EvaluateRequestTime.AllExtensions"); + if (test_observer_) + test_observer_->OnEvaluateRequest(request, is_incognito_context); + + const GURL& url = request.url; const url::Origin first_party_origin = request.initiator.value_or(url::Origin()); const flat_rule::ElementType element_type = GetElementType(request); - const bool is_third_party = - IsThirdPartyRequest(request.url, first_party_origin); - - for (const auto& ruleset_data : rulesets_) { - if (!ShouldEvaluateRulesetForRequest(ruleset_data, request, - is_incognito_context)) { - continue; - } + const bool is_third_party = IsThirdPartyRequest(url, first_party_origin); - if (ruleset_data.matcher->ShouldBlockRequest( - request.url, first_party_origin, element_type, is_third_party)) { - return true; + std::vector<bool> should_evaluate_rulesets_for_request(rulesets_.size()); + + // We first check if any extension wants the request to be blocked. + { + size_t i = 0; + auto ruleset_data = rulesets_.begin(); + for (; ruleset_data != rulesets_.end(); ++ruleset_data, ++i) { + // As a minor optimization, cache the value of + // |ShouldEvaluateRulesetForRequest|. + should_evaluate_rulesets_for_request[i] = ShouldEvaluateRulesetForRequest( + *ruleset_data, request, is_incognito_context); + + if (!should_evaluate_rulesets_for_request[i]) + continue; + + if (ruleset_data->matcher->ShouldBlockRequest( + url, first_party_origin, element_type, is_third_party)) { + return Action::BLOCK; + } } } - return false; -} - -bool RulesetManager::ShouldRedirectRequest(const WebRequestInfo& request, - bool is_incognito_context, - GURL* redirect_url) const { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(redirect_url); - if (!ShouldEvaluateRequest(request)) - return false; + // The request shouldn't be blocked. Now check if any extension wants to + // redirect the request. // Redirecting WebSocket handshake request is prohibited. - const flat_rule::ElementType element_type = GetElementType(request); if (element_type == flat_rule::ElementType_WEBSOCKET) - return false; - - SCOPED_UMA_HISTOGRAM_TIMER( - "Extensions.DeclarativeNetRequest.ShouldRedirectRequestTime." - "AllExtensions"); - - const GURL& url = request.url; - const url::Origin first_party_origin = - request.initiator.value_or(url::Origin()); - const bool is_third_party = IsThirdPartyRequest(url, first_party_origin); + return Action::NONE; // This iterates in decreasing order of extension installation time. Hence // more recently installed extensions get higher priority in choosing the // redirect url. - for (const auto& ruleset_data : rulesets_) { - if (!ShouldEvaluateRulesetForRequest(ruleset_data, request, - is_incognito_context)) { - continue; - } - - if (ruleset_data.matcher->ShouldRedirectRequest( - url, first_party_origin, element_type, is_third_party, - redirect_url)) { - return true; + { + size_t i = 0; + auto ruleset_data = rulesets_.begin(); + for (; ruleset_data != rulesets_.end(); ++ruleset_data, ++i) { + if (!should_evaluate_rulesets_for_request[i]) + continue; + + if (ruleset_data->matcher->ShouldRedirectRequest( + url, first_party_origin, element_type, is_third_party, + redirect_url)) { + return Action::REDIRECT; + } } } - return false; + return Action::NONE; } void RulesetManager::SetObserverForTest(TestObserver* observer) { @@ -295,7 +292,7 @@ bool RulesetManager::ShouldEvaluateRulesetForRequest( // have to do for split mode incognito extensions, pass false for // |crosses_incognito|. const bool crosses_incognito = false; - PermissionsData::AccessType result = + PermissionsData::PageAccess result = WebRequestPermissions::CanExtensionAccessURL( info_map_, ruleset.extension_id, request.url, tab_id, crosses_incognito, @@ -303,7 +300,7 @@ bool RulesetManager::ShouldEvaluateRulesetForRequest( request.initiator); // TODO(crbug.com/809680): Handle ACCESS_WITHHELD. - return result == PermissionsData::ACCESS_ALLOWED; + return result == PermissionsData::PageAccess::kAllowed; } } // namespace declarative_net_request diff --git a/chromium/extensions/browser/api/declarative_net_request/ruleset_manager.h b/chromium/extensions/browser/api/declarative_net_request/ruleset_manager.h index c4b2d6ac926..dd161d229b0 100644 --- a/chromium/extensions/browser/api/declarative_net_request/ruleset_manager.h +++ b/chromium/extensions/browser/api/declarative_net_request/ruleset_manager.h @@ -28,14 +28,20 @@ class RulesetMatcher; // same sequence. class RulesetManager { public: + enum class Action { + NONE, + BLOCK, + REDIRECT, + }; + explicit RulesetManager(const InfoMap* info_map); ~RulesetManager(); // An interface used for testing purposes. class TestObserver { public: - virtual void OnShouldBlockRequest(const WebRequestInfo& request, - bool is_incognito_context) = 0; + virtual void OnEvaluateRequest(const WebRequestInfo& request, + bool is_incognito_context) = 0; protected: virtual ~TestObserver() {} @@ -50,15 +56,14 @@ class RulesetManager { // corresponding AddRuleset. void RemoveRuleset(const ExtensionId& extension_id); - // Returns whether the given |request| should be blocked. - bool ShouldBlockRequest(const WebRequestInfo& request, - bool is_incognito_context) const; - - // Returns whether the given |request| should be redirected along with the - // |redirect_url|. |redirect_url| must not be null. - bool ShouldRedirectRequest(const WebRequestInfo& request, - bool is_incognito_context, - GURL* redirect_url) const; + // Returns the action to take for the given request. |redirect_url| will be + // populated if the returned action is |REDIRECT|. Blocking rules have higher + // priority than redirect rules. For determining the |redirect_url|, most + // recently installed extensions are given preference. |redirect_url| must not + // be null. + Action EvaluateRequest(const WebRequestInfo& request, + bool is_incognito_context, + GURL* redirect_url) const; // Returns the number of RulesetMatcher currently being managed. size_t GetMatcherCountForTest() const { return rulesets_.size(); } diff --git a/chromium/extensions/browser/api/declarative_webrequest/webrequest_action.cc b/chromium/extensions/browser/api/declarative_webrequest/webrequest_action.cc index 0045f147a61..b6957e49d93 100644 --- a/chromium/extensions/browser/api/declarative_webrequest/webrequest_action.cc +++ b/chromium/extensions/browser/api/declarative_webrequest/webrequest_action.cc @@ -508,7 +508,7 @@ bool WebRequestAction::HasPermission(ApplyInfo* apply_info, return WebRequestPermissions::CanExtensionAccessURL( extension_info_map, extension_id, request->url, -1, apply_info->crosses_incognito, permission_check, - request->initiator) == PermissionsData::ACCESS_ALLOWED; + request->initiator) == PermissionsData::PageAccess::kAllowed; } // static diff --git a/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc b/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc index c3d35ce84cd..6d5571f09df 100644 --- a/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc +++ b/chromium/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc @@ -41,7 +41,7 @@ const char kUnknownConditionName[] = "unknownType"; base::FilePath TestDataPath(base::StringPiece relative_to_src) { base::FilePath src_dir; - CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &src_dir)); + CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &src_dir)); return src_dir.AppendASCII(relative_to_src); } diff --git a/chromium/extensions/browser/api/extensions_api_client.cc b/chromium/extensions/browser/api/extensions_api_client.cc index 7e2881d24b4..213c0a76ae2 100644 --- a/chromium/extensions/browser/api/extensions_api_client.cc +++ b/chromium/extensions/browser/api/extensions_api_client.cc @@ -44,7 +44,7 @@ bool ExtensionsAPIClient::ShouldHideResponseHeader( } bool ExtensionsAPIClient::ShouldHideBrowserNetworkRequest( - const GURL& url) const { + const WebRequestInfo& request) const { return false; } diff --git a/chromium/extensions/browser/api/extensions_api_client.h b/chromium/extensions/browser/api/extensions_api_client.h index c5e4a6d8c80..32ddf2ba2f2 100644 --- a/chromium/extensions/browser/api/extensions_api_client.h +++ b/chromium/extensions/browser/api/extensions_api_client.h @@ -55,6 +55,7 @@ class ValueStoreCache; class ValueStoreFactory; class VirtualKeyboardDelegate; class WebRequestEventRouterDelegate; +struct WebRequestInfo; class WebViewGuest; class WebViewGuestDelegate; class WebViewPermissionHelper; @@ -94,9 +95,10 @@ class ExtensionsAPIClient { virtual bool ShouldHideResponseHeader(const GURL& url, const std::string& header_name) const; - // Returns true if a request from the given URL from the browser context - // should be hidden from extensions. - virtual bool ShouldHideBrowserNetworkRequest(const GURL& url) const; + // Returns true if the given |request| should be hidden from extensions. This + // should be invoked on the IO thread. + virtual bool ShouldHideBrowserNetworkRequest( + const WebRequestInfo& request) const; // Creates the AppViewGuestDelegate. virtual AppViewGuestDelegate* CreateAppViewGuestDelegate() const; diff --git a/chromium/extensions/browser/api/file_system/file_system_api.cc b/chromium/extensions/browser/api/file_system/file_system_api.cc index e4163081e8c..c1a510e26c8 100644 --- a/chromium/extensions/browser/api/file_system/file_system_api.cc +++ b/chromium/extensions/browser/api/file_system/file_system_api.cc @@ -551,7 +551,7 @@ void FileSystemChooseEntryFunction::ConfirmDirectoryAccessAsync( for (size_t i = 0; i < arraysize(kGraylistedPaths); i++) { base::FilePath graylisted_path; - if (!PathService::Get(kGraylistedPaths[i], &graylisted_path)) + if (!base::PathService::Get(kGraylistedPaths[i], &graylisted_path)) continue; if (check_path != graylisted_path && !check_path.IsParent(graylisted_path)) continue; diff --git a/chromium/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc b/chromium/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc index 8a11ac17bc8..7fb278f33d2 100644 --- a/chromium/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc +++ b/chromium/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc @@ -146,11 +146,9 @@ std::unique_ptr<extensions::UserScript> ParseContentScript( // The default for WebUI is not having special access, but we can change that // if needed. - bool allowed_everywhere = false; - if (extension && - extensions::PermissionsData::CanExecuteScriptEverywhere(extension)) - allowed_everywhere = true; - + bool allowed_everywhere = + extension && extensions::PermissionsData::CanExecuteScriptEverywhere( + extension->id(), extension->location()); for (const std::string& match : script_value.matches) { URLPattern pattern(UserScript::ValidUserScriptSchemes(allowed_everywhere)); if (pattern.Parse(match) != URLPattern::PARSE_SUCCESS) { diff --git a/chromium/extensions/browser/api/idle/idle_api_unittest.cc b/chromium/extensions/browser/api/idle/idle_api_unittest.cc index 3b1749619ec..72cc783ddff 100644 --- a/chromium/extensions/browser/api/idle/idle_api_unittest.cc +++ b/chromium/extensions/browser/api/idle/idle_api_unittest.cc @@ -32,10 +32,10 @@ namespace { class MockEventDelegate : public IdleManager::EventDelegate { public: MockEventDelegate() {} - virtual ~MockEventDelegate() {} + ~MockEventDelegate() override {} MOCK_METHOD2(OnStateChanged, void(const std::string&, ui::IdleState)); - virtual void RegisterObserver(EventRouter::Observer* observer) {} - virtual void UnregisterObserver(EventRouter::Observer* observer) {} + void RegisterObserver(EventRouter::Observer* observer) override {} + void UnregisterObserver(EventRouter::Observer* observer) override {} }; class TestIdleProvider : public IdleManager::IdleTimeProvider { diff --git a/chromium/extensions/browser/api/lock_screen_data/data_item_unittest.cc b/chromium/extensions/browser/api/lock_screen_data/data_item_unittest.cc index b6b17f9b493..a12783f796a 100644 --- a/chromium/extensions/browser/api/lock_screen_data/data_item_unittest.cc +++ b/chromium/extensions/browser/api/lock_screen_data/data_item_unittest.cc @@ -13,6 +13,7 @@ #include "base/callback.h" #include "base/files/scoped_temp_dir.h" #include "base/run_loop.h" +#include "base/sequenced_task_runner.h" #include "base/values.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "content/public/test/test_browser_context.h" @@ -170,7 +171,7 @@ class DataItemTest : public testing::Test { ListBuilder app_handlers_builder; app_handlers_builder.Append(DictionaryBuilder() .Set("action", "new_note") - .SetBoolean("enabled_on_lock_screen", true) + .Set("enabled_on_lock_screen", true) .Build()); scoped_refptr<const Extension> extension = ExtensionBuilder() diff --git a/chromium/extensions/browser/api/lock_screen_data/lock_screen_item_storage_unittest.cc b/chromium/extensions/browser/api/lock_screen_data/lock_screen_item_storage_unittest.cc index 0574a1b3f40..25dd3bb696b 100644 --- a/chromium/extensions/browser/api/lock_screen_data/lock_screen_item_storage_unittest.cc +++ b/chromium/extensions/browser/api/lock_screen_data/lock_screen_item_storage_unittest.cc @@ -656,7 +656,7 @@ class LockScreenItemStorageTest : public ExtensionsTest { ListBuilder app_handlers_builder; app_handlers_builder.Append(DictionaryBuilder() .Set("action", "new_note") - .SetBoolean("enabled_on_lock_screen", true) + .Set("enabled_on_lock_screen", true) .Build()); scoped_refptr<const Extension> extension = ExtensionBuilder() diff --git a/chromium/extensions/browser/api/lock_screen_data/lock_screen_value_store_migrator_impl_unittest.cc b/chromium/extensions/browser/api/lock_screen_data/lock_screen_value_store_migrator_impl_unittest.cc index a440c3fdd17..8594adec810 100644 --- a/chromium/extensions/browser/api/lock_screen_data/lock_screen_value_store_migrator_impl_unittest.cc +++ b/chromium/extensions/browser/api/lock_screen_data/lock_screen_value_store_migrator_impl_unittest.cc @@ -270,7 +270,7 @@ class LockScreenValueStoreMigratorImplTest : public testing::Test { ListBuilder app_handlers_builder; app_handlers_builder.Append(DictionaryBuilder() .Set("action", "new_note") - .SetBoolean("enabled_on_lock_screen", true) + .Set("enabled_on_lock_screen", true) .Build()); scoped_refptr<const Extension> extension = ExtensionBuilder() diff --git a/chromium/extensions/browser/api/management/management_api.cc b/chromium/extensions/browser/api/management/management_api.cc index 9c9fa6cb6e0..6aaccbe269e 100644 --- a/chromium/extensions/browser/api/management/management_api.cc +++ b/chromium/extensions/browser/api/management/management_api.cc @@ -37,6 +37,7 @@ #include "extensions/common/error_utils.h" #include "extensions/common/extension.h" #include "extensions/common/extension_icon_set.h" +#include "extensions/common/manifest.h" #include "extensions/common/manifest_handlers/icons_handler.h" #include "extensions/common/manifest_handlers/offline_enabled_info.h" #include "extensions/common/manifest_handlers/options_page_info.h" @@ -96,6 +97,7 @@ std::vector<management::LaunchType> GetAvailableLaunchTypes( } management::ExtensionInfo CreateExtensionInfo( + const Extension* source_extension, const Extension& extension, content::BrowserContext* context) { ExtensionSystem* system = ExtensionSystem::Get(context); @@ -116,8 +118,8 @@ management::ExtensionInfo CreateExtensionInfo( info.options_url = OptionsPageInfo::GetOptionsPage(&extension).spec(); info.homepage_url.reset( new std::string(ManifestURL::GetHomepageURL(&extension).spec())); - info.may_disable = - system->management_policy()->UserMayModifySettings(&extension, NULL); + info.may_disable = system->management_policy()->ExtensionMayModifySettings( + source_extension, &extension, nullptr); info.is_app = extension.is_app(); if (info.is_app) { if (extension.is_legacy_packaged_app()) @@ -144,8 +146,8 @@ management::ExtensionInfo CreateExtensionInfo( } info.may_enable = std::make_unique<bool>( - system->management_policy()->UserMayModifySettings(&extension, - nullptr) && + system->management_policy()->ExtensionMayModifySettings( + source_extension, &extension, nullptr) && !system->management_policy()->MustRemainDisabled(&extension, nullptr, nullptr)); } @@ -257,7 +259,8 @@ management::ExtensionInfo CreateExtensionInfo( return info; } -void AddExtensionInfo(const ExtensionSet& extensions, +void AddExtensionInfo(const Extension* source_extension, + const ExtensionSet& extensions, ExtensionInfoList* extension_list, content::BrowserContext* context) { for (ExtensionSet::const_iterator iter = extensions.begin(); @@ -267,7 +270,8 @@ void AddExtensionInfo(const ExtensionSet& extensions, if (!extension.ShouldExposeViaManagementAPI()) continue; - extension_list->push_back(CreateExtensionInfo(extension, context)); + extension_list->push_back( + CreateExtensionInfo(source_extension, extension, context)); } } @@ -277,11 +281,11 @@ ExtensionFunction::ResponseAction ManagementGetAllFunction::Run() { ExtensionInfoList extensions; ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context()); - AddExtensionInfo(registry->enabled_extensions(), &extensions, + AddExtensionInfo(extension(), registry->enabled_extensions(), &extensions, browser_context()); - AddExtensionInfo(registry->disabled_extensions(), &extensions, + AddExtensionInfo(extension(), registry->disabled_extensions(), &extensions, browser_context()); - AddExtensionInfo(registry->terminated_extensions(), &extensions, + AddExtensionInfo(extension(), registry->terminated_extensions(), &extensions, browser_context()); return RespondNow( @@ -294,18 +298,18 @@ ExtensionFunction::ResponseAction ManagementGetFunction::Run() { EXTENSION_FUNCTION_VALIDATE(params.get()); ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context()); - const Extension* extension = + const Extension* target_extension = registry->GetExtensionById(params->id, ExtensionRegistry::EVERYTHING); - if (!extension) + if (!target_extension) return RespondNow(Error(keys::kNoExtensionError, params->id)); return RespondNow(ArgumentList(management::Get::Results::Create( - CreateExtensionInfo(*extension, browser_context())))); + CreateExtensionInfo(extension(), *target_extension, browser_context())))); } ExtensionFunction::ResponseAction ManagementGetSelfFunction::Run() { return RespondNow(ArgumentList(management::Get::Results::Create( - CreateExtensionInfo(*extension_, browser_context())))); + CreateExtensionInfo(extension(), *extension_, browser_context())))); } ExtensionFunction::ResponseAction @@ -436,8 +440,8 @@ ExtensionFunction::ResponseAction ManagementSetEnabledFunction::Run() { bool enabled = params->enabled; const ManagementPolicy* policy = ExtensionSystem::Get(browser_context())->management_policy(); - if (!policy->UserMayModifySettings(target_extension, nullptr) || - (!enabled && policy->MustRemainEnabled(target_extension, nullptr)) || + if (!policy->ExtensionMayModifySettings(extension(), target_extension, + nullptr) || (enabled && policy->MustRemainDisabled(target_extension, nullptr, nullptr))) { return RespondNow(Error(keys::kUserCantModifyError, extension_id_)); @@ -471,8 +475,11 @@ ExtensionFunction::ResponseAction ManagementSetEnabledFunction::Run() { } delegate->EnableExtension(browser_context(), extension_id_); } else if (currently_enabled && !params->enabled) { - delegate->DisableExtension(browser_context(), extension_id_, - disable_reason::DISABLE_USER_ACTION); + delegate->DisableExtension( + browser_context(), extension(), extension_id_, + Manifest::IsPolicyLocation(target_extension->location()) + ? disable_reason::DISABLE_BLOCKED_BY_POLICY + : disable_reason::DISABLE_USER_ACTION); } return RespondNow(NoArguments()); @@ -769,9 +776,10 @@ void ManagementGenerateAppForLinkFunction::FinishCreateBookmarkApp( const Extension* extension, const WebApplicationInfo& web_app_info) { ResponseValue response = - extension ? ArgumentList(management::GenerateAppForLink::Results::Create( - CreateExtensionInfo(*extension, browser_context()))) - : Error(keys::kGenerateAppForLinkInstallError); + extension + ? ArgumentList(management::GenerateAppForLink::Results::Create( + CreateExtensionInfo(nullptr, *extension, browser_context()))) + : Error(keys::kGenerateAppForLinkInstallError); Respond(std::move(response)); Release(); // Balanced in Run(). } @@ -859,7 +867,8 @@ void ManagementEventRouter::BroadcastEvent( if (event_name == management::OnUninstalled::kEventName) { args->AppendString(extension->id()); } else { - args->Append(CreateExtensionInfo(*extension, browser_context_).ToValue()); + args->Append( + CreateExtensionInfo(nullptr, *extension, browser_context_).ToValue()); } EventRouter::Get(browser_context_) diff --git a/chromium/extensions/browser/api/management/management_api_delegate.h b/chromium/extensions/browser/api/management/management_api_delegate.h index 7c5e0f70dc4..13a46e53765 100644 --- a/chromium/extensions/browser/api/management/management_api_delegate.h +++ b/chromium/extensions/browser/api/management/management_api_delegate.h @@ -87,9 +87,11 @@ class ManagementAPIDelegate { virtual void EnableExtension(content::BrowserContext* context, const std::string& extension_id) const = 0; - // Disables the extension identified by |extension_id|. + // Disables the extension identified by |extension_id|. |source_extension| (if + // specified) is the extension that originated the request. virtual void DisableExtension( content::BrowserContext* context, + const Extension* source_extension, const std::string& extension_id, disable_reason::DisableReason disable_reason) const = 0; diff --git a/chromium/extensions/browser/api/media_perception_private/media_perception_api_delegate.h b/chromium/extensions/browser/api/media_perception_private/media_perception_api_delegate.h index a8db42327c4..b31f7150658 100644 --- a/chromium/extensions/browser/api/media_perception_private/media_perception_api_delegate.h +++ b/chromium/extensions/browser/api/media_perception_private/media_perception_api_delegate.h @@ -14,10 +14,9 @@ namespace extensions { class MediaPerceptionAPIDelegate { public: // Callback for loading a CrOS component. |mount_point| will contain a path to - // the loaded component, if installation succeeded. If the component failed to - // install, |mount_point| will be empty. + // the loaded component, if |success| is true (installation succeeded). using LoadCrOSComponentCallback = - base::OnceCallback<void(const base::FilePath& mount_point)>; + base::OnceCallback<void(bool success, const base::FilePath& mount_point)>; virtual ~MediaPerceptionAPIDelegate() {} diff --git a/chromium/extensions/browser/api/media_perception_private/media_perception_api_manager.cc b/chromium/extensions/browser/api/media_perception_private/media_perception_api_manager.cc index 7864742b44f..700c923391f 100644 --- a/chromium/extensions/browser/api/media_perception_private/media_perception_api_manager.cc +++ b/chromium/extensions/browser/api/media_perception_private/media_perception_api_manager.cc @@ -137,8 +137,9 @@ void MediaPerceptionAPIManager::SetAnalyticsComponent( void MediaPerceptionAPIManager::LoadComponentCallback( APISetAnalyticsComponentCallback callback, + bool success, const base::FilePath& mount_point) { - if (mount_point.empty()) { + if (!success) { std::move(callback).Run(GetFailedToInstallComponentState()); return; } diff --git a/chromium/extensions/browser/api/media_perception_private/media_perception_api_manager.h b/chromium/extensions/browser/api/media_perception_private/media_perception_api_manager.h index c3e05f055c5..f0f88473b0b 100644 --- a/chromium/extensions/browser/api/media_perception_private/media_perception_api_manager.h +++ b/chromium/extensions/browser/api/media_perception_private/media_perception_api_manager.h @@ -98,6 +98,7 @@ class MediaPerceptionAPIManager // Callback with the mount point for a loaded component. void LoadComponentCallback(APISetAnalyticsComponentCallback callback, + bool success, const base::FilePath& mount_point); bool ComponentIsLoaded(); diff --git a/chromium/extensions/browser/api/media_perception_private/media_perception_private_api.cc b/chromium/extensions/browser/api/media_perception_private/media_perception_private_api.cc index b5295259e0b..f9f95881cf1 100644 --- a/chromium/extensions/browser/api/media_perception_private/media_perception_private_api.cc +++ b/chromium/extensions/browser/api/media_perception_private/media_perception_private_api.cc @@ -130,4 +130,15 @@ void MediaPerceptionPrivateSetAnalyticsComponentFunction:: Respond(OneArgument(component_state.ToValue())); } +MediaPerceptionPrivateSetComponentProcessStateFunction:: + MediaPerceptionPrivateSetComponentProcessStateFunction() = default; + +MediaPerceptionPrivateSetComponentProcessStateFunction:: + ~MediaPerceptionPrivateSetComponentProcessStateFunction() = default; + +ExtensionFunction::ResponseAction +MediaPerceptionPrivateSetComponentProcessStateFunction::Run() { + return RespondNow(Error("Not implemented.")); +} + } // namespace extensions diff --git a/chromium/extensions/browser/api/media_perception_private/media_perception_private_api.h b/chromium/extensions/browser/api/media_perception_private/media_perception_private_api.h index 8d8bfb580e4..8c62bdb35e1 100644 --- a/chromium/extensions/browser/api/media_perception_private/media_perception_private_api.h +++ b/chromium/extensions/browser/api/media_perception_private/media_perception_private_api.h @@ -86,6 +86,23 @@ class MediaPerceptionPrivateSetAnalyticsComponentFunction DISALLOW_COPY_AND_ASSIGN(MediaPerceptionPrivateSetAnalyticsComponentFunction); }; +class MediaPerceptionPrivateSetComponentProcessStateFunction + : public UIThreadExtensionFunction { + public: + MediaPerceptionPrivateSetComponentProcessStateFunction(); + DECLARE_EXTENSION_FUNCTION("mediaPerceptionPrivate.setComponentProcessState", + MEDIAPERCEPTIONPRIVATE_SETCOMPONENTPROCESSSTATE); + + private: + ~MediaPerceptionPrivateSetComponentProcessStateFunction() override; + + // ExtensionFunction: + ResponseAction Run() override; + + DISALLOW_COPY_AND_ASSIGN( + MediaPerceptionPrivateSetComponentProcessStateFunction); +}; + } // namespace extensions #endif // EXTENSIONS_BROWSER_API_MEDIA_PERCEPTION_PRIVATE_MEDIA_PERCEPTION_PRIVATE_API_H_ diff --git a/chromium/extensions/browser/api/media_perception_private/media_perception_private_apitest.cc b/chromium/extensions/browser/api/media_perception_private/media_perception_private_apitest.cc index 9329523eef2..98e722f2c12 100644 --- a/chromium/extensions/browser/api/media_perception_private/media_perception_private_apitest.cc +++ b/chromium/extensions/browser/api/media_perception_private/media_perception_private_apitest.cc @@ -35,15 +35,16 @@ class TestMediaPerceptionAPIDelegate : public MediaPerceptionAPIDelegate { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce( - std::move(load_callback), + std::move(load_callback), true, base::FilePath("/run/imageloader/rtanalytics-light/1.0"))); return; } - // Firing callback with empty string indicates that the installation of the + // Firing callback with false indicates that the installation of the // component failed. base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(std::move(load_callback), base::FilePath())); + FROM_HERE, + base::BindOnce(std::move(load_callback), false, base::FilePath())); } }; diff --git a/chromium/extensions/browser/api/messaging/message_property_provider.cc b/chromium/extensions/browser/api/messaging/message_property_provider.cc index fee4361a8b0..bb1e14c8e5f 100644 --- a/chromium/extensions/browser/api/messaging/message_property_provider.cc +++ b/chromium/extensions/browser/api/messaging/message_property_provider.cc @@ -62,12 +62,19 @@ void MessagePropertyProvider::GetChannelIDOnIOThread( const std::string& host, const ChannelIDCallback& reply) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - net::ChannelIDService* channel_id_service = - request_context_getter->GetURLRequestContext()->channel_id_service(); + const net::HttpNetworkSession::Params* network_params = + request_context_getter->GetURLRequestContext()->GetNetworkSessionParams(); GetChannelIDOutput* output = new GetChannelIDOutput(); net::CompletionCallback net_completion_callback = base::Bind(&MessagePropertyProvider::GotChannelID, original_task_runner, base::Owned(output), reply); + if (!network_params->enable_token_binding && + !network_params->enable_channel_id) { + GotChannelID(original_task_runner, output, reply, net::ERR_FILE_NOT_FOUND); + return; + } + net::ChannelIDService* channel_id_service = + request_context_getter->GetURLRequestContext()->channel_id_service(); int status = channel_id_service->GetChannelID( host, &output->channel_id_key, net_completion_callback, &output->request); if (status == net::ERR_IO_PENDING) diff --git a/chromium/extensions/browser/api/mime_handler_private/mime_handler_private.cc b/chromium/extensions/browser/api/mime_handler_private/mime_handler_private.cc index 3704ae0fb4b..09c6ff94b26 100644 --- a/chromium/extensions/browser/api/mime_handler_private/mime_handler_private.cc +++ b/chromium/extensions/browser/api/mime_handler_private/mime_handler_private.cc @@ -4,9 +4,9 @@ #include "extensions/browser/api/mime_handler_private/mime_handler_private.h" -#include <unordered_map> #include <utility> +#include "base/containers/flat_map.h" #include "base/strings/string_util.h" #include "content/public/browser/stream_handle.h" #include "content/public/browser/stream_info.h" @@ -19,9 +19,9 @@ namespace extensions { namespace { -std::unordered_map<std::string, std::string> CreateResponseHeadersMap( +base::flat_map<std::string, std::string> CreateResponseHeadersMap( const net::HttpResponseHeaders* headers) { - std::unordered_map<std::string, std::string> result; + base::flat_map<std::string, std::string> result; if (!headers) return result; diff --git a/chromium/extensions/browser/api/networking_private/networking_private_chromeos_unittest.cc b/chromium/extensions/browser/api/networking_private/networking_private_chromeos_unittest.cc index 58a2402e9d4..d3daa37da48 100644 --- a/chromium/extensions/browser/api/networking_private/networking_private_chromeos_unittest.cc +++ b/chromium/extensions/browser/api/networking_private/networking_private_chromeos_unittest.cc @@ -9,7 +9,6 @@ #include "base/callback.h" #include "base/json/json_string_value_serializer.h" #include "base/macros.h" -#include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" @@ -189,40 +188,44 @@ class NetworkingPrivateApiTest : public ApiUnitTest { *device_policy_onc, base::DictionaryValue()); } + void SetDeviceProperty(const std::string& device_path, + const std::string& name, + const base::Value& value) { + device_test_->SetDeviceProperty(device_path, name, value, + /*notify_changed=*/false); + } + void SetUpCellular() { // Add a Cellular GSM Device. device_test_->AddDevice(kCellularDevicePath, shill::kTypeCellular, "stub_cellular_device1"); - device_test_->SetDeviceProperty(kCellularDevicePath, - shill::kCarrierProperty, - base::Value("Cellular1_Carrier")); + SetDeviceProperty(kCellularDevicePath, shill::kCarrierProperty, + base::Value("Cellular1_Carrier")); base::DictionaryValue home_provider; home_provider.SetString("name", "Cellular1_Provider"); home_provider.SetString("code", "000000"); home_provider.SetString("country", "us"); - device_test_->SetDeviceProperty( - kCellularDevicePath, shill::kHomeProviderProperty, home_provider); - device_test_->SetDeviceProperty(kCellularDevicePath, - shill::kTechnologyFamilyProperty, - base::Value(shill::kNetworkTechnologyGsm)); - device_test_->SetDeviceProperty(kCellularDevicePath, shill::kMeidProperty, - base::Value("test_meid")); - device_test_->SetDeviceProperty(kCellularDevicePath, shill::kImeiProperty, - base::Value("test_imei")); - device_test_->SetDeviceProperty(kCellularDevicePath, shill::kIccidProperty, - base::Value("test_iccid")); - device_test_->SetDeviceProperty(kCellularDevicePath, shill::kImsiProperty, - base::Value("test_imsi")); - device_test_->SetDeviceProperty(kCellularDevicePath, shill::kEsnProperty, - base::Value("test_esn")); - device_test_->SetDeviceProperty(kCellularDevicePath, shill::kMdnProperty, - base::Value("test_mdn")); - device_test_->SetDeviceProperty(kCellularDevicePath, shill::kMinProperty, - base::Value("test_min")); - device_test_->SetDeviceProperty(kCellularDevicePath, - shill::kModelIdProperty, - base::Value("test_model_id")); + SetDeviceProperty(kCellularDevicePath, shill::kHomeProviderProperty, + home_provider); + SetDeviceProperty(kCellularDevicePath, shill::kTechnologyFamilyProperty, + base::Value(shill::kNetworkTechnologyGsm)); + SetDeviceProperty(kCellularDevicePath, shill::kMeidProperty, + base::Value("test_meid")); + SetDeviceProperty(kCellularDevicePath, shill::kImeiProperty, + base::Value("test_imei")); + SetDeviceProperty(kCellularDevicePath, shill::kIccidProperty, + base::Value("test_iccid")); + SetDeviceProperty(kCellularDevicePath, shill::kImsiProperty, + base::Value("test_imsi")); + SetDeviceProperty(kCellularDevicePath, shill::kEsnProperty, + base::Value("test_esn")); + SetDeviceProperty(kCellularDevicePath, shill::kMdnProperty, + base::Value("test_mdn")); + SetDeviceProperty(kCellularDevicePath, shill::kMinProperty, + base::Value("test_min")); + SetDeviceProperty(kCellularDevicePath, shill::kModelIdProperty, + base::Value("test_model_id")); std::unique_ptr<base::DictionaryValue> apn = DictionaryBuilder() .Set(shill::kApnProperty, "test-apn") @@ -231,8 +234,8 @@ class NetworkingPrivateApiTest : public ApiUnitTest { .Build(); std::unique_ptr<base::ListValue> apn_list = ListBuilder().Append(apn->CreateDeepCopy()).Build(); - device_test_->SetDeviceProperty(kCellularDevicePath, - shill::kCellularApnListProperty, *apn_list); + SetDeviceProperty(kCellularDevicePath, shill::kCellularApnListProperty, + *apn_list); service_test_->AddService(kCellularServicePath, kCellularGuid, kCellularName, shill::kTypeCellular, @@ -1081,8 +1084,8 @@ TEST_F(NetworkingPrivateApiTest, GetCellularProperties) { DictionaryBuilder() .Set("Cellular", DictionaryBuilder() - .SetBoolean("AllowRoaming", false) - .SetBoolean("AutoConnect", true) + .Set("AllowRoaming", false) + .Set("AutoConnect", true) .Set("Carrier", "Cellular1_Carrier") .Set("Family", "GSM") .Set("HomeProvider", DictionaryBuilder() @@ -1093,7 +1096,7 @@ TEST_F(NetworkingPrivateApiTest, GetCellularProperties) { .Set("ModelID", "test_model_id") .Set("NetworkTechnology", "GSM") .Set("RoamingState", "Home") - .SetBoolean("Scanning", false) + .Set("Scanning", false) .Build()) .Set("ConnectionState", "Connected") .Set("GUID", "cellular_guid") @@ -1128,8 +1131,8 @@ TEST_F(NetworkingPrivateApiTest, GetCellularPropertiesFromWebUi) { DictionaryBuilder() .Set("Cellular", DictionaryBuilder() - .SetBoolean("AllowRoaming", false) - .SetBoolean("AutoConnect", true) + .Set("AllowRoaming", false) + .Set("AutoConnect", true) .Set("Carrier", "Cellular1_Carrier") .Set("ESN", "test_esn") .Set("Family", "GSM") @@ -1147,7 +1150,7 @@ TEST_F(NetworkingPrivateApiTest, GetCellularPropertiesFromWebUi) { .Set("MIN", "test_min") .Set("NetworkTechnology", "GSM") .Set("RoamingState", "Home") - .SetBoolean("Scanning", false) + .Set("Scanning", false) .Set("APNList", ListBuilder() .Append(expected_apn->CreateDeepCopy()) .Build()) diff --git a/chromium/extensions/browser/api/networking_private/networking_private_linux.h b/chromium/extensions/browser/api/networking_private/networking_private_linux.h index 2a15c2619d4..171824f8481 100644 --- a/chromium/extensions/browser/api/networking_private/networking_private_linux.h +++ b/chromium/extensions/browser/api/networking_private/networking_private_linux.h @@ -11,7 +11,6 @@ #include <vector> #include "base/macros.h" -#include "base/message_loop/message_loop.h" #include "base/threading/thread.h" #include "components/keyed_service/core/keyed_service.h" #include "extensions/browser/api/networking_private/networking_private_delegate.h" diff --git a/chromium/extensions/browser/api/printer_provider/printer_provider_apitest.cc b/chromium/extensions/browser/api/printer_provider/printer_provider_apitest.cc index 2b5d573e9fb..eccef576b68 100644 --- a/chromium/extensions/browser/api/printer_provider/printer_provider_apitest.cc +++ b/chromium/extensions/browser/api/printer_provider/printer_provider_apitest.cc @@ -8,10 +8,6 @@ #include <vector> #include "base/bind.h" -#include "base/files/file.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" #include "base/json/json_string_value_serializer.h" #include "base/macros.h" #include "base/memory/ref_counted_memory.h" @@ -95,16 +91,11 @@ class PrinterProviderApiTest : public ShellApiTest { public: enum PrintRequestDataType { PRINT_REQUEST_DATA_TYPE_NOT_SET, - PRINT_REQUEST_DATA_TYPE_FILE, - PRINT_REQUEST_DATA_TYPE_FILE_DELETED, PRINT_REQUEST_DATA_TYPE_BYTES }; PrinterProviderApiTest() {} - ~PrinterProviderApiTest() override { - base::ScopedAllowBlockingForTesting allow_blocking; - ignore_result(data_dir_.Delete()); - } + ~PrinterProviderApiTest() override = default; void StartGetPrintersRequest( const PrinterProviderAPI::GetPrintersCallback& callback) { @@ -152,29 +143,6 @@ class PrinterProviderApiTest : public ShellApiTest { ->DispatchPrintRequested(job, std::move(callback)); } - bool StartPrintRequestUsingFileInfo( - const std::string& extension_id, - PrinterProviderAPI::PrintCallback callback) { - PrinterProviderPrintJob job; - - const char kBytes[] = {'b', 'y', 't', 'e', 's'}; - if (!CreateTempFileWithContents(kBytes, static_cast<int>(arraysize(kBytes)), - &job.document_path, &job.file_info)) { - ADD_FAILURE() << "Failed to create test file."; - return false; - } - - job.printer_id = extension_id + ":printer_id"; - job.job_title = base::ASCIIToUTF16("Print job"); - job.ticket_json = "{}"; - job.content_type = "image/pwg-raster"; - - PrinterProviderAPIFactory::GetInstance() - ->GetForBrowserContext(browser_context()) - ->DispatchPrintRequested(job, std::move(callback)); - return true; - } - void StartCapabilityRequest( const std::string& extension_id, PrinterProviderAPI::GetCapabilityCallback callback) { @@ -240,17 +208,6 @@ class PrinterProviderApiTest : public ShellApiTest { case PRINT_REQUEST_DATA_TYPE_NOT_SET: StartPrintRequestWithNoData(extension_id, std::move(callback)); break; - case PRINT_REQUEST_DATA_TYPE_FILE: - ASSERT_TRUE( - StartPrintRequestUsingFileInfo(extension_id, std::move(callback))); - break; - case PRINT_REQUEST_DATA_TYPE_FILE_DELETED: { - ASSERT_TRUE( - StartPrintRequestUsingFileInfo(extension_id, std::move(callback))); - base::ScopedAllowBlockingForTesting allow_blocking; - ASSERT_TRUE(data_dir_.Delete()); - break; - } case PRINT_REQUEST_DATA_TYPE_BYTES: StartPrintRequestUsingDocumentBytes(extension_id, std::move(callback)); break; @@ -352,27 +309,6 @@ class PrinterProviderApiTest : public ShellApiTest { device::MockUsbService usb_service_; private: - // Initializes |data_dir_| if needed and creates a file in it containing - // provided data. - bool CreateTempFileWithContents(const char* data, - int size, - base::FilePath* path, - base::File::Info* file_info) { - base::ScopedAllowBlockingForTesting allow_blocking; - if (!data_dir_.IsValid() && !data_dir_.CreateUniqueTempDir()) - return false; - - *path = data_dir_.GetPath().AppendASCII("data.pwg"); - int written = base::WriteFile(*path, data, size); - if (written != size) - return false; - if (!base::GetFileInfo(*path, file_info)) - return false; - return true; - } - - base::ScopedTempDir data_dir_; - DISALLOW_COPY_AND_ASSIGN(PrinterProviderApiTest); }; @@ -386,16 +322,6 @@ IN_PROC_BROWSER_TEST_F(PrinterProviderApiTest, MAYBE_PrintJobSuccess) { RunPrintRequestTestApp("OK", PRINT_REQUEST_DATA_TYPE_BYTES, "OK"); } -IN_PROC_BROWSER_TEST_F(PrinterProviderApiTest, PrintJobWithFileSuccess) { - RunPrintRequestTestApp("OK", PRINT_REQUEST_DATA_TYPE_FILE, "OK"); -} - -IN_PROC_BROWSER_TEST_F(PrinterProviderApiTest, - PrintJobWithFile_FileDeletedBeforeDispatch) { - RunPrintRequestTestApp("OK", PRINT_REQUEST_DATA_TYPE_FILE_DELETED, - "INVALID_DATA"); -} - IN_PROC_BROWSER_TEST_F(PrinterProviderApiTest, PrintJobAsyncSuccess) { RunPrintRequestTestApp("ASYNC_RESPONSE", PRINT_REQUEST_DATA_TYPE_BYTES, "OK"); } diff --git a/chromium/extensions/browser/api/printer_provider/printer_provider_print_job.h b/chromium/extensions/browser/api/printer_provider/printer_provider_print_job.h index a9f4b4b5555..682e150c44b 100644 --- a/chromium/extensions/browser/api/printer_provider/printer_provider_print_job.h +++ b/chromium/extensions/browser/api/printer_provider/printer_provider_print_job.h @@ -7,8 +7,6 @@ #include <string> -#include "base/files/file.h" -#include "base/files/file_path.h" #include "base/memory/ref_counted.h" #include "base/memory/ref_counted_memory.h" #include "base/strings/string16.h" @@ -17,9 +15,7 @@ namespace extensions { // Struct describing print job that should be forwarded to an extension via // chrome.printerProvider.onPrintRequested event. -// TODO(tbarzic): This should probably be a class and have some methods, e.g. -// whether the job is initialized and whether the data is described using a file -// or bytes. +// TODO(tbarzic): This should probably be a class and have some methods. struct PrinterProviderPrintJob { PrinterProviderPrintJob(); PrinterProviderPrintJob(const PrinterProviderPrintJob& other); @@ -41,17 +37,8 @@ struct PrinterProviderPrintJob { // Content type of the document that should be printed. std::string content_type; - // The document data that should be printed. Should be NULL if document data - // is kept in a file. + // The document data that should be printed. scoped_refptr<base::RefCountedMemory> document_bytes; - - // Path of the file which contains data to be printed. Should be set only if - // |document_bytes| are NULL. - base::FilePath document_path; - - // Information about the file which contains data to be printed. Should be - // set only if |document_path| is set. - base::File::Info file_info; }; } // namespace extensions diff --git a/chromium/extensions/browser/api/printer_provider_internal/printer_provider_internal_api.cc b/chromium/extensions/browser/api/printer_provider_internal/printer_provider_internal_api.cc index 220f9d8a04b..3400e9d7083 100644 --- a/chromium/extensions/browser/api/printer_provider_internal/printer_provider_internal_api.cc +++ b/chromium/extensions/browser/api/printer_provider_internal/printer_provider_internal_api.cc @@ -194,25 +194,17 @@ PrinterProviderInternalGetPrintDataFunction::Run() { if (!job) return RespondNow(Error("Print request not found.")); - if (job->document_bytes.get()) { - // |job->document_bytes| are passed to the callback to make sure the ref - // counted memory does not go away before the memory backed blob is created. - content::BrowserContext::CreateMemoryBackedBlob( - browser_context(), job->document_bytes->front_as<char>(), - job->document_bytes->size(), "", - base::Bind(&PrinterProviderInternalGetPrintDataFunction::OnBlob, this, - job->content_type, job->document_bytes->size(), - job->document_bytes)); - } else if (!job->document_path.empty()) { - content::BrowserContext::CreateFileBackedBlob( - browser_context(), job->document_path, 0 /* offset */, - job->file_info.size, job->file_info.last_modified, - base::Bind(&PrinterProviderInternalGetPrintDataFunction::OnBlob, this, - job->content_type, job->file_info.size, - scoped_refptr<base::RefCountedMemory>())); - } else { + if (!job->document_bytes) return RespondNow(Error("Job data not set")); - } + + // |job->document_bytes| are passed to the callback to make sure the ref + // counted memory does not go away before the memory backed blob is created. + content::BrowserContext::CreateMemoryBackedBlob( + browser_context(), job->document_bytes->front_as<char>(), + job->document_bytes->size(), "", + base::BindOnce(&PrinterProviderInternalGetPrintDataFunction::OnBlob, this, + job->content_type, job->document_bytes->size(), + job->document_bytes)); return RespondLater(); } diff --git a/chromium/extensions/browser/api/sockets_udp/sockets_udp_apitest.cc b/chromium/extensions/browser/api/sockets_udp/sockets_udp_apitest.cc index 3431997188d..884e1c7840d 100644 --- a/chromium/extensions/browser/api/sockets_udp/sockets_udp_apitest.cc +++ b/chromium/extensions/browser/api/sockets_udp/sockets_udp_apitest.cc @@ -4,6 +4,7 @@ #include "base/memory/ref_counted.h" #include "base/strings/stringprintf.h" +#include "build/build_config.h" #include "extensions/browser/api/dns/host_resolver_wrapper.h" #include "extensions/browser/api/dns/mock_host_resolver_creator.h" #include "extensions/browser/api/sockets_udp/sockets_udp_api.h" @@ -71,7 +72,15 @@ IN_PROC_BROWSER_TEST_F(SocketsUdpApiTest, SocketsUdpCreateGood) { ASSERT_TRUE(socketId > 0); } -IN_PROC_BROWSER_TEST_F(SocketsUdpApiTest, SocketsUdpExtension) { +// Disable SocketsUdpExtension on Mac ASAN due to time out. +// See https://crbug.com/844402 +#if defined(OS_MACOSX) && defined(ADDRESS_SANITIZER) +#define MAYBE_SocketsUdpExtension DISABLED_SocketsUdpExtension +#else +#define MAYBE_SocketsUdpExtension SocketsUdpExtension +#endif + +IN_PROC_BROWSER_TEST_F(SocketsUdpApiTest, MAYBE_SocketsUdpExtension) { std::unique_ptr<net::SpawnedTestServer> test_server( new net::SpawnedTestServer( net::SpawnedTestServer::TYPE_UDP_ECHO, diff --git a/chromium/extensions/browser/api/storage/settings_storage_quota_enforcer.cc b/chromium/extensions/browser/api/storage/settings_storage_quota_enforcer.cc index 1b3603cec5e..30356b0e7f7 100644 --- a/chromium/extensions/browser/api/storage/settings_storage_quota_enforcer.cc +++ b/chromium/extensions/browser/api/storage/settings_storage_quota_enforcer.cc @@ -8,7 +8,6 @@ #include "base/bind.h" #include "base/json/json_writer.h" -#include "base/message_loop/message_loop.h" #include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "extensions/common/extension_api.h" diff --git a/chromium/extensions/browser/api/system_display/display_info_provider.cc b/chromium/extensions/browser/api/system_display/display_info_provider.cc index a1fb62f2951..e30270b70dc 100644 --- a/chromium/extensions/browser/api/system_display/display_info_provider.cc +++ b/chromium/extensions/browser/api/system_display/display_info_provider.cc @@ -48,15 +48,9 @@ DisplayInfoProvider* DisplayInfoProvider::Get() { // static void DisplayInfoProvider::InitializeForTesting( DisplayInfoProvider* display_info_provider) { - DCHECK(display_info_provider); - g_display_info_provider = display_info_provider; -} - -// static -void DisplayInfoProvider::ResetForTesting() { if (g_display_info_provider) delete g_display_info_provider; - g_display_info_provider = nullptr; + g_display_info_provider = display_info_provider; } // static @@ -150,10 +144,6 @@ void DisplayInfoProvider::ShowNativeTouchCalibration(const std::string& id, NOTREACHED(); // Implemented on Chrome OS only in override. } -bool DisplayInfoProvider::IsNativeTouchCalibrationActive() { - return false; -} - bool DisplayInfoProvider::StartCustomTouchCalibration(const std::string& id) { NOTREACHED(); // Implemented on Chrome OS only in override. return false; @@ -171,10 +161,6 @@ bool DisplayInfoProvider::ClearTouchCalibration(const std::string& id) { return false; } -bool DisplayInfoProvider::IsCustomTouchCalibrationActive() { - return false; -} - void DisplayInfoProvider::SetMirrorMode( const api::system_display::MirrorModeInfo& info, ErrorCallback callback) { diff --git a/chromium/extensions/browser/api/system_display/display_info_provider.h b/chromium/extensions/browser/api/system_display/display_info_provider.h index 3b5f72776d9..492ab33eed3 100644 --- a/chromium/extensions/browser/api/system_display/display_info_provider.h +++ b/chromium/extensions/browser/api/system_display/display_info_provider.h @@ -96,8 +96,6 @@ class DisplayInfoProvider { // calibration has completed. virtual void ShowNativeTouchCalibration(const std::string& id, ErrorCallback callback); - // Returns true if native touch calibration is in progress. - virtual bool IsNativeTouchCalibrationActive(); // These methods implement custom touch calibration. They will return false // if |id| is invalid or if the operation is invalid. @@ -106,8 +104,6 @@ class DisplayInfoProvider { const api::system_display::TouchCalibrationPairQuad& pairs, const api::system_display::Bounds& bounds); virtual bool ClearTouchCalibration(const std::string& id); - // Returns true if custom touch calibration is in progress. - virtual bool IsCustomTouchCalibrationActive(); // Sets the display mode to the specified mirror mode. See system_display.idl. // |info|: Mirror mode properties to apply. diff --git a/chromium/extensions/browser/api/system_display/system_display_api.cc b/chromium/extensions/browser/api/system_display/system_display_api.cc index 150bbf16642..58528bfd3d8 100644 --- a/chromium/extensions/browser/api/system_display/system_display_api.cc +++ b/chromium/extensions/browser/api/system_display/system_display_api.cc @@ -317,13 +317,6 @@ ExtensionFunction::ResponseAction SystemDisplayShowNativeTouchCalibrationFunction::Run() { std::unique_ptr<display::ShowNativeTouchCalibration::Params> params( display::ShowNativeTouchCalibration::Params::Create(*args_)); - - if (DisplayInfoProvider::Get()->IsNativeTouchCalibrationActive()) - return RespondNow(Error("Native touch calibration already active.")); - - if (DisplayInfoProvider::Get()->IsCustomTouchCalibrationActive()) - return RespondNow(Error("Custom touch calibration is active.")); - DisplayInfoProvider::Get()->ShowNativeTouchCalibration( params->id, base::BindOnce(&SystemDisplayShowNativeTouchCalibrationFunction:: @@ -342,10 +335,6 @@ ExtensionFunction::ResponseAction SystemDisplayStartCustomTouchCalibrationFunction::Run() { std::unique_ptr<display::StartCustomTouchCalibration::Params> params( display::StartCustomTouchCalibration::Params::Create(*args_)); - - if (DisplayInfoProvider::Get()->IsNativeTouchCalibrationActive()) - return RespondNow(Error("Native touch calibration is active.")); - if (!DisplayInfoProvider::Get()->StartCustomTouchCalibration(params->id)) { return RespondNow( Error("Custom touch calibration not available for display.")); @@ -357,13 +346,6 @@ ExtensionFunction::ResponseAction SystemDisplayCompleteCustomTouchCalibrationFunction::Run() { std::unique_ptr<display::CompleteCustomTouchCalibration::Params> params( display::CompleteCustomTouchCalibration::Params::Create(*args_)); - - if (DisplayInfoProvider::Get()->IsNativeTouchCalibrationActive()) - return RespondNow(Error("Native touch calibration is active.")); - - if (!DisplayInfoProvider::Get()->IsCustomTouchCalibrationActive()) - return RespondNow(Error("Custom touch calibration is not active.")); - if (!DisplayInfoProvider::Get()->CompleteCustomTouchCalibration( params->pairs, params->bounds)) { return RespondNow(Error("Custom touch calibration completion failed.")); @@ -375,14 +357,6 @@ ExtensionFunction::ResponseAction SystemDisplayClearTouchCalibrationFunction::Run() { std::unique_ptr<display::ClearTouchCalibration::Params> params( display::ClearTouchCalibration::Params::Create(*args_)); - - if (DisplayInfoProvider::Get()->IsNativeTouchCalibrationActive()) - return RespondNow(Error("Native touch calibration is active.")); - - // TODO(malaykeshav@): Document and test whether - // IsCustomTouchCalibrationActive() should be true or false and enforce in - // DisplayInfoProvider::ClearTouchCalibration. - if (!DisplayInfoProvider::Get()->ClearTouchCalibration(params->id)) return RespondNow(Error("Failed to clear custom touch calibration data.")); return RespondNow(NoArguments()); diff --git a/chromium/extensions/browser/api/usb/usb_api.cc b/chromium/extensions/browser/api/usb/usb_api.cc index fb8e4f0e269..eb6ddd6d9b7 100644 --- a/chromium/extensions/browser/api/usb/usb_api.cc +++ b/chromium/extensions/browser/api/usb/usb_api.cc @@ -26,6 +26,7 @@ #include "extensions/browser/api/extensions_api_client.h" #include "extensions/browser/api/usb/usb_device_resource.h" #include "extensions/browser/api/usb/usb_guid_map.h" +#include "extensions/browser/extension_function_constants.h" #include "extensions/browser/extension_system.h" #include "extensions/common/api/usb.h" #include "extensions/common/permissions/permissions_data.h" @@ -668,8 +669,14 @@ ExtensionFunction::ResponseAction UsbGetUserSelectedDevicesFunction::Run() { filters.push_back(ConvertDeviceFilter(filter)); } - prompt_ = ExtensionsAPIClient::Get()->CreateDevicePermissionsPrompt( - GetAssociatedWebContents()); + content::WebContents* web_contents = GetSenderWebContents(); + if (!web_contents) { + return RespondNow( + Error(function_constants::kCouldNotFindSenderWebContents)); + } + + prompt_ = + ExtensionsAPIClient::Get()->CreateDevicePermissionsPrompt(web_contents); if (!prompt_) { return RespondNow(Error(kErrorNotSupported)); } diff --git a/chromium/extensions/browser/api/usb/usb_manual_apitest.cc b/chromium/extensions/browser/api/usb/usb_manual_apitest.cc index d28be9d390a..800e26f2826 100644 --- a/chromium/extensions/browser/api/usb/usb_manual_apitest.cc +++ b/chromium/extensions/browser/api/usb/usb_manual_apitest.cc @@ -5,11 +5,7 @@ #include "chrome/browser/extensions/api/permissions/permissions_api.h" #include "chrome/browser/extensions/extension_apitest.h" -namespace { - -class UsbManualApiTest : public ExtensionApiTest {}; - -} // namespace +using UsbManualApiTest = extensions::ExtensionApiTest; IN_PROC_BROWSER_TEST_F(UsbManualApiTest, MANUAL_ListInterfaces) { extensions::PermissionsRequestFunction::SetIgnoreUserGestureForTests(true); diff --git a/chromium/extensions/browser/api/web_request/form_data_parser.cc b/chromium/extensions/browser/api/web_request/form_data_parser.cc index f006684d015..aba2b4a6a1e 100644 --- a/chromium/extensions/browser/api/web_request/form_data_parser.cc +++ b/chromium/extensions/browser/api/web_request/form_data_parser.cc @@ -100,7 +100,6 @@ class FormDataParserUrlEncoded : public FormDataParser { // Auxiliary constant for using RE2. Number of arguments for parsing // name-value pairs (one for name, one for value). static const size_t args_size_ = 2u; - static const net::UnescapeRule::Type unescape_rules_; re2::StringPiece source_; bool source_set_; @@ -369,12 +368,6 @@ std::unique_ptr<FormDataParser> FormDataParser::CreateFromContentTypeHeader( FormDataParser::FormDataParser() {} -const net::UnescapeRule::Type FormDataParserUrlEncoded::unescape_rules_ = - net::UnescapeRule::PATH_SEPARATORS | - net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS | - net::UnescapeRule::SPOOFING_AND_CONTROL_CHARS | net::UnescapeRule::SPACES | - net::UnescapeRule::REPLACE_PLUS_WITH_SPACE; - FormDataParserUrlEncoded::FormDataParserUrlEncoded() : source_(NULL), source_set_(false), @@ -399,9 +392,12 @@ bool FormDataParserUrlEncoded::GetNextNameValue(Result* result) { bool success = RE2::ConsumeN(&source_, pattern(), args_, args_size_); if (success) { - result->set_name(net::UnescapeURLComponent(name_, unescape_rules_)); + const net::UnescapeRule::Type kUnescapeRules = + net::UnescapeRule::REPLACE_PLUS_WITH_SPACE; + + result->set_name(net::UnescapeBinaryURLComponent(name_, kUnescapeRules)); const std::string unescaped_value = - net::UnescapeURLComponent(value_, unescape_rules_); + net::UnescapeBinaryURLComponent(value_, kUnescapeRules); const base::StringPiece unescaped_data(unescaped_value.data(), unescaped_value.length()); if (base::IsStringUTF8(unescaped_data)) { @@ -550,11 +546,7 @@ bool FormDataParserMultipart::GetNextNameValue(Result* result) { return_value = FinishReadingPart(value_assigned ? nullptr : &value); } - std::string unescaped_name = net::UnescapeURLComponent( - name.as_string(), - net::UnescapeRule::PATH_SEPARATORS | - net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS | - net::UnescapeRule::SPOOFING_AND_CONTROL_CHARS); + std::string unescaped_name = net::UnescapeBinaryURLComponent(name); result->set_name(unescaped_name); if (value_assigned) { // Hold filename as value. diff --git a/chromium/extensions/browser/api/web_request/upload_data_presenter.cc b/chromium/extensions/browser/api/web_request/upload_data_presenter.cc index 022abc08ac3..9ded224b58d 100644 --- a/chromium/extensions/browser/api/web_request/upload_data_presenter.cc +++ b/chromium/extensions/browser/api/web_request/upload_data_presenter.cc @@ -8,6 +8,7 @@ #include "base/files/file_path.h" #include "base/memory/ptr_util.h" +#include "base/numerics/checked_math.h" #include "base/strings/string_util.h" #include "base/values.h" #include "extensions/browser/api/web_request/form_data_parser.h" @@ -106,7 +107,39 @@ void ParsedDataPresenter::FeedBytes(base::StringPiece bytes) { if (!success_) return; - if (!parser_->SetSource(bytes)) { + if (pending_bytes_.empty()) { + // First data chunk: track externally. + DCHECK(buffer_.empty()); + + pending_bytes_ = bytes; + return; + } + + // Pending data is either tracked externally or is located in our buffer. + DCHECK(buffer_.empty() || pending_bytes_.data() == buffer_.data()); + DCHECK(buffer_.empty() || pending_bytes_.size() == buffer_.size()); + + const auto safe_size = base::CheckAdd(pending_bytes_.size(), bytes.size()); + if (!safe_size.IsValid()) { + Abort(); + return; + } + + buffer_.reserve(safe_size.ValueOrDie()); + if (buffer_.empty()) { + // Second data chunk: copy pending external data to our internal buffer. + buffer_.append(pending_bytes_.data(), pending_bytes_.size()); + } + + buffer_.append(bytes.data(), bytes.size()); + pending_bytes_.set(buffer_.data(), buffer_.size()); +} + +void ParsedDataPresenter::CommitPendingBytes() { + if (!success_ || pending_bytes_.empty()) + return; + + if (!parser_->SetSource(pending_bytes_)) { Abort(); return; } @@ -116,11 +149,17 @@ void ParsedDataPresenter::FeedBytes(base::StringPiece bytes) { base::Value* list = GetOrCreateList(dictionary_.get(), result.name()); list->GetList().emplace_back(result.take_value()); } + + buffer_.clear(); + pending_bytes_.clear(); } -void ParsedDataPresenter::FeedFile(const base::FilePath& path) {} +void ParsedDataPresenter::FeedFile(const base::FilePath&) { + CommitPendingBytes(); +} bool ParsedDataPresenter::Succeeded() { + CommitPendingBytes(); if (success_ && !parser_->AllDataReadOK()) Abort(); return success_; diff --git a/chromium/extensions/browser/api/web_request/upload_data_presenter.h b/chromium/extensions/browser/api/web_request/upload_data_presenter.h index 98c0765dc59..3c9fa56b5bf 100644 --- a/chromium/extensions/browser/api/web_request/upload_data_presenter.h +++ b/chromium/extensions/browser/api/web_request/upload_data_presenter.h @@ -124,10 +124,17 @@ class ParsedDataPresenter : public UploadDataPresenter { // Clears resources and the success flag. void Abort(); + // Flushes any pending data to the parser. + void CommitPendingBytes(); + std::unique_ptr<FormDataParser> parser_; bool success_; std::unique_ptr<base::DictionaryValue> dictionary_; + // Buffered data (not yet commited to the parser). + base::StringPiece pending_bytes_; + std::string buffer_; + DISALLOW_COPY_AND_ASSIGN(ParsedDataPresenter); }; diff --git a/chromium/extensions/browser/api/web_request/upload_data_presenter_unittest.cc b/chromium/extensions/browser/api/web_request/upload_data_presenter_unittest.cc index 92f7afccca8..6716e11ac52 100644 --- a/chromium/extensions/browser/api/web_request/upload_data_presenter_unittest.cc +++ b/chromium/extensions/browser/api/web_request/upload_data_presenter_unittest.cc @@ -6,6 +6,7 @@ #include <utility> +#include "base/files/file_path.h" #include "base/values.h" #include "extensions/browser/api/web_request/upload_data_presenter.h" #include "extensions/browser/api/web_request/web_request_api_constants.h" @@ -81,4 +82,46 @@ TEST(WebRequestUploadDataPresenterTest, RawData) { EXPECT_TRUE(result->Equals(&expected_list)); } +TEST(WebRequestUploadDataPresenterTest, ParsedDataSegmented) { + // Input. + static constexpr char block1[] = "v1=FOO"; + static constexpr char block2[] = "BAR&v2=BAZ"; + static constexpr size_t block1_size = sizeof(block1) - 1; + static constexpr size_t block2_size = sizeof(block2) - 1; + + // Expected output. + auto v1 = std::make_unique<base::ListValue>(); + v1->AppendString("FOOBAR"); + auto v2 = std::make_unique<base::ListValue>(); + v2->AppendString("BAZ"); + + base::DictionaryValue expected_form; + expected_form.SetWithoutPathExpansion("v1", std::move(v1)); + expected_form.SetWithoutPathExpansion("v2", std::move(v2)); + + { + // Consecutive data segments should be consolidated and parsed successfuly. + auto parsed_data_presenter = ParsedDataPresenter::CreateForTests(); + ASSERT_TRUE(parsed_data_presenter.get()); + parsed_data_presenter->FeedBytes(base::StringPiece(block1, block1_size)); + parsed_data_presenter->FeedBytes(base::StringPiece(block2, block2_size)); + + EXPECT_TRUE(parsed_data_presenter->Succeeded()); + auto result = parsed_data_presenter->Result(); + ASSERT_TRUE(result); + EXPECT_EQ(*result, expected_form); + } + + { + // Data segments separate by file inputs should not be consolidated. + auto parsed_data_presenter = ParsedDataPresenter::CreateForTests(); + ASSERT_TRUE(parsed_data_presenter.get()); + parsed_data_presenter->FeedBytes(base::StringPiece(block1, block1_size)); + parsed_data_presenter->FeedFile(base::FilePath()); + parsed_data_presenter->FeedBytes(base::StringPiece(block2, block2_size)); + + EXPECT_FALSE(parsed_data_presenter->Succeeded()); + } +} + } // namespace extensions diff --git a/chromium/extensions/browser/api/web_request/web_request_api.cc b/chromium/extensions/browser/api/web_request/web_request_api.cc index 6d8f151cf4b..82d2809d071 100644 --- a/chromium/extensions/browser/api/web_request/web_request_api.cc +++ b/chromium/extensions/browser/api/web_request/web_request_api.cc @@ -26,6 +26,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "base/values.h" +#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" @@ -451,12 +452,17 @@ bool WebRequestAPI::MaybeProxyURLLoaderFactory( } auto proxy = base::MakeRefCounted<WebRequestProxyingURLLoaderFactory>( - frame->GetProcess()->GetBrowserContext(), info_map_); + frame->GetProcess()->GetBrowserContext(), + frame->GetProcess()->GetBrowserContext()->GetResourceContext(), + info_map_); proxies_.emplace(proxy.get(), proxy); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::BindOnce(&WebRequestProxyingURLLoaderFactory::StartProxying, proxy, - frame->GetProcess()->GetID(), frame->GetRoutingID(), + // Match the behavior of the WebRequestInfo constructor + // which takes a net::URLRequest*. + is_navigation ? -1 : frame->GetProcess()->GetID(), + is_navigation ? MSG_ROUTING_NONE : frame->GetRoutingID(), std::move(navigation_ui_data), std::move(proxied_request), std::move(target_factory_info), base::BindOnce(&WebRequestAPI::RemoveProxyThreadSafe, @@ -671,16 +677,14 @@ int ExtensionWebRequestEventRouter::OnBeforeRequest( // OnBeforeRequest call. // |extension_info_map| is null for system level requests. if (extension_info_map) { - // Give priority to blocking rules over redirect rules. - if (extension_info_map->GetRulesetManager()->ShouldBlockRequest( - *request, is_incognito_context)) { - return net::ERR_BLOCKED_BY_CLIENT; - } + using Action = declarative_net_request::RulesetManager::Action; - if (extension_info_map->GetRulesetManager()->ShouldRedirectRequest( - *request, is_incognito_context, new_url)) { + Action action = extension_info_map->GetRulesetManager()->EvaluateRequest( + *request, is_incognito_context, new_url); + if (action == Action::BLOCK) + return net::ERR_BLOCKED_BY_CLIENT; + if (action == Action::REDIRECT) return net::OK; - } } // Whether to initialized |blocked_requests_|. @@ -1460,7 +1464,7 @@ void ExtensionWebRequestEventRouter::GetMatchingListenersImpl( } if (!request->is_web_view) { - PermissionsData::AccessType access = + PermissionsData::PageAccess access = WebRequestPermissions::CanExtensionAccessURL( extension_info_map, listener->id.extension_id, request->url, request->frame_data ? request->frame_data->tab_id : -1, @@ -1468,8 +1472,8 @@ void ExtensionWebRequestEventRouter::GetMatchingListenersImpl( WebRequestPermissions::REQUIRE_HOST_PERMISSION_FOR_URL, request->initiator); - if (access != PermissionsData::ACCESS_ALLOWED) { - if (access == PermissionsData::ACCESS_WITHHELD && + if (access != PermissionsData::PageAccess::kAllowed) { + if (access == PermissionsData::PageAccess::kWithheld && web_request_event_router_delegate_) { web_request_event_router_delegate_->NotifyWebRequestWithheld( request->render_process_id, request->frame_id, @@ -1937,8 +1941,6 @@ bool ExtensionWebRequestEventRouter::ProcessDeclarativeRules( has_declarative_rules); } - base::Time start = base::Time::Now(); - bool deltas_created = false; for (const auto& it : relevant_registries) { WebRequestRulesRegistry* rules_registry = it.first; @@ -1955,10 +1957,6 @@ bool ExtensionWebRequestEventRouter::ProcessDeclarativeRules( } } - base::TimeDelta elapsed_time = start - base::Time::Now(); - UMA_HISTOGRAM_TIMES("Extensions.DeclarativeWebRequestNetworkDelay", - elapsed_time); - return deltas_created; } diff --git a/chromium/extensions/browser/api/web_request/web_request_api_helpers.cc b/chromium/extensions/browser/api/web_request/web_request_api_helpers.cc index 75f4554fb2b..4f363a8fb4a 100644 --- a/chromium/extensions/browser/api/web_request/web_request_api_helpers.cc +++ b/chromium/extensions/browser/api/web_request/web_request_api_helpers.cc @@ -32,6 +32,7 @@ #include "extensions/common/extension_messages.h" #include "net/cookies/cookie_util.h" #include "net/cookies/parsed_cookie.h" +#include "net/http/http_request_headers.h" #include "net/http/http_util.h" #include "net/log/net_log_event_type.h" #include "url/url_constants.h" @@ -49,7 +50,7 @@ namespace extension_web_request_api_helpers { namespace { -using ParsedResponseCookies = std::vector<linked_ptr<net::ParsedCookie>>; +using ParsedResponseCookies = std::vector<std::unique_ptr<net::ParsedCookie>>; // Mirrors the histogram enum of the same name. DO NOT REORDER THESE VALUES OR // CHANGE THEIR MEANING. @@ -710,6 +711,101 @@ static std::string FindRemoveRequestHeader( return std::string(); } +// TODO(yhirano): Remove this once https://crbug.com/827582 is solved. +class WebSocketRequestHeaderModificationStatusReporter final { + public: + WebSocketRequestHeaderModificationStatusReporter() = default; + + void Report(const std::set<std::string>& removed_headers, + const std::set<std::string>& set_headers) { + auto modification = + WebRequestWSRequestHeadersModification::kRiskyModification; + if (removed_headers.empty() && set_headers.empty()) + modification = WebRequestWSRequestHeadersModification::kNone; + if (removed_headers.empty() && set_headers.size() == 1 && + base::ToLowerASCII(*set_headers.begin()) == "user-agent") { + modification = WebRequestWSRequestHeadersModification::kSetUserAgentOnly; + } + UMA_HISTOGRAM_ENUMERATION( + "Extensions.WebRequest.WS_RequestHeadersModification", modification); + + for (const std::string& header : removed_headers) + Update(header); + for (const std::string& header : set_headers) + Update(header); + + UMA_HISTOGRAM_BOOLEAN("Extensions.WebRequest.WS_RequestHeaders_SecOrProxy", + modified_sec_or_proxy_headers_); + UMA_HISTOGRAM_BOOLEAN( + "Extensions.WebRequest.WS_RequestHeaders_SecOrProxyExceptProtocol", + modified_sec_or_proxy_headers_except_sec_websocket_protocol_); + UMA_HISTOGRAM_BOOLEAN("Extensions.WebRequest.WS_RequestHeaders_Unsafe", + modified_unsafe_headers_); + UMA_HISTOGRAM_BOOLEAN("Extensions.WebRequest.WS_RequestHeaders_WebSocket", + modified_websocket_headers_); + UMA_HISTOGRAM_BOOLEAN( + "Extensions.WebRequest.WS_RequestHeaders_WebSocketExceptProtocol", + modified_websocket_headers_except_sec_websocket_protocol_); + UMA_HISTOGRAM_BOOLEAN("Extensions.WebRequest.WS_RequestHeaders_Origin", + modified_origin_); + UMA_HISTOGRAM_BOOLEAN( + "Extensions.WebRequest.WS_RequestHeaders_OriginOrCookie", + modified_origin_or_cookie_); + } + + private: + void Update(const std::string& header) { + std::string lower_header = base::ToLowerASCII(header); + + if (base::StartsWith(lower_header, "sec-", base::CompareCase::SENSITIVE)) { + if (lower_header != "sec-websocket-protocol") + modified_sec_or_proxy_headers_except_sec_websocket_protocol_ = true; + modified_sec_or_proxy_headers_ = true; + + if (base::StartsWith(lower_header, "sec-websocket-", + base::CompareCase::SENSITIVE)) { + if (lower_header != "sec-websocket-protocol") + modified_websocket_headers_except_sec_websocket_protocol_ = true; + modified_websocket_headers_ = true; + } + } else if (base::StartsWith(lower_header, "proxy-", + base::CompareCase::SENSITIVE)) { + modified_sec_or_proxy_headers_ = true; + modified_sec_or_proxy_headers_except_sec_websocket_protocol_ = true; + } else if (lower_header == "cookie" || lower_header == "cookie2") { + modified_origin_or_cookie_ = true; + } else if (lower_header == "cache-control" || lower_header == "pragma" || + lower_header == "upgrade" || lower_header == "connection" || + lower_header == "host") { + modified_websocket_headers_ = true; + modified_websocket_headers_except_sec_websocket_protocol_ = true; + } else if (lower_header == "origin") { + // As we don't have an option to allow "origin" modification, all + // booleans should be set here. + modified_sec_or_proxy_headers_ = true; + modified_sec_or_proxy_headers_except_sec_websocket_protocol_ = true; + modified_unsafe_headers_ = true; + modified_websocket_headers_ = true; + modified_websocket_headers_except_sec_websocket_protocol_ = true; + modified_origin_ = true; + modified_origin_or_cookie_ = true; + } else if (!net::HttpUtil::IsSafeHeader(lower_header) && + lower_header != "user-agent") { + modified_unsafe_headers_ = true; + } + } + + bool modified_sec_or_proxy_headers_ = false; + bool modified_sec_or_proxy_headers_except_sec_websocket_protocol_ = false; + bool modified_unsafe_headers_ = false; + bool modified_websocket_headers_ = false; + bool modified_websocket_headers_except_sec_websocket_protocol_ = false; + bool modified_origin_ = false; + bool modified_origin_or_cookie_ = false; + + DISALLOW_COPY_AND_ASSIGN(WebSocketRequestHeaderModificationStatusReporter); +}; + void MergeOnBeforeSendHeadersResponses( const GURL& url, const EventResponseDeltas& deltas, @@ -842,18 +938,9 @@ void MergeOnBeforeSendHeadersResponses( removal); if (url.SchemeIsWSOrWSS()) { - auto modification = - WebRequestWSRequestHeadersModification::kRiskyModification; - if (removed_headers.empty() && set_headers.empty()) - modification = WebRequestWSRequestHeadersModification::kNone; - if (removed_headers.empty() && set_headers.size() == 1 && - base::ToLowerASCII(*set_headers.begin()) == "user-agent") { - modification = WebRequestWSRequestHeadersModification::kSetUserAgentOnly; - } - UMA_HISTOGRAM_ENUMERATION( - "Extensions.WebRequest.WS_RequestHeadersModification", modification); + WebSocketRequestHeaderModificationStatusReporter().Report(removed_headers, + set_headers); } - MergeCookiesInOnBeforeSendHeadersResponses(url, deltas, request_headers, conflicting_extensions, logger); } @@ -867,7 +954,7 @@ static ParsedResponseCookies GetResponseCookies( std::string value; while (override_response_headers->EnumerateHeader(&iter, "Set-Cookie", &value)) { - result.push_back(make_linked_ptr(new net::ParsedCookie(value))); + result.push_back(std::make_unique<net::ParsedCookie>(value)); } return result; } @@ -878,9 +965,9 @@ static void StoreResponseCookies( const ParsedResponseCookies& cookies, scoped_refptr<net::HttpResponseHeaders> override_response_headers) { override_response_headers->RemoveHeader("Set-Cookie"); - for (ParsedResponseCookies::const_iterator i = cookies.begin(); - i != cookies.end(); ++i) { - override_response_headers->AddHeader("Set-Cookie: " + (*i)->ToCookieLine()); + for (const std::unique_ptr<net::ParsedCookie>& cookie : cookies) { + override_response_headers->AddHeader("Set-Cookie: " + + cookie->ToCookieLine()); } } @@ -976,10 +1063,9 @@ static bool MergeAddResponseCookieModifications( continue; // Cookie names are not unique in response cookies so we always append // and never override. - linked_ptr<net::ParsedCookie> cookie( - new net::ParsedCookie(std::string())); + auto cookie = std::make_unique<net::ParsedCookie>(std::string()); ApplyResponseCookieModification((*mod)->modification.get(), cookie.get()); - cookies->push_back(cookie); + cookies->push_back(std::move(cookie)); modified = true; } } @@ -1003,12 +1089,10 @@ static bool MergeEditResponseCookieModifications( if ((*mod)->type != EDIT || !(*mod)->modification.get()) continue; - for (ParsedResponseCookies::iterator cookie = cookies->begin(); - cookie != cookies->end(); ++cookie) { - if (DoesResponseCookieMatchFilter(cookie->get(), - (*mod)->filter.get())) { + for (const std::unique_ptr<net::ParsedCookie>& cookie : *cookies) { + if (DoesResponseCookieMatchFilter(cookie.get(), (*mod)->filter.get())) { modified |= ApplyResponseCookieModification( - (*mod)->modification.get(), cookie->get()); + (*mod)->modification.get(), cookie.get()); } } } diff --git a/chromium/extensions/browser/api/web_request/web_request_info.cc b/chromium/extensions/browser/api/web_request/web_request_info.cc index ac1873d2545..bc7969facf8 100644 --- a/chromium/extensions/browser/api/web_request/web_request_info.cc +++ b/chromium/extensions/browser/api/web_request/web_request_info.cc @@ -256,6 +256,7 @@ WebRequestInfo::WebRequestInfo(net::URLRequest* url_request) type = info->GetResourceType(); web_request_type = ToWebRequestResourceType(type.value()); is_async = info->IsAsync(); + resource_context = info->GetContext(); } else { // There may be basic process and frame info associated with the request // even when |info| is null. Attempt to grab it as a last ditch effort. If @@ -286,6 +287,7 @@ WebRequestInfo::WebRequestInfo( int render_frame_id, std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data, int32_t routing_id, + content::ResourceContext* resource_context, const network::ResourceRequest& request) : id(request_id), url(request.url), @@ -298,7 +300,8 @@ WebRequestInfo::WebRequestInfo( initiator(request.request_initiator), type(static_cast<content::ResourceType>(request.resource_type)), extra_request_headers(request.headers), - logger(std::make_unique<NetworkServiceLogger>()) { + logger(std::make_unique<NetworkServiceLogger>()), + resource_context(resource_context) { if (url.SchemeIsWSOrWSS()) web_request_type = WebRequestResourceType::WEB_SOCKET; else diff --git a/chromium/extensions/browser/api/web_request/web_request_info.h b/chromium/extensions/browser/api/web_request/web_request_info.h index f66459cf471..b8d01992a8b 100644 --- a/chromium/extensions/browser/api/web_request/web_request_info.h +++ b/chromium/extensions/browser/api/web_request/web_request_info.h @@ -24,6 +24,10 @@ #include "url/gurl.h" #include "url/origin.h" +namespace content { +class ResourceContext; +} // namespace content + namespace net { class HttpResponseHeaders; class URLRequest; @@ -70,6 +74,7 @@ struct WebRequestInfo { int render_frame_id, std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data, int32_t routing_id, + content::ResourceContext* resource_context, const network::ResourceRequest& request); ~WebRequestInfo(); @@ -165,6 +170,9 @@ struct WebRequestInfo { // of Logger above. This is always non-null. std::unique_ptr<Logger> logger; + // The ResourceContext associated with this request. May be null. + content::ResourceContext* resource_context = nullptr; + private: void InitializeWebViewAndFrameData( const ExtensionNavigationUIData* navigation_ui_data); diff --git a/chromium/extensions/browser/api/web_request/web_request_permissions.cc b/chromium/extensions/browser/api/web_request/web_request_permissions.cc index 426bdc33602..2165a0e9d5a 100644 --- a/chromium/extensions/browser/api/web_request/web_request_permissions.cc +++ b/chromium/extensions/browser/api/web_request/web_request_permissions.cc @@ -42,7 +42,7 @@ bool HasWebRequestScheme(const GURL& url) { bool g_allow_all_extension_locations_in_public_session = false; -PermissionsData::AccessType GetHostAccessForURL( +PermissionsData::PageAccess GetHostAccessForURL( const extensions::Extension& extension, const GURL& url, int tab_id) { @@ -50,28 +50,28 @@ PermissionsData::AccessType GetHostAccessForURL( // anyway. if (url.SchemeIs(url::kAboutScheme) || url::IsSameOriginWith(url, extension.url())) { - return PermissionsData::ACCESS_ALLOWED; + return PermissionsData::PageAccess::kAllowed; } - return extension.permissions_data()->GetPageAccess(&extension, url, tab_id, + return extension.permissions_data()->GetPageAccess(url, tab_id, nullptr /*error*/); } // Returns the most restricted access type out of |access1| and |access2|. -PermissionsData::AccessType GetMinimumAccessType( - PermissionsData::AccessType access1, - PermissionsData::AccessType access2) { - PermissionsData::AccessType access = PermissionsData::ACCESS_DENIED; +PermissionsData::PageAccess GetMinimumAccessType( + PermissionsData::PageAccess access1, + PermissionsData::PageAccess access2) { + PermissionsData::PageAccess access = PermissionsData::PageAccess::kDenied; switch (access1) { - case PermissionsData::ACCESS_DENIED: - access = PermissionsData::ACCESS_DENIED; + case PermissionsData::PageAccess::kDenied: + access = PermissionsData::PageAccess::kDenied; break; - case PermissionsData::ACCESS_WITHHELD: - access = (access2 == PermissionsData::ACCESS_DENIED - ? PermissionsData::ACCESS_DENIED - : PermissionsData::ACCESS_WITHHELD); + case PermissionsData::PageAccess::kWithheld: + access = (access2 == PermissionsData::PageAccess::kDenied + ? PermissionsData::PageAccess::kDenied + : PermissionsData::PageAccess::kWithheld); break; - case PermissionsData::ACCESS_ALLOWED: + case PermissionsData::PageAccess::kAllowed: access = access2; break; } @@ -95,15 +95,15 @@ bool IsWebUIAllowedToMakeNetworkRequests(const url::Origin& origin) { } // namespace -// Returns true if the URL is sensitive and requests to this URL must not be +// Returns true if the given |request| is sensitive and must not be // modified/canceled by extensions, e.g. because it is targeted to the webstore // to check for updates, extension blacklisting, etc. -bool IsSensitiveURL(const GURL& url, - base::Optional<url::Origin> initiator, - bool is_request_from_browser, - bool is_request_from_webui_renderer) { +bool IsSensitiveRequest(const extensions::WebRequestInfo& request, + bool is_request_from_browser, + bool is_request_from_webui_renderer) { const bool is_request_from_sensitive_source = is_request_from_browser || is_request_from_webui_renderer; + const GURL& url = request.url; const bool is_network_request = url.SchemeIsHTTPOrHTTPS() || url.SchemeIsWSOrWSS(); @@ -114,10 +114,10 @@ bool IsSensitiveURL(const GURL& url, // The DCHECK helps avoid proliferation of such behavior. In any case, we // treat the requests as sensitive to ensure that the Web Request API // doesn't see them. - DCHECK(initiator.has_value()); - DCHECK(IsWebUIAllowedToMakeNetworkRequests(*initiator)) - << "Unsupported network request from " << initiator->GetURL().spec() - << " for " << url.spec(); + DCHECK(request.initiator.has_value()); + DCHECK(IsWebUIAllowedToMakeNetworkRequests(*request.initiator)) + << "Unsupported network request from " + << request.initiator->GetURL().spec() << " for " << url.spec(); return true; } @@ -168,14 +168,10 @@ bool IsSensitiveURL(const GURL& url, base::CompareCase::SENSITIVE)); } - if (is_request_from_sensitive_source) { - sensitive_chrome_url = - sensitive_chrome_url || - extensions::ExtensionsAPIClient::Get()->ShouldHideBrowserNetworkRequest( - url); - } - - return sensitive_chrome_url || extension_urls::IsWebstoreUpdateUrl(url) || + return sensitive_chrome_url || + extensions::ExtensionsAPIClient::Get() + ->ShouldHideBrowserNetworkRequest(request) || + extension_urls::IsWebstoreUpdateUrl(url) || extension_urls::IsBlacklistUpdateUrl(url) || extension_urls::IsSafeBrowsingUrl(origin, url.path_piece()); } @@ -221,8 +217,8 @@ bool WebRequestPermissions::HideRequest( request.render_process_id); } - return IsSensitiveURL(request.url, request.initiator, is_request_from_browser, - is_request_from_webui_renderer) || + return IsSensitiveRequest(request, is_request_from_browser, + is_request_from_webui_renderer) || !HasWebRequestScheme(request.url); } @@ -233,7 +229,7 @@ void WebRequestPermissions:: } // static -PermissionsData::AccessType WebRequestPermissions::CanExtensionAccessURL( +PermissionsData::PageAccess WebRequestPermissions::CanExtensionAccessURL( const extensions::InfoMap* extension_info_map, const std::string& extension_id, const GURL& url, @@ -243,18 +239,18 @@ PermissionsData::AccessType WebRequestPermissions::CanExtensionAccessURL( const base::Optional<url::Origin>& initiator) { // extension_info_map can be NULL in testing. if (!extension_info_map) - return PermissionsData::ACCESS_ALLOWED; + return PermissionsData::PageAccess::kAllowed; const extensions::Extension* extension = extension_info_map->extensions().GetByID(extension_id); if (!extension) - return PermissionsData::ACCESS_DENIED; + return PermissionsData::PageAccess::kDenied; // Prevent viewing / modifying requests initiated by a host protected by // policy. if (initiator && - extension->permissions_data()->IsRuntimeBlockedHost(initiator->GetURL())) - return PermissionsData::ACCESS_DENIED; + extension->permissions_data()->IsPolicyBlockedHost(initiator->GetURL())) + return PermissionsData::PageAccess::kDenied; // When we are in a Public Session, allow all URLs for webRequests initiated // by a regular extension (but don't allow chrome:// URLs). @@ -267,35 +263,35 @@ PermissionsData::AccessType WebRequestPermissions::CanExtensionAccessURL( // in Public Session is that all extensions are installed by policy). CHECK(g_allow_all_extension_locations_in_public_session || extensions::Manifest::IsPolicyLocation(extension->location())); - return PermissionsData::ACCESS_ALLOWED; + return PermissionsData::PageAccess::kAllowed; } #endif // Check if this event crosses incognito boundaries when it shouldn't. if (crosses_incognito && !extension_info_map->CanCrossIncognito(extension)) - return PermissionsData::ACCESS_DENIED; + return PermissionsData::PageAccess::kDenied; - PermissionsData::AccessType access = PermissionsData::ACCESS_DENIED; + PermissionsData::PageAccess access = PermissionsData::PageAccess::kDenied; switch (host_permissions_check) { case DO_NOT_CHECK_HOST: - access = PermissionsData::ACCESS_ALLOWED; + access = PermissionsData::PageAccess::kAllowed; break; case REQUIRE_HOST_PERMISSION_FOR_URL: access = GetHostAccessForURL(*extension, url, tab_id); break; case REQUIRE_HOST_PERMISSION_FOR_URL_AND_INITIATOR: { - PermissionsData::AccessType request_access = + PermissionsData::PageAccess request_access = GetHostAccessForURL(*extension, url, tab_id); - PermissionsData::AccessType initiator_access = + PermissionsData::PageAccess initiator_access = initiator ? GetHostAccessForURL(*extension, initiator->GetURL(), tab_id) - : PermissionsData::ACCESS_ALLOWED; + : PermissionsData::PageAccess::kAllowed; access = GetMinimumAccessType(request_access, initiator_access); break; } case REQUIRE_ALL_URLS: if (extension->permissions_data()->HasEffectiveAccessToAllHosts()) - access = PermissionsData::ACCESS_ALLOWED; + access = PermissionsData::PageAccess::kAllowed; // else ACCESS_DENIED break; } @@ -310,12 +306,12 @@ bool WebRequestPermissions::CanExtensionAccessInitiator( const base::Optional<url::Origin>& initiator, int tab_id, bool crosses_incognito) { - PermissionsData::AccessType access = PermissionsData::ACCESS_ALLOWED; + PermissionsData::PageAccess access = PermissionsData::PageAccess::kAllowed; if (initiator) { access = CanExtensionAccessURL( extension_info_map, extension_id, initiator->GetURL(), tab_id, crosses_incognito, WebRequestPermissions::REQUIRE_HOST_PERMISSION_FOR_URL, base::nullopt); } - return access == PermissionsData::ACCESS_ALLOWED; + return access == PermissionsData::PageAccess::kAllowed; } diff --git a/chromium/extensions/browser/api/web_request/web_request_permissions.h b/chromium/extensions/browser/api/web_request/web_request_permissions.h index 4a3c6fde7ea..af3608f1037 100644 --- a/chromium/extensions/browser/api/web_request/web_request_permissions.h +++ b/chromium/extensions/browser/api/web_request/web_request_permissions.h @@ -21,12 +21,12 @@ struct WebRequestInfo; } // Exposed for unit testing. -bool IsSensitiveURL(const GURL& url, - base::Optional<url::Origin> initiator, - bool is_request_from_browser, - bool is_request_from_webui_renderer); +bool IsSensitiveRequest(const extensions::WebRequestInfo& request, + bool is_request_from_browser, + bool is_request_from_webui_renderer); -// This class is used to test whether extensions may modify web requests. +// This class is used to test whether extensions may modify web requests. It +// should be used on the IO thread. class WebRequestPermissions { public: // Different host permission checking modes for CanExtensionAccessURL. @@ -50,7 +50,7 @@ class WebRequestPermissions { // |host_permission_check| controls how permissions are checked with regard to // |url| and |initiator| if an initiator exists. - static extensions::PermissionsData::AccessType CanExtensionAccessURL( + static extensions::PermissionsData::PageAccess CanExtensionAccessURL( const extensions::InfoMap* extension_info_map, const std::string& extension_id, const GURL& url, diff --git a/chromium/extensions/browser/api/web_request/web_request_permissions_unittest.cc b/chromium/extensions/browser/api/web_request/web_request_permissions_unittest.cc index f3afe687ba6..3df0f6c131c 100644 --- a/chromium/extensions/browser/api/web_request/web_request_permissions_unittest.cc +++ b/chromium/extensions/browser/api/web_request/web_request_permissions_unittest.cc @@ -5,12 +5,13 @@ #include "extensions/browser/api/web_request/web_request_permissions.h" #include "extensions/browser/api/extensions_api_client.h" +#include "extensions/browser/api/web_request/web_request_info.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" namespace extensions { -TEST(ExtensionWebRequestPermissions, IsSensitiveURL) { +TEST(ExtensionWebRequestPermissions, IsSensitiveRequest) { ExtensionsAPIClient api_client; struct TestCase { const char* url; @@ -55,19 +56,22 @@ TEST(ExtensionWebRequestPermissions, IsSensitiveURL) { {"https://chrome.google.com/webstore?query", true, true}, }; for (const TestCase& test : cases) { - GURL url(test.url); - EXPECT_TRUE(url.is_valid()) << test.url; + WebRequestInfo request; + request.url = GURL(test.url); + EXPECT_TRUE(request.url.is_valid()) << test.url; + + request.initiator = url::Origin::Create(request.url); EXPECT_EQ(test.is_sensitive_if_request_from_common_renderer, - IsSensitiveURL(url, url::Origin::Create(url), - false /* is_request_from_browser */, - false /* is_request_from_web_ui_renderer */)) + IsSensitiveRequest(request, false /* is_request_from_browser */, + false /* is_request_from_web_ui_renderer */)) << test.url; - const bool supported_in_webui_renderers = !url.SchemeIsHTTPOrHTTPS(); - EXPECT_EQ( - test.is_sensitive_if_request_from_browser_or_webui_renderer, - IsSensitiveURL(url, base::nullopt, true /* is_request_from_browser */, - supported_in_webui_renderers)) + const bool supported_in_webui_renderers = + !request.url.SchemeIsHTTPOrHTTPS(); + request.initiator = base::nullopt; + EXPECT_EQ(test.is_sensitive_if_request_from_browser_or_webui_renderer, + IsSensitiveRequest(request, true /* is_request_from_browser */, + supported_in_webui_renderers)) << test.url; } } diff --git a/chromium/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc b/chromium/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc index 466a63d172f..7b275e1abab 100644 --- a/chromium/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc +++ b/chromium/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc @@ -52,7 +52,7 @@ void WebRequestProxyingURLLoaderFactory::InProgressRequest::Restart() { request_id_, factory_->render_process_id_, factory_->render_frame_id_, factory_->navigation_ui_data_ ? factory_->navigation_ui_data_->DeepCopy() : nullptr, - routing_id_, request_); + routing_id_, factory_->resource_context_, request_); auto continuation = base::BindRepeating(&InProgressRequest::ContinueToBeforeSendHeaders, @@ -83,14 +83,18 @@ void WebRequestProxyingURLLoaderFactory::InProgressRequest::Restart() { ContinueToBeforeSendHeaders(net::OK); } -void WebRequestProxyingURLLoaderFactory::InProgressRequest::FollowRedirect() { +void WebRequestProxyingURLLoaderFactory::InProgressRequest::FollowRedirect( + const base::Optional<net::HttpRequestHeaders>& modified_request_headers) { + DCHECK(!modified_request_headers.has_value()) << "Redirect with modified " + "headers was not supported " + "yet. crbug.com/845683"; if (ignore_next_follow_redirect_) { ignore_next_follow_redirect_ = false; return; } if (target_loader_.is_bound()) - target_loader_->FollowRedirect(); + target_loader_->FollowRedirect(base::nullopt); Restart(); } @@ -404,10 +408,12 @@ void WebRequestProxyingURLLoaderFactory::InProgressRequest::OnRequestError( WebRequestProxyingURLLoaderFactory::WebRequestProxyingURLLoaderFactory( void* browser_context, + content::ResourceContext* resource_context, InfoMap* info_map) : RefCountedDeleteOnSequence(content::BrowserThread::GetTaskRunnerForThread( content::BrowserThread::IO)), browser_context_(browser_context), + resource_context_(resource_context), info_map_(info_map) {} void WebRequestProxyingURLLoaderFactory::StartProxying( diff --git a/chromium/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h b/chromium/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h index c3c8283bff0..91edf881dcc 100644 --- a/chromium/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h +++ b/chromium/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h @@ -25,6 +25,10 @@ #include "services/network/public/mojom/url_loader_factory.mojom.h" #include "url/gurl.h" +namespace content { +class ResourceContext; +} // namespace content + namespace extensions { class ExtensionNavigationUIData; @@ -60,7 +64,8 @@ class WebRequestProxyingURLLoaderFactory void Restart(); // network::mojom::URLLoader: - void FollowRedirect() override; + void FollowRedirect(const base::Optional<net::HttpRequestHeaders>& + modified_request_headers) override; void ProceedWithResponse() override; void SetPriority(net::RequestPriority priority, int32_t intra_priority_value) override; @@ -131,7 +136,9 @@ class WebRequestProxyingURLLoaderFactory DISALLOW_COPY_AND_ASSIGN(InProgressRequest); }; - WebRequestProxyingURLLoaderFactory(void* browser_context, InfoMap* info_map); + WebRequestProxyingURLLoaderFactory(void* browser_context, + content::ResourceContext* resource_context, + InfoMap* info_map); void StartProxying( int render_process_id, @@ -164,6 +171,7 @@ class WebRequestProxyingURLLoaderFactory void RemoveRequest(uint64_t request_id); void* const browser_context_; + content::ResourceContext* const resource_context_; int render_process_id_ = -1; int render_frame_id_ = -1; std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data_; diff --git a/chromium/extensions/browser/api_unittest.cc b/chromium/extensions/browser/api_unittest.cc index c442c394b83..186b6d3d940 100644 --- a/chromium/extensions/browser/api_unittest.cc +++ b/chromium/extensions/browser/api_unittest.cc @@ -51,10 +51,9 @@ void ApiUnitTest::CreateBackgroundPage() { GURL url = BackgroundInfo::GetBackgroundURL(extension()); if (url.is_empty()) url = GURL(url::kAboutBlankURL); - contents_.reset( - content::WebContents::Create(content::WebContents::CreateParams( - browser_context(), - content::SiteInstance::CreateForURL(browser_context(), url)))); + contents_ = content::WebContents::Create(content::WebContents::CreateParams( + browser_context(), + content::SiteInstance::CreateForURL(browser_context(), url))); } } diff --git a/chromium/extensions/browser/app_window/app_delegate.h b/chromium/extensions/browser/app_window/app_delegate.h index a513cba211d..30c8fb3827c 100644 --- a/chromium/extensions/browser/app_window/app_delegate.h +++ b/chromium/extensions/browser/app_window/app_delegate.h @@ -48,11 +48,12 @@ class AppDelegate { content::BrowserContext* context, content::WebContents* source, const content::OpenURLParams& params) = 0; - virtual void AddNewContents(content::BrowserContext* context, - content::WebContents* new_contents, - WindowOpenDisposition disposition, - const gfx::Rect& initial_rect, - bool user_gesture) = 0; + virtual void AddNewContents( + content::BrowserContext* context, + std::unique_ptr<content::WebContents> new_contents, + WindowOpenDisposition disposition, + const gfx::Rect& initial_rect, + bool user_gesture) = 0; // Feature support. virtual content::ColorChooser* ShowColorChooser( diff --git a/chromium/extensions/browser/app_window/app_window.cc b/chromium/extensions/browser/app_window/app_window.cc index 5b090151ef9..5de2af6210e 100644 --- a/chromium/extensions/browser/app_window/app_window.cc +++ b/chromium/extensions/browser/app_window/app_window.cc @@ -366,14 +366,14 @@ WebContents* AppWindow::OpenURLFromTab(WebContents* source, } void AppWindow::AddNewContents(WebContents* source, - WebContents* new_contents, + std::unique_ptr<WebContents> new_contents, WindowOpenDisposition disposition, const gfx::Rect& initial_rect, bool user_gesture, bool* was_blocked) { DCHECK(new_contents->GetBrowserContext() == browser_context_); - app_delegate_->AddNewContents(browser_context_, new_contents, disposition, - initial_rect, user_gesture); + app_delegate_->AddNewContents(browser_context_, std::move(new_contents), + disposition, initial_rect, user_gesture); } content::KeyboardEventProcessingResult AppWindow::PreHandleKeyboardEvent( @@ -904,8 +904,10 @@ void AppWindow::NavigationStateChanged(content::WebContents* source, native_app_window_->UpdateWindowIcon(); } -void AppWindow::EnterFullscreenModeForTab(content::WebContents* source, - const GURL& origin) { +void AppWindow::EnterFullscreenModeForTab( + content::WebContents* source, + const GURL& origin, + const blink::WebFullscreenOptions& options) { ToggleFullscreenModeForTab(source, true); } diff --git a/chromium/extensions/browser/app_window/app_window.h b/chromium/extensions/browser/app_window/app_window.h index 84026c02489..dff33dc639e 100644 --- a/chromium/extensions/browser/app_window/app_window.h +++ b/chromium/extensions/browser/app_window/app_window.h @@ -407,8 +407,10 @@ class AppWindow : public content::WebContentsDelegate, const gfx::Rect& pos) override; void NavigationStateChanged(content::WebContents* source, content::InvalidateTypes changed_flags) override; - void EnterFullscreenModeForTab(content::WebContents* source, - const GURL& origin) override; + void EnterFullscreenModeForTab( + content::WebContents* source, + const GURL& origin, + const blink::WebFullscreenOptions& options) override; void ExitFullscreenModeForTab(content::WebContents* source) override; bool IsFullscreenForTabOrPending( const content::WebContents* source) const override; @@ -425,7 +427,7 @@ class AppWindow : public content::WebContentsDelegate, content::WebContents* source, const content::OpenURLParams& params) override; void AddNewContents(content::WebContents* source, - content::WebContents* new_contents, + std::unique_ptr<content::WebContents> new_contents, WindowOpenDisposition disposition, const gfx::Rect& initial_rect, bool user_gesture, diff --git a/chromium/extensions/browser/app_window/app_window_contents.cc b/chromium/extensions/browser/app_window/app_window_contents.cc index 2c4759af72b..9285be93623 100644 --- a/chromium/extensions/browser/app_window/app_window_contents.cc +++ b/chromium/extensions/browser/app_window/app_window_contents.cc @@ -34,7 +34,7 @@ void AppWindowContentsImpl::Initialize(content::BrowserContext* context, context, creator_frame->GetSiteInstance()); create_params.opener_render_process_id = creator_frame->GetProcess()->GetID(); create_params.opener_render_frame_id = creator_frame->GetRoutingID(); - web_contents_.reset(content::WebContents::Create(create_params)); + web_contents_ = content::WebContents::Create(create_params); Observe(web_contents_.get()); web_contents_->GetMutableRendererPrefs()-> diff --git a/chromium/extensions/browser/browsertest_util.cc b/chromium/extensions/browser/browsertest_util.cc index 0b24b689033..634d3801b42 100644 --- a/chromium/extensions/browser/browsertest_util.cc +++ b/chromium/extensions/browser/browsertest_util.cc @@ -12,9 +12,11 @@ namespace extensions { namespace browsertest_util { -std::string ExecuteScriptInBackgroundPage(content::BrowserContext* context, - const std::string& extension_id, - const std::string& script) { +std::string ExecuteScriptInBackgroundPage( + content::BrowserContext* context, + const std::string& extension_id, + const std::string& script, + ScriptUserActivation script_user_activation) { ExtensionHost* host = ProcessManager::Get(context)->GetBackgroundHostForExtension(extension_id); if (!host) { @@ -23,8 +25,17 @@ std::string ExecuteScriptInBackgroundPage(content::BrowserContext* context, } std::string result; - if (!content::ExecuteScriptAndExtractString(host->host_contents(), script, - &result)) { + bool success; + if (script_user_activation == ScriptUserActivation::kActivate) { + success = content::ExecuteScriptAndExtractString(host->host_contents(), + script, &result); + } else { + DCHECK_EQ(script_user_activation, ScriptUserActivation::kDontActivate); + success = content::ExecuteScriptWithoutUserGestureAndExtractString( + host->host_contents(), script, &result); + } + + if (!success) { ADD_FAILURE() << "Executing script failed: " << script; result.clear(); } diff --git a/chromium/extensions/browser/browsertest_util.h b/chromium/extensions/browser/browsertest_util.h index e2798c0ed6a..9774259f952 100644 --- a/chromium/extensions/browser/browsertest_util.h +++ b/chromium/extensions/browser/browsertest_util.h @@ -14,13 +14,25 @@ class BrowserContext; namespace extensions { namespace browsertest_util { +// Determine if a user activation notification should be triggered before +// executing a script +enum class ScriptUserActivation { + kActivate, + kDontActivate, +}; + // Waits until |script| calls "window.domAutomationController.send(result)", // where |result| is a string, and returns |result|. Fails the test and returns // an empty string if |extension_id| isn't installed in |context| or doesn't -// have a background page, or if executing the script fails. -std::string ExecuteScriptInBackgroundPage(content::BrowserContext* context, - const std::string& extension_id, - const std::string& script); +// have a background page, or if executing the script fails. The argument +// |script_user_activation| determines if the script should be executed after a +// user activation. +std::string ExecuteScriptInBackgroundPage( + content::BrowserContext* context, + const std::string& extension_id, + const std::string& script, + ScriptUserActivation script_user_activation = + ScriptUserActivation::kActivate); // Same as ExecuteScriptInBackgroundPage, but doesn't wait for the script // to return a result. Fails the test and returns false if |extension_id| diff --git a/chromium/extensions/browser/computed_hashes.cc b/chromium/extensions/browser/computed_hashes.cc index de77d45341a..cfe0a9e84e8 100644 --- a/chromium/extensions/browser/computed_hashes.cc +++ b/chromium/extensions/browser/computed_hashes.cc @@ -187,7 +187,7 @@ void ComputedHashes::ComputeHashesForContent(const std::string& contents, hashes->push_back(std::string()); std::string* buffer = &(hashes->back()); buffer->resize(crypto::kSHA256Length); - hash->Finish(base::string_as_array(buffer), buffer->size()); + hash->Finish(base::data(*buffer), buffer->size()); // If |contents| is empty, then we want to just exit here. if (bytes_to_read == 0) diff --git a/chromium/extensions/browser/content_hash_fetcher_unittest.cc b/chromium/extensions/browser/content_hash_fetcher_unittest.cc index 8f7b3829260..c38800cab75 100644 --- a/chromium/extensions/browser/content_hash_fetcher_unittest.cc +++ b/chromium/extensions/browser/content_hash_fetcher_unittest.cc @@ -180,7 +180,7 @@ class ContentHashFetcherTest : public ExtensionsTest { // data dir. base::FilePath GetTestPath(const base::FilePath& relative_path) { base::FilePath base_path; - EXPECT_TRUE(PathService::Get(extensions::DIR_TEST_DATA, &base_path)); + EXPECT_TRUE(base::PathService::Get(extensions::DIR_TEST_DATA, &base_path)); base_path = base_path.AppendASCII("content_hash_fetcher"); return base_path.Append(relative_path); } diff --git a/chromium/extensions/browser/content_hash_tree.cc b/chromium/extensions/browser/content_hash_tree.cc index e1298cf4ca0..2e2180f680d 100644 --- a/chromium/extensions/browser/content_hash_tree.cc +++ b/chromium/extensions/browser/content_hash_tree.cc @@ -41,8 +41,7 @@ std::string ComputeTreeHashRoot(const std::vector<std::string>& leaf_hashes, ++i; } parent_nodes.push_back(std::string(crypto::kSHA256Length, 0)); - std::string* output = &(parent_nodes.back()); - hash->Finish(base::string_as_array(output), output->size()); + hash->Finish(base::data(parent_nodes.back()), crypto::kSHA256Length); } current_nodes.swap(parent_nodes); parent_nodes.clear(); diff --git a/chromium/extensions/browser/content_hash_tree_unittest.cc b/chromium/extensions/browser/content_hash_tree_unittest.cc index f9be82eb8b8..9f7281eb1ec 100644 --- a/chromium/extensions/browser/content_hash_tree_unittest.cc +++ b/chromium/extensions/browser/content_hash_tree_unittest.cc @@ -43,7 +43,7 @@ TEST(ContentHashTreeTest, HashTreeBasics) { std::unique_ptr<SecureHash> hash(SecureHash::Create(SecureHash::SHA256)); hash->Update(node1.data(), node1.size()); hash->Update(node2.data(), node2.size()); - hash->Finish(base::string_as_array(&expected), expected.size()); + hash->Finish(base::data(expected), expected.size()); EXPECT_EQ(expected, ComputeTreeHashRoot(nodes, 16)); } diff --git a/chromium/extensions/browser/content_verifier/content_hash.cc b/chromium/extensions/browser/content_verifier/content_hash.cc index f12b5889a8f..87a0a1a3879 100644 --- a/chromium/extensions/browser/content_verifier/content_hash.cc +++ b/chromium/extensions/browser/content_verifier/content_hash.cc @@ -46,8 +46,7 @@ std::unique_ptr<VerifiedContents> GetVerifiedContents( bool delete_invalid_file) { base::AssertBlockingAllowed(); DCHECK(GetExtensionFileTaskRunner()->RunsTasksInCurrentSequence()); - auto verified_contents = std::make_unique<VerifiedContents>( - key.verifier_key.data, key.verifier_key.size); + auto verified_contents = std::make_unique<VerifiedContents>(key.verifier_key); base::FilePath verified_contents_path = file_util::GetVerifiedContentsPath(key.extension_root); if (!verified_contents->InitFrom(verified_contents_path)) { @@ -65,12 +64,14 @@ std::unique_ptr<VerifiedContents> GetVerifiedContents( ContentHash::ExtensionKey::ExtensionKey(const ExtensionId& extension_id, const base::FilePath& extension_root, const base::Version& extension_version, - const ContentVerifierKey& verifier_key) + ContentVerifierKey verifier_key) : extension_id(extension_id), extension_root(extension_root), extension_version(extension_version), verifier_key(verifier_key) {} +ContentHash::ExtensionKey::~ExtensionKey() = default; + ContentHash::ExtensionKey::ExtensionKey( const ContentHash::ExtensionKey& other) = default; diff --git a/chromium/extensions/browser/content_verifier/content_hash.h b/chromium/extensions/browser/content_verifier/content_hash.h index 4e7d8079eb5..56e8f86a951 100644 --- a/chromium/extensions/browser/content_verifier/content_hash.h +++ b/chromium/extensions/browser/content_verifier/content_hash.h @@ -62,7 +62,8 @@ class ContentHash : public base::RefCountedThreadSafe<ContentHash> { ExtensionKey(const ExtensionId& extension_id, const base::FilePath& extension_root, const base::Version& extension_version, - const ContentVerifierKey& verifier_key); + ContentVerifierKey verifier_key); + ~ExtensionKey(); ExtensionKey(const ExtensionKey& other); ExtensionKey& operator=(const ExtensionKey& other); diff --git a/chromium/extensions/browser/content_verifier/content_verifier_key.h b/chromium/extensions/browser/content_verifier/content_verifier_key.h index a4aa4013fbb..6cba2694830 100644 --- a/chromium/extensions/browser/content_verifier/content_verifier_key.h +++ b/chromium/extensions/browser/content_verifier/content_verifier_key.h @@ -5,19 +5,11 @@ #ifndef EXTENSIONS_BROWSER_CONTENT_VERIFIER_CONTENT_VERIFIER_KEY_H_ #define EXTENSIONS_BROWSER_CONTENT_VERIFIER_CONTENT_VERIFIER_KEY_H_ -#include <stdint.h> +#include "base/containers/span.h" namespace extensions { -// A pointer to the bytes of a public key, and the number of bytes for content -// verification. -struct ContentVerifierKey { - const uint8_t* data; - size_t size; - - ContentVerifierKey(const uint8_t* data, size_t size) - : data(data), size(size) {} -}; +using ContentVerifierKey = base::span<const uint8_t>; } // namespace extensions diff --git a/chromium/extensions/browser/content_verifier_unittest.cc b/chromium/extensions/browser/content_verifier_unittest.cc index a64c252d18b..73ed463fe8f 100644 --- a/chromium/extensions/browser/content_verifier_unittest.cc +++ b/chromium/extensions/browser/content_verifier_unittest.cc @@ -17,6 +17,7 @@ #include "extensions/common/manifest_constants.h" #include "extensions/common/manifest_handlers/background_info.h" #include "extensions/common/manifest_handlers/content_scripts_handler.h" +#include "extensions/common/scoped_testing_manifest_handler_registry.h" #include "testing/gtest/include/gtest/gtest.h" namespace extensions { @@ -78,8 +79,7 @@ class ContentVerifierTest // Manually register handlers since the |ContentScriptsHandler| is not // usually registered in extensions_unittests. - ManifestHandlerRegistry registry; - ManifestHandlerRegistry::SetForTesting(®istry); + ScopedTestingManifestHandlerRegistry registry; (new BackgroundManifestHandler)->Register(); (new ContentScriptsHandler)->Register(); ManifestHandler::FinalizeRegistration(); @@ -152,7 +152,7 @@ class ContentVerifierTest manifest.Set(manifest_keys::kContentScripts, std::move(content_scripts)); base::FilePath path; - EXPECT_TRUE(PathService::Get(DIR_TEST_DATA, &path)); + EXPECT_TRUE(base::PathService::Get(DIR_TEST_DATA, &path)); std::string error; scoped_refptr<Extension> extension(Extension::Create( diff --git a/chromium/extensions/browser/content_verify_job.cc b/chromium/extensions/browser/content_verify_job.cc index 086b2fd8558..01cf9616b1e 100644 --- a/chromium/extensions/browser/content_verify_job.cc +++ b/chromium/extensions/browser/content_verify_job.cc @@ -90,6 +90,7 @@ void ContentVerifyJob::DidGetContentHashOnIO( void ContentVerifyJob::BytesRead(int count, const char* data) { base::AutoLock auto_lock(lock_); + DCHECK(!done_reading_); BytesReadImpl(count, data); } @@ -100,6 +101,7 @@ void ContentVerifyJob::DoneReading() { return; if (g_ignore_verification_for_tests) return; + DCHECK(!done_reading_); done_reading_ = true; if (hashes_ready_) { if (!FinishBlock()) { @@ -167,7 +169,7 @@ bool ContentVerifyJob::FinishBlock() { current_hash_ = crypto::SecureHash::Create(crypto::SecureHash::SHA256); } std::string final(crypto::kSHA256Length, 0); - current_hash_->Finish(base::string_as_array(& final), final.size()); + current_hash_->Finish(base::data(final), final.size()); current_hash_.reset(); current_hash_byte_count_ = 0; @@ -218,7 +220,7 @@ void ContentVerifyJob::OnHashesReady( if (!queue_.empty()) { std::string tmp; queue_.swap(tmp); - BytesReadImpl(tmp.size(), base::string_as_array(&tmp)); + BytesReadImpl(tmp.size(), base::data(tmp)); if (failed_) return; } diff --git a/chromium/extensions/browser/content_verify_job_unittest.cc b/chromium/extensions/browser/content_verify_job_unittest.cc index dcea5263acc..07171f2ec01 100644 --- a/chromium/extensions/browser/content_verify_job_unittest.cc +++ b/chromium/extensions/browser/content_verify_job_unittest.cc @@ -54,7 +54,7 @@ class ContentVerifyJobUnittest : public ExtensionsTest { // data dir. base::FilePath GetTestPath(const std::string& relative_path) { base::FilePath base_path; - EXPECT_TRUE(PathService::Get(DIR_TEST_DATA, &base_path)); + EXPECT_TRUE(base::PathService::Get(DIR_TEST_DATA, &base_path)); return base_path.AppendASCII("content_hash_fetcher") .AppendASCII(relative_path); } @@ -97,7 +97,7 @@ class ContentVerifyJobUnittest : public ExtensionsTest { std::string* resource_contents) { // Simulate serving |resource_contents| from |resource_path|. verify_job->BytesRead(resource_contents->size(), - base::string_as_array(resource_contents)); + base::data(*resource_contents)); verify_job->DoneReading(); }; diff --git a/chromium/extensions/browser/event_router.cc b/chromium/extensions/browser/event_router.cc index 066571ff141..3bde19d9349 100644 --- a/chromium/extensions/browser/event_router.cc +++ b/chromium/extensions/browser/event_router.cc @@ -11,7 +11,6 @@ #include "base/atomic_sequence_num.h" #include "base/bind.h" -#include "base/message_loop/message_loop.h" #include "base/metrics/histogram_macros.h" #include "base/stl_util.h" #include "base/values.h" @@ -273,9 +272,9 @@ void EventRouter::OnListenerRemoved(const EventListener* listener) { observer->second->OnListenerRemoved(details); } -void EventRouter::RenderProcessExited(content::RenderProcessHost* host, - base::TerminationStatus status, - int exit_code) { +void EventRouter::RenderProcessExited( + content::RenderProcessHost* host, + const content::ChildProcessTerminationInfo& info) { listeners_.RemoveListenersForProcess(host); observed_process_set_.erase(host); host->RemoveObserver(this); diff --git a/chromium/extensions/browser/event_router.h b/chromium/extensions/browser/event_router.h index b7d81347b9c..512ff10bfcc 100644 --- a/chromium/extensions/browser/event_router.h +++ b/chromium/extensions/browser/event_router.h @@ -340,9 +340,9 @@ class EventRouter : public KeyedService, void OnListenerRemoved(const EventListener* listener) override; // RenderProcessHostObserver implementation. - void RenderProcessExited(content::RenderProcessHost* host, - base::TerminationStatus status, - int exit_code) override; + void RenderProcessExited( + content::RenderProcessHost* host, + const content::ChildProcessTerminationInfo& info) override; void RenderProcessHostDestroyed(content::RenderProcessHost* host) override; content::BrowserContext* const browser_context_; diff --git a/chromium/extensions/browser/extension_error_test_util.cc b/chromium/extensions/browser/extension_error_test_util.cc index 8f42ec937c8..583fcc1dba2 100644 --- a/chromium/extensions/browser/extension_error_test_util.cc +++ b/chromium/extensions/browser/extension_error_test_util.cc @@ -39,7 +39,7 @@ std::unique_ptr<ExtensionError> CreateNewRuntimeError( new RuntimeError(extension_id, from_incognito, source, base::UTF8ToUTF16(message), stack_trace, GURL::EmptyGURL(), // no context url - logging::LOG_INFO, + logging::LOG_ERROR, 0, // Render frame id 0)); // Render process id } diff --git a/chromium/extensions/browser/extension_event_histogram_value.h b/chromium/extensions/browser/extension_event_histogram_value.h index e8ab2167436..11bc707d137 100644 --- a/chromium/extensions/browser/extension_event_histogram_value.h +++ b/chromium/extensions/browser/extension_event_histogram_value.h @@ -431,6 +431,13 @@ enum HistogramValue { OMNIBOX_ON_DELETE_SUGGESTION, VIRTUAL_KEYBOARD_PRIVATE_ON_KEYBOARD_CONFIG_CHANGED, PASSWORDS_PRIVATE_ON_PASSWORDS_FILE_EXPORT_PROGRESS, + SAFE_BROWSING_PRIVATE_ON_POLICY_SPECIFIED_PASSWORD_REUSE_DETECTED, + SAFE_BROWSING_PRIVATE_ON_POLICY_SPECIFIED_PASSWORD_CHANGED, + SAFE_BROWSING_PRIVATE_ON_DANGEROUS_DOWNLOAD_OPENED, + SAFE_BROWSING_PRIVATE_ON_SECURITY_INTERSTITIAL_SHOWN, + SAFE_BROWSING_PRIVATE_ON_SECURITY_INTERSTITIAL_PROCEEDED, + ACCESSIBILITY_PRIVATE_ON_SELECT_TO_SPEAK_STATE_CHANGE_REQUESTED, + INPUT_METHOD_PRIVATE_ON_FOCUS, // Last entry: Add new entries above, then run: // python tools/metrics/histograms/update_extension_histograms.py ENUM_BOUNDARY diff --git a/chromium/extensions/browser/extension_function.cc b/chromium/extensions/browser/extension_function.cc index a093683ab40..2c14386244f 100644 --- a/chromium/extensions/browser/extension_function.cc +++ b/chromium/extensions/browser/extension_function.cc @@ -564,14 +564,6 @@ void UIThreadExtensionFunction::SetRenderFrameHost( render_frame_host ? new RenderFrameHostTracker(this) : nullptr); } -content::WebContents* UIThreadExtensionFunction::GetAssociatedWebContents() { - content::WebContents* web_contents = NULL; - if (dispatcher()) - web_contents = dispatcher()->GetAssociatedWebContents(); - - return web_contents; -} - content::WebContents* UIThreadExtensionFunction::GetSenderWebContents() { return render_frame_host_ ? content::WebContents::FromRenderFrameHost(render_frame_host_) : nullptr; diff --git a/chromium/extensions/browser/extension_function.h b/chromium/extensions/browser/extension_function.h index 7b5d3b6a53d..0b70be6cfa6 100644 --- a/chromium/extensions/browser/extension_function.h +++ b/chromium/extensions/browser/extension_function.h @@ -538,12 +538,6 @@ class UIThreadExtensionFunction : public ExtensionFunction { service_worker_version_id_ = version_id; } - // Gets the "current" web contents if any. If there is no associated web - // contents then defaults to the foremost one. - // NOTE: "current" can mean different things in different contexts. You - // probably want to use GetSenderWebContents(). - virtual content::WebContents* GetAssociatedWebContents(); - // Returns the web contents associated with the sending |render_frame_host_|. // This can be null. content::WebContents* GetSenderWebContents(); diff --git a/chromium/extensions/browser/extension_function_constants.cc b/chromium/extensions/browser/extension_function_constants.cc new file mode 100644 index 00000000000..423a6ba6a4e --- /dev/null +++ b/chromium/extensions/browser/extension_function_constants.cc @@ -0,0 +1,20 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/browser/extension_function_constants.h" + +namespace extensions { +namespace function_constants { + +// An error thrown when determining the WebContents that sent the request for +// the API call failed. Note: typically, this would only happen if the +// WebContents disappeared after the API call (i.e., the caller is no longer +// alive, such as a tab closing or background page suspending). For this reason, +// the error is not overly helpful. However, it is important that we have a +// specific error message in order to track down any peculiar cases. +const char kCouldNotFindSenderWebContents[] = + "Could not find sender WebContents."; + +} // namespace function_constants +} // namespace extensions diff --git a/chromium/extensions/browser/extension_function_constants.h b/chromium/extensions/browser/extension_function_constants.h new file mode 100644 index 00000000000..9fe331bad28 --- /dev/null +++ b/chromium/extensions/browser/extension_function_constants.h @@ -0,0 +1,17 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_BROWSER_EXTENSION_FUNCTION_CONSTANTS_H_ +#define EXTENSIONS_BROWSER_EXTENSION_FUNCTION_CONSTANTS_H_ + +namespace extensions { +namespace function_constants { + +// TODO(devlin): Move ExtensionFunction::kUnknownErrorDoNotUse here. +extern const char kCouldNotFindSenderWebContents[]; + +} // namespace function_constants +} // namespace extensions + +#endif // EXTENSIONS_BROWSER_EXTENSION_FUNCTION_CONSTANTS_H_ diff --git a/chromium/extensions/browser/extension_function_dispatcher.cc b/chromium/extensions/browser/extension_function_dispatcher.cc index 84143680b9f..249fd4c34ea 100644 --- a/chromium/extensions/browser/extension_function_dispatcher.cc +++ b/chromium/extensions/browser/extension_function_dispatcher.cc @@ -186,9 +186,9 @@ class ExtensionFunctionDispatcher::UIThreadWorkerResponseCallbackWrapper ~UIThreadWorkerResponseCallbackWrapper() override {} // content::RenderProcessHostObserver override. - void RenderProcessExited(content::RenderProcessHost* rph, - base::TerminationStatus status, - int exit_code) override { + void RenderProcessExited( + content::RenderProcessHost* rph, + const content::ChildProcessTerminationInfo& info) override { CleanUp(); } diff --git a/chromium/extensions/browser/extension_function_histogram_value.h b/chromium/extensions/browser/extension_function_histogram_value.h index a119ce9d737..4b5f1c5096b 100644 --- a/chromium/extensions/browser/extension_function_histogram_value.h +++ b/chromium/extensions/browser/extension_function_histogram_value.h @@ -1302,6 +1302,21 @@ enum HistogramValue { FILEMANAGERPRIVATE_ENSUREFILEDOWNLOADED, FILEMANAGERPRIVATE_OPENSETTINGSSUBPAGE, ENTERPRISEREPORTINGPRIVATE_UPLOADCHROMEDESKTOPREPORT, + CECPRIVATE_SENDSTANDBY, + CECPRIVATE_SENDWAKEUP, + WEBSTOREPRIVATE_GETREFERRERCHAIN, + AUTOTESTPRIVATE_UPDATEPRINTER, + AUTOTESTPRIVATE_REMOVEPRINTER, + WALLPAPERPRIVATE_GETCURRENTWALLPAPERTHUMBNAIL, + ACCESSIBILITY_PRIVATE_ONSELECTTOSPEAKSTATECHANGED, + INPUTMETHODPRIVATE_GETCOMPOSITIONBOUNDS, + FILEMANAGERPRIVATE_ISCROSTINIENABLED, + FILEMANAGERPRIVATE_MOUNTCROSTINICONTAINER, + CECPRIVATE_QUERYDISPLAYCECPOWERSTATE, + DEVELOPERPRIVATE_ADDHOSTPERMISSION, + DEVELOPERPRIVATE_REMOVEHOSTPERMISSION, + MEDIAPERCEPTIONPRIVATE_SETCOMPONENTPROCESSSTATE, + USERSPRIVATE_GETCURRENTUSER, // Last entry: Add new entries above, then run: // python tools/metrics/histograms/update_extension_histograms.py ENUM_BOUNDARY diff --git a/chromium/extensions/browser/extension_host.cc b/chromium/extensions/browser/extension_host.cc index a5a82184012..294243d2e7d 100644 --- a/chromium/extensions/browser/extension_host.cc +++ b/chromium/extensions/browser/extension_host.cc @@ -68,8 +68,8 @@ ExtensionHost::ExtensionHost(const Extension* extension, DCHECK(host_type == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE || host_type == VIEW_TYPE_EXTENSION_DIALOG || host_type == VIEW_TYPE_EXTENSION_POPUP); - host_contents_.reset(WebContents::Create( - WebContents::CreateParams(browser_context_, site_instance))), + host_contents_ = WebContents::Create( + WebContents::CreateParams(browser_context_, site_instance)), content::WebContentsObserver::Observe(host_contents_.get()); host_contents_->SetDelegate(this); SetViewType(host_contents_.get(), host_type); @@ -389,7 +389,7 @@ content::JavaScriptDialogManager* ExtensionHost::GetJavaScriptDialogManager( } void ExtensionHost::AddNewContents(WebContents* source, - WebContents* new_contents, + std::unique_ptr<WebContents> new_contents, WindowOpenDisposition disposition, const gfx::Rect& initial_rect, bool user_gesture, @@ -409,16 +409,16 @@ void ExtensionHost::AddNewContents(WebContents* source, new_contents->GetBrowserContext()) { WebContentsDelegate* delegate = associated_contents->GetDelegate(); if (delegate) { - delegate->AddNewContents( - associated_contents, new_contents, disposition, initial_rect, - user_gesture, was_blocked); + delegate->AddNewContents(associated_contents, std::move(new_contents), + disposition, initial_rect, user_gesture, + was_blocked); return; } } } - delegate_->CreateTab( - new_contents, extension_id_, disposition, initial_rect, user_gesture); + delegate_->CreateTab(std::move(new_contents), extension_id_, disposition, + initial_rect, user_gesture); } void ExtensionHost::RenderViewReady() { diff --git a/chromium/extensions/browser/extension_host.h b/chromium/extensions/browser/extension_host.h index c93e3a48c7e..8c7a96fdc17 100644 --- a/chromium/extensions/browser/extension_host.h +++ b/chromium/extensions/browser/extension_host.h @@ -113,7 +113,7 @@ class ExtensionHost : public DeferredStartRenderHost, content::JavaScriptDialogManager* GetJavaScriptDialogManager( content::WebContents* source) override; void AddNewContents(content::WebContents* source, - content::WebContents* new_contents, + std::unique_ptr<content::WebContents> new_contents, WindowOpenDisposition disposition, const gfx::Rect& initial_rect, bool user_gesture, diff --git a/chromium/extensions/browser/extension_host_delegate.h b/chromium/extensions/browser/extension_host_delegate.h index a7c908cde91..c7b0096651f 100644 --- a/chromium/extensions/browser/extension_host_delegate.h +++ b/chromium/extensions/browser/extension_host_delegate.h @@ -45,7 +45,7 @@ class ExtensionHostDelegate { // Creates a new tab or popup window with |web_contents|. The embedder may // choose to do nothing if tabs and popups are not supported. - virtual void CreateTab(content::WebContents* web_contents, + virtual void CreateTab(std::unique_ptr<content::WebContents> web_contents, const std::string& extension_id, WindowOpenDisposition disposition, const gfx::Rect& initial_rect, diff --git a/chromium/extensions/browser/extension_icon_image_unittest.cc b/chromium/extensions/browser/extension_icon_image_unittest.cc index c823bd2fc2f..9ef5962c8d5 100644 --- a/chromium/extensions/browser/extension_icon_image_unittest.cc +++ b/chromium/extensions/browser/extension_icon_image_unittest.cc @@ -87,7 +87,7 @@ class ExtensionIconImageTest : public ExtensionsTest, Manifest::Location location) { // Create and load an extension. base::FilePath test_file; - if (!PathService::Get(DIR_TEST_DATA, &test_file)) { + if (!base::PathService::Get(DIR_TEST_DATA, &test_file)) { EXPECT_FALSE(true); return NULL; } diff --git a/chromium/extensions/browser/extension_navigation_throttle.cc b/chromium/extensions/browser/extension_navigation_throttle.cc index 9ff926c267d..880a1b8b25d 100644 --- a/chromium/extensions/browser/extension_navigation_throttle.cc +++ b/chromium/extensions/browser/extension_navigation_throttle.cc @@ -85,13 +85,6 @@ ExtensionNavigationThrottle::WillStartOrRedirectRequest() { navigation_handle()->GetStartingSiteInstance()->GetSiteURL()); if (!url_has_extension_scheme && !current_frame_is_extension_process) { - // Relax this restriction for navigations that will result in downloads. - // See https://crbug.com/714373. - if (target_origin.scheme() == kExtensionScheme && - navigation_handle()->GetSuggestedFilename().has_value()) { - return content::NavigationThrottle::PROCEED; - } - // Relax this restriction for apps that use <webview>. See // https://crbug.com/652077. bool has_webview_permission = diff --git a/chromium/extensions/browser/extension_pref_value_map_unittest.cc b/chromium/extensions/browser/extension_pref_value_map_unittest.cc index 36c2fb936d7..5c0c7289915 100644 --- a/chromium/extensions/browser/extension_pref_value_map_unittest.cc +++ b/chromium/extensions/browser/extension_pref_value_map_unittest.cc @@ -76,7 +76,7 @@ class ExtensionPrefValueMapObserverMock : public ExtensionPrefValueMap::Observer { public: ExtensionPrefValueMapObserverMock() {} - virtual ~ExtensionPrefValueMapObserverMock() {} + ~ExtensionPrefValueMapObserverMock() override {} MOCK_METHOD1(OnPrefValueChanged, void(const std::string&)); MOCK_METHOD0(OnInitializationCompleted, void()); diff --git a/chromium/extensions/browser/extension_protocols.cc b/chromium/extensions/browser/extension_protocols.cc index 56b5cb968c4..543b08cedae 100644 --- a/chromium/extensions/browser/extension_protocols.cc +++ b/chromium/extensions/browser/extension_protocols.cc @@ -21,7 +21,6 @@ #include "base/logging.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/message_loop/message_loop.h" #include "base/metrics/field_trial.h" #include "base/metrics/histogram.h" #include "base/metrics/histogram_functions.h" @@ -263,7 +262,7 @@ class URLRequestExtensionJob : public net::URLRequestFileJob { // proceed; see crbug.com/703888. if (verify_job_.get()) { std::string tmp; - verify_job_->BytesRead(0, base::string_as_array(&tmp)); + verify_job_->BytesRead(0, base::data(tmp)); verify_job_->DoneReading(); } } @@ -695,20 +694,6 @@ class FileLoaderObserver : public content::FileURLLoaderObserver { request_timer_.reset(new base::ElapsedTimer()); } - void OnOpenComplete(int result) override { - if (result < 0) { - // This can happen when the file is unreadable (which can happen during - // corruption or third-party interaction). We need to be sure to inform - // the verification job that we've finished reading so that it can - // proceed; see crbug.com/703888. - if (verify_job_.get()) { - std::string tmp; - verify_job_->BytesRead(0, base::string_as_array(&tmp)); - verify_job_->DoneReading(); - } - } - } - void OnSeekComplete(int64_t result) override { DCHECK_EQ(seek_position_, 0); base::AutoLock auto_lock(lock_); @@ -755,17 +740,30 @@ class FileLoaderObserver : public content::FileURLLoaderObserver { class ExtensionURLLoaderFactory : public network::mojom::URLLoaderFactory { public: - // |frame_host| is the RenderFrameHost which is either being navigated or - // loading a subresource. For navigation requests, |frame_url| is empty; for - // subresource requests it's the URL of the currently committed navigation on - // |frame_host|. - explicit ExtensionURLLoaderFactory( - content::RenderFrameHost* frame_host, - const GURL& frame_url, - scoped_refptr<extensions::InfoMap> extension_info_map) - : frame_host_(frame_host), - frame_url_(frame_url), - extension_info_map_(std::move(extension_info_map)) {} + ExtensionURLLoaderFactory(int render_process_id, int render_frame_id) + : render_process_id_(render_process_id) { + content::RenderProcessHost* process_host = + content::RenderProcessHost::FromID(render_process_id); + browser_context_ = process_host->GetBrowserContext(); + is_web_view_request_ = WebViewGuest::FromFrameID( + render_process_id_, render_frame_id) != nullptr; + Init(); + } + + ExtensionURLLoaderFactory(content::BrowserContext* browser_context, + bool is_web_view_request) + : browser_context_(browser_context), + is_web_view_request_(is_web_view_request), + render_process_id_(-1) { + Init(); + } + + void Init() { + extension_info_map_ = + extensions::ExtensionSystem::Get(browser_context_)->info_map(); + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + } + ~ExtensionURLLoaderFactory() override = default; // network::mojom::URLLoaderFactory: @@ -779,23 +777,21 @@ class ExtensionURLLoaderFactory : public network::mojom::URLLoaderFactory { traffic_annotation) override { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(!request.download_to_file); - const content::RenderProcessHost* process_host = frame_host_->GetProcess(); - BrowserContext* browser_context = process_host->GetBrowserContext(); const std::string extension_id = request.url.host(); - ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context); + ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_); scoped_refptr<const Extension> extension = registry->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING); const ExtensionSet& enabled_extensions = registry->enabled_extensions(); - const ProcessMap* process_map = ProcessMap::Get(browser_context); + const ProcessMap* process_map = ProcessMap::Get(browser_context_); bool incognito_enabled = - extensions::util::IsIncognitoEnabled(extension_id, browser_context); + extensions::util::IsIncognitoEnabled(extension_id, browser_context_); if (!AllowExtensionResourceLoad( request.url, static_cast<content::ResourceType>(request.resource_type), static_cast<ui::PageTransition>(request.transition_type), - process_host->GetID(), browser_context->IsOffTheRecord(), + render_process_id_, browser_context_->IsOffTheRecord(), extension.get(), incognito_enabled, enabled_extensions, *process_map)) { client->OnComplete( @@ -830,13 +826,9 @@ class ExtensionURLLoaderFactory : public network::mojom::URLLoaderFactory { bool send_cors_header = false; bool follow_symlinks_anywhere = false; if (extension) { - const bool is_web_view_request = - WebViewGuest::FromWebContents( - content::WebContents::FromRenderFrameHost(frame_host_)) != - nullptr; - GetSecurityPolicyForURL(request.url, extension.get(), is_web_view_request, - &content_security_policy, &send_cors_header, - &follow_symlinks_anywhere); + GetSecurityPolicyForURL(request.url, extension.get(), + is_web_view_request_, &content_security_policy, + &send_cors_header, &follow_symlinks_anywhere); } if (IsBackgroundPageURL(request.url)) { @@ -900,9 +892,7 @@ class ExtensionURLLoaderFactory : public network::mojom::URLLoaderFactory { std::string new_relative_path; SharedModuleInfo::ParseImportedPath(path, &new_extension_id, &new_relative_path); - BrowserContext* browser_context = - frame_host_->GetProcess()->GetBrowserContext(); - ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context); + ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_); const Extension* new_extension = registry->enabled_extensions().GetByID(new_extension_id); if (SharedModuleInfo::ImportsExtensionById(extension.get(), @@ -986,8 +976,12 @@ class ExtensionURLLoaderFactory : public network::mojom::URLLoaderFactory { std::move(response_headers)); } - content::RenderFrameHost* const frame_host_; - const GURL frame_url_; + content::BrowserContext* browser_context_; + bool is_web_view_request_; + // We store the ID and get RenderProcessHost each time it's needed. This is to + // avoid holding on to stale pointers if we get requests past the lifetime of + // the objects. + const int render_process_id_; scoped_refptr<extensions::InfoMap> extension_info_map_; mojo::BindingSet<network::mojom::URLLoaderFactory> bindings_; @@ -1047,29 +1041,16 @@ void SetExtensionProtocolTestHandler(ExtensionProtocolTestHandler* handler) { std::unique_ptr<network::mojom::URLLoaderFactory> CreateExtensionNavigationURLLoaderFactory( - content::RenderFrameHost* frame_host, - scoped_refptr<extensions::InfoMap> extension_info_map) { - return std::make_unique<ExtensionURLLoaderFactory>( - frame_host, GURL(), std::move(extension_info_map)); + content::BrowserContext* browser_context, + bool is_web_view_request) { + return std::make_unique<ExtensionURLLoaderFactory>(browser_context, + is_web_view_request); } std::unique_ptr<network::mojom::URLLoaderFactory> -MaybeCreateExtensionSubresourceURLLoaderFactory( - content::RenderFrameHost* frame_host, - const GURL& frame_url, - scoped_refptr<extensions::InfoMap> extension_info_map) { - // Ensure we have a non-empty URL so that the factory we create knows it's - // only for subresources. - CHECK(!frame_url.is_empty()); - - // TODO(rockot): We can probably avoid creating this factory in cases where - // |frame_url| corresponds to a non-extensions URL and the URL in question - // cannot have any active content scripts running and has no access to - // any extension's web accessible resources. For now we always create a - // factory, because the loader itself correctly prevents disallowed resources - // from loading in an invalid context. - return std::make_unique<ExtensionURLLoaderFactory>( - frame_host, frame_url, std::move(extension_info_map)); +CreateExtensionURLLoaderFactory(int render_process_id, int render_frame_id) { + return std::make_unique<ExtensionURLLoaderFactory>(render_process_id, + render_frame_id); } } // namespace extensions diff --git a/chromium/extensions/browser/extension_protocols.h b/chromium/extensions/browser/extension_protocols.h index 4188fdc6f2a..1ddcd71d3ee 100644 --- a/chromium/extensions/browser/extension_protocols.h +++ b/chromium/extensions/browser/extension_protocols.h @@ -19,15 +19,13 @@ class Time; } namespace content { -class RenderFrameHost; +class BrowserContext; } namespace net { class HttpResponseHeaders; } -class GURL; - namespace extensions { class InfoMap; @@ -57,18 +55,18 @@ void SetExtensionProtocolTestHandler(ExtensionProtocolTestHandler* handler); // handling navigation requests to extension URLs. std::unique_ptr<network::mojom::URLLoaderFactory> CreateExtensionNavigationURLLoaderFactory( - content::RenderFrameHost* frame_host, - scoped_refptr<extensions::InfoMap> extension_info_map); - -// Attempts to create a network::mojom::URLLoaderFactory implementation suitable -// for handling subresource requests for extension URLs from |frame_host|. May -// return null if |frame_host| is never allowed to load extension subresources -// from its current navigation URL. + content::BrowserContext* browser_context, + bool is_web_view_request); + +// Creates a network::mojom::URLLoaderFactory implementation suitable for +// handling subresource requests for extension URLs for the frame identified by +// |render_process_id| and |render_frame_id|. +// This function can also be used to make a factory for other non-subresource +// requests to extension URLs, such as for the service worker script when +// starting a service worker. In that case, render_frame_id will be +// MSG_ROUTING_NONE. std::unique_ptr<network::mojom::URLLoaderFactory> -MaybeCreateExtensionSubresourceURLLoaderFactory( - content::RenderFrameHost* frame_host, - const GURL& frame_url, - scoped_refptr<extensions::InfoMap> extension_info_map); +CreateExtensionURLLoaderFactory(int render_process_id, int render_frame_id); } // namespace extensions diff --git a/chromium/extensions/browser/extension_system.h b/chromium/extensions/browser/extension_system.h index 21ea3b6d691..303b2277075 100644 --- a/chromium/extensions/browser/extension_system.h +++ b/chromium/extensions/browser/extension_system.h @@ -9,8 +9,10 @@ #include "base/callback_forward.h" #include "base/memory/ref_counted.h" +#include "base/optional.h" #include "build/build_config.h" #include "components/keyed_service/core/keyed_service.h" +#include "extensions/browser/install/crx_install_error.h" #include "extensions/buildflags/buildflags.h" #include "extensions/common/extension.h" @@ -47,7 +49,8 @@ class ValueStoreFactory; class ExtensionSystem : public KeyedService { public: // A callback to be executed when InstallUpdate finishes. - using InstallUpdateCallback = base::OnceCallback<void(bool success)>; + using InstallUpdateCallback = + base::OnceCallback<void(const base::Optional<CrxInstallError>& result)>; ExtensionSystem(); ~ExtensionSystem() override; diff --git a/chromium/extensions/browser/file_reader_unittest.cc b/chromium/extensions/browser/file_reader_unittest.cc index dcee191f88e..b839f5c8c71 100644 --- a/chromium/extensions/browser/file_reader_unittest.cc +++ b/chromium/extensions/browser/file_reader_unittest.cc @@ -62,7 +62,7 @@ class Receiver { void RunBasicTest(const char* filename) { base::FilePath path; - PathService::Get(DIR_TEST_DATA, &path); + base::PathService::Get(DIR_TEST_DATA, &path); std::string extension_id = crx_file::id_util::GenerateId("test"); ExtensionResource resource( extension_id, path, base::FilePath().AppendASCII(filename)); @@ -88,7 +88,7 @@ TEST_F(FileReaderTest, BiggerFile) { TEST_F(FileReaderTest, NonExistantFile) { base::FilePath path; - PathService::Get(DIR_TEST_DATA, &path); + base::PathService::Get(DIR_TEST_DATA, &path); std::string extension_id = crx_file::id_util::GenerateId("test"); ExtensionResource resource(extension_id, path, base::FilePath( FILE_PATH_LITERAL("file_that_does_not_exist"))); diff --git a/chromium/extensions/browser/guest_view/app_view/app_view_apitest.cc b/chromium/extensions/browser/guest_view/app_view/app_view_apitest.cc index b6a87bf948b..28a1dfde439 100644 --- a/chromium/extensions/browser/guest_view/app_view/app_view_apitest.cc +++ b/chromium/extensions/browser/guest_view/app_view/app_view_apitest.cc @@ -116,7 +116,7 @@ class AppViewTest : public AppShellTest, const Extension* LoadApp(const std::string& app_location) { base::ScopedAllowBlockingForTesting allow_blocking; base::FilePath test_data_dir; - PathService::Get(DIR_TEST_DATA, &test_data_dir); + base::PathService::Get(DIR_TEST_DATA, &test_data_dir); test_data_dir = test_data_dir.AppendASCII(app_location.c_str()); return extension_system_->LoadApp(test_data_dir); } diff --git a/chromium/extensions/browser/guest_view/app_view/app_view_guest.cc b/chromium/extensions/browser/guest_view/app_view/app_view_guest.cc index 6ca37ed2230..af1c95c7fa2 100644 --- a/chromium/extensions/browser/guest_view/app_view/app_view_guest.cc +++ b/chromium/extensions/browser/guest_view/app_view/app_view_guest.cc @@ -247,7 +247,9 @@ void AppViewGuest::CompleteCreateWebContents( content::SiteInstance::CreateForURL(browser_context(), guest_extension->url())); params.guest_delegate = this; - callback.Run(WebContents::Create(params)); + // TODO(erikchen): Fix ownership semantics for guest views. + // https://crbug.com/832879. + callback.Run(WebContents::Create(params).release()); } void AppViewGuest::LaunchAppAndFireEvent( diff --git a/chromium/extensions/browser/guest_view/extension_options/extension_options_apitest.cc b/chromium/extensions/browser/guest_view/extension_options/extension_options_apitest.cc index 7e69ab7bcc0..8abfe07e7ac 100644 --- a/chromium/extensions/browser/guest_view/extension_options/extension_options_apitest.cc +++ b/chromium/extensions/browser/guest_view/extension_options/extension_options_apitest.cc @@ -18,10 +18,10 @@ using extensions::Extension; using extensions::FeatureSwitch; -class ExtensionOptionsApiTest : public ExtensionApiTest, +class ExtensionOptionsApiTest : public extensions::ExtensionApiTest, public testing::WithParamInterface<bool> { void SetUpCommandLine(base::CommandLine* command_line) override { - ExtensionApiTest::SetUpCommandLine(command_line); + extensions::ExtensionApiTest::SetUpCommandLine(command_line); bool use_cross_process_frames_for_guests = GetParam(); if (use_cross_process_frames_for_guests) { diff --git a/chromium/extensions/browser/guest_view/extension_options/extension_options_guest.cc b/chromium/extensions/browser/guest_view/extension_options/extension_options_guest.cc index 1a748720200..53d7ee31c07 100644 --- a/chromium/extensions/browser/guest_view/extension_options/extension_options_guest.cc +++ b/chromium/extensions/browser/guest_view/extension_options/extension_options_guest.cc @@ -110,9 +110,9 @@ void ExtensionOptionsGuest::CreateWebContents( browser_context(), content::SiteInstance::CreateForURL(browser_context(), extension_url)); params.guest_delegate = this; - WebContents* wc = WebContents::Create(params); - SetViewType(wc, VIEW_TYPE_EXTENSION_GUEST); - callback.Run(wc); + // TODO(erikchen): Fix ownership semantics for guest views. + // https://crbug.com/832879. + callback.Run(WebContents::Create(params).release()); } void ExtensionOptionsGuest::DidInitialize( @@ -152,17 +152,23 @@ void ExtensionOptionsGuest::OnPreferredSizeChanged(const gfx::Size& pref_size) { options.ToValue())); } -void ExtensionOptionsGuest::AddNewContents(WebContents* source, - WebContents* new_contents, - WindowOpenDisposition disposition, - const gfx::Rect& initial_rect, - bool user_gesture, - bool* was_blocked) { +void ExtensionOptionsGuest::AddNewContents( + WebContents* source, + std::unique_ptr<WebContents> new_contents, + WindowOpenDisposition disposition, + const gfx::Rect& initial_rect, + bool user_gesture, + bool* was_blocked) { + // |new_contents| is potentially used as a non-embedded WebContents, so we + // check that it isn't a guest. The only place that this method should be + // called is WebContentsImpl::ViewSource - which generates a non-guest + // WebContents. + DCHECK(!ExtensionOptionsGuest::FromWebContents(new_contents.get())); if (!attached() || !embedder_web_contents()->GetDelegate()) return; embedder_web_contents()->GetDelegate()->AddNewContents( - source, new_contents, disposition, initial_rect, user_gesture, + source, std::move(new_contents), disposition, initial_rect, user_gesture, was_blocked); } diff --git a/chromium/extensions/browser/guest_view/extension_options/extension_options_guest.h b/chromium/extensions/browser/guest_view/extension_options/extension_options_guest.h index 12250fc127d..9ff1ba65bd5 100644 --- a/chromium/extensions/browser/guest_view/extension_options/extension_options_guest.h +++ b/chromium/extensions/browser/guest_view/extension_options/extension_options_guest.h @@ -39,7 +39,7 @@ class ExtensionOptionsGuest // content::WebContentsDelegate implementation. void AddNewContents(content::WebContents* source, - content::WebContents* new_contents, + std::unique_ptr<content::WebContents> new_contents, WindowOpenDisposition disposition, const gfx::Rect& initial_rect, bool user_gesture, diff --git a/chromium/extensions/browser/guest_view/extension_view/extension_view_guest.cc b/chromium/extensions/browser/guest_view/extension_view/extension_view_guest.cc index 34a16b9c547..2d4dd61c9e9 100644 --- a/chromium/extensions/browser/guest_view/extension_view/extension_view_guest.cc +++ b/chromium/extensions/browser/guest_view/extension_view/extension_view_guest.cc @@ -93,7 +93,9 @@ void ExtensionViewGuest::CreateWebContents( browser_context(), content::SiteInstance::CreateForURL(browser_context(), extension_url_)); params.guest_delegate = this; - callback.Run(WebContents::Create(params)); + // TODO(erikchen): Fix ownership semantics for guest views. + // https://crbug.com/832879. + callback.Run(WebContents::Create(params).release()); } void ExtensionViewGuest::DidInitialize( diff --git a/chromium/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc b/chromium/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc index 1661c0c6582..ffa79cf2918 100644 --- a/chromium/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc +++ b/chromium/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc @@ -24,6 +24,7 @@ #include "extensions/browser/guest_view/web_view/web_view_guest.h" #include "extensions/browser/process_manager.h" #include "extensions/browser/process_map.h" +#include "extensions/browser/view_type_utils.h" #include "extensions/common/features/feature.h" #include "extensions/common/features/feature_provider.h" @@ -40,6 +41,12 @@ ExtensionsGuestViewManagerDelegate::ExtensionsGuestViewManagerDelegate( ExtensionsGuestViewManagerDelegate::~ExtensionsGuestViewManagerDelegate() { } +void ExtensionsGuestViewManagerDelegate::OnGuestAdded( + content::WebContents* guest_web_contents) const { + // Set the view type so extensions sees the guest view as a foreground page. + SetViewType(guest_web_contents, VIEW_TYPE_EXTENSION_GUEST); +} + void ExtensionsGuestViewManagerDelegate::DispatchEvent( const std::string& event_name, std::unique_ptr<base::DictionaryValue> args, diff --git a/chromium/extensions/browser/guest_view/extensions_guest_view_manager_delegate.h b/chromium/extensions/browser/guest_view/extensions_guest_view_manager_delegate.h index 8bbdf1d38da..211e602acee 100644 --- a/chromium/extensions/browser/guest_view/extensions_guest_view_manager_delegate.h +++ b/chromium/extensions/browser/guest_view/extensions_guest_view_manager_delegate.h @@ -22,6 +22,7 @@ class ExtensionsGuestViewManagerDelegate ~ExtensionsGuestViewManagerDelegate() override; // GuestViewManagerDelegate implementation. + void OnGuestAdded(content::WebContents* guest_web_contents) const override; void DispatchEvent(const std::string& event_name, std::unique_ptr<base::DictionaryValue> args, guest_view::GuestViewBase* guest, diff --git a/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc b/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc index 7a8be11115b..59b822431b2 100644 --- a/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc +++ b/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc @@ -25,8 +25,7 @@ #include "extensions/browser/process_manager.h" #include "extensions/test/result_catcher.h" #include "net/test/embedded_test_server/embedded_test_server.h" -#include "net/url_request/url_request_filter.h" -#include "net/url_request/url_request_interceptor.h" +#include "net/test/embedded_test_server/http_request.h" using extensions::ExtensionsAPIClient; using extensions::MimeHandlerViewGuest; @@ -39,89 +38,7 @@ using guest_view::TestGuestViewManagerFactory; // The test extension id is set by the key value in the manifest. const char kExtensionId[] = "oickdpebdnfbgkcaoklfcdhjniefkcji"; -// Counts the number of URL requests made for a given URL. -class URLRequestCounter { - public: - explicit URLRequestCounter(const GURL& url) : url_(url), count_(0) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - base::RunLoop run_loop; - content::BrowserThread::PostTaskAndReply( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&URLRequestCounter::AddInterceptor, base::Unretained(this)), - run_loop.QuitClosure()); - run_loop.Run(); - } - - ~URLRequestCounter() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - base::RunLoop run_loop; - content::BrowserThread::PostTaskAndReply( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&URLRequestCounter::RemoveInterceptor, - base::Unretained(this)), - run_loop.QuitClosure()); - run_loop.Run(); - } - - int GetCount() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - // Do a round-trip to the IO thread to guarantee that the UI thread has - // been notified of all the requests triggered by the IO thread. - base::RunLoop run_loop; - content::BrowserThread::PostTaskAndReply(content::BrowserThread::IO, - FROM_HERE, base::DoNothing(), - run_loop.QuitClosure()); - run_loop.Run(); - return count_; - } - - private: - // This class runs a callback when a URL request is intercepted. It doesn't - // handle the request itself. - class SimpleRequestInterceptor : public net::URLRequestInterceptor { - public: - explicit SimpleRequestInterceptor(const base::Closure& callback) - : callback_(callback) {} - - // URLRequestInterceptor implementation: - net::URLRequestJob* MaybeInterceptRequest( - net::URLRequest* request, - net::NetworkDelegate* network_delegate) const override { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - callback_); - return nullptr; - } - - private: - const base::Closure callback_; - }; - - void RequestFired() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - ++count_; - } - - void AddInterceptor() { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - net::URLRequestFilter::GetInstance()->AddUrlInterceptor( - url_, std::make_unique<SimpleRequestInterceptor>(base::Bind( - &URLRequestCounter::RequestFired, base::Unretained(this)))); - } - - void RemoveInterceptor() { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - net::URLRequestFilter::GetInstance()->RemoveUrlHandler(url_); - } - - const GURL url_; - // |count_| is only accessed on the UI thread. - int count_; - - DISALLOW_COPY_AND_ASSIGN(URLRequestCounter); -}; - -class MimeHandlerViewTest : public ExtensionApiTest, +class MimeHandlerViewTest : public extensions::ExtensionApiTest, public testing::WithParamInterface<bool> { public: MimeHandlerViewTest() { @@ -131,10 +48,12 @@ class MimeHandlerViewTest : public ExtensionApiTest, ~MimeHandlerViewTest() override {} void SetUpOnMainThread() override { - ExtensionApiTest::SetUpOnMainThread(); + extensions::ExtensionApiTest::SetUpOnMainThread(); embedded_test_server()->ServeFilesFromDirectory( test_data_dir_.AppendASCII("mime_handler_view")); + embedded_test_server()->RegisterRequestMonitor(base::BindRepeating( + &MimeHandlerViewTest::MonitorRequest, base::Unretained(this))); ASSERT_TRUE(StartEmbeddedTestServer()); } @@ -144,7 +63,7 @@ class MimeHandlerViewTest : public ExtensionApiTest, // MimeHandlerViewGuest will be based on OOPIF and we can remove this comment // (https://crbug.com/642826). void SetUpCommandLine(base::CommandLine* command_line) override { - ExtensionApiTest::SetUpCommandLine(command_line); + extensions::ExtensionApiTest::SetUpCommandLine(command_line); bool use_cross_process_frames_for_guests = GetParam(); if (use_cross_process_frames_for_guests) { @@ -207,9 +126,17 @@ class MimeHandlerViewTest : public ExtensionApiTest, RunTestWithUrl(embedded_test_server()->GetURL("/" + path)); } + int basic_count() const { return basic_count_; } + private: + void MonitorRequest(const net::test_server::HttpRequest& request) { + if (request.relative_url == "/testBasic.csv") + basic_count_++; + } + TestGuestViewManagerFactory factory_; base::test::ScopedFeatureList scoped_feature_list_; + int basic_count_ = 0; }; INSTANTIATE_TEST_CASE_P(MimeHandlerViewTests, @@ -281,9 +208,8 @@ IN_PROC_BROWSER_TEST_P(MimeHandlerViewTest, ResizeBeforeAttach) { // Regression test for crbug.com/587709. IN_PROC_BROWSER_TEST_P(MimeHandlerViewTest, SingleRequest) { GURL url(embedded_test_server()->GetURL("/testBasic.csv")); - URLRequestCounter request_counter(url); RunTest("testBasic.csv"); - EXPECT_EQ(1, request_counter.GetCount()); + EXPECT_EQ(1, basic_count()); } // Test that a mime handler view can keep a background page alive. diff --git a/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc b/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc index 57e98ae8a5b..07f7fb42f53 100644 --- a/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc +++ b/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc @@ -193,9 +193,13 @@ void MimeHandlerViewGuest::CreateWebContents( WebContents::CreateParams params(browser_context(), guest_site_instance.get()); params.guest_delegate = this; - auto* web_contents = WebContents::Create(params); - SetViewType(web_contents, VIEW_TYPE_EXTENSION_GUEST); - callback.Run(web_contents); + // TODO(erikchen): Fix ownership semantics for guest views. + // https://crbug.com/832879. + callback.Run( + WebContents::CreateWithSessionStorage( + params, + owner_web_contents()->GetController().GetSessionStorageNamespaceMap()) + .release()); registry_.AddInterface( base::Bind(&MimeHandlerServiceImpl::Create, stream_->GetWeakPtr())); @@ -308,11 +312,13 @@ void MimeHandlerViewGuest::OnRenderFrameHostDeleted(int process_id, } } -void MimeHandlerViewGuest::EnterFullscreenModeForTab(content::WebContents*, - const GURL& origin) { +void MimeHandlerViewGuest::EnterFullscreenModeForTab( + content::WebContents*, + const GURL& origin, + const blink::WebFullscreenOptions& options) { if (SetFullscreenState(true)) { embedder_web_contents()->GetDelegate()->EnterFullscreenModeForTab( - embedder_web_contents(), origin); + embedder_web_contents(), origin, options); } } diff --git a/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h b/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h index 2bc53e063aa..7f0df3d7dc3 100644 --- a/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h +++ b/chromium/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h @@ -121,8 +121,10 @@ class MimeHandlerViewGuest : content::WebContents* source) final; bool SaveFrame(const GURL& url, const content::Referrer& referrer) final; void OnRenderFrameHostDeleted(int process_id, int routing_id) final; - void EnterFullscreenModeForTab(content::WebContents* web_contents, - const GURL& origin) override; + void EnterFullscreenModeForTab( + content::WebContents* web_contents, + const GURL& origin, + const blink::WebFullscreenOptions& options) override; void ExitFullscreenModeForTab(content::WebContents*) override; bool IsFullscreenForTabOrPending( const content::WebContents* web_contents) const override; diff --git a/chromium/extensions/browser/guest_view/web_view/web_view_apitest.cc b/chromium/extensions/browser/guest_view/web_view/web_view_apitest.cc index 2258fc3a77e..91b21b4489e 100644 --- a/chromium/extensions/browser/guest_view/web_view/web_view_apitest.cc +++ b/chromium/extensions/browser/guest_view/web_view/web_view_apitest.cc @@ -10,6 +10,7 @@ #include "base/command_line.h" #include "base/macros.h" +#include "base/memory/scoped_refptr.h" #include "base/path_service.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" @@ -21,6 +22,7 @@ #include "components/guest_view/browser/test_guest_view_manager.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_view_host.h" #include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" #include "content/public/test/browser_test_utils.h" @@ -45,6 +47,10 @@ #include "net/test/embedded_test_server/http_response.h" #include "ui/display/display_switches.h" +#if defined(USE_AURA) +#include "third_party/blink/public/platform/web_mouse_event.h" +#endif + using guest_view::GuestViewManager; using guest_view::TestGuestViewManager; @@ -144,7 +150,7 @@ WebViewAPITest::WebViewAPITest() { void WebViewAPITest::LaunchApp(const std::string& app_location) { base::ScopedAllowBlockingForTesting allow_blocking; base::FilePath test_data_dir; - PathService::Get(DIR_TEST_DATA, &test_data_dir); + base::PathService::Get(DIR_TEST_DATA, &test_data_dir); test_data_dir = test_data_dir.AppendASCII(app_location.c_str()); const Extension* extension = extension_system_->LoadApp(test_data_dir); @@ -200,7 +206,7 @@ void WebViewAPITest::StartTestServer(const std::string& app_location) { base::ScopedAllowBlockingForTesting allow_blocking; base::FilePath test_data_dir; - PathService::Get(DIR_TEST_DATA, &test_data_dir); + base::PathService::Get(DIR_TEST_DATA, &test_data_dir); test_data_dir = test_data_dir.AppendASCII(app_location.c_str()); embedded_test_server()->ServeFilesFromDirectory(test_data_dir); @@ -471,6 +477,32 @@ IN_PROC_BROWSER_TEST_F(WebViewAPITest, TestContentLoadEvent) { RunTest("testContentLoadEvent", "web_view/apitest"); } +#if defined(USE_AURA) +// Verifies that trying to show the context menu doesn't crash +// (https://crbug.com/820604). +IN_PROC_BROWSER_TEST_F(WebViewAPITest, TestContextMenu) { + // Launch some test app that displays a webview. + LaunchApp("web_view/visibility_changed"); + + // Ensure the webview's surface is ready for hit testing. + content::WebContents* guest_web_contents = GetGuestWebContents(); + content::WaitForGuestSurfaceReady(guest_web_contents); + + // Register a ContextMenuFilter to wait for the context menu event to be sent. + content::RenderProcessHost* guest_process_host = + guest_web_contents->GetMainFrame()->GetProcess(); + auto context_menu_filter = base::MakeRefCounted<content::ContextMenuFilter>(); + guest_process_host->AddFilter(context_menu_filter.get()); + + // Trigger the context menu. AppShell doesn't show a context menu; this is + // just a sanity check that nothing breaks. + content::SimulateRoutedMouseClickAt( + guest_web_contents, blink::WebInputEvent::kNoModifiers, + blink::WebMouseEvent::Button::kRight, gfx::Point(10, 10)); + context_menu_filter->Wait(); +} +#endif + IN_PROC_BROWSER_TEST_F(WebViewAPITest, TestDeclarativeWebRequestAPI) { std::string app_location = "web_view/apitest"; StartTestServer(app_location); diff --git a/chromium/extensions/browser/guest_view/web_view/web_view_guest.cc b/chromium/extensions/browser/guest_view/web_view/web_view_guest.cc index 122bd3cfed8..8611c34be99 100644 --- a/chromium/extensions/browser/guest_view/web_view/web_view_guest.cc +++ b/chromium/extensions/browser/guest_view/web_view/web_view_guest.cc @@ -12,7 +12,6 @@ #include <utility> #include "base/lazy_instance.h" -#include "base/message_loop/message_loop.h" #include "base/metrics/user_metrics.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" @@ -371,7 +370,9 @@ void WebViewGuest::CreateWebContents( owner_render_process_host->GetBrowserContext(), std::move(guest_site_instance)); params.guest_delegate = this; - WebContents* new_contents = WebContents::Create(params); + // TODO(erikchen): Fix ownership semantics for guest views. + // https://crbug.com/832879. + WebContents* new_contents = WebContents::Create(params).release(); // Grant access to the origin of the embedder to the guest process. This // allows blob:/filesystem: URLs with the embedder origin to be created @@ -424,29 +425,26 @@ void WebViewGuest::ClearDataInternal(base::Time remove_since, return; } - content::StoragePartition::CookieMatcherFunction cookie_matcher; - - bool remove_session_cookies = - !!(removal_mask & webview::WEB_VIEW_REMOVE_DATA_MASK_SESSION_COOKIES); - bool remove_persistent_cookies = - !!(removal_mask & webview::WEB_VIEW_REMOVE_DATA_MASK_PERSISTENT_COOKIES); - bool remove_all_cookies = - (!!(removal_mask & webview::WEB_VIEW_REMOVE_DATA_MASK_COOKIES)) || - (remove_session_cookies && remove_persistent_cookies); - - // Leaving the cookie_matcher unset will cause all cookies to be purged. - if (!remove_all_cookies) { - if (remove_session_cookies) { - cookie_matcher = - base::Bind([](const net::CanonicalCookie& cookie) -> bool { - return !cookie.IsPersistent(); - }); - } else if (remove_persistent_cookies) { - cookie_matcher = - base::Bind([](const net::CanonicalCookie& cookie) -> bool { - return cookie.IsPersistent(); - }); - } + auto cookie_delete_filter = network::mojom::CookieDeletionFilter::New(); + // Intentionally do not set the deletion filter time interval because the + // time interval parameters to ClearData() will be used. + + // TODO(cmumford): Make this (and webview::* constants) constexpr. + const uint32_t ALL_COOKIES_MASK = + webview::WEB_VIEW_REMOVE_DATA_MASK_SESSION_COOKIES | + webview::WEB_VIEW_REMOVE_DATA_MASK_PERSISTENT_COOKIES; + + if ((removal_mask & ALL_COOKIES_MASK) == ALL_COOKIES_MASK) { + cookie_delete_filter->session_control = + network::mojom::CookieDeletionSessionControl::IGNORE_CONTROL; + } else if (removal_mask & + webview::WEB_VIEW_REMOVE_DATA_MASK_SESSION_COOKIES) { + cookie_delete_filter->session_control = + network::mojom::CookieDeletionSessionControl::SESSION_COOKIES; + } else if (removal_mask & + webview::WEB_VIEW_REMOVE_DATA_MASK_PERSISTENT_COOKIES) { + cookie_delete_filter->session_control = + network::mojom::CookieDeletionSessionControl::PERSISTENT_COOKIES; } content::StoragePartition* partition = @@ -456,8 +454,9 @@ void WebViewGuest::ClearDataInternal(base::Time remove_since, partition->ClearData( storage_partition_removal_mask, content::StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, - content::StoragePartition::OriginMatcherFunction(), cookie_matcher, - remove_since, base::Time::Now(), callback); + content::StoragePartition::OriginMatcherFunction(), + std::move(cookie_delete_filter), remove_since, base::Time::Now(), + callback); } void WebViewGuest::GuestViewDidStopLoading() { @@ -572,14 +571,6 @@ void WebViewGuest::FindReply(WebContents* source, active_match_ordinal, final_update); } -void WebViewGuest::OnAudioStateChanged(content::WebContents* web_contents, - bool audible) { - auto args = std::make_unique<base::DictionaryValue>(); - args->Set(webview::kAudible, std::make_unique<base::Value>(audible)); - DispatchEventToView(std::make_unique<GuestViewEvent>( - webview::kEventAudioStateChanged, std::move(args))); -} - double WebViewGuest::GetZoom() const { double zoom_level = ZoomController::FromWebContents(web_contents())->GetZoomLevel(); @@ -733,7 +724,7 @@ void WebViewGuest::Stop() { void WebViewGuest::Terminate() { base::RecordAction(UserMetricsAction("WebView.Guest.Terminate")); base::ProcessHandle process_handle = - web_contents()->GetMainFrame()->GetProcess()->GetHandle(); + web_contents()->GetMainFrame()->GetProcess()->GetProcess().Handle(); if (process_handle) { web_contents()->GetMainFrame()->GetProcess()->Shutdown( content::RESULT_CODE_KILLED); @@ -916,6 +907,13 @@ void WebViewGuest::FrameNameChanged(RenderFrameHost* render_frame_host, ReportFrameNameChange(name); } +void WebViewGuest::OnAudioStateChanged(bool audible) { + auto args = std::make_unique<base::DictionaryValue>(); + args->Set(webview::kAudible, std::make_unique<base::Value>(audible)); + DispatchEventToView(std::make_unique<GuestViewEvent>( + webview::kEventAudioStateChanged, std::move(args))); +} + void WebViewGuest::ReportFrameNameChange(const std::string& name) { name_ = name; auto args = std::make_unique<base::DictionaryValue>(); @@ -1195,7 +1193,7 @@ void WebViewGuest::SetTransparency() { if (allow_transparency_) view->SetBackgroundColor(SK_ColorTRANSPARENT); else - view->SetBackgroundColorToDefault(); + view->SetBackgroundColor(SK_ColorWHITE); } void WebViewGuest::SetAllowScaling(bool allow) { @@ -1246,17 +1244,17 @@ bool WebViewGuest::LoadDataWithBaseURL(const std::string& data_url, } void WebViewGuest::AddNewContents(WebContents* source, - WebContents* new_contents, + std::unique_ptr<WebContents> new_contents, WindowOpenDisposition disposition, const gfx::Rect& initial_rect, bool user_gesture, bool* was_blocked) { + // TODO(erikchen): Fix ownership semantics for WebContents inside this class. + // https://crbug.com/832879. if (was_blocked) *was_blocked = false; - RequestNewWindowPermission(disposition, - initial_rect, - user_gesture, - new_contents); + RequestNewWindowPermission(disposition, initial_rect, user_gesture, + new_contents.release()); } WebContents* WebViewGuest::OpenURLFromTab( @@ -1337,8 +1335,10 @@ void WebViewGuest::WebContentsCreated(WebContents* source_contents, std::make_pair(guest, NewWindowInfo(target_url, frame_name))); } -void WebViewGuest::EnterFullscreenModeForTab(WebContents* web_contents, - const GURL& origin) { +void WebViewGuest::EnterFullscreenModeForTab( + WebContents* web_contents, + const GURL& origin, + const blink::WebFullscreenOptions& options) { // Ask the embedder for permission. base::DictionaryValue request_info; request_info.SetString(webview::kOrigin, origin.spec()); @@ -1516,9 +1516,12 @@ void WebViewGuest::SetFullscreenState(bool is_fullscreen) { DispatchEventToView(std::make_unique<GuestViewEvent>( webview::kEventExitFullscreen, std::move(args))); } - // Since we changed fullscreen state, sending a Resize message ensures that - // renderer/ sees the change. - web_contents()->GetRenderViewHost()->GetWidget()->WasResized(); + // Since we changed fullscreen state, sending a SynchronizeVisualProperties + // message ensures that renderer/ sees the change. + web_contents() + ->GetRenderViewHost() + ->GetWidget() + ->SynchronizeVisualProperties(); } } // namespace extensions diff --git a/chromium/extensions/browser/guest_view/web_view/web_view_guest.h b/chromium/extensions/browser/guest_view/web_view/web_view_guest.h index 5c06f37873f..da06ab393b3 100644 --- a/chromium/extensions/browser/guest_view/web_view/web_view_guest.h +++ b/chromium/extensions/browser/guest_view/web_view/web_view_guest.h @@ -232,7 +232,7 @@ class WebViewGuest : public guest_view::GuestView<WebViewGuest> { content::JavaScriptDialogManager* GetJavaScriptDialogManager( content::WebContents* source) final; void AddNewContents(content::WebContents* source, - content::WebContents* new_contents, + std::unique_ptr<content::WebContents> new_contents, WindowOpenDisposition disposition, const gfx::Rect& initial_rect, bool user_gesture, @@ -246,16 +246,16 @@ class WebViewGuest : public guest_view::GuestView<WebViewGuest> { const std::string& frame_name, const GURL& target_url, content::WebContents* new_contents) final; - void EnterFullscreenModeForTab(content::WebContents* web_contents, - const GURL& origin) final; + void EnterFullscreenModeForTab( + content::WebContents* web_contents, + const GURL& origin, + const blink::WebFullscreenOptions& options) final; void ExitFullscreenModeForTab(content::WebContents* web_contents) final; bool IsFullscreenForTabOrPending( const content::WebContents* web_contents) const final; void RequestToLockMouse(content::WebContents* web_contents, bool user_gesture, bool last_unlocked_by_target) override; - void OnAudioStateChanged(content::WebContents* web_contents, - bool audible) final; // WebContentsObserver implementation. void DidStartNavigation(content::NavigationHandle* navigation_handle) final; @@ -267,6 +267,7 @@ class WebViewGuest : public guest_view::GuestView<WebViewGuest> { void UserAgentOverrideSet(const std::string& user_agent) final; void FrameNameChanged(content::RenderFrameHost* render_frame_host, const std::string& name) final; + void OnAudioStateChanged(bool audible) final; // Informs the embedder of a frame name change. void ReportFrameNameChange(const std::string& name); diff --git a/chromium/extensions/browser/guest_view/web_view/web_view_guest_delegate.h b/chromium/extensions/browser/guest_view/web_view/web_view_guest_delegate.h index b9a33b02e5f..38562b99938 100644 --- a/chromium/extensions/browser/guest_view/web_view/web_view_guest_delegate.h +++ b/chromium/extensions/browser/guest_view/web_view/web_view_guest_delegate.h @@ -20,10 +20,6 @@ class WebViewGuestDelegate { // Shows the context menu for the guest. virtual void OnShowContextMenu(int request_id) = 0; - - // Returns true if the WebViewGuest should handle find requests for its - // embedder. - virtual bool ShouldHandleFindRequestsForEmbedder() const = 0; }; } // namespace extensions diff --git a/chromium/extensions/browser/guest_view/web_view/web_view_permission_helper.cc b/chromium/extensions/browser/guest_view/web_view/web_view_permission_helper.cc index b83fbaf23f0..085189a61ca 100644 --- a/chromium/extensions/browser/guest_view/web_view/web_view_permission_helper.cc +++ b/chromium/extensions/browser/guest_view/web_view/web_view_permission_helper.cc @@ -150,6 +150,7 @@ WebViewPermissionHelper::WebViewPermissionHelper(WebViewGuest* web_view_guest) : content::WebContentsObserver(web_view_guest->web_contents()), next_permission_request_id_(guest_view::kInstanceIDNone), web_view_guest_(web_view_guest), + default_media_access_permission_(false), weak_factory_(this) { web_view_permission_helper_delegate_.reset( ExtensionsAPIClient::Get()->CreateWebViewPermissionHelperDelegate( @@ -202,7 +203,7 @@ void WebViewPermissionHelper::RequestMediaAccessPermission( weak_factory_.GetWeakPtr(), request, callback), - false /* allowed_by_default */); + default_media_access_permission_); } bool WebViewPermissionHelper::CheckMediaAccessPermission( diff --git a/chromium/extensions/browser/guest_view/web_view/web_view_permission_helper.h b/chromium/extensions/browser/guest_view/web_view/web_view_permission_helper.h index 4e3a7f0f53f..8ae06ab2409 100644 --- a/chromium/extensions/browser/guest_view/web_view/web_view_permission_helper.h +++ b/chromium/extensions/browser/guest_view/web_view/web_view_permission_helper.h @@ -119,6 +119,10 @@ class WebViewPermissionHelper WebViewGuest* web_view_guest() { return web_view_guest_; } + void set_default_media_access_permission(bool allow_media_access) { + default_media_access_permission_ = allow_media_access; + } + private: void OnMediaPermissionResponse(const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback, @@ -142,6 +146,8 @@ class WebViewPermissionHelper WebViewGuest* const web_view_guest_; + bool default_media_access_permission_; + base::WeakPtrFactory<WebViewPermissionHelper> weak_factory_; DISALLOW_COPY_AND_ASSIGN(WebViewPermissionHelper); diff --git a/chromium/extensions/browser/image_loader_unittest.cc b/chromium/extensions/browser/image_loader_unittest.cc index 20e9a598d76..26dfbedcf9b 100644 --- a/chromium/extensions/browser/image_loader_unittest.cc +++ b/chromium/extensions/browser/image_loader_unittest.cc @@ -66,7 +66,7 @@ class ImageLoaderTest : public ExtensionsTest { Manifest::Location location) { // Create and load an extension. base::FilePath extension_dir; - if (!PathService::Get(DIR_TEST_DATA, &extension_dir)) { + if (!base::PathService::Get(DIR_TEST_DATA, &extension_dir)) { EXPECT_FALSE(true); return NULL; } diff --git a/chromium/extensions/browser/info_map_unittest.cc b/chromium/extensions/browser/info_map_unittest.cc index 271ed11bb79..14d3a816c18 100644 --- a/chromium/extensions/browser/info_map_unittest.cc +++ b/chromium/extensions/browser/info_map_unittest.cc @@ -27,7 +27,7 @@ class InfoMapTest : public testing::Test { // Returns a barebones test Extension object with the given name. static scoped_refptr<Extension> CreateExtension(const std::string& name) { base::FilePath path; - PathService::Get(DIR_TEST_DATA, &path); + base::PathService::Get(DIR_TEST_DATA, &path); return ExtensionBuilder(name).SetPath(path.AppendASCII(name)).Build(); } diff --git a/chromium/extensions/browser/install/BUILD.gn b/chromium/extensions/browser/install/BUILD.gn index 5922ff52fbe..0eb97983e5a 100644 --- a/chromium/extensions/browser/install/BUILD.gn +++ b/chromium/extensions/browser/install/BUILD.gn @@ -9,9 +9,11 @@ assert(enable_extensions, source_set("install") { sources = [ + "crx_install_error.cc", "crx_install_error.h", "extension_install_ui.cc", "extension_install_ui.h", + "sandboxed_unpacker_failure_reason.h", ] deps = [ diff --git a/chromium/extensions/browser/install/crx_install_error.cc b/chromium/extensions/browser/install/crx_install_error.cc new file mode 100644 index 00000000000..22305ee035e --- /dev/null +++ b/chromium/extensions/browser/install/crx_install_error.cc @@ -0,0 +1,51 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/browser/install/crx_install_error.h" +#include "extensions/browser/install/sandboxed_unpacker_failure_reason.h" + +namespace extensions { + +CrxInstallError::CrxInstallError(CrxInstallErrorType type, + CrxInstallErrorDetail detail, + const base::string16& message) + : type_(type), detail_(detail), message_(message) { + DCHECK_NE(CrxInstallErrorType::NONE, type); + DCHECK_NE(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE, type); +} + +CrxInstallError::CrxInstallError(CrxInstallErrorType type, + CrxInstallErrorDetail detail) + : CrxInstallError(type, detail, base::string16()) {} + +CrxInstallError::CrxInstallError(SandboxedUnpackerFailureReason reason, + const base::string16& message) + : type_(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE), + detail_(CrxInstallErrorDetail::NONE), + sandbox_failure_detail_(reason), + message_(message) {} + +CrxInstallError::CrxInstallError(const CrxInstallError& other) = default; +CrxInstallError::CrxInstallError(CrxInstallError&& other) = default; +CrxInstallError& CrxInstallError::operator=(const CrxInstallError& other) = + default; +CrxInstallError& CrxInstallError::operator=(CrxInstallError&& other) = default; + +CrxInstallError::~CrxInstallError() = default; + +// For SANDBOXED_UNPACKER_FAILURE type, use sandbox_failure_detail(). +CrxInstallErrorDetail CrxInstallError::detail() const { + DCHECK_NE(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE, type_); + return detail_; +} + +// sandbox_failure_detail() only returns a value when the error type is +// SANDBOXED_UNPACKER_FAILURE. +SandboxedUnpackerFailureReason CrxInstallError::sandbox_failure_detail() const { + DCHECK_EQ(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE, type_); + DCHECK(sandbox_failure_detail_); + return sandbox_failure_detail_.value(); +} + +} // namespace extensions diff --git a/chromium/extensions/browser/install/crx_install_error.h b/chromium/extensions/browser/install/crx_install_error.h index af25df66dbc..ca747b278d5 100644 --- a/chromium/extensions/browser/install/crx_install_error.h +++ b/chromium/extensions/browser/install/crx_install_error.h @@ -5,41 +5,82 @@ #ifndef EXTENSIONS_BROWSER_INSTALL_CRX_INSTALL_ERROR_H_ #define EXTENSIONS_BROWSER_INSTALL_CRX_INSTALL_ERROR_H_ +#include "base/optional.h" #include "base/strings/string16.h" namespace extensions { -// Simple error class for CrxInstaller. -class CrxInstallError { - public: - // Typed errors that need to be handled specially by clients. - // ERROR_OFF_STORE for disallowed off-store installations. - // ERROR_DECLINED for situations when a .crx file seems to be OK, but there +enum class SandboxedUnpackerFailureReason; + +// Typed errors that need to be handled specially by clients. +// Do not change the order of the entries or remove entries in this list. +enum class CrxInstallErrorType { + NONE = 0, + // DECLINED for situations when a .crx file seems to be OK, but there // are some policy restrictions or unmet dependencies that prevent it from // being installed. - // ERROR_HASH_MISMATCH if the expected extension SHA256 hash sum is different - // from the actual one. - enum Type { - ERROR_NONE, - ERROR_OFF_STORE, - ERROR_DECLINED, - ERROR_HASH_MISMATCH, - ERROR_OTHER - }; + DECLINED = 1, + // SANDBOXED_UNPACKER_FAILURE for sandboxed unpacker error. + // CrxInstallErrorDetail will give more detail about the failure. + SANDBOXED_UNPACKER_FAILURE = 2, + OTHER = 3, +}; - CrxInstallError() : type_(ERROR_NONE) {} +// Extended error code that may help explain the error type. +// Do not change the order of the entries or remove entries in this list. +enum class CrxInstallErrorDetail { + NONE, // 0 + CONVERT_USER_SCRIPT_TO_EXTENSION_FAILED, // 1 + UNEXPECTED_ID, // 2 + UNEXPECTED_VERSION, // 3 + MISMATCHED_VERSION, // 4 + MANIFEST_INVALID, // 5 + INSTALL_NOT_ENABLED, // 6 + OFFSTORE_INSTALL_DISALLOWED, // 7 + INCORRECT_APP_CONTENT_TYPE, // 8 + NOT_INSTALLED_FROM_GALLERY, // 9 + INCORRECT_INSTALL_HOST, // 10 + DEPENDENCY_NOT_SHARED_MODULE, // 11 + DEPENDENCY_OLD_VERSION, // 12 + DEPENDENCY_NOT_ALLOWLISTED, // 13 + UNSUPPORTED_REQUIREMENTS, // 14 + EXTENSION_IS_BLOCKLISTED, // 15 + DISALLOWED_BY_POLICY, // 16 + KIOSK_MODE_ONLY, // 17 + OVERLAPPING_WEB_EXTENT, // 18 + CANT_DOWNGRADE_VERSION, // 19 + MOVE_DIRECTORY_TO_PROFILE_FAILED, // 20 + CANT_LOAD_EXTENSION, // 21 + USER_CANCELED, // 22 + USER_ABORTED, // 23 + UPDATE_NON_EXISTING_EXTENSION, // 24 +}; - explicit CrxInstallError(const base::string16& message) - : type_(message.empty() ? ERROR_NONE : ERROR_OTHER), message_(message) {} +// Simple error class for CrxInstaller. +class CrxInstallError { + public: + CrxInstallError(CrxInstallErrorType type, + CrxInstallErrorDetail detail, + const base::string16& message); + CrxInstallError(CrxInstallErrorType type, CrxInstallErrorDetail detail); + CrxInstallError(SandboxedUnpackerFailureReason reason, + const base::string16& message); + ~CrxInstallError(); - CrxInstallError(Type type, const base::string16& message) - : type_(type), message_(message) {} + CrxInstallError(const CrxInstallError& other); + CrxInstallError(CrxInstallError&& other); + CrxInstallError& operator=(const CrxInstallError& other); + CrxInstallError& operator=(CrxInstallError&& other); - Type type() const { return type_; } + CrxInstallErrorType type() const { return type_; } const base::string16& message() const { return message_; } + CrxInstallErrorDetail detail() const; + SandboxedUnpackerFailureReason sandbox_failure_detail() const; private: - Type type_; + CrxInstallErrorType type_; + CrxInstallErrorDetail detail_; + base::Optional<SandboxedUnpackerFailureReason> sandbox_failure_detail_; base::string16 message_; }; diff --git a/chromium/extensions/browser/install/sandboxed_unpacker_failure_reason.h b/chromium/extensions/browser/install/sandboxed_unpacker_failure_reason.h new file mode 100644 index 00000000000..7571fed3e29 --- /dev/null +++ b/chromium/extensions/browser/install/sandboxed_unpacker_failure_reason.h @@ -0,0 +1,84 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_BROWSER_INSTALL_SANDBOXED_UNPACKER_FAILURE_REASON_H_ +#define EXTENSIONS_BROWSER_INSTALL_SANDBOXED_UNPACKER_FAILURE_REASON_H_ + +namespace extensions { + +// Enumerate all the ways SandboxedUnpacker can fail. +// Don't change the order or change the value of the enums. +enum class SandboxedUnpackerFailureReason { + // SandboxedUnpacker::CreateTempDirectory() + COULD_NOT_GET_TEMP_DIRECTORY = 0, + COULD_NOT_CREATE_TEMP_DIRECTORY = 1, + + // SandboxedUnpacker::Start() + FAILED_TO_COPY_EXTENSION_FILE_TO_TEMP_DIRECTORY = 2, + COULD_NOT_GET_SANDBOX_FRIENDLY_PATH = 3, + + // SandboxedUnpacker::UnpackExtensionSucceeded() + COULD_NOT_LOCALIZE_EXTENSION = 4, + INVALID_MANIFEST = 5, + + // SandboxedUnpacker::UnpackExtensionFailed() + UNPACKER_CLIENT_FAILED = 6, + + // SandboxedUnpacker::UtilityProcessCrashed() + UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL = 7, + + // SandboxedUnpacker::ValidateSignature() + CRX_FILE_NOT_READABLE = 8, + CRX_HEADER_INVALID = 9, + CRX_MAGIC_NUMBER_INVALID = 10, + CRX_VERSION_NUMBER_INVALID = 11, + CRX_EXCESSIVELY_LARGE_KEY_OR_SIGNATURE = 12, + CRX_ZERO_KEY_LENGTH = 13, + CRX_ZERO_SIGNATURE_LENGTH = 14, + CRX_PUBLIC_KEY_INVALID = 15, + CRX_SIGNATURE_INVALID = 16, + CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED = 17, + CRX_SIGNATURE_VERIFICATION_FAILED = 18, + + // SandboxedUnpacker::RewriteManifestFile() + ERROR_SERIALIZING_MANIFEST_JSON = 19, + ERROR_SAVING_MANIFEST_JSON = 20, + + // SandboxedUnpacker::RewriteImageFiles() + COULD_NOT_READ_IMAGE_DATA_FROM_DISK_UNUSED = 21, + DECODED_IMAGES_DO_NOT_MATCH_THE_MANIFEST_UNUSED = 22, + INVALID_PATH_FOR_BROWSER_IMAGE = 23, + ERROR_REMOVING_OLD_IMAGE_FILE = 24, + INVALID_PATH_FOR_BITMAP_IMAGE = 25, + ERROR_RE_ENCODING_THEME_IMAGE = 26, + ERROR_SAVING_THEME_IMAGE = 27, + DEPRECATED_ABORTED_DUE_TO_SHUTDOWN = 28, // No longer used; kept for UMA. + + // SandboxedUnpacker::RewriteCatalogFiles() + COULD_NOT_READ_CATALOG_DATA_FROM_DISK_UNUSED = 29, + INVALID_CATALOG_DATA = 30, + INVALID_PATH_FOR_CATALOG_UNUSED = 31, + ERROR_SERIALIZING_CATALOG = 32, + ERROR_SAVING_CATALOG = 33, + + // SandboxedUnpacker::ValidateSignature() + CRX_HASH_VERIFICATION_FAILED = 34, + + UNZIP_FAILED = 35, + DIRECTORY_MOVE_FAILED = 36, + + // SandboxedUnpacker::ValidateSignature() + CRX_FILE_IS_DELTA_UPDATE = 37, + CRX_EXPECTED_HASH_INVALID = 38, + + // SandboxedUnpacker::IndexAndPersistRulesIfNeeded() + ERROR_PARSING_DNR_RULESET = 39, + ERROR_INDEXING_DNR_RULESET = 40, + + NUM_FAILURE_REASONS +}; + +} // namespace extensions + +#endif // EXTENSIONS_BROWSER_INSTALL_SANDBOXED_UNPACKER_FAILURE_REASON_H_ diff --git a/chromium/extensions/browser/json_file_sanitizer.cc b/chromium/extensions/browser/json_file_sanitizer.cc index e57e5761853..fb864c649cd 100644 --- a/chromium/extensions/browser/json_file_sanitizer.cc +++ b/chromium/extensions/browser/json_file_sanitizer.cc @@ -94,7 +94,7 @@ void JsonFileSanitizer::JsonFileRead( void JsonFileSanitizer::JsonParsingDone( const base::FilePath& file_path, - std::unique_ptr<base::Value> json_value, + base::Optional<base::Value> json_value, const base::Optional<std::string>& error) { if (!json_value || !json_value->is_dict()) { ReportError(Status::kDecodingError, error ? *error : std::string()); diff --git a/chromium/extensions/browser/json_file_sanitizer.h b/chromium/extensions/browser/json_file_sanitizer.h index b90e73b5739..4d8181d1b64 100644 --- a/chromium/extensions/browser/json_file_sanitizer.h +++ b/chromium/extensions/browser/json_file_sanitizer.h @@ -77,7 +77,7 @@ class JsonFileSanitizer { std::tuple<std::string, bool, bool> read_and_delete_result); void JsonParsingDone(const base::FilePath& file_path, - std::unique_ptr<base::Value> json_value, + base::Optional<base::Value> json_value, const base::Optional<std::string>& error); void JsonFileWritten(const base::FilePath& file_path, diff --git a/chromium/extensions/browser/lazy_background_task_queue.cc b/chromium/extensions/browser/lazy_background_task_queue.cc index 8efc9fde866..ee3eb077cbc 100644 --- a/chromium/extensions/browser/lazy_background_task_queue.cc +++ b/chromium/extensions/browser/lazy_background_task_queue.cc @@ -42,6 +42,16 @@ void PendingTaskAdapter(LazyContextTaskQueue::PendingTask original_task, } } +// Attempts to create a background host for a lazy background page. Returns true +// if the background host is created. +bool CreateLazyBackgroundHost(ProcessManager* pm, const Extension* extension) { + pm->IncrementLazyKeepaliveCount(extension); + // Creating the background host may fail, e.g. if the extension isn't enabled + // in incognito mode. + return pm->CreateBackgroundHost(extension, + BackgroundInfo::GetBackgroundURL(extension)); +} + } // namespace LazyBackgroundTaskQueue::LazyBackgroundTaskQueue( @@ -104,26 +114,21 @@ void LazyBackgroundTaskQueue::AddPendingTask( PendingTasksKey key(browser_context, extension_id); PendingTasksMap::iterator it = pending_tasks_.find(key); if (it == pending_tasks_.end()) { - auto tasks_list_tmp = std::make_unique<PendingTasksList>(); - tasks_list = tasks_list_tmp.get(); - pending_tasks_[key] = std::move(tasks_list_tmp); - - const Extension* extension = - ExtensionRegistry::Get(browser_context)->enabled_extensions().GetByID( - extension_id); + const Extension* extension = ExtensionRegistry::Get(browser_context) + ->enabled_extensions() + .GetByID(extension_id); if (extension && BackgroundInfo::HasLazyBackgroundPage(extension)) { // If this is the first enqueued task, and we're not waiting for the // background page to unload, ensure the background page is loaded. - ProcessManager* pm = ProcessManager::Get(browser_context); - pm->IncrementLazyKeepaliveCount(extension); - // Creating the background host may fail, e.g. if |profile| is incognito - // but the extension isn't enabled in incognito mode. - if (!pm->CreateBackgroundHost( - extension, BackgroundInfo::GetBackgroundURL(extension))) { + if (!CreateLazyBackgroundHost(ProcessManager::Get(browser_context), + extension)) { std::move(task).Run(nullptr); return; } } + auto tasks_list_tmp = std::make_unique<PendingTasksList>(); + tasks_list = tasks_list_tmp.get(); + pending_tasks_[key] = std::move(tasks_list_tmp); } else { tasks_list = it->second.get(); } @@ -158,14 +163,28 @@ void LazyBackgroundTaskQueue::ProcessPendingTasks( pending_tasks_.erase(key); - // Balance the keepalive in AddPendingTask. Note we don't do this on a - // failure to load, because the keepalive count is reset in that case. + // Balance the keepalive in CreateLazyBackgroundHost. Note we don't do this on + // a failure to load, because the keepalive count is reset in that case. if (host && BackgroundInfo::HasLazyBackgroundPage(extension)) { ProcessManager::Get(browser_context) ->DecrementLazyKeepaliveCount(extension); } } +void LazyBackgroundTaskQueue::NotifyTasksExtensionFailedToLoad( + content::BrowserContext* browser_context, + const Extension* extension) { + ProcessPendingTasks(nullptr, browser_context, extension); + // If this extension is also running in an off-the-record context, notify that + // task queue as well. + ExtensionsBrowserClient* browser_client = ExtensionsBrowserClient::Get(); + if (browser_client->HasOffTheRecordContext(browser_context)) { + ProcessPendingTasks(nullptr, + browser_client->GetOffTheRecordContext(browser_context), + extension); + } +} + void LazyBackgroundTaskQueue::Observe( int type, const content::NotificationSource& source, @@ -203,20 +222,48 @@ void LazyBackgroundTaskQueue::Observe( } } -void LazyBackgroundTaskQueue::OnExtensionUnloaded( +void LazyBackgroundTaskQueue::OnExtensionLoaded( content::BrowserContext* browser_context, - const Extension* extension, - UnloadedExtensionReason reason) { - // Notify consumers that the page failed to load. - ProcessPendingTasks(NULL, browser_context, extension); - // If this extension is also running in an off-the-record context, notify that - // task queue as well. + const Extension* extension) { + // If there are pending tasks for a lazy background page, and its background + // host has not been created yet, then create it. This can happen if a pending + // task was added while the extension is not yet enabled (e.g., component + // extension crashed and waiting to reload, https://crbug.com/835017). + if (!BackgroundInfo::HasLazyBackgroundPage(extension)) + return; + + CreateLazyBackgroundHostOnExtensionLoaded(browser_context, extension); + + // Also try to create the background host for the off-the-record context. ExtensionsBrowserClient* browser_client = ExtensionsBrowserClient::Get(); if (browser_client->HasOffTheRecordContext(browser_context)) { - ProcessPendingTasks(NULL, - browser_client->GetOffTheRecordContext(browser_context), - extension); + CreateLazyBackgroundHostOnExtensionLoaded( + browser_client->GetOffTheRecordContext(browser_context), extension); } } +void LazyBackgroundTaskQueue::OnExtensionUnloaded( + content::BrowserContext* browser_context, + const Extension* extension, + UnloadedExtensionReason reason) { + NotifyTasksExtensionFailedToLoad(browser_context, extension); +} + +void LazyBackgroundTaskQueue::CreateLazyBackgroundHostOnExtensionLoaded( + content::BrowserContext* browser_context, + const Extension* extension) { + PendingTasksKey key(browser_context, extension->id()); + if (!base::ContainsKey(pending_tasks_, key)) + return; + + ProcessManager* pm = ProcessManager::Get(browser_context); + + // Background host already created, just wait for it to finish loading. + if (pm->GetBackgroundHostForExtension(extension->id())) + return; + + if (!CreateLazyBackgroundHost(pm, extension)) + ProcessPendingTasks(nullptr, browser_context, extension); +} + } // namespace extensions diff --git a/chromium/extensions/browser/lazy_background_task_queue.h b/chromium/extensions/browser/lazy_background_task_queue.h index e5e918b281d..f1571cb4d0b 100644 --- a/chromium/extensions/browser/lazy_background_task_queue.h +++ b/chromium/extensions/browser/lazy_background_task_queue.h @@ -76,7 +76,8 @@ class LazyBackgroundTaskQueue : public KeyedService, private: FRIEND_TEST_ALL_PREFIXES(LazyBackgroundTaskQueueTest, AddPendingTask); FRIEND_TEST_ALL_PREFIXES(LazyBackgroundTaskQueueTest, ProcessPendingTasks); - + FRIEND_TEST_ALL_PREFIXES(LazyBackgroundTaskQueueTest, + CreateLazyBackgroundPageOnExtensionLoaded); // A map between a BrowserContext/extension_id pair and the queue of tasks // pending the load of its background page. using PendingTasksKey = std::pair<content::BrowserContext*, ExtensionId>; @@ -90,17 +91,31 @@ class LazyBackgroundTaskQueue : public KeyedService, const content::NotificationDetails& details) override; // ExtensionRegistryObserver interface. + void OnExtensionLoaded(content::BrowserContext* browser_context, + const Extension* extension) override; void OnExtensionUnloaded(content::BrowserContext* browser_context, const Extension* extension, UnloadedExtensionReason reason) override; + // If there are pending tasks for |extension| in |browser_context|, try to + // create the background host. If the background host cannot be created, the + // pending tasks are invoked with nullptr. + void CreateLazyBackgroundHostOnExtensionLoaded( + content::BrowserContext* browser_context, + const Extension* extension); + // Called when a lazy background page has finished loading, or has failed to - // load (host is NULL in that case). All enqueued tasks are run in order. + // load (host is nullptr in that case). All enqueued tasks are run in order. void ProcessPendingTasks( ExtensionHost* host, content::BrowserContext* context, const Extension* extension); + // Notifies queued tasks that a lazy background page has failed to load. + void NotifyTasksExtensionFailedToLoad( + content::BrowserContext* browser_context, + const Extension* extension); + content::BrowserContext* browser_context_; content::NotificationRegistrar registrar_; PendingTasksMap pending_tasks_; diff --git a/chromium/extensions/browser/lazy_background_task_queue_unittest.cc b/chromium/extensions/browser/lazy_background_task_queue_unittest.cc index bb7370edce3..fd99b79aa92 100644 --- a/chromium/extensions/browser/lazy_background_task_queue_unittest.cc +++ b/chromium/extensions/browser/lazy_background_task_queue_unittest.cc @@ -70,6 +70,7 @@ class LazyBackgroundTaskQueueTest : public ExtensionsTest { ~LazyBackgroundTaskQueueTest() override {} int task_run_count() { return task_run_count_; } + TestProcessManager* process_manager() { return process_manager_; } // A simple callback for AddPendingTask. void RunPendingTask(ExtensionHost* host) { @@ -79,12 +80,7 @@ class LazyBackgroundTaskQueueTest : public ExtensionsTest { // Creates and registers an extension without a background page. scoped_refptr<Extension> CreateSimpleExtension() { scoped_refptr<Extension> extension = - ExtensionBuilder() - .SetManifest(DictionaryBuilder() - .Set("name", "No background") - .Set("version", "1") - .Set("manifest_version", 2) - .Build()) + ExtensionBuilder("No background") .SetID("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") .Build(); ExtensionRegistry::Get(browser_context())->AddEnabled(extension); @@ -94,17 +90,8 @@ class LazyBackgroundTaskQueueTest : public ExtensionsTest { // Creates and registers an extension with a lazy background page. scoped_refptr<Extension> CreateLazyBackgroundExtension() { scoped_refptr<Extension> extension = - ExtensionBuilder() - .SetManifest( - DictionaryBuilder() - .Set("name", "Lazy background") - .Set("version", "1") - .Set("manifest_version", 2) - .Set("background", DictionaryBuilder() - .Set("page", "background.html") - .SetBoolean("persistent", false) - .Build()) - .Build()) + ExtensionBuilder("Lazy background") + .SetBackgroundPage(ExtensionBuilder::BackgroundPage::EVENT) .SetID("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") .Build(); ExtensionRegistry::Get(browser_context())->AddEnabled(extension); @@ -115,6 +102,15 @@ class LazyBackgroundTaskQueueTest : public ExtensionsTest { void SetUp() override { ExtensionsTest::SetUp(); user_prefs::UserPrefs::Set(browser_context(), &testing_pref_service_); + + process_manager_ = static_cast<TestProcessManager*>( + ProcessManagerFactory::GetInstance()->SetTestingFactoryAndUse( + browser_context(), CreateTestProcessManager)); + } + + void TearDown() override { + process_manager_ = nullptr; + ExtensionsTest::TearDown(); } private: @@ -122,6 +118,7 @@ class LazyBackgroundTaskQueueTest : public ExtensionsTest { // The total number of pending tasks that have been executed. int task_run_count_; + TestProcessManager* process_manager_ = nullptr; DISALLOW_COPY_AND_ASSIGN(LazyBackgroundTaskQueueTest); }; @@ -143,11 +140,6 @@ TEST_F(LazyBackgroundTaskQueueTest, ShouldEnqueueTask) { // Tests that adding tasks actually increases the pending task count, and that // multiple extensions can have pending tasks. TEST_F(LazyBackgroundTaskQueueTest, AddPendingTask) { - // Get our TestProcessManager. - TestProcessManager* process_manager = static_cast<TestProcessManager*>( - ProcessManagerFactory::GetInstance()->SetTestingFactoryAndUse( - browser_context(), CreateTestProcessManager)); - LazyBackgroundTaskQueue queue(browser_context()); // Build a simple extension with no background page. @@ -178,9 +170,9 @@ TEST_F(LazyBackgroundTaskQueueTest, AddPendingTask) { lazy_background->id(), base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask, base::Unretained(this))); - EXPECT_EQ(2u, queue.pending_tasks_.size()); + EXPECT_EQ(1u, queue.pending_tasks_.size()); // The process manager tried to create a background host. - EXPECT_EQ(1, process_manager->create_count()); + EXPECT_EQ(1, process_manager()->create_count()); // The task ran immediately because the creation failed. EXPECT_EQ(1, task_run_count()); } @@ -215,4 +207,41 @@ TEST_F(LazyBackgroundTaskQueueTest, ProcessPendingTasks) { EXPECT_EQ(0u, queue.pending_tasks_.size()); } +// Tests that if a pending task was added before the extension with a lazy +// background page is loaded, then we will create the lazy background page when +// the extension is loaded. +TEST_F(LazyBackgroundTaskQueueTest, CreateLazyBackgroundPageOnExtensionLoaded) { + LazyBackgroundTaskQueue queue(browser_context()); + + scoped_refptr<Extension> lazy_background = + ExtensionBuilder("Lazy background") + .SetBackgroundPage(ExtensionBuilder::BackgroundPage::EVENT) + .SetID("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") + .Build(); + + queue.OnExtensionLoaded(browser_context(), lazy_background.get()); + // Did not try to create a background host because there are no queued tasks. + EXPECT_EQ(0, process_manager()->create_count()); + + queue.AddPendingTask(browser_context(), lazy_background->id(), + base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask, + base::Unretained(this))); + EXPECT_EQ(1u, queue.pending_tasks_.size()); + // Did not try to create a background host because extension is not yet + // loaded. + EXPECT_EQ(0, process_manager()->create_count()); + // The task is queued. + EXPECT_EQ(0, task_run_count()); + + ExtensionRegistry::Get(browser_context())->AddEnabled(lazy_background); + queue.OnExtensionLoaded(browser_context(), lazy_background.get()); + + // The process manager tried to create a background host because there is a + // queued task. + EXPECT_EQ(1, process_manager()->create_count()); + // The queued task ran because the creation failed. + EXPECT_EQ(1, task_run_count()); + EXPECT_EQ(0u, queue.pending_tasks_.size()); +} + } // namespace extensions diff --git a/chromium/extensions/browser/management_policy.cc b/chromium/extensions/browser/management_policy.cc index 4eef61b085a..b6e70cf704c 100644 --- a/chromium/extensions/browser/management_policy.cc +++ b/chromium/extensions/browser/management_policy.cc @@ -34,6 +34,13 @@ bool ManagementPolicy::Provider::UserMayModifySettings( return true; } +bool ManagementPolicy::Provider::ExtensionMayModifySettings( + const Extension* source_extension, + const Extension* extension, + base::string16* error) const { + return true; +} + bool ManagementPolicy::Provider::MustRemainEnabled(const Extension* extension, base::string16* error) const { @@ -79,6 +86,24 @@ bool ManagementPolicy::UserMayModifySettings(const Extension* extension, &Provider::UserMayModifySettings, "Modification", true, extension, error); } +bool ManagementPolicy::ExtensionMayModifySettings( + const Extension* source_extension, + const Extension* extension, + base::string16* error) const { + for (const Provider* provider : providers_) { + if (!provider->ExtensionMayModifySettings(source_extension, extension, + error)) { + std::string id; + std::string name; + GetExtensionNameAndId(extension, &name, &id); + DVLOG(1) << "Modification of extension " << name << " (" << id << ")" + << " prohibited by " << provider->GetDebugPolicyProviderName(); + return false; + } + } + return true; +} + bool ManagementPolicy::MustRemainEnabled(const Extension* extension, base::string16* error) const { return ApplyToProviderList( @@ -121,9 +146,7 @@ bool ManagementPolicy::ApplyToProviderList(ProviderFunction function, bool normal_result, const Extension* extension, base::string16* error) const { - for (ProviderList::const_iterator it = providers_.begin(); - it != providers_.end(); ++it) { - const Provider* provider = *it; + for (const Provider* provider : providers_) { bool result = (provider->*function)(extension, error); if (result != normal_result) { std::string id; diff --git a/chromium/extensions/browser/management_policy.h b/chromium/extensions/browser/management_policy.h index 9dd3c27413b..e6f1f8521cb 100644 --- a/chromium/extensions/browser/management_policy.h +++ b/chromium/extensions/browser/management_policy.h @@ -5,6 +5,7 @@ #ifndef EXTENSIONS_BROWSER_MANAGEMENT_POLICY_H_ #define EXTENSIONS_BROWSER_MANAGEMENT_POLICY_H_ +#include <memory> #include <set> #include <string> #include <vector> @@ -68,6 +69,12 @@ class ManagementPolicy { virtual bool UserMayModifySettings(const Extension* extension, base::string16* error) const; + // Providers should return false if the originating extension + // |source_extension| cannot disable the |extension|. + virtual bool ExtensionMayModifySettings(const Extension* source_extension, + const Extension* extension, + base::string16* error) const; + // Providers should return true if the |extension| must always remain // enabled. This is distinct from UserMayModifySettings() in that the latter // also prohibits enabling the extension if it is currently disabled. @@ -118,6 +125,12 @@ class ManagementPolicy { bool UserMayModifySettings(const Extension* extension, base::string16* error) const; + // Returns true if the originating extension is permitted to disable the + // given extension. If not, |error| may be set to an appropriate message. + bool ExtensionMayModifySettings(const Extension* source_extension, + const Extension* extension, + base::string16* error) const; + // Returns true if the extension must remain enabled at all times (e.g. a // component extension). In that case, |error| may be set to an appropriate // message. diff --git a/chromium/extensions/browser/media_capture_util.cc b/chromium/extensions/browser/media_capture_util.cc new file mode 100644 index 00000000000..e4c29b52daa --- /dev/null +++ b/chromium/extensions/browser/media_capture_util.cc @@ -0,0 +1,110 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/browser/media_capture_util.h" + +#include <algorithm> +#include <string> +#include <utility> + +#include "base/callback.h" +#include "base/logging.h" +#include "content/public/browser/media_capture_devices.h" +#include "extensions/common/extension.h" +#include "extensions/common/permissions/permissions_data.h" + +using content::MediaCaptureDevices; +using content::MediaStreamDevice; +using content::MediaStreamDevices; +using content::MediaStreamUI; + +namespace extensions { + +namespace { + +const MediaStreamDevice* GetRequestedDeviceOrDefault( + const MediaStreamDevices& devices, + const std::string& requested_device_id) { + if (!requested_device_id.empty()) { + auto it = std::find_if( + devices.begin(), devices.end(), + [requested_device_id](const content::MediaStreamDevice& device) { + return device.id == requested_device_id; + }); + return it != devices.end() ? &(*it) : nullptr; + } + + if (!devices.empty()) + return &devices[0]; + + return nullptr; +} + +} // namespace + +namespace media_capture_util { + +// See also Chrome's MediaCaptureDevicesDispatcher. +void GrantMediaStreamRequest(content::WebContents* web_contents, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback, + const Extension* extension) { + // app_shell only supports audio and video capture, not tab or screen capture. + DCHECK(request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE || + request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE); + + MediaStreamDevices devices; + + if (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE) { + VerifyMediaAccessPermission(request.audio_type, extension); + const MediaStreamDevice* device = GetRequestedDeviceOrDefault( + MediaCaptureDevices::GetInstance()->GetAudioCaptureDevices(), + request.requested_audio_device_id); + if (device) + devices.push_back(*device); + } + + if (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE) { + VerifyMediaAccessPermission(request.video_type, extension); + const MediaStreamDevice* device = GetRequestedDeviceOrDefault( + MediaCaptureDevices::GetInstance()->GetVideoCaptureDevices(), + request.requested_video_device_id); + if (device) + devices.push_back(*device); + } + + // TODO(jamescook): Should we show a recording icon somewhere? If so, where? + std::unique_ptr<MediaStreamUI> ui; + callback.Run(devices, devices.empty() ? content::MEDIA_DEVICE_INVALID_STATE + : content::MEDIA_DEVICE_OK, + std::move(ui)); +} + +void VerifyMediaAccessPermission(content::MediaStreamType type, + const Extension* extension) { + const PermissionsData* permissions_data = extension->permissions_data(); + if (type == content::MEDIA_DEVICE_AUDIO_CAPTURE) { + // app_shell has no UI surface to show an error, and on an embedded device + // it's better to crash than to have a feature not work. + CHECK(permissions_data->HasAPIPermission(APIPermission::kAudioCapture)) + << "Audio capture request but no audioCapture permission in manifest."; + } else { + DCHECK(type == content::MEDIA_DEVICE_VIDEO_CAPTURE); + CHECK(permissions_data->HasAPIPermission(APIPermission::kVideoCapture)) + << "Video capture request but no videoCapture permission in manifest."; + } +} + +bool CheckMediaAccessPermission(content::MediaStreamType type, + const Extension* extension) { + const PermissionsData* permissions_data = extension->permissions_data(); + if (type == content::MEDIA_DEVICE_AUDIO_CAPTURE) { + return permissions_data->HasAPIPermission(APIPermission::kAudioCapture); + } + DCHECK(type == content::MEDIA_DEVICE_VIDEO_CAPTURE); + return permissions_data->HasAPIPermission(APIPermission::kVideoCapture); +} + +} // namespace media_capture_util +} // namespace extensions diff --git a/chromium/extensions/browser/media_capture_util.h b/chromium/extensions/browser/media_capture_util.h new file mode 100644 index 00000000000..df26857da33 --- /dev/null +++ b/chromium/extensions/browser/media_capture_util.h @@ -0,0 +1,42 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_BROWSER_MEDIA_CAPTURE_UTIL_H_ +#define EXTENSIONS_BROWSER_MEDIA_CAPTURE_UTIL_H_ + +#include "base/macros.h" +#include "content/public/common/media_stream_request.h" + +namespace content { +class WebContents; +} + +namespace extensions { + +class Extension; + +namespace media_capture_util { + +// Grants access to audio and video capture devices. +// * If the caller requests specific device ids, grants access to those. +// * If the caller does not request specific ids, grants access to the first +// available device. +// Usually used as a helper for media capture ProcessMediaAccessRequest(). +void GrantMediaStreamRequest(content::WebContents* web_contents, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback, + const Extension* extension); + +// Verifies that the extension has permission for |type|. If not, crash. +void VerifyMediaAccessPermission(content::MediaStreamType type, + const Extension* extension); + +// Check if the extension has permission for |type|. +bool CheckMediaAccessPermission(content::MediaStreamType type, + const Extension* extension); + +} // namespace media_capture_util +} // namespace extensions + +#endif // EXTENSIONS_BROWSER_MEDIA_CAPTURE_UTIL_H_ diff --git a/chromium/extensions/browser/mock_external_provider.cc b/chromium/extensions/browser/mock_external_provider.cc index 988bdb288b6..52820e71378 100644 --- a/chromium/extensions/browser/mock_external_provider.cc +++ b/chromium/extensions/browser/mock_external_provider.cc @@ -24,40 +24,57 @@ void MockExternalProvider::UpdateOrAddExtension(const ExtensionId& id, auto info = std::make_unique<ExternalInstallInfoFile>( id, base::Version(version_str), path, location_, Extension::NO_FLAGS, false, false); - extension_map_[id] = std::move(info); + UpdateOrAddExtension(std::move(info)); } void MockExternalProvider::UpdateOrAddExtension( std::unique_ptr<ExternalInstallInfoFile> info) { - std::string id = info->extension_id; - extension_map_[id] = std::move(info); + const std::string& id = info->extension_id; + CHECK(url_extension_map_.find(id) == url_extension_map_.end()); + file_extension_map_[id] = std::move(info); +} + +void MockExternalProvider::UpdateOrAddExtension( + std::unique_ptr<ExternalInstallInfoUpdateUrl> info) { + const std::string& id = info->extension_id; + CHECK(file_extension_map_.find(id) == file_extension_map_.end()); + url_extension_map_[id] = std::move(info); } void MockExternalProvider::RemoveExtension(const ExtensionId& id) { - extension_map_.erase(id); + file_extension_map_.erase(id); + url_extension_map_.erase(id); } void MockExternalProvider::VisitRegisteredExtension() { visit_count_++; - for (const auto& extension_kv : extension_map_) + for (const auto& extension_kv : file_extension_map_) visitor_->OnExternalExtensionFileFound(*extension_kv.second); + for (const auto& extension_kv : url_extension_map_) + visitor_->OnExternalExtensionUpdateUrlFound(*extension_kv.second, + true /* is_initial_load */); visitor_->OnExternalProviderReady(this); } bool MockExternalProvider::HasExtension(const std::string& id) const { - return extension_map_.find(id) != extension_map_.end(); + return file_extension_map_.find(id) != file_extension_map_.end() || + url_extension_map_.find(id) != url_extension_map_.end(); } bool MockExternalProvider::GetExtensionDetails( const std::string& id, Manifest::Location* location, std::unique_ptr<base::Version>* version) const { - DataMap::const_iterator it = extension_map_.find(id); - if (it == extension_map_.end()) + FileDataMap::const_iterator it1 = file_extension_map_.find(id); + UrlDataMap::const_iterator it2 = url_extension_map_.find(id); + + // |id| can't be on both |file_extension_map_| and |url_extension_map_|. + if (it1 == file_extension_map_.end() && it2 == url_extension_map_.end()) return false; - if (version) - version->reset(new base::Version(it->second->version)); + // Only ExternalInstallInfoFile has version. + if (version && it1 != file_extension_map_.end()) + version->reset(new base::Version(it1->second->version)); if (location) *location = location_; diff --git a/chromium/extensions/browser/mock_external_provider.h b/chromium/extensions/browser/mock_external_provider.h index bc94c4bac94..0069a4d5f39 100644 --- a/chromium/extensions/browser/mock_external_provider.h +++ b/chromium/extensions/browser/mock_external_provider.h @@ -31,6 +31,7 @@ class MockExternalProvider : public ExternalProviderInterface { const std::string& version, const base::FilePath& path); void UpdateOrAddExtension(std::unique_ptr<ExternalInstallInfoFile> info); + void UpdateOrAddExtension(std::unique_ptr<ExternalInstallInfoUpdateUrl> info); void RemoveExtension(const ExtensionId& id); // ExternalProviderInterface implementation: @@ -47,9 +48,12 @@ class MockExternalProvider : public ExternalProviderInterface { void set_visit_count(int visit_count) { visit_count_ = visit_count; } private: - using DataMap = + using FileDataMap = std::map<ExtensionId, std::unique_ptr<ExternalInstallInfoFile>>; - DataMap extension_map_; + using UrlDataMap = + std::map<ExtensionId, std::unique_ptr<ExternalInstallInfoUpdateUrl>>; + FileDataMap file_extension_map_; + UrlDataMap url_extension_map_; Manifest::Location location_; VisitorInterface* visitor_; diff --git a/chromium/extensions/browser/path_util.cc b/chromium/extensions/browser/path_util.cc index 88a714eadc1..24f288a3bea 100644 --- a/chromium/extensions/browser/path_util.cc +++ b/chromium/extensions/browser/path_util.cc @@ -65,8 +65,10 @@ void OnDirectorySizeCalculated( base::FilePath PrettifyPath(const base::FilePath& source_path) { base::FilePath home_path; - if (source_path.empty() || !PathService::Get(base::DIR_HOME, &home_path)) + if (source_path.empty() || + !base::PathService::Get(base::DIR_HOME, &home_path)) { return source_path; + } base::FilePath display_path = base::FilePath(kHomeShortcut); if (source_path == home_path) @@ -127,7 +129,7 @@ base::FilePath ResolveHomeDirectory(const base::FilePath& path) { return path; } base::FilePath result; - PathService::Get(base::DIR_HOME, &result); + base::PathService::Get(base::DIR_HOME, &result); // The user could specify "~" or "~/", so be safe. if (value.length() > 2) { result = result.Append(value.substr(2)); diff --git a/chromium/extensions/browser/path_util_unittest.cc b/chromium/extensions/browser/path_util_unittest.cc index a57d9cca3b7..bdac4ffe4d9 100644 --- a/chromium/extensions/browser/path_util_unittest.cc +++ b/chromium/extensions/browser/path_util_unittest.cc @@ -48,7 +48,7 @@ TEST(ExtensionPathUtilTest, BasicPrettifyPathTest) { TEST(ExtensionPathUtilTest, ResolveHomeDirTest) { FilePath home_dir; - ASSERT_TRUE(PathService::Get(base::DIR_HOME, &home_dir)); + ASSERT_TRUE(base::PathService::Get(base::DIR_HOME, &home_dir)); const FilePath abs_path(FILE_PATH_LITERAL("/foo/bar/baz")); const FilePath rel_path(FILE_PATH_LITERAL("foo/bar/baz")); const FilePath rel_path_with_tilde(FILE_PATH_LITERAL("~/foo/bar")); diff --git a/chromium/extensions/browser/runtime_data_unittest.cc b/chromium/extensions/browser/runtime_data_unittest.cc index 14b4387c436..f52583a5d21 100644 --- a/chromium/extensions/browser/runtime_data_unittest.cc +++ b/chromium/extensions/browser/runtime_data_unittest.cc @@ -20,11 +20,7 @@ namespace { // Creates a very simple extension with a background page. scoped_refptr<Extension> CreateExtensionWithBackgroundPage() { return ExtensionBuilder("test") - .MergeManifest( - DictionaryBuilder() - .Set("background", - DictionaryBuilder().Set("page", "bg.html").Build()) - .Build()) + .SetBackgroundPage(ExtensionBuilder::BackgroundPage::PERSISTENT) .SetID("id2") .Build(); } diff --git a/chromium/extensions/browser/sandboxed_unpacker.cc b/chromium/extensions/browser/sandboxed_unpacker.cc index c4bb27232fc..31cc189b745 100644 --- a/chromium/extensions/browser/sandboxed_unpacker.cc +++ b/chromium/extensions/browser/sandboxed_unpacker.cc @@ -29,6 +29,8 @@ #include "content/public/browser/browser_thread.h" #include "extensions/browser/api/declarative_net_request/utils.h" #include "extensions/browser/extension_file_task_runner.h" +#include "extensions/browser/install/crx_install_error.h" +#include "extensions/browser/install/sandboxed_unpacker_failure_reason.h" #include "extensions/browser/zipfile_installer.h" #include "extensions/common/api/declarative_net_request/dnr_manifest_data.h" #include "extensions/common/constants.h" @@ -174,7 +176,7 @@ bool FindWritableTempLocation(const base::FilePath& extensions_dir, // directory to provide additional security/privacy and speed up the rest of // the extension install process. #if !defined(OS_CHROMEOS) - PathService::Get(base::DIR_TEMP, temp_dir); + base::PathService::Get(base::DIR_TEMP, temp_dir); if (VerifyJunctionFreeLocation(temp_dir)) return true; #endif @@ -249,7 +251,7 @@ bool SandboxedUnpacker::CreateTempDirectory() { base::FilePath temp_dir; if (!FindWritableTempLocation(extensions_dir_, &temp_dir)) { - ReportFailure(COULD_NOT_GET_TEMP_DIRECTORY, + ReportFailure(SandboxedUnpackerFailureReason::COULD_NOT_GET_TEMP_DIRECTORY, l10n_util::GetStringFUTF16( IDS_EXTENSION_PACKAGE_INSTALL_ERROR, ASCIIToUTF16("COULD_NOT_GET_TEMP_DIRECTORY"))); @@ -257,10 +259,11 @@ bool SandboxedUnpacker::CreateTempDirectory() { } if (!temp_dir_.CreateUniqueTempDirUnderPath(temp_dir)) { - ReportFailure(COULD_NOT_CREATE_TEMP_DIRECTORY, - l10n_util::GetStringFUTF16( - IDS_EXTENSION_PACKAGE_INSTALL_ERROR, - ASCIIToUTF16("COULD_NOT_CREATE_TEMP_DIRECTORY"))); + ReportFailure( + SandboxedUnpackerFailureReason::COULD_NOT_CREATE_TEMP_DIRECTORY, + l10n_util::GetStringFUTF16( + IDS_EXTENSION_PACKAGE_INSTALL_ERROR, + ASCIIToUTF16("COULD_NOT_CREATE_TEMP_DIRECTORY"))); return false; } @@ -303,7 +306,8 @@ void SandboxedUnpacker::StartWithCrx(const CRXFileInfo& crx_info) { if (!base::CopyFile(crx_info.path, temp_crx_path)) { // Failed to copy extension file to temporary directory. ReportFailure( - FAILED_TO_COPY_EXTENSION_FILE_TO_TEMP_DIRECTORY, + SandboxedUnpackerFailureReason:: + FAILED_TO_COPY_EXTENSION_FILE_TO_TEMP_DIRECTORY, l10n_util::GetStringFUTF16( IDS_EXTENSION_PACKAGE_INSTALL_ERROR, ASCIIToUTF16("FAILED_TO_COPY_EXTENSION_FILE_TO_TEMP_DIRECTORY"))); @@ -319,8 +323,9 @@ void SandboxedUnpacker::StartWithCrx(const CRXFileInfo& crx_info) { if (!base::NormalizeFilePath(temp_crx_path, &link_free_crx_path)) { LOG(ERROR) << "Could not get the normalized path of " << temp_crx_path.value(); - ReportFailure(COULD_NOT_GET_SANDBOX_FRIENDLY_PATH, - l10n_util::GetStringUTF16(IDS_EXTENSION_UNPACK_FAILED)); + ReportFailure( + SandboxedUnpackerFailureReason::COULD_NOT_GET_SANDBOX_FRIENDLY_PATH, + l10n_util::GetStringUTF16(IDS_EXTENSION_UNPACK_FAILED)); return; } @@ -335,7 +340,7 @@ void SandboxedUnpacker::StartWithCrx(const CRXFileInfo& crx_info) { if (!base::CreateDirectoryAndGetError(unzipped_dir, &error)) { LOG(ERROR) << "Failed to created directory " << unzipped_dir.value() << " with error " << error; - ReportFailure(UNZIP_FAILED, + ReportFailure(SandboxedUnpackerFailureReason::UNZIP_FAILED, l10n_util::GetStringUTF16(IDS_EXTENSION_PACKAGE_UNZIP_ERROR)); return; } @@ -357,7 +362,7 @@ void SandboxedUnpacker::StartWithDirectory(const std::string& extension_id, LOG(ERROR) << "Could not move " << directory.value() << " to " << extension_root_.value(); ReportFailure( - DIRECTORY_MOVE_FAILED, + SandboxedUnpackerFailureReason::DIRECTORY_MOVE_FAILED, l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR, ASCIIToUTF16("DIRECTORY_MOVE_FAILED"))); return; @@ -406,10 +411,10 @@ void SandboxedUnpacker::UnzipDone(const base::FilePath& zip_file, if (!error.empty()) { unpacker_io_task_runner_->PostTask( - FROM_HERE, - base::BindOnce( - &SandboxedUnpacker::ReportFailure, this, UNZIP_FAILED, - l10n_util::GetStringUTF16(IDS_EXTENSION_PACKAGE_UNZIP_ERROR))); + FROM_HERE, base::BindOnce(&SandboxedUnpacker::ReportFailure, this, + SandboxedUnpackerFailureReason::UNZIP_FAILED, + l10n_util::GetStringUTF16( + IDS_EXTENSION_PACKAGE_UNZIP_ERROR))); return; } @@ -428,7 +433,7 @@ void SandboxedUnpacker::Unpack(const base::FilePath& directory) { } void SandboxedUnpacker::ReadManifestDone( - std::unique_ptr<base::Value> manifest, + base::Optional<base::Value> manifest, const base::Optional<std::string>& error) { DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence()); if (error) { @@ -441,7 +446,8 @@ void SandboxedUnpacker::ReadManifestDone( } std::unique_ptr<base::DictionaryValue> manifest_dict = - base::DictionaryValue::From(std::move(manifest)); + base::DictionaryValue::From( + base::Value::ToUniquePtrValue(std::move(manifest.value()))); std::string error_msg; scoped_refptr<Extension> extension( @@ -484,7 +490,7 @@ void SandboxedUnpacker::UnpackExtensionSucceeded( if (!extension_l10n_util::LocalizeExtension( extension_root_, final_manifest.get(), &utf8_error)) { ReportFailure( - COULD_NOT_LOCALIZE_EXTENSION, + SandboxedUnpackerFailureReason::COULD_NOT_LOCALIZE_EXTENSION, l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, base::UTF8ToUTF16(utf8_error))); return; @@ -495,7 +501,7 @@ void SandboxedUnpacker::UnpackExtensionSucceeded( Extension::REQUIRE_KEY | creation_flags_, &utf8_error); if (!extension_.get()) { - ReportFailure(INVALID_MANIFEST, + ReportFailure(SandboxedUnpackerFailureReason::INVALID_MANIFEST, ASCIIToUTF16("Manifest is invalid: " + utf8_error)); return; } @@ -511,10 +517,11 @@ void SandboxedUnpacker::UnpackExtensionSucceeded( base::FilePath::FromUTF8Unsafe(original_install_icon_path), &install_icon_path_)) { // Invalid path for browser image. - ReportFailure(INVALID_PATH_FOR_BROWSER_IMAGE, - l10n_util::GetStringFUTF16( - IDS_EXTENSION_PACKAGE_INSTALL_ERROR, - ASCIIToUTF16("INVALID_PATH_FOR_BROWSER_IMAGE"))); + ReportFailure( + SandboxedUnpackerFailureReason::INVALID_PATH_FOR_BROWSER_IMAGE, + l10n_util::GetStringFUTF16( + IDS_EXTENSION_PACKAGE_INSTALL_ERROR, + ASCIIToUTF16("INVALID_PATH_FOR_BROWSER_IMAGE"))); return; } @@ -544,11 +551,13 @@ void SandboxedUnpacker::ImageSanitizationDone( return; } - FailureReason failure_reason = UNPACKER_CLIENT_FAILED; + SandboxedUnpackerFailureReason failure_reason = + SandboxedUnpackerFailureReason::UNPACKER_CLIENT_FAILED; base::string16 error; switch (status) { case ImageSanitizer::Status::kImagePathError: - failure_reason = INVALID_PATH_FOR_BROWSER_IMAGE; + failure_reason = + SandboxedUnpackerFailureReason::INVALID_PATH_FOR_BROWSER_IMAGE; error = l10n_util::GetStringFUTF16( IDS_EXTENSION_PACKAGE_INSTALL_ERROR, ASCIIToUTF16("INVALID_PATH_FOR_BROWSER_IMAGE")); @@ -561,25 +570,28 @@ void SandboxedUnpacker::ImageSanitizationDone( file_path_for_error.BaseName().LossyDisplayName())); break; case ImageSanitizer::Status::kFileDeleteError: - failure_reason = ERROR_REMOVING_OLD_IMAGE_FILE; + failure_reason = + SandboxedUnpackerFailureReason::ERROR_REMOVING_OLD_IMAGE_FILE; error = l10n_util::GetStringFUTF16( IDS_EXTENSION_PACKAGE_INSTALL_ERROR, ASCIIToUTF16("ERROR_REMOVING_OLD_IMAGE_FILE")); break; case ImageSanitizer::Status::kEncodingError: - failure_reason = ERROR_RE_ENCODING_THEME_IMAGE; + failure_reason = + SandboxedUnpackerFailureReason::ERROR_RE_ENCODING_THEME_IMAGE; error = l10n_util::GetStringFUTF16( IDS_EXTENSION_PACKAGE_INSTALL_ERROR, ASCIIToUTF16("ERROR_RE_ENCODING_THEME_IMAGE")); break; case ImageSanitizer::Status::kFileWriteError: - failure_reason = ERROR_SAVING_THEME_IMAGE; + failure_reason = SandboxedUnpackerFailureReason::ERROR_SAVING_THEME_IMAGE; error = l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR, ASCIIToUTF16("ERROR_SAVING_THEME_IMAGE")); break; case ImageSanitizer::Status::kServiceError: - failure_reason = UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL; + failure_reason = SandboxedUnpackerFailureReason:: + UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL; error = l10n_util::GetStringFUTF16( IDS_EXTENSION_PACKAGE_INSTALL_ERROR, ASCIIToUTF16("ERROR_UTILITY_PROCESS_CRASH")); @@ -633,24 +645,26 @@ void SandboxedUnpacker::MessageCatalogsSanitized( return; } - FailureReason failure_reason = UNPACKER_CLIENT_FAILED; + SandboxedUnpackerFailureReason failure_reason = + SandboxedUnpackerFailureReason::UNPACKER_CLIENT_FAILED; base::string16 error; switch (status) { case JsonFileSanitizer::Status::kFileReadError: case JsonFileSanitizer::Status::kDecodingError: - failure_reason = INVALID_CATALOG_DATA; + failure_reason = SandboxedUnpackerFailureReason::INVALID_CATALOG_DATA; error = l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR, ASCIIToUTF16("INVALID_CATALOG_DATA")); break; case JsonFileSanitizer::Status::kSerializingError: - failure_reason = ERROR_SERIALIZING_CATALOG; + failure_reason = + SandboxedUnpackerFailureReason::ERROR_SERIALIZING_CATALOG; error = l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR, ASCIIToUTF16("ERROR_SERIALIZING_CATALOG")); break; case JsonFileSanitizer::Status::kFileDeleteError: case JsonFileSanitizer::Status::kFileWriteError: - failure_reason = ERROR_SAVING_CATALOG; + failure_reason = SandboxedUnpackerFailureReason::ERROR_SAVING_CATALOG; error = l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR, ASCIIToUTF16("ERROR_SAVING_CATALOG")); break; @@ -671,7 +685,8 @@ void SandboxedUnpacker::ReadJSONRulesetIfNeeded( extension_.get()); if (!resource) { ReadJSONRulesetDone(std::move(manifest), - /*json_ruleset=*/nullptr, /*error=*/base::nullopt); + /*json_ruleset=*/base::nullopt, + /*error=*/base::nullopt); return; } @@ -682,7 +697,7 @@ void SandboxedUnpacker::ReadJSONRulesetIfNeeded( void SandboxedUnpacker::ReadJSONRulesetDone( std::unique_ptr<base::DictionaryValue> manifest, - std::unique_ptr<base::Value> json_ruleset, + base::Optional<base::Value> json_ruleset, const base::Optional<std::string>& error) { DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence()); @@ -698,8 +713,13 @@ void SandboxedUnpacker::ReadJSONRulesetDone( // Index and persist ruleset for the Declarative Net Request API. base::Optional<int> dnr_ruleset_checksum; + std::unique_ptr<base::Value> json_ruleset_ptr = + json_ruleset + ? base::Value::ToUniquePtrValue(std::move(json_ruleset.value())) + : nullptr; + if (!IndexAndPersistRulesIfNeeded( - base::ListValue::From(std::move(json_ruleset)), + base::ListValue::From(std::move(json_ruleset_ptr)), &dnr_ruleset_checksum)) { return; // Failure was already reported. } @@ -728,7 +748,7 @@ bool SandboxedUnpacker::IndexAndPersistRulesIfNeeded( if (!declarative_net_request::IndexAndPersistRules( *json_ruleset, *extension_, &error, &warnings, &ruleset_checksum)) { ReportFailure( - ERROR_INDEXING_DNR_RULESET, + SandboxedUnpackerFailureReason::ERROR_INDEXING_DNR_RULESET, l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, base::UTF8ToUTF16(error))); return false; @@ -745,7 +765,8 @@ data_decoder::mojom::JsonParser* SandboxedUnpacker::GetJsonParserPtr() { connector_->BindInterface(data_decoder_identity_, &json_parser_ptr_); json_parser_ptr_.set_connection_error_handler(base::BindOnce( &SandboxedUnpacker::ReportFailure, this, - UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL, + SandboxedUnpackerFailureReason:: + UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL, l10n_util::GetStringFUTF16( IDS_EXTENSION_PACKAGE_INSTALL_ERROR, ASCIIToUTF16("UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL")) + @@ -764,102 +785,106 @@ void SandboxedUnpacker::ReportUnpackingError(base::StringPiece error) { void SandboxedUnpacker::UnpackExtensionFailed(const base::string16& error) { DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence()); ReportFailure( - UNPACKER_CLIENT_FAILED, + SandboxedUnpackerFailureReason::UNPACKER_CLIENT_FAILED, l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, error)); } base::string16 SandboxedUnpacker::FailureReasonToString16( - FailureReason reason) { + const SandboxedUnpackerFailureReason reason) { switch (reason) { - case COULD_NOT_GET_TEMP_DIRECTORY: + case SandboxedUnpackerFailureReason::COULD_NOT_GET_TEMP_DIRECTORY: return ASCIIToUTF16("COULD_NOT_GET_TEMP_DIRECTORY"); - case COULD_NOT_CREATE_TEMP_DIRECTORY: + case SandboxedUnpackerFailureReason::COULD_NOT_CREATE_TEMP_DIRECTORY: return ASCIIToUTF16("COULD_NOT_CREATE_TEMP_DIRECTORY"); - case FAILED_TO_COPY_EXTENSION_FILE_TO_TEMP_DIRECTORY: + case SandboxedUnpackerFailureReason:: + FAILED_TO_COPY_EXTENSION_FILE_TO_TEMP_DIRECTORY: return ASCIIToUTF16("FAILED_TO_COPY_EXTENSION_FILE_TO_TEMP_DIRECTORY"); - case COULD_NOT_GET_SANDBOX_FRIENDLY_PATH: + case SandboxedUnpackerFailureReason::COULD_NOT_GET_SANDBOX_FRIENDLY_PATH: return ASCIIToUTF16("COULD_NOT_GET_SANDBOX_FRIENDLY_PATH"); - case COULD_NOT_LOCALIZE_EXTENSION: + case SandboxedUnpackerFailureReason::COULD_NOT_LOCALIZE_EXTENSION: return ASCIIToUTF16("COULD_NOT_LOCALIZE_EXTENSION"); - case INVALID_MANIFEST: + case SandboxedUnpackerFailureReason::INVALID_MANIFEST: return ASCIIToUTF16("INVALID_MANIFEST"); - case UNPACKER_CLIENT_FAILED: + case SandboxedUnpackerFailureReason::UNPACKER_CLIENT_FAILED: return ASCIIToUTF16("UNPACKER_CLIENT_FAILED"); - case UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL: + case SandboxedUnpackerFailureReason:: + UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL: return ASCIIToUTF16("UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL"); - case CRX_FILE_NOT_READABLE: + case SandboxedUnpackerFailureReason::CRX_FILE_NOT_READABLE: return ASCIIToUTF16("CRX_FILE_NOT_READABLE"); - case CRX_HEADER_INVALID: + case SandboxedUnpackerFailureReason::CRX_HEADER_INVALID: return ASCIIToUTF16("CRX_HEADER_INVALID"); - case CRX_MAGIC_NUMBER_INVALID: + case SandboxedUnpackerFailureReason::CRX_MAGIC_NUMBER_INVALID: return ASCIIToUTF16("CRX_MAGIC_NUMBER_INVALID"); - case CRX_VERSION_NUMBER_INVALID: + case SandboxedUnpackerFailureReason::CRX_VERSION_NUMBER_INVALID: return ASCIIToUTF16("CRX_VERSION_NUMBER_INVALID"); - case CRX_EXCESSIVELY_LARGE_KEY_OR_SIGNATURE: + case SandboxedUnpackerFailureReason::CRX_EXCESSIVELY_LARGE_KEY_OR_SIGNATURE: return ASCIIToUTF16("CRX_EXCESSIVELY_LARGE_KEY_OR_SIGNATURE"); - case CRX_ZERO_KEY_LENGTH: + case SandboxedUnpackerFailureReason::CRX_ZERO_KEY_LENGTH: return ASCIIToUTF16("CRX_ZERO_KEY_LENGTH"); - case CRX_ZERO_SIGNATURE_LENGTH: + case SandboxedUnpackerFailureReason::CRX_ZERO_SIGNATURE_LENGTH: return ASCIIToUTF16("CRX_ZERO_SIGNATURE_LENGTH"); - case CRX_PUBLIC_KEY_INVALID: + case SandboxedUnpackerFailureReason::CRX_PUBLIC_KEY_INVALID: return ASCIIToUTF16("CRX_PUBLIC_KEY_INVALID"); - case CRX_SIGNATURE_INVALID: + case SandboxedUnpackerFailureReason::CRX_SIGNATURE_INVALID: return ASCIIToUTF16("CRX_SIGNATURE_INVALID"); - case CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED: + case SandboxedUnpackerFailureReason:: + CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED: return ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED"); - case CRX_SIGNATURE_VERIFICATION_FAILED: + case SandboxedUnpackerFailureReason::CRX_SIGNATURE_VERIFICATION_FAILED: return ASCIIToUTF16("CRX_SIGNATURE_VERIFICATION_FAILED"); - case CRX_FILE_IS_DELTA_UPDATE: + case SandboxedUnpackerFailureReason::CRX_FILE_IS_DELTA_UPDATE: return ASCIIToUTF16("CRX_FILE_IS_DELTA_UPDATE"); - case CRX_EXPECTED_HASH_INVALID: + case SandboxedUnpackerFailureReason::CRX_EXPECTED_HASH_INVALID: return ASCIIToUTF16("CRX_EXPECTED_HASH_INVALID"); - case ERROR_SERIALIZING_MANIFEST_JSON: + case SandboxedUnpackerFailureReason::ERROR_SERIALIZING_MANIFEST_JSON: return ASCIIToUTF16("ERROR_SERIALIZING_MANIFEST_JSON"); - case ERROR_SAVING_MANIFEST_JSON: + case SandboxedUnpackerFailureReason::ERROR_SAVING_MANIFEST_JSON: return ASCIIToUTF16("ERROR_SAVING_MANIFEST_JSON"); - case INVALID_PATH_FOR_BROWSER_IMAGE: + case SandboxedUnpackerFailureReason::INVALID_PATH_FOR_BROWSER_IMAGE: return ASCIIToUTF16("INVALID_PATH_FOR_BROWSER_IMAGE"); - case ERROR_REMOVING_OLD_IMAGE_FILE: + case SandboxedUnpackerFailureReason::ERROR_REMOVING_OLD_IMAGE_FILE: return ASCIIToUTF16("ERROR_REMOVING_OLD_IMAGE_FILE"); - case INVALID_PATH_FOR_BITMAP_IMAGE: + case SandboxedUnpackerFailureReason::INVALID_PATH_FOR_BITMAP_IMAGE: return ASCIIToUTF16("INVALID_PATH_FOR_BITMAP_IMAGE"); - case ERROR_RE_ENCODING_THEME_IMAGE: + case SandboxedUnpackerFailureReason::ERROR_RE_ENCODING_THEME_IMAGE: return ASCIIToUTF16("ERROR_RE_ENCODING_THEME_IMAGE"); - case ERROR_SAVING_THEME_IMAGE: + case SandboxedUnpackerFailureReason::ERROR_SAVING_THEME_IMAGE: return ASCIIToUTF16("ERROR_SAVING_THEME_IMAGE"); - case INVALID_CATALOG_DATA: + case SandboxedUnpackerFailureReason::INVALID_CATALOG_DATA: return ASCIIToUTF16("INVALID_CATALOG_DATA"); - case ERROR_SERIALIZING_CATALOG: + case SandboxedUnpackerFailureReason::ERROR_SERIALIZING_CATALOG: return ASCIIToUTF16("ERROR_SERIALIZING_CATALOG"); - case ERROR_SAVING_CATALOG: + case SandboxedUnpackerFailureReason::ERROR_SAVING_CATALOG: return ASCIIToUTF16("ERROR_SAVING_CATALOG"); - case CRX_HASH_VERIFICATION_FAILED: + case SandboxedUnpackerFailureReason::CRX_HASH_VERIFICATION_FAILED: return ASCIIToUTF16("CRX_HASH_VERIFICATION_FAILED"); - case UNZIP_FAILED: + case SandboxedUnpackerFailureReason::UNZIP_FAILED: return ASCIIToUTF16("UNZIP_FAILED"); - case DIRECTORY_MOVE_FAILED: + case SandboxedUnpackerFailureReason::DIRECTORY_MOVE_FAILED: return ASCIIToUTF16("DIRECTORY_MOVE_FAILED"); - case ERROR_PARSING_DNR_RULESET: + case SandboxedUnpackerFailureReason::ERROR_PARSING_DNR_RULESET: return ASCIIToUTF16("ERROR_PARSING_DNR_RULESET"); - case ERROR_INDEXING_DNR_RULESET: + case SandboxedUnpackerFailureReason::ERROR_INDEXING_DNR_RULESET: return ASCIIToUTF16("ERROR_INDEXING_DNR_RULESET"); - case DEPRECATED_ABORTED_DUE_TO_SHUTDOWN: - case NUM_FAILURE_REASONS: + case SandboxedUnpackerFailureReason::DEPRECATED_ABORTED_DUE_TO_SHUTDOWN: + case SandboxedUnpackerFailureReason::NUM_FAILURE_REASONS: default: NOTREACHED(); return base::string16(); } } -void SandboxedUnpacker::FailWithPackageError(FailureReason reason) { +void SandboxedUnpacker::FailWithPackageError( + const SandboxedUnpackerFailureReason reason) { ReportFailure(reason, l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_CODE, FailureReasonToString16(reason))); @@ -870,7 +895,8 @@ bool SandboxedUnpacker::ValidateSignature(const base::FilePath& crx_path, std::vector<uint8_t> hash; if (!expected_hash.empty()) { if (!base::HexStringToBytes(expected_hash, &hash)) { - FailWithPackageError(CRX_EXPECTED_HASH_INVALID); + FailWithPackageError( + SandboxedUnpackerFailureReason::CRX_EXPECTED_HASH_INVALID); return false; } } @@ -885,22 +911,28 @@ bool SandboxedUnpacker::ValidateSignature(const base::FilePath& crx_path, return true; } case crx_file::VerifierResult::OK_DELTA: - FailWithPackageError(CRX_FILE_IS_DELTA_UPDATE); + FailWithPackageError( + SandboxedUnpackerFailureReason::CRX_FILE_IS_DELTA_UPDATE); break; case crx_file::VerifierResult::ERROR_FILE_NOT_READABLE: - FailWithPackageError(CRX_FILE_NOT_READABLE); + FailWithPackageError( + SandboxedUnpackerFailureReason::CRX_FILE_NOT_READABLE); break; case crx_file::VerifierResult::ERROR_HEADER_INVALID: - FailWithPackageError(CRX_HEADER_INVALID); + FailWithPackageError(SandboxedUnpackerFailureReason::CRX_HEADER_INVALID); break; case crx_file::VerifierResult::ERROR_SIGNATURE_INITIALIZATION_FAILED: - FailWithPackageError(CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED); + FailWithPackageError( + SandboxedUnpackerFailureReason:: + CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED); break; case crx_file::VerifierResult::ERROR_SIGNATURE_VERIFICATION_FAILED: - FailWithPackageError(CRX_SIGNATURE_VERIFICATION_FAILED); + FailWithPackageError( + SandboxedUnpackerFailureReason::CRX_SIGNATURE_VERIFICATION_FAILED); break; case crx_file::VerifierResult::ERROR_EXPECTED_HASH_INVALID: - FailWithPackageError(CRX_EXPECTED_HASH_INVALID); + FailWithPackageError( + SandboxedUnpackerFailureReason::CRX_EXPECTED_HASH_INVALID); break; case crx_file::VerifierResult::ERROR_REQUIRED_PROOF_MISSING: // We should never get this result, as we do not call @@ -912,30 +944,28 @@ bool SandboxedUnpacker::ValidateSignature(const base::FilePath& crx_path, // verification of the crx file's hash. CHECK(!expected_hash.empty()); UMA_HISTOGRAM_BOOLEAN("Extensions.SandboxUnpackHashCheck", false); - FailWithPackageError(CRX_HASH_VERIFICATION_FAILED); + FailWithPackageError( + SandboxedUnpackerFailureReason::CRX_HASH_VERIFICATION_FAILED); break; } return false; } -void SandboxedUnpacker::ReportFailure(FailureReason reason, - const base::string16& error) { +void SandboxedUnpacker::ReportFailure( + const SandboxedUnpackerFailureReason reason, + const base::string16& error) { DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence()); - UMA_HISTOGRAM_ENUMERATION("Extensions.SandboxUnpackFailureReason", reason, - NUM_FAILURE_REASONS); + UMA_HISTOGRAM_ENUMERATION( + "Extensions.SandboxUnpackFailureReason", reason, + SandboxedUnpackerFailureReason::NUM_FAILURE_REASONS); if (!crx_unpack_start_time_.is_null()) UMA_HISTOGRAM_TIMES("Extensions.SandboxUnpackFailureTime", base::TimeTicks::Now() - crx_unpack_start_time_); Cleanup(); - CrxInstallError error_info(reason == CRX_HASH_VERIFICATION_FAILED - ? CrxInstallError::ERROR_HASH_MISMATCH - : CrxInstallError::ERROR_OTHER, - error); - - client_->OnUnpackFailure(error_info); + client_->OnUnpackFailure(CrxInstallError(reason, error)); } void SandboxedUnpacker::ReportSuccess( @@ -974,10 +1004,11 @@ base::DictionaryValue* SandboxedUnpacker::RewriteManifestFile( serializer.set_pretty_print(true); if (!serializer.Serialize(*final_manifest)) { // Error serializing manifest.json. - ReportFailure(ERROR_SERIALIZING_MANIFEST_JSON, - l10n_util::GetStringFUTF16( - IDS_EXTENSION_PACKAGE_INSTALL_ERROR, - ASCIIToUTF16("ERROR_SERIALIZING_MANIFEST_JSON"))); + ReportFailure( + SandboxedUnpackerFailureReason::ERROR_SERIALIZING_MANIFEST_JSON, + l10n_util::GetStringFUTF16( + IDS_EXTENSION_PACKAGE_INSTALL_ERROR, + ASCIIToUTF16("ERROR_SERIALIZING_MANIFEST_JSON"))); return NULL; } @@ -986,7 +1017,7 @@ base::DictionaryValue* SandboxedUnpacker::RewriteManifestFile( if (base::WriteFile(manifest_path, manifest_json.data(), size) != size) { // Error saving manifest.json. ReportFailure( - ERROR_SAVING_MANIFEST_JSON, + SandboxedUnpackerFailureReason::ERROR_SAVING_MANIFEST_JSON, l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_INSTALL_ERROR, ASCIIToUTF16("ERROR_SAVING_MANIFEST_JSON"))); return NULL; @@ -1014,7 +1045,7 @@ void SandboxedUnpacker::ParseJsonFile( std::string contents; if (!base::ReadFileToString(path, &contents)) { std::move(callback).Run( - /*value=*/nullptr, + /*value=*/base::nullopt, /*error=*/base::Optional<std::string>("File doesn't exist.")); return; } diff --git a/chromium/extensions/browser/sandboxed_unpacker.h b/chromium/extensions/browser/sandboxed_unpacker.h index 24ea37f80b7..3178b125f1f 100644 --- a/chromium/extensions/browser/sandboxed_unpacker.h +++ b/chromium/extensions/browser/sandboxed_unpacker.h @@ -16,6 +16,7 @@ #include "base/optional.h" #include "base/strings/string_piece.h" #include "base/time/time.h" +#include "base/values.h" #include "extensions/browser/crx_file_info.h" #include "extensions/browser/image_sanitizer.h" #include "extensions/browser/install/crx_install_error.h" @@ -27,8 +28,6 @@ class SkBitmap; namespace base { -class DictionaryValue; -class ListValue; class SequencedTaskRunner; } @@ -38,6 +37,7 @@ class Connector; namespace extensions { class Extension; +enum class SandboxedUnpackerFailureReason; class SandboxedUnpackerClient : public base::RefCountedDeleteOnSequence<SandboxedUnpackerClient> { @@ -99,7 +99,7 @@ class SandboxedUnpackerClient // class SandboxedUnpacker : public base::RefCountedThreadSafe<SandboxedUnpacker> { public: - // Creates a SanboxedUnpacker that will do work to unpack an extension, + // Creates a SandboxedUnpacker that will do work to unpack an extension, // passing the |location| and |creation_flags| to Extension::Create. The // |extensions_dir| parameter should specify the directory under which we'll // create a subdirectory to write the unpacked extension contents. @@ -133,79 +133,6 @@ class SandboxedUnpacker : public base::RefCountedThreadSafe<SandboxedUnpacker> { private: friend class base::RefCountedThreadSafe<SandboxedUnpacker>; - // Enumerate all the ways unpacking can fail. Calls to ReportFailure() - // take a failure reason as an argument, and put it in histogram - // Extensions.SandboxUnpackFailureReason. - enum FailureReason { - // SandboxedUnpacker::CreateTempDirectory() - COULD_NOT_GET_TEMP_DIRECTORY, - COULD_NOT_CREATE_TEMP_DIRECTORY, - - // SandboxedUnpacker::Start() - FAILED_TO_COPY_EXTENSION_FILE_TO_TEMP_DIRECTORY, - COULD_NOT_GET_SANDBOX_FRIENDLY_PATH, - - // SandboxedUnpacker::UnpackExtensionSucceeded() - COULD_NOT_LOCALIZE_EXTENSION, - INVALID_MANIFEST, - - // SandboxedUnpacker::UnpackExtensionFailed() - UNPACKER_CLIENT_FAILED, - - // SandboxedUnpacker::UtilityProcessCrashed() - UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL, - - // SandboxedUnpacker::ValidateSignature() - CRX_FILE_NOT_READABLE, - CRX_HEADER_INVALID, - CRX_MAGIC_NUMBER_INVALID, - CRX_VERSION_NUMBER_INVALID, - CRX_EXCESSIVELY_LARGE_KEY_OR_SIGNATURE, - CRX_ZERO_KEY_LENGTH, - CRX_ZERO_SIGNATURE_LENGTH, - CRX_PUBLIC_KEY_INVALID, - CRX_SIGNATURE_INVALID, - CRX_SIGNATURE_VERIFICATION_INITIALIZATION_FAILED, - CRX_SIGNATURE_VERIFICATION_FAILED, - - // SandboxedUnpacker::RewriteManifestFile() - ERROR_SERIALIZING_MANIFEST_JSON, - ERROR_SAVING_MANIFEST_JSON, - - // SandboxedUnpacker::RewriteImageFiles() - COULD_NOT_READ_IMAGE_DATA_FROM_DISK_UNUSED, - DECODED_IMAGES_DO_NOT_MATCH_THE_MANIFEST_UNUSED, - INVALID_PATH_FOR_BROWSER_IMAGE, - ERROR_REMOVING_OLD_IMAGE_FILE, - INVALID_PATH_FOR_BITMAP_IMAGE, - ERROR_RE_ENCODING_THEME_IMAGE, - ERROR_SAVING_THEME_IMAGE, - DEPRECATED_ABORTED_DUE_TO_SHUTDOWN, // No longer used; kept for UMA. - - // SandboxedUnpacker::RewriteCatalogFiles() - COULD_NOT_READ_CATALOG_DATA_FROM_DISK_UNUSED, - INVALID_CATALOG_DATA, - INVALID_PATH_FOR_CATALOG_UNUSED, - ERROR_SERIALIZING_CATALOG, - ERROR_SAVING_CATALOG, - - // SandboxedUnpacker::ValidateSignature() - CRX_HASH_VERIFICATION_FAILED, - - UNZIP_FAILED, - DIRECTORY_MOVE_FAILED, - - // SandboxedUnpacker::ValidateSignature() - CRX_FILE_IS_DELTA_UPDATE, - CRX_EXPECTED_HASH_INVALID, - - // SandboxedUnpacker::IndexAndPersistRulesIfNeeded() - ERROR_PARSING_DNR_RULESET, - ERROR_INDEXING_DNR_RULESET, - - NUM_FAILURE_REASONS - }; - friend class SandboxedUnpackerTest; ~SandboxedUnpacker(); @@ -214,8 +141,9 @@ class SandboxedUnpacker : public base::RefCountedThreadSafe<SandboxedUnpacker> { bool CreateTempDirectory(); // Helper functions to simplify calling ReportFailure. - base::string16 FailureReasonToString16(FailureReason reason); - void FailWithPackageError(FailureReason reason); + base::string16 FailureReasonToString16( + const SandboxedUnpackerFailureReason reason); + void FailWithPackageError(const SandboxedUnpackerFailureReason reason); // Validates the signature of the extension and extract the key to // |public_key_|. True if the signature validates, false otherwise. @@ -231,7 +159,7 @@ class SandboxedUnpacker : public base::RefCountedThreadSafe<SandboxedUnpacker> { // Unpacks the extension in directory and returns the manifest. void Unpack(const base::FilePath& directory); - void ReadManifestDone(std::unique_ptr<base::Value> manifest, + void ReadManifestDone(base::Optional<base::Value> manifest, const base::Optional<std::string>& error); void UnpackExtensionSucceeded( std::unique_ptr<base::DictionaryValue> manifest); @@ -256,13 +184,17 @@ class SandboxedUnpacker : public base::RefCountedThreadSafe<SandboxedUnpacker> { void ReadJSONRulesetIfNeeded(std::unique_ptr<base::DictionaryValue> manifest); void ReadJSONRulesetDone(std::unique_ptr<base::DictionaryValue> manifest, - std::unique_ptr<base::Value> json_ruleset, + base::Optional<base::Value> json_ruleset, const base::Optional<std::string>& error); // Reports unpack success or failure, or unzip failure. void ReportSuccess(std::unique_ptr<base::DictionaryValue> original_manifest, const base::Optional<int>& dnr_ruleset_checksum); - void ReportFailure(FailureReason reason, const base::string16& error); + + // Puts a sanboxed unpacker failure in histogram + // Extensions.SandboxUnpackFailureReason. + void ReportFailure(const SandboxedUnpackerFailureReason reason, + const base::string16& error); // Overwrites original manifest with safe result from utility process. // Returns NULL on error. Caller owns the returned object. diff --git a/chromium/extensions/browser/sandboxed_unpacker_unittest.cc b/chromium/extensions/browser/sandboxed_unpacker_unittest.cc index a5967b9d886..8f611efe616 100644 --- a/chromium/extensions/browser/sandboxed_unpacker_unittest.cc +++ b/chromium/extensions/browser/sandboxed_unpacker_unittest.cc @@ -23,6 +23,8 @@ #include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_utils.h" #include "extensions/browser/extensions_test.h" +#include "extensions/browser/install/crx_install_error.h" +#include "extensions/browser/install/sandboxed_unpacker_failure_reason.h" #include "extensions/common/constants.h" #include "extensions/common/extension.h" #include "extensions/common/extension_paths.h" @@ -34,6 +36,7 @@ #include "services/data_decoder/public/cpp/test_data_decoder_service.h" #include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/test/test_connector_factory.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/zlib/google/zip.h" @@ -81,7 +84,24 @@ class MockSandboxedUnpackerClient : public SandboxedUnpackerClient { } base::FilePath temp_dir() const { return temp_dir_; } - base::string16 unpack_err() const { return error_; } + base::string16 unpack_error_message() const { + if (error_) + return error_->message(); + return base::string16(); + } + CrxInstallErrorType unpack_error_type() const { + if (error_) + return error_->type(); + return CrxInstallErrorType::NONE; + } + int unpack_error_detail() const { + if (error_) { + return error_->type() == CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE + ? static_cast<int>(error_->sandbox_failure_detail()) + : static_cast<int>(error_->detail()); + } + return 0; + } void set_deleted_tracker(bool* deleted_tracker) { deleted_tracker_ = deleted_tracker; @@ -105,11 +125,11 @@ class MockSandboxedUnpackerClient : public SandboxedUnpackerClient { } void OnUnpackFailure(const CrxInstallError& error) override { - error_ = error.message(); + error_ = error; quit_closure_.Run(); } - base::string16 error_; + base::Optional<CrxInstallError> error_; base::Closure quit_closure_; base::FilePath temp_dir_; bool* deleted_tracker_ = nullptr; @@ -124,9 +144,6 @@ class SandboxedUnpackerTest : public ExtensionsTest { : ExtensionsTest(options) {} void SetUp() override { - // TODO(devlin): Remove this. See https://crbug.com/816679. - allow_legacy_extensions_ = Extension::allow_legacy_extensions_for_testing(); - ExtensionsTest::SetUp(); ASSERT_TRUE(extensions_dir_.CreateUniqueTempDir()); in_process_utility_thread_helper_.reset( @@ -167,12 +184,11 @@ class SandboxedUnpackerTest : public ExtensionsTest { base::RunLoop().RunUntilIdle(); ExtensionsTest::TearDown(); in_process_utility_thread_helper_.reset(); - allow_legacy_extensions_.reset(); } base::FilePath GetCrxFullPath(const std::string& crx_name) { base::FilePath full_path; - EXPECT_TRUE(PathService::Get(extensions::DIR_TEST_DATA, &full_path)); + EXPECT_TRUE(base::PathService::Get(extensions::DIR_TEST_DATA, &full_path)); full_path = full_path.AppendASCII("unpacker").AppendASCII(crx_name); EXPECT_TRUE(base::PathExists(full_path)) << full_path.value(); return full_path; @@ -211,10 +227,18 @@ class SandboxedUnpackerTest : public ExtensionsTest { return client_->temp_dir().AppendASCII(kTempExtensionName); } - base::string16 GetInstallError() const { return client_->unpack_err(); } + base::string16 GetInstallErrorMessage() const { + return client_->unpack_error_message(); + } + + CrxInstallErrorType GetInstallErrorType() const { + return client_->unpack_error_type(); + } + + int GetInstallErrorDetail() const { return client_->unpack_error_detail(); } void ExpectInstallErrorContains(const std::string& error) { - std::string full_error = base::UTF16ToUTF8(client_->unpack_err()); + std::string full_error = base::UTF16ToUTF8(client_->unpack_error_message()); EXPECT_TRUE(full_error.find(error) != std::string::npos) << "Error message " << full_error << " does not contain " << error; } @@ -226,7 +250,7 @@ class SandboxedUnpackerTest : public ExtensionsTest { bool client_deleted = false; client_->set_deleted_tracker(&client_deleted); SetupUnpacker(package_name, ""); - EXPECT_EQ(GetInstallError().empty(), expect_success); + EXPECT_EQ(GetInstallErrorMessage().empty(), expect_success); // Remove our reference to |sandboxed_unpacker_|, it should get deleted // since/ it's the last reference. sandboxed_unpacker_ = nullptr; @@ -243,57 +267,97 @@ class SandboxedUnpackerTest : public ExtensionsTest { std::unique_ptr<service_manager::TestConnectorFactory> test_connector_factory_; std::unique_ptr<service_manager::Connector> connector_; - Extension::ScopedAllowLegacyExtensions allow_legacy_extensions_; }; TEST_F(SandboxedUnpackerTest, EmptyDefaultLocale) { SetupUnpacker("empty_default_locale.crx", ""); ExpectInstallErrorContains(manifest_errors::kInvalidDefaultLocale); + ASSERT_EQ(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE, + GetInstallErrorType()); + EXPECT_EQ( + static_cast<int>(SandboxedUnpackerFailureReason::UNPACKER_CLIENT_FAILED), + GetInstallErrorDetail()); } TEST_F(SandboxedUnpackerTest, HasDefaultLocaleMissingLocalesFolder) { SetupUnpacker("has_default_missing_locales.crx", ""); ExpectInstallErrorContains(manifest_errors::kLocalesTreeMissing); + ASSERT_EQ(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE, + GetInstallErrorType()); + EXPECT_EQ( + static_cast<int>(SandboxedUnpackerFailureReason::UNPACKER_CLIENT_FAILED), + GetInstallErrorDetail()); } TEST_F(SandboxedUnpackerTest, InvalidDefaultLocale) { SetupUnpacker("invalid_default_locale.crx", ""); ExpectInstallErrorContains(manifest_errors::kInvalidDefaultLocale); + ASSERT_EQ(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE, + GetInstallErrorType()); + EXPECT_EQ( + static_cast<int>(SandboxedUnpackerFailureReason::UNPACKER_CLIENT_FAILED), + GetInstallErrorDetail()); } TEST_F(SandboxedUnpackerTest, MissingDefaultData) { SetupUnpacker("missing_default_data.crx", ""); ExpectInstallErrorContains(manifest_errors::kLocalesNoDefaultMessages); + ASSERT_EQ(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE, + GetInstallErrorType()); + EXPECT_EQ( + static_cast<int>(SandboxedUnpackerFailureReason::UNPACKER_CLIENT_FAILED), + GetInstallErrorDetail()); } TEST_F(SandboxedUnpackerTest, MissingDefaultLocaleHasLocalesFolder) { SetupUnpacker("missing_default_has_locales.crx", ""); ExpectInstallErrorContains(l10n_util::GetStringUTF8( IDS_EXTENSION_LOCALES_NO_DEFAULT_LOCALE_SPECIFIED)); + ASSERT_EQ(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE, + GetInstallErrorType()); + EXPECT_EQ( + static_cast<int>(SandboxedUnpackerFailureReason::UNPACKER_CLIENT_FAILED), + GetInstallErrorDetail()); } TEST_F(SandboxedUnpackerTest, MissingMessagesFile) { SetupUnpacker("missing_messages_file.crx", ""); EXPECT_TRUE(base::MatchPattern( - GetInstallError(), + GetInstallErrorMessage(), base::ASCIIToUTF16("*") + base::ASCIIToUTF16(manifest_errors::kLocalesMessagesFileMissing) + base::ASCIIToUTF16("*_locales?en_US?messages.json'."))) - << GetInstallError(); + << GetInstallErrorMessage(); + ASSERT_EQ(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE, + GetInstallErrorType()); + EXPECT_EQ( + static_cast<int>(SandboxedUnpackerFailureReason::UNPACKER_CLIENT_FAILED), + GetInstallErrorDetail()); } TEST_F(SandboxedUnpackerTest, NoLocaleData) { SetupUnpacker("no_locale_data.crx", ""); ExpectInstallErrorContains(manifest_errors::kLocalesNoDefaultMessages); + ASSERT_EQ(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE, + GetInstallErrorType()); + EXPECT_EQ( + static_cast<int>(SandboxedUnpackerFailureReason::UNPACKER_CLIENT_FAILED), + GetInstallErrorDetail()); } TEST_F(SandboxedUnpackerTest, ImageDecodingError) { const char kExpected[] = "Could not decode image: "; SetupUnpacker("bad_image.crx", ""); - EXPECT_TRUE(base::StartsWith(GetInstallError(), base::ASCIIToUTF16(kExpected), + EXPECT_TRUE(base::StartsWith(GetInstallErrorMessage(), + base::ASCIIToUTF16(kExpected), base::CompareCase::INSENSITIVE_ASCII)) << "Expected prefix: \"" << kExpected << "\", actual error: \"" - << GetInstallError() << "\""; + << GetInstallErrorMessage() << "\""; + ASSERT_EQ(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE, + GetInstallErrorType()); + EXPECT_EQ( + static_cast<int>(SandboxedUnpackerFailureReason::UNPACKER_CLIENT_FAILED), + GetInstallErrorDetail()); } TEST_F(SandboxedUnpackerTest, BadPathError) { @@ -302,7 +366,12 @@ TEST_F(SandboxedUnpackerTest, BadPathError) { SetupUnpacker("good_package.crx", ""); // Install should have failed with an error. EXPECT_FALSE(InstallSucceeded()); - EXPECT_FALSE(GetInstallError().empty()); + EXPECT_FALSE(GetInstallErrorMessage().empty()); + ASSERT_EQ(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE, + GetInstallErrorType()); + EXPECT_EQ(static_cast<int>( + SandboxedUnpackerFailureReason::INVALID_PATH_FOR_BROWSER_IMAGE), + GetInstallErrorDetail()); } TEST_F(SandboxedUnpackerTest, NoCatalogsSuccess) { @@ -310,6 +379,7 @@ TEST_F(SandboxedUnpackerTest, NoCatalogsSuccess) { // Check that there is no _locales folder. base::FilePath install_path = GetInstallPath().Append(kLocaleFolder); EXPECT_FALSE(base::PathExists(install_path)); + EXPECT_EQ(CrxInstallErrorType::NONE, GetInstallErrorType()); } TEST_F(SandboxedUnpackerTest, FromDirNoCatalogsSuccess) { @@ -317,6 +387,7 @@ TEST_F(SandboxedUnpackerTest, FromDirNoCatalogsSuccess) { // Check that there is no _locales folder. base::FilePath install_path = GetInstallPath().Append(kLocaleFolder); EXPECT_FALSE(base::PathExists(install_path)); + EXPECT_EQ(CrxInstallErrorType::NONE, GetInstallErrorType()); } TEST_F(SandboxedUnpackerTest, WithCatalogsSuccess) { @@ -324,6 +395,7 @@ TEST_F(SandboxedUnpackerTest, WithCatalogsSuccess) { // Check that there is _locales folder. base::FilePath install_path = GetInstallPath().Append(kLocaleFolder); EXPECT_TRUE(base::PathExists(install_path)); + EXPECT_EQ(CrxInstallErrorType::NONE, GetInstallErrorType()); } TEST_F(SandboxedUnpackerTest, FromDirWithCatalogsSuccess) { @@ -331,6 +403,7 @@ TEST_F(SandboxedUnpackerTest, FromDirWithCatalogsSuccess) { // Check that there is _locales folder. base::FilePath install_path = GetInstallPath().Append(kLocaleFolder); EXPECT_TRUE(base::PathExists(install_path)); + EXPECT_EQ(CrxInstallErrorType::NONE, GetInstallErrorType()); } TEST_F(SandboxedUnpackerTest, FailHashCheck) { @@ -338,7 +411,12 @@ TEST_F(SandboxedUnpackerTest, FailHashCheck) { extensions::switches::kEnableCrxHashCheck); SetupUnpacker("good_l10n.crx", std::string(64, '0')); // Check that there is an error message. - EXPECT_NE(base::string16(), GetInstallError()); + EXPECT_FALSE(GetInstallErrorMessage().empty()); + ASSERT_EQ(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE, + GetInstallErrorType()); + EXPECT_EQ(static_cast<int>( + SandboxedUnpackerFailureReason::CRX_HASH_VERIFICATION_FAILED), + GetInstallErrorDetail()); } TEST_F(SandboxedUnpackerTest, InvalidMessagesFile) { @@ -347,10 +425,15 @@ TEST_F(SandboxedUnpackerTest, InvalidMessagesFile) { base::FilePath install_path = GetInstallPath().Append(kLocaleFolder); EXPECT_FALSE(base::PathExists(install_path)); EXPECT_TRUE(base::MatchPattern( - GetInstallError(), + GetInstallErrorMessage(), base::ASCIIToUTF16("*_locales?en_US?messages.json': Line: 2, column: 10," " Syntax error.'."))) - << GetInstallError(); + << GetInstallErrorMessage(); + ASSERT_EQ(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE, + GetInstallErrorType()); + EXPECT_EQ(static_cast<int>( + SandboxedUnpackerFailureReason::COULD_NOT_LOCALIZE_EXTENSION), + GetInstallErrorDetail()); } TEST_F(SandboxedUnpackerTest, PassHashCheck) { @@ -358,15 +441,17 @@ TEST_F(SandboxedUnpackerTest, PassHashCheck) { extensions::switches::kEnableCrxHashCheck); SetupUnpacker( "good_l10n.crx", - "6fa171c726373785aa4fcd2df448c3db0420a95d5044fbee831f089b979c4068"); + "614AE3D608F4C2185E9173293AB3F93EE7C7C79C9A2C3CF71F633386A3296A6C"); // Check that there is no error message. - EXPECT_EQ(base::string16(), GetInstallError()); + EXPECT_THAT(GetInstallErrorMessage(), testing::IsEmpty()); + EXPECT_EQ(CrxInstallErrorType::NONE, GetInstallErrorType()); } TEST_F(SandboxedUnpackerTest, SkipHashCheck) { SetupUnpacker("good_l10n.crx", "badhash"); // Check that there is no error message. - EXPECT_EQ(base::string16(), GetInstallError()); + EXPECT_THAT(GetInstallErrorMessage(), testing::IsEmpty()); + EXPECT_EQ(CrxInstallErrorType::NONE, GetInstallErrorType()); } // The following tests simulate the utility services failling. @@ -376,7 +461,11 @@ TEST_F(SandboxedUnpackerTest, UnzipperServiceFails) { std::make_unique<unzip::CrashyUnzipService>()); SetupUnpacker("good_package.crx", ""); EXPECT_FALSE(InstallSucceeded()); - EXPECT_FALSE(GetInstallError().empty()); + EXPECT_FALSE(GetInstallErrorMessage().empty()); + ASSERT_EQ(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE, + GetInstallErrorType()); + EXPECT_EQ(static_cast<int>(SandboxedUnpackerFailureReason::UNZIP_FAILED), + GetInstallErrorDetail()); } TEST_F(SandboxedUnpackerTest, JsonParserFails) { @@ -385,7 +474,9 @@ TEST_F(SandboxedUnpackerTest, JsonParserFails) { /*unzip_service=*/nullptr); SetupUnpacker("good_package.crx", ""); EXPECT_FALSE(InstallSucceeded()); - EXPECT_FALSE(GetInstallError().empty()); + EXPECT_FALSE(GetInstallErrorMessage().empty()); + ASSERT_EQ(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE, + GetInstallErrorType()); } TEST_F(SandboxedUnpackerTest, ImageDecoderFails) { @@ -394,7 +485,13 @@ TEST_F(SandboxedUnpackerTest, ImageDecoderFails) { /*unzip_service=*/nullptr); SetupUnpacker("good_package.crx", ""); EXPECT_FALSE(InstallSucceeded()); - EXPECT_FALSE(GetInstallError().empty()); + EXPECT_FALSE(GetInstallErrorMessage().empty()); + ASSERT_EQ(CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE, + GetInstallErrorType()); + EXPECT_EQ( + static_cast<int>(SandboxedUnpackerFailureReason:: + UTILITY_PROCESS_CRASHED_WHILE_TRYING_TO_INSTALL), + GetInstallErrorDetail()); } // SandboxedUnpacker is ref counted and is reference by callbacks and diff --git a/chromium/extensions/browser/test_management_policy.cc b/chromium/extensions/browser/test_management_policy.cc index 42a2f1c5c4b..76b870b89a6 100644 --- a/chromium/extensions/browser/test_management_policy.cc +++ b/chromium/extensions/browser/test_management_policy.cc @@ -56,6 +56,15 @@ bool TestManagementPolicyProvider::UserMayModifySettings( return may_modify_status_; } +bool TestManagementPolicyProvider::ExtensionMayModifySettings( + const Extension* source_extension, + const Extension* extension, + base::string16* error) const { + if (error && !may_modify_status_) + *error = error_message_; + return may_modify_status_; +} + bool TestManagementPolicyProvider::MustRemainEnabled(const Extension* extension, base::string16* error) const { diff --git a/chromium/extensions/browser/test_management_policy.h b/chromium/extensions/browser/test_management_policy.h index 92fe597467e..9f051cbba5d 100644 --- a/chromium/extensions/browser/test_management_policy.h +++ b/chromium/extensions/browser/test_management_policy.h @@ -43,6 +43,10 @@ class TestManagementPolicyProvider : public ManagementPolicy::Provider { bool UserMayModifySettings(const Extension* extension, base::string16* error) const override; + bool ExtensionMayModifySettings(const Extension* source_extension, + const Extension* extension, + base::string16* error) const override; + bool MustRemainEnabled(const Extension* extension, base::string16* error) const override; diff --git a/chromium/extensions/browser/updater/extension_downloader.cc b/chromium/extensions/browser/updater/extension_downloader.cc index d4cd9741964..d2c303f4a10 100644 --- a/chromium/extensions/browser/updater/extension_downloader.cc +++ b/chromium/extensions/browser/updater/extension_downloader.cc @@ -34,7 +34,6 @@ #include "extensions/common/extension_updater_uma.h" #include "extensions/common/extension_urls.h" #include "extensions/common/manifest_url_handlers.h" -#include "google_apis/gaia/identity_provider.h" #include "net/base/backoff_entry.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" @@ -204,13 +203,16 @@ ExtensionDownloader::ExtensionDownloader( delegate_(delegate), request_context_(request_context), connector_(connector), - manifests_queue_(&kDefaultBackoffPolicy, - base::Bind(&ExtensionDownloader::CreateManifestFetcher, - base::Unretained(this))), - extensions_queue_(&kDefaultBackoffPolicy, - base::Bind(&ExtensionDownloader::CreateExtensionFetcher, - base::Unretained(this))), - extension_cache_(NULL), + manifests_queue_( + &kDefaultBackoffPolicy, + base::BindRepeating(&ExtensionDownloader::CreateManifestFetcher, + base::Unretained(this))), + extensions_queue_( + &kDefaultBackoffPolicy, + base::BindRepeating(&ExtensionDownloader::CreateExtensionFetcher, + base::Unretained(this))), + extension_cache_(nullptr), + token_service_(nullptr), weak_ptr_factory_(this) { DCHECK(delegate_); DCHECK(request_context_.get()); @@ -307,9 +309,11 @@ void ExtensionDownloader::StartBlacklistUpdate( StartUpdateCheck(std::move(blacklist_fetch)); } -void ExtensionDownloader::SetWebstoreIdentityProvider( - std::unique_ptr<IdentityProvider> identity_provider) { - identity_provider_.swap(identity_provider); +void ExtensionDownloader::SetWebstoreAuthenticationCapabilities( + const GetWebstoreAccountCallback& webstore_account_callback, + OAuth2TokenService* token_service) { + webstore_account_callback_ = webstore_account_callback; + token_service_ = token_service; } // static @@ -806,9 +810,9 @@ void ExtensionDownloader::NotifyDelegateDownloadFinished( delegate_->OnExtensionDownloadFinished( CRXFileInfo(id, crx_path, package_hash), file_ownership_passed, url, version, ping_results_[id], request_ids, - from_cache ? base::Bind(&ExtensionDownloader::CacheInstallDone, - weak_ptr_factory_.GetWeakPtr(), - base::Passed(&fetch_data)) + from_cache ? base::BindRepeating(&ExtensionDownloader::CacheInstallDone, + weak_ptr_factory_.GetWeakPtr(), + base::Passed(&fetch_data)) : ExtensionDownloaderDelegate::InstallCallback()); if (!from_cache) ping_results_.erase(id); @@ -882,12 +886,12 @@ void ExtensionDownloader::CreateExtensionFetcher() { // We should try OAuth2, but we have no token cached. This // ExtensionFetcher will be started once the token fetch is complete, // in either OnTokenFetchSuccess or OnTokenFetchFailure. - DCHECK(identity_provider_.get()); + DCHECK(token_service_); + DCHECK(!webstore_account_callback_.is_null()); OAuth2TokenService::ScopeSet webstore_scopes; webstore_scopes.insert(kWebstoreOAuth2Scope); - access_token_request_ = - identity_provider_->GetTokenService()->StartRequest( - identity_provider_->GetActiveAccountId(), webstore_scopes, this); + access_token_request_ = token_service_->StartRequest( + webstore_account_callback_.Run(), webstore_scopes, this); return; } extension_fetcher_->AddExtraRequestHeader( @@ -923,9 +927,10 @@ void ExtensionDownloader::OnCRXFetchComplete( const std::string& expected_hash = fetch_data->package_hash; extension_cache_->PutExtension( id, expected_hash, crx_path, version, - base::Bind(&ExtensionDownloader::NotifyDelegateDownloadFinished, - weak_ptr_factory_.GetWeakPtr(), base::Passed(&fetch_data), - false)); + base::BindRepeating( + &ExtensionDownloader::NotifyDelegateDownloadFinished, + weak_ptr_factory_.GetWeakPtr(), base::Passed(&fetch_data), + false)); } else { NotifyDelegateDownloadFinished(std::move(fetch_data), false, crx_path, true); @@ -999,7 +1004,7 @@ bool ExtensionDownloader::IterateFetchCredentialsAfterFailure( // fetch. switch (fetch->credentials) { case ExtensionFetch::CREDENTIALS_NONE: - if (fetch->url.DomainIs(kGoogleDotCom) && identity_provider_) { + if (fetch->url.DomainIs(kGoogleDotCom) && token_service_) { fetch->credentials = ExtensionFetch::CREDENTIALS_OAUTH2_TOKEN; } else { fetch->credentials = ExtensionFetch::CREDENTIALS_COOKIES; @@ -1011,12 +1016,12 @@ bool ExtensionDownloader::IterateFetchCredentialsAfterFailure( // should invalidate the token and try again. if (response_code == net::HTTP_UNAUTHORIZED && fetch->oauth2_attempt_count <= kMaxOAuth2Attempts) { - DCHECK(identity_provider_.get()); + DCHECK(token_service_); + DCHECK(!webstore_account_callback_.is_null()); OAuth2TokenService::ScopeSet webstore_scopes; webstore_scopes.insert(kWebstoreOAuth2Scope); - identity_provider_->GetTokenService()->InvalidateAccessToken( - identity_provider_->GetActiveAccountId(), webstore_scopes, - access_token_); + token_service_->InvalidateAccessToken(webstore_account_callback_.Run(), + webstore_scopes, access_token_); access_token_.clear(); return true; } diff --git a/chromium/extensions/browser/updater/extension_downloader.h b/chromium/extensions/browser/updater/extension_downloader.h index ce8f52a3688..80d3d541df2 100644 --- a/chromium/extensions/browser/updater/extension_downloader.h +++ b/chromium/extensions/browser/updater/extension_downloader.h @@ -25,8 +25,6 @@ #include "net/url_request/url_fetcher_delegate.h" #include "url/gurl.h" -class IdentityProvider; - namespace net { class URLFetcher; class URLRequestContextGetter; @@ -60,9 +58,13 @@ class ExtensionDownloader : public net::URLFetcherDelegate, public: // A closure which constructs a new ExtensionDownloader to be owned by the // caller. - typedef base::Callback<std::unique_ptr<ExtensionDownloader>( - ExtensionDownloaderDelegate* delegate)> - Factory; + using Factory = base::RepeatingCallback<std::unique_ptr<ExtensionDownloader>( + ExtensionDownloaderDelegate* delegate)>; + + // A closure that returns the account to use for authentication to the + // webstore. + using GetWebstoreAccountCallback = + base::RepeatingCallback<const std::string&()>; // |delegate| is stored as a raw pointer and must outlive the // ExtensionDownloader. @@ -109,10 +111,12 @@ class ExtensionDownloader : public net::URLFetcherDelegate, const ManifestFetchData::PingData& ping_data, int request_id); - // Sets an IdentityProvider to be used for OAuth2 authentication on protected - // Webstore downloads. - void SetWebstoreIdentityProvider( - std::unique_ptr<IdentityProvider> identity_provider); + // Sets GetWebstoreAccountCallback and TokenService instances to be used for + // OAuth2 authentication on protected Webstore downloads. Both objects must be + // valid to use for the lifetime of this object. + void SetWebstoreAuthenticationCapabilities( + const GetWebstoreAccountCallback& webstore_account_callback, + OAuth2TokenService* token_service); void set_brand_code(const std::string& brand_code) { brand_code_ = brand_code; @@ -348,9 +352,13 @@ class ExtensionDownloader : public net::URLFetcherDelegate, // Cache for .crx files. ExtensionCache* extension_cache_; - // An IdentityProvider which may be used for authentication on protected - // download requests. May be NULL. - std::unique_ptr<IdentityProvider> identity_provider_; + // Gets the account to use for protected download requests. May be null. If + // non-null, valid to call for the lifetime of this object. + GetWebstoreAccountCallback webstore_account_callback_; + + // May be used to fetch access tokens for protected download requests. May be + // null. If non-null, guaranteed to outlive this object. + OAuth2TokenService* token_service_; // A Webstore download-scoped access token for the |identity_provider_|'s // active account, if any. diff --git a/chromium/extensions/browser/updater/request_queue_impl.h b/chromium/extensions/browser/updater/request_queue_impl.h index 5eb5148a959..7e1442edb36 100644 --- a/chromium/extensions/browser/updater/request_queue_impl.h +++ b/chromium/extensions/browser/updater/request_queue_impl.h @@ -13,7 +13,6 @@ #include "base/bind.h" #include "base/compiler_specific.h" -#include "base/message_loop/message_loop.h" #include "extensions/browser/updater/request_queue.h" namespace extensions { diff --git a/chromium/extensions/browser/updater/update_data_provider.cc b/chromium/extensions/browser/updater/update_data_provider.cc index b7421dc61b0..161f072815b 100644 --- a/chromium/extensions/browser/updater/update_data_provider.cc +++ b/chromium/extensions/browser/updater/update_data_provider.cc @@ -4,13 +4,16 @@ #include "extensions/browser/updater/update_data_provider.h" +#include <utility> + #include "base/base64.h" #include "base/bind.h" #include "base/files/file_path.h" #include "base/files/file_util.h" +#include "base/optional.h" #include "base/strings/string_util.h" #include "base/task_scheduler/post_task.h" -#include "components/update_client/update_client.h" +#include "components/update_client/utils.h" #include "content/public/browser/browser_thread.h" #include "crypto/sha2.h" #include "extensions/browser/content_verifier.h" @@ -18,6 +21,8 @@ #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_system.h" #include "extensions/browser/extensions_browser_client.h" +#include "extensions/browser/install/crx_install_error.h" +#include "extensions/browser/updater/manifest_fetch_data.h" #include "extensions/common/extension.h" namespace extensions { @@ -31,17 +36,26 @@ void InstallUpdateCallback(content::BrowserContext* context, const std::string& public_key, const base::FilePath& unpacked_dir, UpdateClientCallback update_client_callback) { - using InstallError = update_client::InstallError; - using Result = update_client::CrxInstaller::Result; - + // Note that error codes are converted into custom error codes, which are all + // based on a constant (see ToInstallerResult). This means that custom codes + // from different embedders may collide. However, for any given extension ID, + // there should be only one embedder, so this should be OK from Omaha. ExtensionSystem::Get(context)->InstallUpdate( extension_id, public_key, unpacked_dir, base::BindOnce( - [](UpdateClientCallback update_client_callback, bool success) { + [](UpdateClientCallback callback, + const base::Optional<CrxInstallError>& error) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - std::move(update_client_callback) - .Run(Result(success ? InstallError::NONE - : InstallError::GENERIC_ERROR)); + update_client::CrxInstaller::Result result(0); + if (error.has_value()) { + int detail = + error->type() == + CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE + ? static_cast<int>(error->sandbox_failure_detail()) + : static_cast<int>(error->detail()); + result = update_client::ToInstallerResult(error->type(), detail); + } + std::move(callback).Run(result); }, std::move(update_client_callback))); } @@ -57,33 +71,34 @@ void UpdateDataProvider::Shutdown() { browser_context_ = nullptr; } -void UpdateDataProvider::GetData( - const ExtensionUpdateDataMap& update_info, - const std::vector<std::string>& ids, - std::vector<update_client::CrxComponent>* data) { +std::vector<std::unique_ptr<update_client::CrxComponent>> +UpdateDataProvider::GetData(const ExtensionUpdateDataMap& update_crx_component, + const std::vector<std::string>& ids) { + std::vector<std::unique_ptr<update_client::CrxComponent>> data; if (!browser_context_) - return; + return data; const ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_); const ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(browser_context_); for (const auto& id : ids) { const Extension* extension = registry->GetInstalledExtension(id); + data.push_back(extension ? std::make_unique<update_client::CrxComponent>() + : nullptr); if (!extension) continue; - DCHECK_GT(update_info.count(id), 0ULL); - const ExtensionUpdateData& extension_data = update_info.at(id); - data->push_back(update_client::CrxComponent()); - update_client::CrxComponent* info = &data->back(); + DCHECK_NE(0u, update_crx_component.count(id)); + const ExtensionUpdateData& extension_data = update_crx_component.at(id); + update_client::CrxComponent* crx_component = data.back().get(); std::string pubkey_bytes; base::Base64Decode(extension->public_key(), &pubkey_bytes); - info->pk_hash.resize(crypto::kSHA256Length, 0); - crypto::SHA256HashString(pubkey_bytes, info->pk_hash.data(), - info->pk_hash.size()); - info->version = extension_data.is_corrupt_reinstall - ? base::Version("0.0.0.0") - : extension->version(); - info->allows_background_download = false; - info->requires_network_encryption = true; - info->installer = base::MakeRefCounted<ExtensionInstaller>( + crx_component->pk_hash.resize(crypto::kSHA256Length, 0); + crypto::SHA256HashString(pubkey_bytes, crx_component->pk_hash.data(), + crx_component->pk_hash.size()); + crx_component->version = extension_data.is_corrupt_reinstall + ? base::Version("0.0.0.0") + : extension->version(); + crx_component->allows_background_download = false; + crx_component->requires_network_encryption = true; + crx_component->installer = base::MakeRefCounted<ExtensionInstaller>( id, extension->path(), base::BindOnce(&UpdateDataProvider::RunInstallCallback, this)); if (!ExtensionsBrowserClient::Get()->IsExtensionEnabled(id, @@ -91,17 +106,20 @@ void UpdateDataProvider::GetData( int disabled_reasons = extension_prefs->GetDisableReasons(id); if (disabled_reasons == extensions::disable_reason::DISABLE_NONE || disabled_reasons >= extensions::disable_reason::DISABLE_REASON_LAST) { - info->disabled_reasons.push_back(0); + crx_component->disabled_reasons.push_back(0); } for (int enum_value = 1; enum_value < extensions::disable_reason::DISABLE_REASON_LAST; enum_value <<= 1) { if (disabled_reasons & enum_value) - info->disabled_reasons.push_back(enum_value); + crx_component->disabled_reasons.push_back(enum_value); } } - info->install_source = extension_data.install_source; + crx_component->install_source = extension_data.install_source; + crx_component->install_location = + ManifestFetchData::GetSimpleLocationString(extension->location()); } + return data; } void UpdateDataProvider::RunInstallCallback( diff --git a/chromium/extensions/browser/updater/update_data_provider.h b/chromium/extensions/browser/updater/update_data_provider.h index 83b04bf0cfe..61a212b0810 100644 --- a/chromium/extensions/browser/updater/update_data_provider.h +++ b/chromium/extensions/browser/updater/update_data_provider.h @@ -6,6 +6,7 @@ #define EXTENSIONS_BROWSER_UPDATER_UPDATE_DATA_PROVIDER_H_ #include <map> +#include <memory> #include <string> #include <vector> @@ -47,9 +48,9 @@ class UpdateDataProvider : public base::RefCounted<UpdateDataProvider> { void Shutdown(); // Matches update_client::UpdateClient::CrxDataCallback - void GetData(const ExtensionUpdateDataMap& update_info, - const std::vector<std::string>& ids, - std::vector<update_client::CrxComponent>* data); + std::vector<std::unique_ptr<update_client::CrxComponent>> GetData( + const ExtensionUpdateDataMap& update_info, + const std::vector<std::string>& ids); private: friend class base::RefCounted<UpdateDataProvider>; diff --git a/chromium/extensions/browser/updater/update_data_provider_unittest.cc b/chromium/extensions/browser/updater/update_data_provider_unittest.cc index 2ae8bc14250..3e3749e0525 100644 --- a/chromium/extensions/browser/updater/update_data_provider_unittest.cc +++ b/chromium/extensions/browser/updater/update_data_provider_unittest.cc @@ -89,7 +89,8 @@ class UpdateDataProviderTest : public ExtensionsTest { void AddExtension(const std::string& extension_id, const std::string& version, bool enabled, - int disable_reasons) { + int disable_reasons, + Manifest::Location location) { base::ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); ASSERT_TRUE(base::PathExists(temp_dir.GetPath())); @@ -109,6 +110,7 @@ class UpdateDataProviderTest : public ExtensionsTest { .Build()); builder.SetID(extension_id); builder.SetPath(temp_dir.GetPath()); + builder.SetLocation(location); auto* test_browser_client = static_cast<UpdateDataProviderExtensionsBrowserClient*>( @@ -136,9 +138,8 @@ TEST_F(UpdateDataProviderTest, GetData_NoDataAdded) { scoped_refptr<UpdateDataProvider> data_provider = base::MakeRefCounted<UpdateDataProvider>(nullptr); - std::vector<std::string> ids({kExtensionId1}); - std::vector<update_client::CrxComponent> data; - data_provider->GetData(ExtensionUpdateDataMap(), ids, &data); + const auto data = + data_provider->GetData(ExtensionUpdateDataMap(), {kExtensionId1}); EXPECT_EQ(0UL, data.size()); } @@ -148,19 +149,19 @@ TEST_F(UpdateDataProviderTest, GetData_EnabledExtension) { const std::string version = "0.1.2.3"; AddExtension(kExtensionId1, version, true, - disable_reason::DisableReason::DISABLE_NONE); + disable_reason::DisableReason::DISABLE_NONE, Manifest::INTERNAL); ExtensionUpdateDataMap update_data; update_data[kExtensionId1] = {}; std::vector<std::string> ids({kExtensionId1}); - std::vector<update_client::CrxComponent> data; - data_provider->GetData(update_data, ids, &data); + const auto data = data_provider->GetData(update_data, ids); ASSERT_EQ(1UL, data.size()); - EXPECT_EQ(version, data[0].version.GetString()); - EXPECT_NE(nullptr, data[0].installer.get()); - EXPECT_EQ(0UL, data[0].disabled_reasons.size()); + EXPECT_EQ(version, data[0]->version.GetString()); + EXPECT_NE(nullptr, data[0]->installer.get()); + EXPECT_EQ(0UL, data[0]->disabled_reasons.size()); + EXPECT_EQ("internal", data[0]->install_location); } TEST_F(UpdateDataProviderTest, GetData_EnabledExtensionWithData) { @@ -169,22 +170,22 @@ TEST_F(UpdateDataProviderTest, GetData_EnabledExtensionWithData) { const std::string version = "0.1.2.3"; AddExtension(kExtensionId1, version, true, - disable_reason::DisableReason::DISABLE_NONE); + disable_reason::DisableReason::DISABLE_NONE, + Manifest::EXTERNAL_PREF); ExtensionUpdateDataMap update_data; auto& info = update_data[kExtensionId1]; info.is_corrupt_reinstall = true; info.install_source = "webstore"; - std::vector<std::string> ids({kExtensionId1}); - std::vector<update_client::CrxComponent> data; - data_provider->GetData(update_data, ids, &data); + const auto data = data_provider->GetData(update_data, {kExtensionId1}); ASSERT_EQ(1UL, data.size()); - EXPECT_EQ("0.0.0.0", data[0].version.GetString()); - EXPECT_EQ("webstore", data[0].install_source); - EXPECT_NE(nullptr, data[0].installer.get()); - EXPECT_EQ(0UL, data[0].disabled_reasons.size()); + EXPECT_EQ("0.0.0.0", data[0]->version.GetString()); + EXPECT_EQ("webstore", data[0]->install_source); + EXPECT_EQ("external", data[0]->install_location); + EXPECT_NE(nullptr, data[0]->installer.get()); + EXPECT_EQ(0UL, data[0]->disabled_reasons.size()); } TEST_F(UpdateDataProviderTest, GetData_DisabledExtension_WithNoReason) { @@ -193,21 +194,21 @@ TEST_F(UpdateDataProviderTest, GetData_DisabledExtension_WithNoReason) { const std::string version = "0.1.2.3"; AddExtension(kExtensionId1, version, false, - disable_reason::DisableReason::DISABLE_NONE); + disable_reason::DisableReason::DISABLE_NONE, + Manifest::EXTERNAL_REGISTRY); ExtensionUpdateDataMap update_data; update_data[kExtensionId1] = {}; - std::vector<std::string> ids({kExtensionId1}); - std::vector<update_client::CrxComponent> data; - data_provider->GetData(update_data, ids, &data); + const auto data = data_provider->GetData(update_data, {kExtensionId1}); ASSERT_EQ(1UL, data.size()); - EXPECT_EQ(version, data[0].version.GetString()); - EXPECT_NE(nullptr, data[0].installer.get()); - ASSERT_EQ(1UL, data[0].disabled_reasons.size()); + EXPECT_EQ(version, data[0]->version.GetString()); + EXPECT_NE(nullptr, data[0]->installer.get()); + ASSERT_EQ(1UL, data[0]->disabled_reasons.size()); EXPECT_EQ(disable_reason::DisableReason::DISABLE_NONE, - data[0].disabled_reasons[0]); + data[0]->disabled_reasons[0]); + EXPECT_EQ("external", data[0]->install_location); } TEST_F(UpdateDataProviderTest, GetData_DisabledExtension_UnknownReason) { @@ -216,21 +217,21 @@ TEST_F(UpdateDataProviderTest, GetData_DisabledExtension_UnknownReason) { const std::string version = "0.1.2.3"; AddExtension(kExtensionId1, version, false, - disable_reason::DisableReason::DISABLE_REASON_LAST); + disable_reason::DisableReason::DISABLE_REASON_LAST, + Manifest::COMMAND_LINE); ExtensionUpdateDataMap update_data; update_data[kExtensionId1] = {}; - std::vector<std::string> ids({kExtensionId1}); - std::vector<update_client::CrxComponent> data; - data_provider->GetData(update_data, ids, &data); + const auto data = data_provider->GetData(update_data, {kExtensionId1}); ASSERT_EQ(1UL, data.size()); - EXPECT_EQ(version, data[0].version.GetString()); - EXPECT_NE(nullptr, data[0].installer.get()); - ASSERT_EQ(1UL, data[0].disabled_reasons.size()); + EXPECT_EQ(version, data[0]->version.GetString()); + EXPECT_NE(nullptr, data[0]->installer.get()); + ASSERT_EQ(1UL, data[0]->disabled_reasons.size()); EXPECT_EQ(disable_reason::DisableReason::DISABLE_NONE, - data[0].disabled_reasons[0]); + data[0]->disabled_reasons[0]); + EXPECT_EQ("other", data[0]->install_location); } TEST_F(UpdateDataProviderTest, GetData_DisabledExtension_WithReasons) { @@ -240,23 +241,23 @@ TEST_F(UpdateDataProviderTest, GetData_DisabledExtension_WithReasons) { const std::string version = "0.1.2.3"; AddExtension(kExtensionId1, version, false, disable_reason::DisableReason::DISABLE_USER_ACTION | - disable_reason::DisableReason::DISABLE_CORRUPTED); + disable_reason::DisableReason::DISABLE_CORRUPTED, + Manifest::EXTERNAL_POLICY_DOWNLOAD); ExtensionUpdateDataMap update_data; update_data[kExtensionId1] = {}; - std::vector<std::string> ids({kExtensionId1}); - std::vector<update_client::CrxComponent> data; - data_provider->GetData(update_data, ids, &data); + const auto data = data_provider->GetData(update_data, {kExtensionId1}); ASSERT_EQ(1UL, data.size()); - EXPECT_EQ(version, data[0].version.GetString()); - EXPECT_NE(nullptr, data[0].installer.get()); - ASSERT_EQ(2UL, data[0].disabled_reasons.size()); + EXPECT_EQ(version, data[0]->version.GetString()); + EXPECT_NE(nullptr, data[0]->installer.get()); + ASSERT_EQ(2UL, data[0]->disabled_reasons.size()); EXPECT_EQ(disable_reason::DisableReason::DISABLE_USER_ACTION, - data[0].disabled_reasons[0]); + data[0]->disabled_reasons[0]); EXPECT_EQ(disable_reason::DisableReason::DISABLE_CORRUPTED, - data[0].disabled_reasons[1]); + data[0]->disabled_reasons[1]); + EXPECT_EQ("policy", data[0]->install_location); } TEST_F(UpdateDataProviderTest, @@ -268,25 +269,25 @@ TEST_F(UpdateDataProviderTest, AddExtension(kExtensionId1, version, false, disable_reason::DisableReason::DISABLE_USER_ACTION | disable_reason::DisableReason::DISABLE_CORRUPTED | - disable_reason::DisableReason::DISABLE_REASON_LAST); + disable_reason::DisableReason::DISABLE_REASON_LAST, + Manifest::EXTERNAL_PREF_DOWNLOAD); ExtensionUpdateDataMap update_data; update_data[kExtensionId1] = {}; - std::vector<std::string> ids({kExtensionId1}); - std::vector<update_client::CrxComponent> data; - data_provider->GetData(update_data, ids, &data); + const auto data = data_provider->GetData(update_data, {kExtensionId1}); ASSERT_EQ(1UL, data.size()); - EXPECT_EQ(version, data[0].version.GetString()); - EXPECT_NE(nullptr, data[0].installer.get()); - ASSERT_EQ(3UL, data[0].disabled_reasons.size()); + EXPECT_EQ(version, data[0]->version.GetString()); + EXPECT_NE(nullptr, data[0]->installer.get()); + ASSERT_EQ(3UL, data[0]->disabled_reasons.size()); EXPECT_EQ(disable_reason::DisableReason::DISABLE_NONE, - data[0].disabled_reasons[0]); + data[0]->disabled_reasons[0]); EXPECT_EQ(disable_reason::DisableReason::DISABLE_USER_ACTION, - data[0].disabled_reasons[1]); + data[0]->disabled_reasons[1]); EXPECT_EQ(disable_reason::DisableReason::DISABLE_CORRUPTED, - data[0].disabled_reasons[2]); + data[0]->disabled_reasons[2]); + EXPECT_EQ("external", data[0]->install_location); } TEST_F(UpdateDataProviderTest, GetData_MultipleExtensions) { @@ -297,25 +298,27 @@ TEST_F(UpdateDataProviderTest, GetData_MultipleExtensions) { const std::string version1 = "0.1.2.3"; const std::string version2 = "9.8.7.6"; AddExtension(kExtensionId1, version1, true, - disable_reason::DisableReason::DISABLE_NONE); + disable_reason::DisableReason::DISABLE_NONE, + Manifest::EXTERNAL_REGISTRY); AddExtension(kExtensionId2, version2, true, - disable_reason::DisableReason::DISABLE_NONE); + disable_reason::DisableReason::DISABLE_NONE, Manifest::UNPACKED); ExtensionUpdateDataMap update_data; update_data[kExtensionId1] = {}; update_data[kExtensionId2] = {}; - std::vector<std::string> ids({kExtensionId1, kExtensionId2}); - std::vector<update_client::CrxComponent> data; - data_provider->GetData(update_data, ids, &data); + const auto data = + data_provider->GetData(update_data, {kExtensionId1, kExtensionId2}); ASSERT_EQ(2UL, data.size()); - EXPECT_EQ(version1, data[0].version.GetString()); - EXPECT_NE(nullptr, data[0].installer.get()); - EXPECT_EQ(0UL, data[0].disabled_reasons.size()); - EXPECT_EQ(version2, data[1].version.GetString()); - EXPECT_NE(nullptr, data[1].installer.get()); - EXPECT_EQ(0UL, data[1].disabled_reasons.size()); + EXPECT_EQ(version1, data[0]->version.GetString()); + EXPECT_NE(nullptr, data[0]->installer.get()); + EXPECT_EQ(0UL, data[0]->disabled_reasons.size()); + EXPECT_EQ("external", data[0]->install_location); + EXPECT_EQ(version2, data[1]->version.GetString()); + EXPECT_NE(nullptr, data[1]->installer.get()); + EXPECT_EQ(0UL, data[1]->disabled_reasons.size()); + EXPECT_EQ("other", data[1]->install_location); } TEST_F(UpdateDataProviderTest, GetData_MultipleExtensions_DisabledExtension) { @@ -326,28 +329,31 @@ TEST_F(UpdateDataProviderTest, GetData_MultipleExtensions_DisabledExtension) { const std::string version1 = "0.1.2.3"; const std::string version2 = "9.8.7.6"; AddExtension(kExtensionId1, version1, false, - disable_reason::DisableReason::DISABLE_CORRUPTED); + disable_reason::DisableReason::DISABLE_CORRUPTED, + Manifest::INTERNAL); AddExtension(kExtensionId2, version2, true, - disable_reason::DisableReason::DISABLE_NONE); + disable_reason::DisableReason::DISABLE_NONE, + Manifest::EXTERNAL_PREF_DOWNLOAD); ExtensionUpdateDataMap update_data; update_data[kExtensionId1] = {}; update_data[kExtensionId2] = {}; - std::vector<std::string> ids({kExtensionId1, kExtensionId2}); - std::vector<update_client::CrxComponent> data; - data_provider->GetData(update_data, ids, &data); + const auto data = + data_provider->GetData(update_data, {kExtensionId1, kExtensionId2}); ASSERT_EQ(2UL, data.size()); - EXPECT_EQ(version1, data[0].version.GetString()); - EXPECT_NE(nullptr, data[0].installer.get()); - ASSERT_EQ(1UL, data[0].disabled_reasons.size()); + EXPECT_EQ(version1, data[0]->version.GetString()); + EXPECT_NE(nullptr, data[0]->installer.get()); + ASSERT_EQ(1UL, data[0]->disabled_reasons.size()); EXPECT_EQ(disable_reason::DisableReason::DISABLE_CORRUPTED, - data[0].disabled_reasons[0]); + data[0]->disabled_reasons[0]); + EXPECT_EQ("internal", data[0]->install_location); - EXPECT_EQ(version2, data[1].version.GetString()); - EXPECT_NE(nullptr, data[1].installer.get()); - EXPECT_EQ(0UL, data[1].disabled_reasons.size()); + EXPECT_EQ(version2, data[1]->version.GetString()); + EXPECT_NE(nullptr, data[1]->installer.get()); + EXPECT_EQ(0UL, data[1]->disabled_reasons.size()); + EXPECT_EQ("external", data[1]->install_location); } TEST_F(UpdateDataProviderTest, @@ -358,20 +364,24 @@ TEST_F(UpdateDataProviderTest, const std::string version = "0.1.2.3"; AddExtension(kExtensionId1, version, true, - disable_reason::DisableReason::DISABLE_NONE); + disable_reason::DisableReason::DISABLE_NONE, + Manifest::COMPONENT); ExtensionUpdateDataMap update_data; update_data[kExtensionId1] = {}; update_data[kExtensionId2] = {}; - std::vector<std::string> ids({kExtensionId1, kExtensionId2}); - std::vector<update_client::CrxComponent> data; - data_provider->GetData(update_data, ids, &data); + const auto data = + data_provider->GetData(update_data, {kExtensionId1, kExtensionId2}); - ASSERT_EQ(1UL, data.size()); - EXPECT_EQ(version, data[0].version.GetString()); - EXPECT_NE(nullptr, data[0].installer.get()); - EXPECT_EQ(0UL, data[0].disabled_reasons.size()); + ASSERT_EQ(2UL, data.size()); + ASSERT_NE(nullptr, data[0]); + EXPECT_EQ(version, data[0]->version.GetString()); + EXPECT_NE(nullptr, data[0]->installer.get()); + EXPECT_EQ(0UL, data[0]->disabled_reasons.size()); + EXPECT_EQ("other", data[0]->install_location); + + EXPECT_EQ(nullptr, data[1]); } TEST_F(UpdateDataProviderTest, GetData_MultipleExtensions_CorruptExtension) { @@ -384,9 +394,11 @@ TEST_F(UpdateDataProviderTest, GetData_MultipleExtensions_CorruptExtension) { const std::string version2 = "9.8.7.6"; const std::string initial_version = "0.0.0.0"; AddExtension(kExtensionId1, version1, true, - disable_reason::DisableReason::DISABLE_NONE); + disable_reason::DisableReason::DISABLE_NONE, + Manifest::EXTERNAL_COMPONENT); AddExtension(kExtensionId2, version2, true, - disable_reason::DisableReason::DISABLE_NONE); + disable_reason::DisableReason::DISABLE_NONE, + Manifest::EXTERNAL_POLICY); ExtensionUpdateDataMap update_data; auto& info1 = update_data[kExtensionId1]; @@ -396,19 +408,20 @@ TEST_F(UpdateDataProviderTest, GetData_MultipleExtensions_CorruptExtension) { info2.is_corrupt_reinstall = true; info2.install_source = "sideload"; - std::vector<std::string> ids({kExtensionId1, kExtensionId2}); - std::vector<update_client::CrxComponent> data; - data_provider->GetData(update_data, ids, &data); + const auto data = + data_provider->GetData(update_data, {kExtensionId1, kExtensionId2}); ASSERT_EQ(2UL, data.size()); - EXPECT_EQ(version1, data[0].version.GetString()); - EXPECT_EQ("webstore", data[0].install_source); - EXPECT_NE(nullptr, data[0].installer.get()); - EXPECT_EQ(0UL, data[0].disabled_reasons.size()); - EXPECT_EQ(initial_version, data[1].version.GetString()); - EXPECT_EQ("sideload", data[1].install_source); - EXPECT_NE(nullptr, data[1].installer.get()); - EXPECT_EQ(0UL, data[1].disabled_reasons.size()); + EXPECT_EQ(version1, data[0]->version.GetString()); + EXPECT_EQ("webstore", data[0]->install_source); + EXPECT_EQ("other", data[0]->install_location); + EXPECT_NE(nullptr, data[0]->installer.get()); + EXPECT_EQ(0UL, data[0]->disabled_reasons.size()); + EXPECT_EQ(initial_version, data[1]->version.GetString()); + EXPECT_EQ("sideload", data[1]->install_source); + EXPECT_EQ("policy", data[1]->install_location); + EXPECT_NE(nullptr, data[1]->installer.get()); + EXPECT_EQ(0UL, data[1]->disabled_reasons.size()); } } // namespace diff --git a/chromium/extensions/browser/updater/update_service.cc b/chromium/extensions/browser/updater/update_service.cc index fd513ac785a..7c495aab218 100644 --- a/chromium/extensions/browser/updater/update_service.cc +++ b/chromium/extensions/browser/updater/update_service.cc @@ -30,6 +30,10 @@ namespace extensions { namespace { +// 98% of update checks have 20 or less extensions +// (see Extensions.UpdateCheckExtension histogram). +constexpr size_t kMaxExtensionsPerUpdate = 20; + void SendUninstallPingCompleteCallback(update_client::Error error) {} } // namespace @@ -54,7 +58,7 @@ void UpdateService::Shutdown() { update_data_provider_->Shutdown(); update_data_provider_ = nullptr; } - update_client_->RemoveObserver(this); + RemoveUpdateClientObserver(this); update_client_ = nullptr; browser_context_ = nullptr; } @@ -102,10 +106,40 @@ void UpdateService::OnEvent(Events event, const std::string& extension_id) { break; case Events::COMPONENT_UPDATE_ERROR: complete_event = true; - UMA_HISTOGRAM_ENUMERATION( - "Extensions.ExtensionUpdaterUpdateResults", - ExtensionUpdaterUpdateResult::UPDATE_ERROR, - ExtensionUpdaterUpdateResult::UPDATE_RESULT_COUNT); + { + update_client::CrxUpdateItem update_item; + if (!update_client_->GetCrxUpdateState(extension_id, &update_item)) { + NOTREACHED(); + } + switch (update_item.error_category) { + case update_client::ErrorCategory::kUpdateCheck: + UMA_HISTOGRAM_ENUMERATION( + "Extensions.ExtensionUpdaterUpdateResults", + ExtensionUpdaterUpdateResult::UPDATE_CHECK_ERROR, + ExtensionUpdaterUpdateResult::UPDATE_RESULT_COUNT); + break; + case update_client::ErrorCategory::kDownload: + UMA_HISTOGRAM_ENUMERATION( + "Extensions.ExtensionUpdaterUpdateResults", + ExtensionUpdaterUpdateResult::UPDATE_DOWNLOAD_ERROR, + ExtensionUpdaterUpdateResult::UPDATE_RESULT_COUNT); + break; + case update_client::ErrorCategory::kUnpack: + case update_client::ErrorCategory::kInstall: + UMA_HISTOGRAM_ENUMERATION( + "Extensions.ExtensionUpdaterUpdateResults", + ExtensionUpdaterUpdateResult::UPDATE_INSTALL_ERROR, + ExtensionUpdaterUpdateResult::UPDATE_RESULT_COUNT); + break; + case update_client::ErrorCategory::kNone: + case update_client::ErrorCategory::kService: + UMA_HISTOGRAM_ENUMERATION( + "Extensions.ExtensionUpdaterUpdateResults", + ExtensionUpdaterUpdateResult::UPDATE_SERVICE_ERROR, + ExtensionUpdaterUpdateResult::UPDATE_RESULT_COUNT); + break; + } + } break; case Events::COMPONENT_NOT_UPDATED: complete_event = true; @@ -123,15 +157,18 @@ void UpdateService::OnEvent(Events event, const std::string& extension_id) { case Events::COMPONENT_UPDATE_FOUND: { UMA_HISTOGRAM_COUNTS_100("Extensions.ExtensionUpdaterUpdateFoundCount", 1); - update_client::CrxUpdateItem update_item; - if (update_client_->GetCrxUpdateState(extension_id, &update_item)) { - VLOG(3) << "UpdateService::OnEvent COMPONENT_UPDATE_FOUND: " - << extension_id << " " << update_item.next_version.GetString(); - UpdateDetails update_info(extension_id, update_item.next_version); - content::NotificationService::current()->Notify( - extensions::NOTIFICATION_EXTENSION_UPDATE_FOUND, - content::NotificationService::AllBrowserContextsAndSources(), - content::Details<UpdateDetails>(&update_info)); + { + update_client::CrxUpdateItem update_item; + if (update_client_->GetCrxUpdateState(extension_id, &update_item)) { + VLOG(3) << "UpdateService::OnEvent COMPONENT_UPDATE_FOUND: " + << extension_id << " " + << update_item.next_version.GetString(); + UpdateDetails update_info(extension_id, update_item.next_version); + content::NotificationService::current()->Notify( + extensions::NOTIFICATION_EXTENSION_UPDATE_FOUND, + content::NotificationService::AllBrowserContextsAndSources(), + content::Details<UpdateDetails>(&update_info)); + } } break; } @@ -162,7 +199,7 @@ UpdateService::UpdateService( DCHECK(update_client_); update_data_provider_ = base::MakeRefCounted<UpdateDataProvider>(browser_context_); - update_client->AddObserver(this); + AddUpdateClientObserver(this); } UpdateService::~UpdateService() { @@ -189,10 +226,9 @@ void UpdateService::StartUpdateCheck( in_progress_updates_.push_back(InProgressUpdate(std::move(callback))); InProgressUpdate& update = in_progress_updates_.back(); + // |update_data| only store update info of extensions that are not being + // updated at the moment. ExtensionUpdateDataMap update_data; - // |extension_ids_to_update| stores the extension IDs from the new update - // check request that are not being updated at the moment. - std::vector<std::string> extension_ids_to_update; for (const auto& update_info : update_params.update_info) { const std::string& extension_id = update_info.first; @@ -201,7 +237,6 @@ void UpdateService::StartUpdateCheck( continue; updating_extension_ids_.insert(extension_id); - extension_ids_to_update.push_back(extension_id); ExtensionUpdateData data = update_info.second; if (data.is_corrupt_reinstall) { @@ -215,20 +250,31 @@ void UpdateService::StartUpdateCheck( } UMA_HISTOGRAM_COUNTS_100("Extensions.ExtensionUpdaterUpdateCalls", - extension_ids_to_update.size()); - - // If all extension IDs are being updated by previous update check requests, - // there's no need to update these extensions again. - if (extension_ids_to_update.empty()) - return; + update_data.size()); + + // Divide extensions into batches to reduce the size of update check + // requests generated by the update client. + for (auto it = update_data.begin(); it != update_data.end();) { + ExtensionUpdateDataMap batch_data; + size_t batch_size = + std::min(kMaxExtensionsPerUpdate, + static_cast<size_t>(std::distance(it, update_data.end()))); + + std::vector<std::string> batch_ids; + batch_ids.reserve(batch_size); + for (size_t i = 0; i < batch_size; ++i, ++it) { + batch_ids.push_back(it->first); + batch_data.emplace(it->first, std::move(it->second)); + } - update_client_->Update( - extension_ids_to_update, - base::BindOnce(&UpdateDataProvider::GetData, update_data_provider_, - std::move(update_data)), - update_params.priority == ExtensionUpdateCheckParams::FOREGROUND, - base::BindOnce(&UpdateService::UpdateCheckComplete, - weak_ptr_factory_.GetWeakPtr())); + update_client_->Update( + batch_ids, + base::BindOnce(&UpdateDataProvider::GetData, update_data_provider_, + std::move(batch_data)), + update_params.priority == ExtensionUpdateCheckParams::FOREGROUND, + base::BindOnce(&UpdateService::UpdateCheckComplete, + weak_ptr_factory_.GetWeakPtr())); + } } void UpdateService::UpdateCheckComplete(update_client::Error error) { @@ -238,8 +284,11 @@ void UpdateService::UpdateCheckComplete(update_client::Error error) { // There must be at least one in-progress update (the one that just // finished). DCHECK(!in_progress_updates_.empty()); - // And that the first update should have all of its pendings finished. - DCHECK(in_progress_updates_[0].pending_extension_ids.empty()); + + if (!in_progress_updates_[0].pending_extension_ids.empty()) { + // This can happen when the update check request is batched. + return; + } // Find all updates that have finished and remove them from the list. in_progress_updates_.erase( @@ -255,4 +304,16 @@ void UpdateService::UpdateCheckComplete(update_client::Error error) { in_progress_updates_.end()); } +void UpdateService::AddUpdateClientObserver( + update_client::UpdateClient::Observer* observer) { + if (update_client_) + update_client_->AddObserver(observer); +} + +void UpdateService::RemoveUpdateClientObserver( + update_client::UpdateClient::Observer* observer) { + if (update_client_) + update_client_->RemoveObserver(observer); +} + } // namespace extensions diff --git a/chromium/extensions/browser/updater/update_service.h b/chromium/extensions/browser/updater/update_service.h index 957d54470ec..08a32e8859f 100644 --- a/chromium/extensions/browser/updater/update_service.h +++ b/chromium/extensions/browser/updater/update_service.h @@ -33,9 +33,10 @@ class UpdateClient; namespace extensions { +class ExtensionUpdateClientBaseTest; +struct ExtensionUpdateCheckParams; class UpdateDataProvider; class UpdateServiceFactory; -struct ExtensionUpdateCheckParams; // This service manages the autoupdate of extensions. It should eventually // replace ExtensionUpdater in Chrome. @@ -62,10 +63,11 @@ class UpdateService : public KeyedService, // |extension_id|. bool CanUpdate(const std::string& extension_id) const; - // Overriden from update_client::UpdateClient::Observer. + // Overriden from |update_client::UpdateClient::Observer|. void OnEvent(Events event, const std::string& id) override; private: + friend class ExtensionUpdateClientBaseTest; friend class UpdateServiceFactory; friend std::unique_ptr<UpdateService>::deleter_type; @@ -91,6 +93,13 @@ class UpdateService : public KeyedService, std::set<std::string> pending_extension_ids; }; + // Adds/Removes observer to/from |update_client::UpdateClient|. + // Mainly used for browser tests. + void AddUpdateClientObserver(update_client::UpdateClient::Observer* observer); + void RemoveUpdateClientObserver( + update_client::UpdateClient::Observer* observer); + + private: content::BrowserContext* browser_context_; scoped_refptr<update_client::UpdateClient> update_client_; diff --git a/chromium/extensions/browser/updater/update_service_unittest.cc b/chromium/extensions/browser/updater/update_service_unittest.cc index ad80d16c0f9..ecfae44fba7 100644 --- a/chromium/extensions/browser/updater/update_service_unittest.cc +++ b/chromium/extensions/browser/updater/update_service_unittest.cc @@ -48,7 +48,9 @@ class FakeUpdateClient : public update_client::UpdateClient { // Returns the data we've gotten from the CrxDataCallback for ids passed to // the Update function. - std::vector<update_client::CrxComponent>* data() { return &data_; } + std::vector<std::unique_ptr<update_client::CrxComponent>>* data() { + return &data_; + } // Used for tests that uninstall pings get requested properly. struct UninstallPing { @@ -120,7 +122,7 @@ class FakeUpdateClient : public update_client::UpdateClient { friend class base::RefCounted<FakeUpdateClient>; ~FakeUpdateClient() override {} - std::vector<update_client::CrxComponent> data_; + std::vector<std::unique_ptr<update_client::CrxComponent>> data_; std::vector<UninstallPing> uninstall_pings_; std::vector<Observer*> observers_; @@ -137,7 +139,7 @@ void FakeUpdateClient::Update(const std::vector<std::string>& ids, CrxDataCallback crx_data_callback, bool is_foreground, update_client::Callback callback) { - std::move(crx_data_callback).Run(ids, &data_); + data_ = std::move(crx_data_callback).Run(ids); if (delay_update()) { delayed_requests_.push_back({ids, std::move(callback)}); @@ -235,7 +237,7 @@ class FakeExtensionSystem : public MockExtensionSystem { if (!next_install_callback_.is_null()) { std::move(next_install_callback_).Run(); } - std::move(install_update_callback).Run(true); + std::move(install_update_callback).Run(base::nullopt); } private: @@ -329,12 +331,12 @@ TEST_F(UpdateServiceTest, BasicUpdateOperations) { update_check_params, base::BindOnce([](bool* executed) { *executed = true; }, &executed)); ASSERT_TRUE(executed); - std::vector<update_client::CrxComponent>* data = update_client()->data(); + const auto* data = update_client()->data(); ASSERT_NE(nullptr, data); ASSERT_EQ(1u, data->size()); - ASSERT_EQ(data->at(0).version, extension1->version()); - update_client::CrxInstaller* installer = data->at(0).installer.get(); + ASSERT_EQ(data->at(0)->version, extension1->version()); + update_client::CrxInstaller* installer = data->at(0)->installer.get(); ASSERT_NE(installer, nullptr); // The GetInstalledFile method is used when processing differential updates @@ -393,17 +395,11 @@ TEST_F(UpdateServiceTest, UninstallPings) { // Build 3 extensions. scoped_refptr<Extension> extension1 = - ExtensionBuilder("1") - .MergeManifest(DictionaryBuilder().Set("version", "1.2").Build()) - .Build(); + ExtensionBuilder("1").SetManifestKey("version", "1.2").Build(); scoped_refptr<Extension> extension2 = - ExtensionBuilder("2") - .MergeManifest(DictionaryBuilder().Set("version", "2.3").Build()) - .Build(); + ExtensionBuilder("2").SetManifestKey("version", "2.3").Build(); scoped_refptr<Extension> extension3 = - ExtensionBuilder("3") - .MergeManifest(DictionaryBuilder().Set("version", "3.4").Build()) - .Build(); + ExtensionBuilder("3").SetManifestKey("version", "3.4").Build(); EXPECT_TRUE(extension1->id() != extension2->id() && extension1->id() != extension3->id() && extension2->id() != extension3->id()); @@ -480,7 +476,7 @@ TEST_F(UpdateServiceTest, InProgressUpdate_Successful) { base::BindOnce([](bool* executed) { *executed = true; }, &executed)); EXPECT_FALSE(executed); - auto& request = update_client()->update_request(0); + const auto& request = update_client()->update_request(0); EXPECT_THAT(request.extension_ids, testing::ElementsAre("A", "B", "C", "D", "E")); @@ -517,7 +513,7 @@ TEST_F(UpdateServiceTest, InProgressUpdate_Duplicate) { ASSERT_EQ(1, update_client()->num_update_requests()); - auto& request = update_client()->update_request(0); + const auto& request = update_client()->update_request(0); EXPECT_THAT(request.extension_ids, testing::ElementsAre("A", "B", "C", "D", "E")); @@ -551,8 +547,8 @@ TEST_F(UpdateServiceTest, InProgressUpdate_NonOverlapped) { EXPECT_FALSE(executed2); ASSERT_EQ(2, update_client()->num_update_requests()); - auto& request1 = update_client()->update_request(0); - auto& request2 = update_client()->update_request(1); + const auto& request1 = update_client()->update_request(0); + const auto& request2 = update_client()->update_request(1); EXPECT_THAT(request1.extension_ids, testing::ElementsAre("A", "B", "C")); EXPECT_THAT(request2.extension_ids, testing::ElementsAre("D", "E")); @@ -588,8 +584,8 @@ TEST_F(UpdateServiceTest, InProgressUpdate_Overlapped) { base::BindOnce([](bool* executed) { *executed = true; }, &executed2)); EXPECT_FALSE(executed2); - auto& request1 = update_client()->update_request(0); - auto& request2 = update_client()->update_request(1); + const auto& request1 = update_client()->update_request(0); + const auto& request2 = update_client()->update_request(1); EXPECT_THAT(request1.extension_ids, testing::ElementsAre("A", "B", "C")); EXPECT_THAT(request2.extension_ids, testing::ElementsAre("D")); @@ -641,8 +637,8 @@ TEST_F(UpdateServiceTest, InProgressUpdate_3Overlapped) { EXPECT_FALSE(executed3); ASSERT_EQ(2, update_client()->num_update_requests()); - auto& request1 = update_client()->update_request(0); - auto& request2 = update_client()->update_request(1); + const auto& request1 = update_client()->update_request(0); + const auto& request2 = update_client()->update_request(1); EXPECT_THAT(request1.extension_ids, testing::ElementsAre("A", "B", "C")); EXPECT_THAT(request2.extension_ids, testing::ElementsAre("D", "E")); @@ -707,9 +703,9 @@ TEST_F(UpdateServiceTest, InProgressUpdate_4Overlapped) { EXPECT_FALSE(executed4); ASSERT_EQ(3, update_client()->num_update_requests()); - auto& request1 = update_client()->update_request(0); - auto& request2 = update_client()->update_request(1); - auto& request3 = update_client()->update_request(2); + const auto& request1 = update_client()->update_request(0); + const auto& request2 = update_client()->update_request(1); + const auto& request3 = update_client()->update_request(2); EXPECT_THAT(request1.extension_ids, testing::ElementsAre("A", "B", "C")); EXPECT_THAT(request2.extension_ids, testing::ElementsAre("D", "E")); @@ -730,6 +726,113 @@ TEST_F(UpdateServiceTest, InProgressUpdate_4Overlapped) { ASSERT_TRUE(executed4); } +TEST_F(UpdateServiceTest, InProgressUpdate_Batch) { + // Verify that extensions are batched when the number of extensions exceeds + // 20. + update_client()->set_delay_update(); + ExtensionUpdateCheckParams uc; + + for (int i = 0; i < 50; ++i) + uc.update_info[base::StringPrintf("A%02d", i)] = ExtensionUpdateData(); + + bool executed = false; + update_service()->StartUpdateCheck( + uc, base::BindOnce([](bool* executed) { *executed = true; }, &executed)); + EXPECT_FALSE(executed); + + ASSERT_EQ(3, update_client()->num_update_requests()); + + const auto& request1 = update_client()->update_request(0); + const auto& request2 = update_client()->update_request(1); + const auto& request3 = update_client()->update_request(2); + + EXPECT_THAT( + request1.extension_ids, + testing::ElementsAre("A00", "A01", "A02", "A03", "A04", "A05", "A06", + "A07", "A08", "A09", "A10", "A11", "A12", "A13", + "A14", "A15", "A16", "A17", "A18", "A19")); + EXPECT_THAT( + request2.extension_ids, + testing::ElementsAre("A20", "A21", "A22", "A23", "A24", "A25", "A26", + "A27", "A28", "A29", "A30", "A31", "A32", "A33", + "A34", "A35", "A36", "A37", "A38", "A39")); + EXPECT_THAT(request3.extension_ids, + testing::ElementsAre("A40", "A41", "A42", "A43", "A44", "A45", + "A46", "A47", "A48", "A49")); + + update_client()->RunDelayedUpdate(0); + EXPECT_FALSE(executed); + + update_client()->RunDelayedUpdate(1); + EXPECT_FALSE(executed); + + update_client()->RunDelayedUpdate(2); + EXPECT_TRUE(executed); +} + +TEST_F(UpdateServiceTest, InProgressUpdate_NoBatchAndBatch) { + update_client()->set_delay_update(); + ExtensionUpdateCheckParams uc1; + ExtensionUpdateCheckParams uc2; + + uc1.update_info["AA"] = ExtensionUpdateData(); + uc1.update_info["BB"] = ExtensionUpdateData(); + uc1.update_info["CC"] = ExtensionUpdateData(); + uc1.update_info["DD"] = ExtensionUpdateData(); + + for (int i = 0; i < 50; ++i) + uc2.update_info[base::StringPrintf("A%02d", i)] = ExtensionUpdateData(); + + bool executed1 = false; + update_service()->StartUpdateCheck( + uc1, + base::BindOnce([](bool* executed) { *executed = true; }, &executed1)); + EXPECT_FALSE(executed1); + + bool executed2 = false; + update_service()->StartUpdateCheck( + uc2, + base::BindOnce([](bool* executed) { *executed = true; }, &executed2)); + EXPECT_FALSE(executed2); + + ASSERT_EQ(4, update_client()->num_update_requests()); + + const auto& request1 = update_client()->update_request(0); + const auto& request2 = update_client()->update_request(1); + const auto& request3 = update_client()->update_request(2); + const auto& request4 = update_client()->update_request(3); + + EXPECT_THAT(request1.extension_ids, + testing::ElementsAre("AA", "BB", "CC", "DD")); + + EXPECT_THAT( + request2.extension_ids, + testing::ElementsAre("A00", "A01", "A02", "A03", "A04", "A05", "A06", + "A07", "A08", "A09", "A10", "A11", "A12", "A13", + "A14", "A15", "A16", "A17", "A18", "A19")); + EXPECT_THAT( + request3.extension_ids, + testing::ElementsAre("A20", "A21", "A22", "A23", "A24", "A25", "A26", + "A27", "A28", "A29", "A30", "A31", "A32", "A33", + "A34", "A35", "A36", "A37", "A38", "A39")); + EXPECT_THAT(request4.extension_ids, + testing::ElementsAre("A40", "A41", "A42", "A43", "A44", "A45", + "A46", "A47", "A48", "A49")); + + update_client()->RunDelayedUpdate(0); + EXPECT_TRUE(executed1); + EXPECT_FALSE(executed2); + + update_client()->RunDelayedUpdate(1); + EXPECT_FALSE(executed2); + + update_client()->RunDelayedUpdate(2); + EXPECT_FALSE(executed2); + + update_client()->RunDelayedUpdate(3); + EXPECT_TRUE(executed2); +} + class UpdateServiceCanUpdateTest : public UpdateServiceTest, public ::testing::WithParamInterface<bool> { public: diff --git a/chromium/extensions/browser/user_script_loader.cc b/chromium/extensions/browser/user_script_loader.cc index 143b3ddeae1..0c584cd87a6 100644 --- a/chromium/extensions/browser/user_script_loader.cc +++ b/chromium/extensions/browser/user_script_loader.cc @@ -417,7 +417,7 @@ void UserScriptLoader::SendUpdate(content::RenderProcessHost* process, // If the process is being started asynchronously, early return. We'll end up // calling InitUserScripts when it's created which will call this again. - base::ProcessHandle handle = process->GetHandle(); + base::ProcessHandle handle = process->GetProcess().Handle(); if (!handle) return; diff --git a/chromium/extensions/browser/value_store/leveldb_value_store_unittest.cc b/chromium/extensions/browser/value_store/leveldb_value_store_unittest.cc index 53223c38fba..71f3f3da9c2 100644 --- a/chromium/extensions/browser/value_store/leveldb_value_store_unittest.cc +++ b/chromium/extensions/browser/value_store/leveldb_value_store_unittest.cc @@ -10,7 +10,6 @@ #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" #include "base/values.h" #include "content/public/test/test_browser_thread_bundle.h" #include "extensions/browser/value_store/leveldb_value_store.h" diff --git a/chromium/extensions/browser/value_store/value_store_frontend_unittest.cc b/chromium/extensions/browser/value_store/value_store_frontend_unittest.cc index 612889ddc48..71764252219 100644 --- a/chromium/extensions/browser/value_store/value_store_frontend_unittest.cc +++ b/chromium/extensions/browser/value_store/value_store_frontend_unittest.cc @@ -24,7 +24,8 @@ class ValueStoreFrontendTest : public testing::Test { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); base::FilePath test_data_dir; - ASSERT_TRUE(PathService::Get(extensions::DIR_TEST_DATA, &test_data_dir)); + ASSERT_TRUE( + base::PathService::Get(extensions::DIR_TEST_DATA, &test_data_dir)); base::FilePath src_db(test_data_dir.AppendASCII("value_store_db")); db_path_ = temp_dir_.GetPath().AppendASCII("temp_db"); base::CopyDirectory(src_db, db_path_, true); diff --git a/chromium/extensions/browser/verified_contents.cc b/chromium/extensions/browser/verified_contents.cc index bfe81ea90bd..ea6e9a49276 100644 --- a/chromium/extensions/browser/verified_contents.cc +++ b/chromium/extensions/browser/verified_contents.cc @@ -62,10 +62,8 @@ const DictionaryValue* FindDictionaryWithValue(const ListValue* list, namespace extensions { -VerifiedContents::VerifiedContents(const uint8_t* public_key, - size_t public_key_size) +VerifiedContents::VerifiedContents(base::span<const uint8_t> public_key) : public_key_(public_key), - public_key_size_(public_key_size), valid_signature_(false), // Guilty until proven innocent. block_size_(0) {} @@ -301,22 +299,18 @@ bool VerifiedContents::VerifySignature(const std::string& protected_value, crypto::SignatureVerifier signature_verifier; if (!signature_verifier.VerifyInit( crypto::SignatureVerifier::RSA_PKCS1_SHA256, - reinterpret_cast<const uint8_t*>(signature_bytes.data()), - signature_bytes.size(), public_key_, public_key_size_)) { + base::as_bytes(base::make_span(signature_bytes)), public_key_)) { VLOG(1) << "Could not verify signature - VerifyInit failure"; return false; } signature_verifier.VerifyUpdate( - reinterpret_cast<const uint8_t*>(protected_value.data()), - protected_value.size()); + base::as_bytes(base::make_span(protected_value))); std::string dot("."); - signature_verifier.VerifyUpdate(reinterpret_cast<const uint8_t*>(dot.data()), - dot.size()); + signature_verifier.VerifyUpdate(base::as_bytes(base::make_span(dot))); - signature_verifier.VerifyUpdate( - reinterpret_cast<const uint8_t*>(payload.data()), payload.size()); + signature_verifier.VerifyUpdate(base::as_bytes(base::make_span(payload))); if (!signature_verifier.VerifyFinal()) { VLOG(1) << "Could not verify signature - VerifyFinal failure"; diff --git a/chromium/extensions/browser/verified_contents.h b/chromium/extensions/browser/verified_contents.h index 6a4497221b8..4dd9ddb096e 100644 --- a/chromium/extensions/browser/verified_contents.h +++ b/chromium/extensions/browser/verified_contents.h @@ -11,6 +11,7 @@ #include <string> #include <vector> +#include "base/containers/span.h" #include "base/files/file_path.h" #include "base/macros.h" #include "base/version.h" @@ -24,7 +25,7 @@ namespace extensions { class VerifiedContents { public: // Note: the public_key must remain valid for the lifetime of this object. - VerifiedContents(const uint8_t* public_key, size_t public_key_size); + explicit VerifiedContents(base::span<const uint8_t> public_key); ~VerifiedContents(); // Returns true if we successfully parsed the verified_contents.json file at @@ -58,8 +59,7 @@ class VerifiedContents { const std::string& signature_bytes); // The public key we should use for signature verification. - const uint8_t* public_key_; - const size_t public_key_size_; + base::span<const uint8_t> public_key_; // Indicates whether the signature was successfully validated or not. bool valid_signature_; diff --git a/chromium/extensions/browser/verified_contents_unittest.cc b/chromium/extensions/browser/verified_contents_unittest.cc index ab8dfbbbe89..2995f1cefc6 100644 --- a/chromium/extensions/browser/verified_contents_unittest.cc +++ b/chromium/extensions/browser/verified_contents_unittest.cc @@ -47,14 +47,13 @@ bool GetPublicKey(const base::FilePath& path, std::string* public_key) { TEST(VerifiedContents, Simple) { // Figure out our test data directory. base::FilePath path; - PathService::Get(DIR_TEST_DATA, &path); + base::PathService::Get(DIR_TEST_DATA, &path); path = path.AppendASCII(kContentVerifierDirectory); // Initialize the VerifiedContents object. std::string public_key; ASSERT_TRUE(GetPublicKey(path.AppendASCII(kPublicKeyPem), &public_key)); - VerifiedContents contents(reinterpret_cast<const uint8_t*>(public_key.data()), - public_key.size()); + VerifiedContents contents(base::as_bytes(base::make_span(public_key))); base::FilePath verified_contents_path = path.AppendASCII("verified_contents.json"); @@ -141,14 +140,13 @@ TEST(VerifiedContents, FailsOnBase64) { // will be considered to be invalid data. Verify that it gets rejected. base::FilePath path; - PathService::Get(DIR_TEST_DATA, &path); + base::PathService::Get(DIR_TEST_DATA, &path); path = path.AppendASCII(kContentVerifierDirectory); // Initialize the VerifiedContents object. std::string public_key; ASSERT_TRUE(GetPublicKey(path.AppendASCII(kPublicKeyPem), &public_key)); - VerifiedContents contents(reinterpret_cast<const uint8_t*>(public_key.data()), - public_key.size()); + VerifiedContents contents(base::as_bytes(base::make_span(public_key))); base::FilePath verified_contents_path = path.AppendASCII("verified_contents_base64.json"); |
