diff options
Diffstat (limited to 'src/core/profile_adapter.cpp')
-rw-r--r-- | src/core/profile_adapter.cpp | 637 |
1 files changed, 475 insertions, 162 deletions
diff --git a/src/core/profile_adapter.cpp b/src/core/profile_adapter.cpp index b04fa0d46..b26f9b1de 100644 --- a/src/core/profile_adapter.cpp +++ b/src/core/profile_adapter.cpp @@ -1,65 +1,47 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 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 "profile_adapter.h" +#include "base/files/file_util.h" +#include "base/task/cancelable_task_tracker.h" +#include "base/threading/thread_restrictions.h" +#include "base/time/time_to_iso8601.h" +#include "components/embedder_support/user_agent_utils.h" +#include "components/favicon/core/favicon_service.h" +#include "components/history/content/browser/history_database_helper.h" +#include "components/history/core/browser/history_database_params.h" +#include "components/history/core/browser/history_service.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/browsing_data_remover.h" #include "content/public/browser/download_manager.h" +#include "content/public/browser/storage_partition.h" +#include "services/network/public/mojom/network_context.mojom.h" +#include "url/url_util.h" #include "api/qwebengineurlscheme.h" -#include "content_client_qt.h" +#include "content_browser_client_qt.h" #include "download_manager_delegate_qt.h" -#include "net/url_request_context_getter_qt.h" +#include "favicon_service_factory_qt.h" #include "permission_manager_qt.h" +#include "profile_adapter_client.h" +#include "profile_io_data_qt.h" #include "profile_qt.h" #include "renderer_host/user_resource_controller_host.h" #include "type_conversion.h" #include "visited_links_manager_qt.h" -#include "web_engine_context.h" #include "web_contents_adapter_client.h" +#include "web_engine_context.h" -#include "components/keyed_service/content/browser_context_dependency_manager.h" +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "extensions/browser/extension_system.h" +#endif #include <QCoreApplication> #include <QDir> +#include <QJsonObject> +#include <QSet> #include <QString> #include <QStandardPaths> @@ -79,29 +61,45 @@ namespace QtWebEngineCore { ProfileAdapter::ProfileAdapter(const QString &storageName): m_name(storageName) , m_offTheRecord(storageName.isEmpty()) + , m_downloadPath(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation)) , m_httpCacheType(DiskHttpCache) , m_persistentCookiesPolicy(AllowPersistentCookies) , m_visitedLinksPolicy(TrackVisitedLinksOnDisk) + , m_clientHintsEnabled(true) + , m_pushServiceEnabled(false) , m_httpCacheMaxSize(0) { WebEngineContext::current()->addProfileAdapter(this); // creation of profile requires webengine context m_profile.reset(new ProfileQt(this)); - content::BrowserContext::Initialize(m_profile.data(), toFilePath(dataPath())); // fixme: this should not be here m_profile->m_profileIOData->initializeOnUIThread(); + m_customUrlSchemeHandlers.insert(QByteArrayLiteral("qrc"), &m_qrcHandler); +#if BUILDFLAG(ENABLE_EXTENSIONS) + if (!storageName.isEmpty()) + extensions::ExtensionSystem::Get(m_profile.data())->InitForRegularProfile(true); +#endif + m_cancelableTaskTracker.reset(new base::CancelableTaskTracker()); + + m_profile->DoFinalInit(); } ProfileAdapter::~ProfileAdapter() { - while (!m_webContentsAdapterClients.isEmpty()) { - m_webContentsAdapterClients.first()->releaseProfile(); - } + m_cancelableTaskTracker->TryCancelAll(); + m_profile->NotifyWillBeDestroyed(); + releaseAllWebContentsAdapterClients(); + WebEngineContext::current()->removeProfileAdapter(this); if (m_downloadManagerDelegate) { - m_profile->GetDownloadManager(m_profile.data())->Shutdown(); + m_profile->GetDownloadManager()->Shutdown(); m_downloadManagerDelegate.reset(); } +#if QT_CONFIG(ssl) + delete m_clientCertificateStore; + m_clientCertificateStore = nullptr; +#endif + WebEngineContext::flushMessages(); } void ProfileAdapter::setStorageName(const QString &storageName) @@ -110,10 +108,13 @@ void ProfileAdapter::setStorageName(const QString &storageName) return; m_name = storageName; if (!m_offTheRecord) { - if (m_profile->m_urlRequestContextGetter.get()) - m_profile->m_profileIOData->updateStorageSettings(); + m_profile->setupPrefService(); + if (!m_profile->m_profileIOData->isClearHttpCacheInProgress()) + m_profile->m_profileIOData->resetNetworkContext(); if (m_visitedLinksManager) resetVisitedLinksManager(); + + reinitializeHistoryService(); } } @@ -122,10 +123,19 @@ void ProfileAdapter::setOffTheRecord(bool offTheRecord) if (offTheRecord == m_offTheRecord) return; m_offTheRecord = offTheRecord; - if (m_profile->m_urlRequestContextGetter.get()) - m_profile->m_profileIOData->updateStorageSettings(); + m_profile->setupPrefService(); + if (!m_profile->m_profileIOData->isClearHttpCacheInProgress()) + m_profile->m_profileIOData->resetNetworkContext(); if (m_visitedLinksManager) resetVisitedLinksManager(); + + if (offTheRecord) { + favicon::FaviconService *faviconService = + FaviconServiceFactoryQt::GetForBrowserContext(m_profile.data()); + faviconService->SetHistoryService(nullptr); + } else if (!m_name.isEmpty()) { + reinitializeHistoryService(); + } } ProfileQt *ProfileAdapter::profile() @@ -133,6 +143,26 @@ ProfileQt *ProfileAdapter::profile() return m_profile.data(); } +bool ProfileAdapter::ensureDataPathExists() +{ + Q_ASSERT(!m_offTheRecord); + base::ScopedAllowBlocking allowBlock; + const base::FilePath &path = toFilePath(dataPath()); + if (path.empty()) + return false; + if (base::DirectoryExists(path)) + return true; + + base::File::Error error; + if (base::CreateDirectoryAndGetError(path, &error)) + return true; + + std::string errorstr = base::File::ErrorToString(error); + qWarning("Cannot create directory %s. Error: %s.", path.AsUTF8Unsafe().c_str(), + errorstr.c_str()); + return false; +} + VisitedLinksManagerQt *ProfileAdapter::visitedLinksManager() { if (!m_visitedLinksManager) @@ -161,11 +191,7 @@ QWebEngineUrlRequestInterceptor *ProfileAdapter::requestInterceptor() void ProfileAdapter::setRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor) { - if (m_requestInterceptor == interceptor) - return; m_requestInterceptor = interceptor; - if (m_profile->m_urlRequestContextGetter.get()) - m_profile->m_profileIOData->updateRequestInterceptor(); } void ProfileAdapter::addClient(ProfileAdapterClient *adapterClient) @@ -178,9 +204,9 @@ void ProfileAdapter::removeClient(ProfileAdapterClient *adapterClient) m_clients.removeOne(adapterClient); } -void ProfileAdapter::cancelDownload(quint32 downloadId) +bool ProfileAdapter::cancelDownload(quint32 downloadId) { - downloadManagerDelegate()->cancelDownload(downloadId); + return downloadManagerDelegate()->cancelDownload(downloadId); } void ProfileAdapter::pauseDownload(quint32 downloadId) @@ -216,13 +242,17 @@ QObject* ProfileAdapter::globalQObjectRoot() QString ProfileAdapter::dataPath() const { - if (m_offTheRecord) - return QString(); if (!m_dataPath.isEmpty()) return m_dataPath; - if (!m_name.isNull()) - return buildLocationFromStandardPath(QStandardPaths::writableLocation(QStandardPaths::DataLocation), m_name); - return QString(); + // And off-the-record or memory-only profile should not write to disk + // but Chromium often creates temporary directories anyway, so given them + // a location to do so. + QString name = m_name; + if (m_offTheRecord) + name = QStringLiteral("OffTheRecord"); + else if (m_name.isEmpty()) + name = QStringLiteral("UnknownProfile"); + return buildLocationFromStandardPath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation), name); } void ProfileAdapter::setDataPath(const QString &path) @@ -230,12 +260,19 @@ void ProfileAdapter::setDataPath(const QString &path) if (m_dataPath == path) return; m_dataPath = path; - if (!m_offTheRecord) { - if (m_profile->m_urlRequestContextGetter.get()) - m_profile->m_profileIOData->updateStorageSettings(); - if (m_visitedLinksManager) - resetVisitedLinksManager(); - } + m_profile->setupPrefService(); + if (!m_profile->m_profileIOData->isClearHttpCacheInProgress()) + m_profile->m_profileIOData->resetNetworkContext(); + if (!m_offTheRecord && m_visitedLinksManager) + resetVisitedLinksManager(); + + if (!m_offTheRecord) + reinitializeHistoryService(); +} + +void ProfileAdapter::setDownloadPath(const QString &path) +{ + m_downloadPath = path.isEmpty() ? QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) : path; } QString ProfileAdapter::cachePath() const @@ -254,33 +291,8 @@ void ProfileAdapter::setCachePath(const QString &path) if (m_cachePath == path) return; m_cachePath = path; - if (!m_offTheRecord && m_profile->m_urlRequestContextGetter.get()) - m_profile->m_profileIOData->updateHttpCache(); -} - -QString ProfileAdapter::cookiesPath() const -{ - if (m_offTheRecord) - return QString(); - QString basePath = dataPath(); - if (!basePath.isEmpty()) { - // This is a typo fix. We still need the old path in order to avoid breaking migration. - QDir coookiesFolder(basePath % QLatin1String("/Coookies")); - if (coookiesFolder.exists()) - return coookiesFolder.path(); - return basePath % QLatin1String("/Cookies"); - } - return QString(); -} - -QString ProfileAdapter::channelIdPath() const -{ - if (m_offTheRecord) - return QString(); - QString basePath = dataPath(); - if (!basePath.isEmpty()) - return basePath % QLatin1String("/Origin Bound Certs"); - return QString(); + if (!m_offTheRecord && !m_profile->m_profileIOData->isClearHttpCacheInProgress()) + m_profile->m_profileIOData->resetNetworkContext(); } QString ProfileAdapter::httpCachePath() const @@ -296,23 +308,30 @@ QString ProfileAdapter::httpCachePath() const QString ProfileAdapter::httpUserAgent() const { if (m_httpUserAgent.isNull()) - return QString::fromStdString(ContentClientQt::getUserAgent()); + return QString::fromStdString(ContentBrowserClientQt::getUserAgent()); return m_httpUserAgent; } void ProfileAdapter::setHttpUserAgent(const QString &userAgent) { - if (m_httpUserAgent == userAgent) + const QString httpUserAgent = userAgent.simplified(); + if (m_httpUserAgent == httpUserAgent) return; - m_httpUserAgent = userAgent.simplified(); + m_httpUserAgent = httpUserAgent; + const std::string stdUserAgent = httpUserAgent.toStdString(); std::vector<content::WebContentsImpl *> list = content::WebContentsImpl::GetAllWebContents(); for (content::WebContentsImpl *web_contents : list) - if (web_contents->GetBrowserContext() == m_profile.data()) - web_contents->SetUserAgentOverride(m_httpUserAgent.toStdString(), true); + if (web_contents->GetBrowserContext() == m_profile.data()) { + auto userAgentOverride = blink::UserAgentOverride::UserAgentOnly(stdUserAgent); + userAgentOverride.ua_metadata_override = m_profile->m_userAgentMetadata; + web_contents->SetUserAgentOverride(userAgentOverride, true); + } - if (m_profile->m_urlRequestContextGetter.get()) - m_profile->m_profileIOData->updateUserAgent(); + m_profile->ForEachLoadedStoragePartition( + base::BindRepeating([](const std::string &user_agent, content::StoragePartition *storage_partition) { + storage_partition->GetNetworkContext()->SetUserAgent(user_agent); + }, stdUserAgent)); } ProfileAdapter::HttpCacheType ProfileAdapter::httpCacheType() const @@ -330,13 +349,14 @@ void ProfileAdapter::setHttpCacheType(ProfileAdapter::HttpCacheType newhttpCache m_httpCacheType = newhttpCacheType; if (oldCacheType == httpCacheType()) return; - if (!m_offTheRecord && m_profile->m_urlRequestContextGetter.get()) - m_profile->m_profileIOData->updateHttpCache(); + if (!m_offTheRecord && !m_profile->m_profileIOData->isClearHttpCacheInProgress()) { + m_profile->m_profileIOData->resetNetworkContext(); + } } ProfileAdapter::PersistentCookiesPolicy ProfileAdapter::persistentCookiesPolicy() const { - if (isOffTheRecord() || cookiesPath().isEmpty()) + if (isOffTheRecord() || m_name.isEmpty()) return NoPersistentCookies; return m_persistentCookiesPolicy; } @@ -347,15 +367,15 @@ void ProfileAdapter::setPersistentCookiesPolicy(ProfileAdapter::PersistentCookie m_persistentCookiesPolicy = newPersistentCookiesPolicy; if (oldPolicy == persistentCookiesPolicy()) return; - if (!m_offTheRecord && m_profile->m_urlRequestContextGetter.get()) - m_profile->m_profileIOData->updateCookieStore(); + if (!m_offTheRecord && !m_profile->m_profileIOData->isClearHttpCacheInProgress()) + m_profile->m_profileIOData->resetNetworkContext(); } ProfileAdapter::VisitedLinksPolicy ProfileAdapter::visitedLinksPolicy() const { if (isOffTheRecord() || m_visitedLinksPolicy == DoNotTrackVisitedLinks) return DoNotTrackVisitedLinks; - if (dataPath().isEmpty()) + if (m_name.isEmpty()) return TrackVisitedLinksInMemory; return m_visitedLinksPolicy; } @@ -402,13 +422,43 @@ void ProfileAdapter::setHttpCacheMaxSize(int maxSize) if (m_httpCacheMaxSize == maxSize) return; m_httpCacheMaxSize = maxSize; - if (!m_offTheRecord && m_profile->m_urlRequestContextGetter.get()) - m_profile->m_profileIOData->updateHttpCache(); + if (!m_offTheRecord && !m_profile->m_profileIOData->isClearHttpCacheInProgress()) + m_profile->m_profileIOData->resetNetworkContext(); +} + +enum class SchemeType { Protected, Overridable, Custom, Unknown }; +static SchemeType schemeType(const QByteArray &canonicalScheme) +{ + static const QSet<QByteArray> blacklist{ + QByteArrayLiteral("about"), + QByteArrayLiteral("blob"), + QByteArrayLiteral("data"), + QByteArrayLiteral("javascript"), + QByteArrayLiteral("qrc"), + // See also kStandardURLSchemes in url/url_util.cc (through url::IsStandard below) + }; + + static const QSet<QByteArray> whitelist{ + QByteArrayLiteral("gopher"), + }; + + bool standardSyntax = url::IsStandard(canonicalScheme.data(), url::Component(0, canonicalScheme.size())); + bool customScheme = QWebEngineUrlScheme::schemeByName(canonicalScheme) != QWebEngineUrlScheme(); + bool blacklisted = blacklist.contains(canonicalScheme); + bool whitelisted = whitelist.contains(canonicalScheme); + + if (whitelisted) + return SchemeType::Overridable; + if (blacklisted || (standardSyntax && !customScheme)) + return SchemeType::Protected; + if (customScheme) + return SchemeType::Custom; + return SchemeType::Unknown; } -const QHash<QByteArray, QWebEngineUrlSchemeHandler *> &ProfileAdapter::customUrlSchemeHandlers() const +QWebEngineUrlSchemeHandler *ProfileAdapter::urlSchemeHandler(const QByteArray &scheme) { - return m_customUrlSchemeHandlers; + return m_customUrlSchemeHandlers.value(scheme.toLower()).data(); } const QList<QByteArray> ProfileAdapter::customUrlSchemes() const @@ -418,16 +468,23 @@ const QList<QByteArray> ProfileAdapter::customUrlSchemes() const void ProfileAdapter::updateCustomUrlSchemeHandlers() { - if (m_profile->m_urlRequestContextGetter.get()) - m_profile->m_profileIOData->updateJobFactory(); + m_profile->ForEachLoadedStoragePartition( + base::BindRepeating([](content::StoragePartition *storage_partition) { + storage_partition->ResetURLLoaderFactories(); + })); } -bool ProfileAdapter::removeCustomUrlSchemeHandler(QWebEngineUrlSchemeHandler *handler) +void ProfileAdapter::removeUrlSchemeHandler(QWebEngineUrlSchemeHandler *handler) { + Q_ASSERT(handler); bool removedOneOrMore = false; auto it = m_customUrlSchemeHandlers.begin(); while (it != m_customUrlSchemeHandlers.end()) { if (it.value() == handler) { + if (schemeType(it.key()) == SchemeType::Protected) { + qWarning("Cannot remove the URL scheme handler for an internal scheme: %s", it.key().constData()); + continue; + } it = m_customUrlSchemeHandlers.erase(it); removedOneOrMore = true; continue; @@ -436,61 +493,50 @@ bool ProfileAdapter::removeCustomUrlSchemeHandler(QWebEngineUrlSchemeHandler *ha } if (removedOneOrMore) updateCustomUrlSchemeHandlers(); - return removedOneOrMore; } -QWebEngineUrlSchemeHandler *ProfileAdapter::takeCustomUrlSchemeHandler(const QByteArray &scheme) +void ProfileAdapter::removeUrlScheme(const QByteArray &scheme) { - QWebEngineUrlSchemeHandler *handler = m_customUrlSchemeHandlers.take(scheme.toLower()); - if (handler) + QByteArray canonicalScheme = scheme.toLower(); + if (schemeType(canonicalScheme) == SchemeType::Protected) { + qWarning("Cannot remove the URL scheme handler for an internal scheme: %s", scheme.constData()); + return; + } + if (m_customUrlSchemeHandlers.remove(canonicalScheme)) updateCustomUrlSchemeHandlers(); - return handler; } -bool ProfileAdapter::addCustomUrlSchemeHandler(const QByteArray &scheme, QWebEngineUrlSchemeHandler *handler) +void ProfileAdapter::installUrlSchemeHandler(const QByteArray &scheme, QWebEngineUrlSchemeHandler *handler) { - static const QSet<QByteArray> blacklist{ - QByteArrayLiteral("about"), - QByteArrayLiteral("blob"), - QByteArrayLiteral("data"), - QByteArrayLiteral("javascript"), - QByteArrayLiteral("qrc"), - // See also kStandardURLSchemes in url/url_util.cc (through url::IsStandard below) - }; - - static const QSet<QByteArray> whitelist{ - QByteArrayLiteral("gopher"), - }; + Q_ASSERT(handler); + QByteArray canonicalScheme = scheme.toLower(); + SchemeType type = schemeType(canonicalScheme); - const QByteArray canonicalScheme = scheme.toLower(); - bool standardSyntax = url::IsStandard(canonicalScheme.data(), url::Component(0, canonicalScheme.size())); - bool customScheme = QWebEngineUrlScheme::schemeByName(canonicalScheme) != QWebEngineUrlScheme(); - bool blacklisted = blacklist.contains(canonicalScheme) || (standardSyntax && !customScheme); - bool whitelisted = whitelist.contains(canonicalScheme); - - if (blacklisted && !whitelisted) { + if (type == SchemeType::Protected) { qWarning("Cannot install a URL scheme handler overriding internal scheme: %s", scheme.constData()); - return false; + return; } if (m_customUrlSchemeHandlers.value(canonicalScheme, handler) != handler) { qWarning("URL scheme handler already installed for the scheme: %s", scheme.constData()); - return false; + return; } - if (!whitelisted && !customScheme) + if (type == SchemeType::Unknown) qWarning("Please register the custom scheme '%s' via QWebEngineUrlScheme::registerScheme() " "before installing the custom scheme handler.", scheme.constData()); m_customUrlSchemeHandlers.insert(canonicalScheme, handler); updateCustomUrlSchemeHandlers(); - return true; } -void ProfileAdapter::clearCustomUrlSchemeHandlers() +void ProfileAdapter::removeAllUrlSchemeHandlers() { - m_customUrlSchemeHandlers.clear(); - updateCustomUrlSchemeHandlers(); + if (m_customUrlSchemeHandlers.size() > 1) { + m_customUrlSchemeHandlers.clear(); + m_customUrlSchemeHandlers.insert(QByteArrayLiteral("qrc"), &m_qrcHandler); + updateCustomUrlSchemeHandlers(); + } } UserResourceControllerHost *ProfileAdapter::userResourceController() @@ -500,7 +546,7 @@ UserResourceControllerHost *ProfileAdapter::userResourceController() return m_userResourceController.data(); } -void ProfileAdapter::permissionRequestReply(const QUrl &origin, PermissionType type, bool reply) +void ProfileAdapter::permissionRequestReply(const QUrl &origin, PermissionType type, PermissionState reply) { static_cast<PermissionManagerQt*>(profile()->GetPermissionControllerDelegate())->permissionRequestReply(origin, type, reply); } @@ -533,38 +579,143 @@ void ProfileAdapter::setHttpAcceptLanguage(const QString &httpAcceptLanguage) return; m_httpAcceptLanguage = httpAcceptLanguage; + std::string http_accept_language = httpAcceptLanguageWithoutQualities().toStdString(); + std::vector<content::WebContentsImpl *> list = content::WebContentsImpl::GetAllWebContents(); for (content::WebContentsImpl *web_contents : list) { if (web_contents->GetBrowserContext() == m_profile.data()) { - content::RendererPreferences* rendererPrefs = web_contents->GetMutableRendererPrefs(); - rendererPrefs->accept_languages = httpAcceptLanguageWithoutQualities().toStdString(); - web_contents->GetRenderViewHost()->SyncRendererPrefs(); + blink::RendererPreferences *rendererPrefs = web_contents->GetMutableRendererPrefs(); + rendererPrefs->accept_languages = http_accept_language; + web_contents->SyncRendererPrefs(); } } - if (m_profile->m_urlRequestContextGetter.get()) - m_profile->m_profileIOData->updateUserAgent(); + m_profile->ForEachLoadedStoragePartition( + base::BindRepeating([](std::string accept_language, content::StoragePartition *storage_partition) { + storage_partition->GetNetworkContext()->SetAcceptLanguage(accept_language); + }, http_accept_language)); +} + +QVariant ProfileAdapter::clientHint(ClientHint clientHint) const +{ + blink::UserAgentMetadata &userAgentMetadata = m_profile->m_userAgentMetadata; + switch (clientHint) { + case ProfileAdapter::UAArchitecture: + return QVariant(toQString(userAgentMetadata.architecture)); + case ProfileAdapter::UAPlatform: + return QVariant(toQString(userAgentMetadata.platform)); + case ProfileAdapter::UAModel: + return QVariant(toQString(userAgentMetadata.model)); + case ProfileAdapter::UAMobile: + return QVariant(userAgentMetadata.mobile); + case ProfileAdapter::UAFullVersion: + return QVariant(toQString(userAgentMetadata.full_version)); + case ProfileAdapter::UAPlatformVersion: + return QVariant(toQString(userAgentMetadata.platform_version)); + case ProfileAdapter::UABitness: + return QVariant(toQString(userAgentMetadata.bitness)); + case ProfileAdapter::UAFullVersionList: { + QJsonObject ret; + for (const auto &value : userAgentMetadata.brand_full_version_list) + ret.insert(toQString(value.brand), QJsonValue(toQString(value.version))); + return QVariant(ret); + } + case ProfileAdapter::UAWOW64: + return QVariant(userAgentMetadata.wow64); + default: + return QVariant(); + } +} + +void ProfileAdapter::setClientHint(ClientHint clientHint, const QVariant &value) +{ + blink::UserAgentMetadata &userAgentMetadata = m_profile->m_userAgentMetadata; + switch (clientHint) { + case ProfileAdapter::UAArchitecture: + userAgentMetadata.architecture = value.toString().toStdString(); + break; + case ProfileAdapter::UAPlatform: + userAgentMetadata.platform = value.toString().toStdString(); + break; + case ProfileAdapter::UAModel: + userAgentMetadata.model = value.toString().toStdString(); + break; + case ProfileAdapter::UAMobile: + userAgentMetadata.mobile = value.toBool(); + break; + case ProfileAdapter::UAFullVersion: + userAgentMetadata.full_version = value.toString().toStdString(); + break; + case ProfileAdapter::UAPlatformVersion: + userAgentMetadata.platform_version = value.toString().toStdString(); + break; + case ProfileAdapter::UABitness: + userAgentMetadata.bitness = value.toString().toStdString(); + break; + case ProfileAdapter::UAFullVersionList: { + userAgentMetadata.brand_full_version_list.clear(); + QJsonObject fullVersionList = value.toJsonObject(); + for (const QString &key : fullVersionList.keys()) + userAgentMetadata.brand_full_version_list.push_back({ + key.toStdString(), + fullVersionList.value(key).toString().toStdString() + }); + break; + } + case ProfileAdapter::UAWOW64: + userAgentMetadata.wow64 = value.toBool(); + break; + default: + break; + } + + std::vector<content::WebContentsImpl *> list = content::WebContentsImpl::GetAllWebContents(); + for (content::WebContentsImpl *web_contents : list) { + if (web_contents->GetBrowserContext() == m_profile.data()) { + web_contents->GetMutableRendererPrefs()->user_agent_override.ua_metadata_override = userAgentMetadata; + web_contents->SyncRendererPrefs(); + } + } +} + +bool ProfileAdapter::clientHintsEnabled() +{ + return m_clientHintsEnabled; +} + +void ProfileAdapter::setClientHintsEnabled(bool enabled) +{ + m_clientHintsEnabled = enabled; +} + +void ProfileAdapter::resetClientHints() +{ + m_profile->m_userAgentMetadata = embedder_support::GetUserAgentMetadata(); + std::vector<content::WebContentsImpl *> list = content::WebContentsImpl::GetAllWebContents(); + for (content::WebContentsImpl *web_contents : list) { + if (web_contents->GetBrowserContext() == m_profile.data()) { + web_contents->GetMutableRendererPrefs()->user_agent_override.ua_metadata_override = m_profile->m_userAgentMetadata; + web_contents->SyncRendererPrefs(); + } + } } void ProfileAdapter::clearHttpCache() { - content::BrowsingDataRemover *remover = content::BrowserContext::GetBrowsingDataRemover(m_profile.data()); - remover->Remove(base::Time(), base::Time::Max(), - content::BrowsingDataRemover::DATA_TYPE_CACHE, - content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB | content::BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB); + m_profile->m_profileIOData->clearHttpCache(); } void ProfileAdapter::setSpellCheckLanguages(const QStringList &languages) { #if QT_CONFIG(webengine_spellchecker) - m_profile->setSpellCheckLanguages(languages); + m_profile->prefServiceAdapter().setSpellCheckLanguages(languages); #endif } QStringList ProfileAdapter::spellCheckLanguages() const { #if QT_CONFIG(webengine_spellchecker) - return m_profile->spellCheckLanguages(); + return m_profile->prefServiceAdapter().spellCheckLanguages(); #else return QStringList(); #endif @@ -573,19 +724,29 @@ QStringList ProfileAdapter::spellCheckLanguages() const void ProfileAdapter::setSpellCheckEnabled(bool enabled) { #if QT_CONFIG(webengine_spellchecker) - m_profile->setSpellCheckEnabled(enabled); + m_profile->prefServiceAdapter().setSpellCheckEnabled(enabled); #endif } bool ProfileAdapter::isSpellCheckEnabled() const { #if QT_CONFIG(webengine_spellchecker) - return m_profile->isSpellCheckEnabled(); + return m_profile->prefServiceAdapter().isSpellCheckEnabled(); #else return false; #endif } +bool ProfileAdapter::pushServiceEnabled() const +{ + return m_pushServiceEnabled; +} + +void ProfileAdapter::setPushServiceEnabled(bool enabled) +{ + m_pushServiceEnabled = enabled; +} + void ProfileAdapter::addWebContentsAdapterClient(WebContentsAdapterClient *client) { m_webContentsAdapterClients.append(client); @@ -596,9 +757,161 @@ void ProfileAdapter::removeWebContentsAdapterClient(WebContentsAdapterClient *cl m_webContentsAdapterClients.removeAll(client); } +void ProfileAdapter::releaseAllWebContentsAdapterClients() +{ + while (!m_webContentsAdapterClients.isEmpty()) + m_webContentsAdapterClients.first()->releaseProfile(); +} + void ProfileAdapter::resetVisitedLinksManager() { - m_visitedLinksManager.reset(new VisitedLinksManagerQt(this)); + m_visitedLinksManager.reset(new VisitedLinksManagerQt(m_profile.data(), persistVisitedLinks())); +} + +void ProfileAdapter::reinitializeHistoryService() +{ + Q_ASSERT(!m_offTheRecord); + if (ensureDataPathExists()) { + favicon::FaviconService *faviconService = + FaviconServiceFactoryQt::GetForBrowserContext(m_profile.data()); + history::HistoryService *historyService = static_cast<history::HistoryService *>( + HistoryServiceFactoryQt::GetInstance()->GetForBrowserContext(m_profile.data())); + Q_ASSERT(historyService); + faviconService->SetHistoryService(historyService); + } else { + qWarning("Favicon database is not available for this profile."); + } +} + +QString ProfileAdapter::determineDownloadPath(const QString &downloadDirectory, const QString &suggestedFilename, const time_t &startTime) +{ + QFileInfo suggestedFile(QDir(downloadDirectory).absoluteFilePath(suggestedFilename)); + QString suggestedFilePath = suggestedFile.absoluteFilePath(); + base::FilePath tmpFilePath(toFilePath(suggestedFilePath).NormalizePathSeparatorsTo('/')); + + int uniquifier = 0; + { + base::ScopedAllowBlocking allowBlock; + uniquifier = base::GetUniquePathNumber(tmpFilePath); + } + if (uniquifier > 0) + suggestedFilePath = toQt(tmpFilePath.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", uniquifier)).AsUTF8Unsafe()); + else if (uniquifier == -1) { + base::Time::Exploded exploded; + base::Time::FromTimeT(startTime).LocalExplode(&exploded); + std::string suffix = base::StringPrintf( + " - %04d-%02d-%02dT%02d%02d%02d.%03d", exploded.year, exploded.month, + exploded.day_of_month, exploded.hour, exploded.minute, + exploded.second, exploded.millisecond); + suggestedFilePath = toQt(tmpFilePath.InsertBeforeExtensionASCII(suffix).AsUTF8Unsafe()); + } + return suggestedFilePath; +} + +#if QT_CONFIG(ssl) +QWebEngineClientCertificateStore *ProfileAdapter::clientCertificateStore() +{ + if (!m_clientCertificateStore) + m_clientCertificateStore = new QWebEngineClientCertificateStore(m_profile->m_profileIOData->clientCertificateStoreData()); + return m_clientCertificateStore; +} +#endif + +static void callbackOnIconAvailableForPageURL(std::function<void (const QIcon &, const QUrl &, const QUrl &)> iconAvailableCallback, + const QUrl &pageUrl, + const favicon_base::FaviconRawBitmapResult &result) +{ + if (!result.is_valid()) { + iconAvailableCallback(QIcon(), toQt(result.icon_url), pageUrl); + return; + } + QPixmap pixmap(toQt(result.pixel_size)); + pixmap.loadFromData(result.bitmap_data->data(), result.bitmap_data->size()); + iconAvailableCallback(QIcon(pixmap), toQt(result.icon_url), pageUrl); +} + +void ProfileAdapter::requestIconForPageURL(const QUrl &pageUrl, + int desiredSizeInPixel, + bool touchIconsEnabled, + std::function<void (const QIcon &, const QUrl &, const QUrl &)> iconAvailableCallback) +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + favicon::FaviconService *service = FaviconServiceFactoryQt::GetForBrowserContext(m_profile.data()); + + if (!service->HistoryService()) { + callbackOnIconAvailableForPageURL(iconAvailableCallback, pageUrl, + favicon_base::FaviconRawBitmapResult()); + return; + } + + favicon_base::IconTypeSet types = { favicon_base::IconType::kFavicon }; + if (touchIconsEnabled) { + types.insert(favicon_base::IconType::kTouchIcon); + types.insert(favicon_base::IconType::kTouchPrecomposedIcon); + types.insert(favicon_base::IconType::kWebManifestIcon); + } + service->GetRawFaviconForPageURL( + toGurl(pageUrl), types, desiredSizeInPixel, true /* fallback_to_host */, + base::BindOnce(&callbackOnIconAvailableForPageURL, iconAvailableCallback, pageUrl), + m_cancelableTaskTracker.get()); +} + +static void callbackOnIconAvailableForIconURL(std::function<void (const QIcon &, const QUrl &)> iconAvailableCallback, + ProfileAdapter *profileAdapter, + const QUrl &iconUrl, int iconType, + int desiredSizeInPixel, + bool touchIconsEnabled, + const favicon_base::FaviconRawBitmapResult &result) +{ + if (!result.is_valid()) { + // If touch icons are disabled there is no need to try further icon types. + if (!touchIconsEnabled) { + iconAvailableCallback(QIcon(), iconUrl); + return; + } + if (static_cast<favicon_base::IconType>(iconType) != favicon_base::IconType::kMax) { + //Q_ASSERT(profileAdapter->profile()); + favicon::FaviconService *service = FaviconServiceFactoryQt::GetForBrowserContext(profileAdapter->profile()); + service->GetRawFavicon(toGurl(iconUrl), + static_cast<favicon_base::IconType>(iconType + 1), + desiredSizeInPixel, + base::BindOnce(&callbackOnIconAvailableForIconURL, iconAvailableCallback, + profileAdapter, iconUrl, iconType + 1, desiredSizeInPixel, + touchIconsEnabled), + profileAdapter->cancelableTaskTracker()); + return; + } + iconAvailableCallback(QIcon(), iconUrl); + return; + } + QPixmap pixmap(toQt(result.pixel_size)); + pixmap.loadFromData(result.bitmap_data->data(), result.bitmap_data->size()); + iconAvailableCallback(QIcon(pixmap), toQt(result.icon_url)); +} + +void ProfileAdapter::requestIconForIconURL(const QUrl &iconUrl, + int desiredSizeInPixel, + bool touchIconsEnabled, + std::function<void (const QIcon &, const QUrl &)> iconAvailableCallback) +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + favicon::FaviconService *service = FaviconServiceFactoryQt::GetForBrowserContext(m_profile.data()); + + if (!service->HistoryService()) { + callbackOnIconAvailableForIconURL(iconAvailableCallback, + this, + iconUrl, + static_cast<int>(favicon_base::IconType::kMax), 0, + touchIconsEnabled, + favicon_base::FaviconRawBitmapResult()); + return; + } + service->GetRawFavicon( + toGurl(iconUrl), favicon_base::IconType::kFavicon, desiredSizeInPixel, + base::BindOnce(&callbackOnIconAvailableForIconURL, iconAvailableCallback, this, iconUrl, + static_cast<int>(favicon_base::IconType::kFavicon), desiredSizeInPixel, + touchIconsEnabled), + m_cancelableTaskTracker.get()); } } // namespace QtWebEngineCore |