diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2022-11-14 16:01:54 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2022-12-04 10:35:43 +0100 |
commit | 185a273ea69a355e3e8d4122512daf4bb12cb4c9 (patch) | |
tree | f36ddc3d8245e6113645c5118737879700dfa624 /src | |
parent | 83e21a1bf821408f189dc2495e39df338525a302 (diff) |
Add Support for Client Hints Headers
[ChangeLog][WebEngineCore] Client hint headers now added to HTTP
requests
Fixes: QTBUG-107451
Change-Id: I450fe1fe782b702fc81a3d90c82c0ece6a19ea45
Reviewed-by: Michal Klocek <michal.klocek@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/core/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/core/client_hints.cpp | 164 | ||||
-rw-r--r-- | src/core/client_hints.h | 94 | ||||
-rw-r--r-- | src/core/profile_qt.cpp | 3 |
4 files changed, 261 insertions, 1 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index dfbdb7a61..80cfb902c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -90,6 +90,7 @@ foreach(arch ${archs}) certificate_error_controller.cpp certificate_error_controller.h chromium_overrides.cpp client_cert_select_controller.cpp client_cert_select_controller.h + client_hints.cpp client_hints.h clipboard_change_observer.h clipboard_qt.cpp clipboard_qt.h color_chooser_controller.cpp color_chooser_controller.h color_chooser_controller_p.h diff --git a/src/core/client_hints.cpp b/src/core/client_hints.cpp new file mode 100644 index 000000000..f80fa5797 --- /dev/null +++ b/src/core/client_hints.cpp @@ -0,0 +1,164 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +#include "client_hints.h" + +#include "web_contents_delegate_qt.h" +#include "web_engine_settings.h" + +#include "components/embedder_support/user_agent_utils.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "content/public/browser/network_service_instance.h" +#include "extensions/buildflags/buildflags.h" +#include "services/network/public/cpp/is_potentially_trustworthy.h" +#include "services/network/public/cpp/network_quality_tracker.h" + +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "components/guest_view/browser/guest_view_base.h" +#endif + +namespace QtWebEngineCore { + +// based on weblayer/browser/client_hints_factory.cc: +// Copyright 2020 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. + +// static +ClientHints *ClientHintsFactory::GetForBrowserContext(content::BrowserContext *browser_context) +{ + return static_cast<ClientHints*>(GetInstance()->GetServiceForBrowserContext(browser_context, true)); +} + +// static +ClientHintsFactory *ClientHintsFactory::GetInstance() +{ + static base::NoDestructor<ClientHintsFactory> factory; + return factory.get(); +} + +ClientHintsFactory::ClientHintsFactory() + : BrowserContextKeyedServiceFactory("ClientHints", BrowserContextDependencyManager::GetInstance()) +{ +} + +ClientHintsFactory::~ClientHintsFactory() = default; + +KeyedService *ClientHintsFactory::BuildServiceInstanceFor(content::BrowserContext *context) const +{ + return new ClientHints(context); +} + +content::BrowserContext *ClientHintsFactory::GetBrowserContextToUse(content::BrowserContext *context) const +{ + return context; +} + +// based on components/client_hints/browser/in_memory_client_hints_controller_delegate.cc: +// Copyright 2022 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. + +ClientHints::ClientHints(content::BrowserContext *context) +{ +} + +ClientHints::~ClientHints() = default; + +// Enabled Client Hints are only cached and not persisted in this +// implementation. +void ClientHints::PersistClientHints(const url::Origin &primary_origin, + content::RenderFrameHost *parent_rfh, + const std::vector<network::mojom::WebClientHintsType> &client_hints) +{ + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + const GURL primary_url = primary_origin.GetURL(); + DCHECK(primary_url.is_valid()); + if (!network::IsUrlPotentiallyTrustworthy(primary_url)) + return; + + // Client hints should only be enabled when JavaScript is enabled. + if (!IsJavaScriptAllowed(primary_url, parent_rfh)) + return; + + blink::EnabledClientHints enabled_hints; + for (auto hint : client_hints) { + enabled_hints.SetIsEnabled(hint, true); + } + accept_ch_cache_[primary_origin] = enabled_hints; +} + +// Looks up enabled Client Hints for the URL origin, and adds additional Client +// Hints if set. +void ClientHints::GetAllowedClientHintsFromSource(const url::Origin &origin, + blink::EnabledClientHints *client_hints) +{ + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(client_hints); + // Can not assert this, as we get here for unregistered custom schemes: + if (!network::IsOriginPotentiallyTrustworthy(origin)) + return; + + const auto &it = accept_ch_cache_.find(origin); + if (it != accept_ch_cache_.end()) { + *client_hints = it->second; + } + + for (auto hint : additional_hints_) + client_hints->SetIsEnabled(hint, true); +} + +void ClientHints::SetAdditionalClientHints(const std::vector<network::mojom::WebClientHintsType> &hints) +{ + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + additional_hints_ = hints; +} + +void ClientHints::ClearAdditionalClientHints() +{ + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + additional_hints_.clear(); +} + +network::NetworkQualityTracker *ClientHints::GetNetworkQualityTracker() +{ + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!network_quality_tracker_) { + network_quality_tracker_ = + std::make_unique<network::NetworkQualityTracker>( + base::BindRepeating(&content::GetNetworkService)); + } + return network_quality_tracker_.get(); +} + +bool ClientHints::IsJavaScriptAllowed(const GURL &url, content::RenderFrameHost *parent_rfh) +{ + content::WebContents *webContents = content::WebContents::FromRenderFrameHost(parent_rfh); + +#if BUILDFLAG(ENABLE_EXTENSIONS) + if (webContents && guest_view::GuestViewBase::IsGuest(webContents)) + webContents = guest_view::GuestViewBase::GetTopLevelWebContents(webContents); +#endif + + if (webContents) { + WebContentsDelegateQt* delegate = + static_cast<WebContentsDelegateQt*>(webContents->GetDelegate()); + if (delegate) { + WebEngineSettings *settings = delegate->webEngineSettings(); + if (settings) + return settings->testAttribute(QWebEngineSettings::JavascriptEnabled); + } + } + return true; +} + +bool ClientHints::AreThirdPartyCookiesBlocked(const GURL &url) +{ + return false; // we probably can not report anything more specific +} + +blink::UserAgentMetadata ClientHints::GetUserAgentMetadata() +{ + return embedder_support::GetUserAgentMetadata(); +} + +} // namespace diff --git a/src/core/client_hints.h b/src/core/client_hints.h new file mode 100644 index 000000000..841f41993 --- /dev/null +++ b/src/core/client_hints.h @@ -0,0 +1,94 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef CLIENT_HINTS_H_ +#define CLIENT_HINTS_H_ + +// based on components/client_hints/browser/client_hints.h: +// Copyright 2017 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/memory/raw_ptr.h" +#include "base/no_destructor.h" +#include "base/sequence_checker.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" +#include "components/keyed_service/core/keyed_service.h" +#include "content/public/browser/client_hints_controller_delegate.h" +#include "third_party/blink/public/common/user_agent/user_agent_metadata.h" + +namespace QtWebEngineCore { + +class ClientHints; + +class ClientHintsFactory : public BrowserContextKeyedServiceFactory +{ +public: + ClientHintsFactory(const ClientHintsFactory &) = delete; + ClientHintsFactory &operator=(const ClientHintsFactory &) = delete; + + static ClientHints *GetForBrowserContext(content::BrowserContext *browser_context); + static ClientHintsFactory *GetInstance(); + +private: + friend class base::NoDestructor<ClientHintsFactory>; + + ClientHintsFactory(); + ~ClientHintsFactory() override; + + // BrowserContextKeyedServiceFactory methods: + KeyedService *BuildServiceInstanceFor(content::BrowserContext *profile) const override; + content::BrowserContext *GetBrowserContextToUse(content::BrowserContext *context) const override; +}; + +class ClientHints : public KeyedService, public content::ClientHintsControllerDelegate +{ +public: + ClientHints(content::BrowserContext *context); + + ClientHints(const ClientHints &) = delete; + ClientHints &operator=(const ClientHints &) = delete; + + ~ClientHints() override; + + // content::ClientHintsControllerDelegate: + network::NetworkQualityTracker *GetNetworkQualityTracker() override; + + void GetAllowedClientHintsFromSource(const url::Origin &origin, blink::EnabledClientHints *client_hints) override; + + bool IsJavaScriptAllowed(const GURL &url, content::RenderFrameHost *parent_rfh) override; + + bool AreThirdPartyCookiesBlocked(const GURL &url) override; + + blink::UserAgentMetadata GetUserAgentMetadata() override; + + void PersistClientHints(const url::Origin &primary_origin, + content::RenderFrameHost *parent_rfh, + const std::vector<network::mojom::WebClientHintsType> &client_hints) override; + + void SetAdditionalClientHints(const std::vector<network::mojom::WebClientHintsType> &) override; + + void ClearAdditionalClientHints() override; + +private: + SEQUENCE_CHECKER(sequence_checker_); + + raw_ptr<content::BrowserContext> context_ = nullptr; + + // Stores enabled Client Hint types for an origin. + std::map<url::Origin, blink::EnabledClientHints> accept_ch_cache_ + GUARDED_BY_CONTEXT(sequence_checker_); + + // Additional Client Hint types for Client Hints Reliability. If additional + // hints are set, they would be included by subsequent calls to + // GetAllowedClientHintsFromSource. + std::vector<network::mojom::WebClientHintsType> additional_hints_ + GUARDED_BY_CONTEXT(sequence_checker_); + + std::unique_ptr<network::NetworkQualityTracker> network_quality_tracker_ + GUARDED_BY_CONTEXT(sequence_checker_); +}; + +} // namespace QtWebEngineCore + +#endif diff --git a/src/core/profile_qt.cpp b/src/core/profile_qt.cpp index 1e35f6966..b1db2a2ce 100644 --- a/src/core/profile_qt.cpp +++ b/src/core/profile_qt.cpp @@ -5,6 +5,7 @@ #include "profile_adapter.h" #include "browsing_data_remover_delegate_qt.h" +#include "client_hints.h" #include "download_manager_delegate_qt.h" #include "file_system_access/file_system_access_permission_context_factory_qt.h" #include "net/ssl_host_state_delegate_qt.h" @@ -209,7 +210,7 @@ content::PermissionControllerDelegate *ProfileQt::GetPermissionControllerDelegat content::ClientHintsControllerDelegate *ProfileQt::GetClientHintsControllerDelegate() { - return nullptr; + return ClientHintsFactory::GetForBrowserContext(this); } content::StorageNotificationService *ProfileQt::GetStorageNotificationService() |