1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWebEngine module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "profile_adapter.h"
41
42 #include "content/browser/web_contents/web_contents_impl.h"
43 #include "content/public/browser/browser_thread.h"
44 #include "content/public/browser/browsing_data_remover.h"
45 #include "content/public/browser/download_manager.h"
46 #include "content/public/browser/shared_cors_origin_access_list.h"
47 #include "content/public/browser/storage_partition.h"
48 #include "services/network/public/cpp/cors/origin_access_list.h"
49 #include "url/url_util.h"
50
51 #include "api/qwebengineurlscheme.h"
52 #include "content_browser_client_qt.h"
53 #include "download_manager_delegate_qt.h"
54 #include "permission_manager_qt.h"
55 #include "profile_adapter_client.h"
56 #include "profile_io_data_qt.h"
57 #include "profile_qt.h"
58 #include "renderer_host/user_resource_controller_host.h"
59 #include "type_conversion.h"
60 #include "visited_links_manager_qt.h"
61 #include "web_engine_context.h"
62 #include "web_contents_adapter_client.h"
63
64 #include "base/files/file_util.h"
65 #include "base/time/time_to_iso8601.h"
66 #include "components/keyed_service/content/browser_context_dependency_manager.h"
67
68 #if BUILDFLAG(ENABLE_EXTENSIONS)
69 #include "extensions/browser/extension_system.h"
70 #endif
71
72 #include <QCoreApplication>
73 #include <QDir>
74 #include <QString>
75 #include <QStandardPaths>
76
77 namespace {
buildLocationFromStandardPath(const QString & standardPath,const QString & name)78 inline QString buildLocationFromStandardPath(const QString &standardPath, const QString &name) {
79 QString location = standardPath;
80 if (location.isEmpty())
81 location = QDir::homePath() % QLatin1String("/.") % QCoreApplication::applicationName();
82
83 location.append(QLatin1String("/QtWebEngine/") % name);
84 return location;
85 }
86 }
87
88 namespace QtWebEngineCore {
89
ProfileAdapter(const QString & storageName)90 ProfileAdapter::ProfileAdapter(const QString &storageName):
91 m_name(storageName)
92 , m_offTheRecord(storageName.isEmpty())
93 , m_downloadPath(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation))
94 , m_httpCacheType(DiskHttpCache)
95 , m_persistentCookiesPolicy(AllowPersistentCookies)
96 , m_visitedLinksPolicy(TrackVisitedLinksOnDisk)
97 , m_httpCacheMaxSize(0)
98 {
99 WebEngineContext::current()->addProfileAdapter(this);
100 // creation of profile requires webengine context
101 m_profile.reset(new ProfileQt(this));
102 content::BrowserContext::Initialize(m_profile.data(), toFilePath(dataPath()));
103 // fixme: this should not be here
104 m_profile->m_profileIOData->initializeOnUIThread();
105 m_customUrlSchemeHandlers.insert(QByteArrayLiteral("qrc"), &m_qrcHandler);
106 #if BUILDFLAG(ENABLE_EXTENSIONS)
107 if (!storageName.isEmpty())
108 extensions::ExtensionSystem::Get(m_profile.data())->InitForRegularProfile(true);
109 #endif
110
111 // Allow XMLHttpRequests from qrc to file.
112 // ### consider removing for Qt6
113 url::Origin qrc = url::Origin::Create(GURL("qrc://"));
114 auto pattern = network::mojom::CorsOriginPattern::New("file", "", 0,
115 network::mojom::CorsDomainMatchMode::kAllowSubdomains,
116 network::mojom::CorsPortMatchMode::kAllowAnyPort,
117 network::mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
118 std::vector<network::mojom::CorsOriginPatternPtr> list;
119 list.push_back(std::move(pattern));
120 m_profile->GetSharedCorsOriginAccessList()->SetForOrigin(qrc, std::move(list), {}, base::BindOnce([]{}));
121 }
122
~ProfileAdapter()123 ProfileAdapter::~ProfileAdapter()
124 {
125 while (!m_webContentsAdapterClients.isEmpty()) {
126 m_webContentsAdapterClients.first()->releaseProfile();
127 }
128 WebEngineContext::current()->removeProfileAdapter(this);
129 if (m_downloadManagerDelegate) {
130 m_profile->GetDownloadManager(m_profile.data())->Shutdown();
131 m_downloadManagerDelegate.reset();
132 }
133 #if QT_CONFIG(ssl)
134 delete m_clientCertificateStore;
135 #endif
136 }
137
setStorageName(const QString & storageName)138 void ProfileAdapter::setStorageName(const QString &storageName)
139 {
140 if (storageName == m_name)
141 return;
142 m_name = storageName;
143 if (!m_offTheRecord) {
144 m_profile->setupPrefService();
145 if (!m_profile->m_profileIOData->isClearHttpCacheInProgress())
146 m_profile->m_profileIOData->resetNetworkContext();
147 if (m_visitedLinksManager)
148 resetVisitedLinksManager();
149 }
150 }
151
setOffTheRecord(bool offTheRecord)152 void ProfileAdapter::setOffTheRecord(bool offTheRecord)
153 {
154 if (offTheRecord == m_offTheRecord)
155 return;
156 m_offTheRecord = offTheRecord;
157 m_profile->setupPrefService();
158 if (!m_profile->m_profileIOData->isClearHttpCacheInProgress())
159 m_profile->m_profileIOData->resetNetworkContext();
160 if (m_visitedLinksManager)
161 resetVisitedLinksManager();
162 }
163
profile()164 ProfileQt *ProfileAdapter::profile()
165 {
166 return m_profile.data();
167 }
168
visitedLinksManager()169 VisitedLinksManagerQt *ProfileAdapter::visitedLinksManager()
170 {
171 if (!m_visitedLinksManager)
172 resetVisitedLinksManager();
173 return m_visitedLinksManager.data();
174 }
175
downloadManagerDelegate()176 DownloadManagerDelegateQt *ProfileAdapter::downloadManagerDelegate()
177 {
178 if (!m_downloadManagerDelegate)
179 m_downloadManagerDelegate.reset(new DownloadManagerDelegateQt(this));
180 return m_downloadManagerDelegate.data();
181 }
182
cookieStore()183 QWebEngineCookieStore *ProfileAdapter::cookieStore()
184 {
185 if (!m_cookieStore)
186 m_cookieStore.reset(new QWebEngineCookieStore);
187 return m_cookieStore.data();
188 }
189
requestInterceptor()190 QWebEngineUrlRequestInterceptor *ProfileAdapter::requestInterceptor()
191 {
192 return m_requestInterceptor.data();
193 }
194
setRequestInterceptor(QWebEngineUrlRequestInterceptor * interceptor)195 void ProfileAdapter::setRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor)
196 {
197 m_requestInterceptor = interceptor;
198 }
199
addClient(ProfileAdapterClient * adapterClient)200 void ProfileAdapter::addClient(ProfileAdapterClient *adapterClient)
201 {
202 m_clients.append(adapterClient);
203 }
204
removeClient(ProfileAdapterClient * adapterClient)205 void ProfileAdapter::removeClient(ProfileAdapterClient *adapterClient)
206 {
207 m_clients.removeOne(adapterClient);
208 }
209
cancelDownload(quint32 downloadId)210 void ProfileAdapter::cancelDownload(quint32 downloadId)
211 {
212 downloadManagerDelegate()->cancelDownload(downloadId);
213 }
214
pauseDownload(quint32 downloadId)215 void ProfileAdapter::pauseDownload(quint32 downloadId)
216 {
217 downloadManagerDelegate()->pauseDownload(downloadId);
218 }
219
resumeDownload(quint32 downloadId)220 void ProfileAdapter::resumeDownload(quint32 downloadId)
221 {
222 downloadManagerDelegate()->resumeDownload(downloadId);
223 }
224
removeDownload(quint32 downloadId)225 void ProfileAdapter::removeDownload(quint32 downloadId)
226 {
227 downloadManagerDelegate()->removeDownload(downloadId);
228 }
229
createDefaultProfileAdapter()230 ProfileAdapter *ProfileAdapter::createDefaultProfileAdapter()
231 {
232 return WebEngineContext::current()->createDefaultProfileAdapter();
233 }
234
defaultProfileAdapter()235 ProfileAdapter *ProfileAdapter::defaultProfileAdapter()
236 {
237 WebEngineContext *context = WebEngineContext::current();
238 return context ? context->defaultProfileAdapter() : nullptr;
239 }
240
globalQObjectRoot()241 QObject* ProfileAdapter::globalQObjectRoot()
242 {
243 return WebEngineContext::current()->globalQObject();
244 }
245
dataPath() const246 QString ProfileAdapter::dataPath() const
247 {
248 if (!m_dataPath.isEmpty())
249 return m_dataPath;
250 // And off-the-record or memory-only profile should not write to disk
251 // but Chromium often creates temporary directories anyway, so given them
252 // a location to do so.
253 QString name = m_name;
254 if (m_offTheRecord)
255 name = QStringLiteral("OffTheRecord");
256 else if (m_name.isEmpty())
257 name = QStringLiteral("UnknownProfile");
258 return buildLocationFromStandardPath(QStandardPaths::writableLocation(QStandardPaths::DataLocation), name);
259 }
260
setDataPath(const QString & path)261 void ProfileAdapter::setDataPath(const QString &path)
262 {
263 if (m_dataPath == path)
264 return;
265 m_dataPath = path;
266 m_profile->setupPrefService();
267 if (!m_profile->m_profileIOData->isClearHttpCacheInProgress())
268 m_profile->m_profileIOData->resetNetworkContext();
269 if (!m_offTheRecord && m_visitedLinksManager)
270 resetVisitedLinksManager();
271 }
272
setDownloadPath(const QString & path)273 void ProfileAdapter::setDownloadPath(const QString &path)
274 {
275 m_downloadPath = path.isEmpty() ? QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) : path;
276 }
277
cachePath() const278 QString ProfileAdapter::cachePath() const
279 {
280 if (m_offTheRecord)
281 return QString();
282 if (!m_cachePath.isEmpty())
283 return m_cachePath;
284 if (!m_name.isNull())
285 return buildLocationFromStandardPath(QStandardPaths::writableLocation(QStandardPaths::CacheLocation), m_name);
286 return QString();
287 }
288
setCachePath(const QString & path)289 void ProfileAdapter::setCachePath(const QString &path)
290 {
291 if (m_cachePath == path)
292 return;
293 m_cachePath = path;
294 if (!m_offTheRecord && !m_profile->m_profileIOData->isClearHttpCacheInProgress())
295 m_profile->m_profileIOData->resetNetworkContext();
296 }
297
httpCachePath() const298 QString ProfileAdapter::httpCachePath() const
299 {
300 if (m_offTheRecord)
301 return QString();
302 QString basePath = cachePath();
303 if (!basePath.isEmpty())
304 return basePath % QLatin1String("/Cache");
305 return QString();
306 }
307
httpUserAgent() const308 QString ProfileAdapter::httpUserAgent() const
309 {
310 if (m_httpUserAgent.isNull())
311 return QString::fromStdString(ContentBrowserClientQt::getUserAgent());
312 return m_httpUserAgent;
313 }
314
setHttpUserAgent(const QString & userAgent)315 void ProfileAdapter::setHttpUserAgent(const QString &userAgent)
316 {
317 const QString httpUserAgent = userAgent.simplified();
318 if (m_httpUserAgent == httpUserAgent)
319 return;
320 m_httpUserAgent = httpUserAgent;
321 const std::string stdUserAgent = httpUserAgent.toStdString();
322
323 std::vector<content::WebContentsImpl *> list = content::WebContentsImpl::GetAllWebContents();
324 for (content::WebContentsImpl *web_contents : list)
325 if (web_contents->GetBrowserContext() == m_profile.data())
326 web_contents->SetUserAgentOverride(blink::UserAgentOverride::UserAgentOnly(stdUserAgent), true);
327
328 content::BrowserContext::ForEachStoragePartition(
329 m_profile.get(), base::BindRepeating([](const std::string &user_agent, content::StoragePartition *storage_partition) {
330 storage_partition->GetNetworkContext()->SetUserAgent(user_agent);
331 }, stdUserAgent));
332 }
333
httpCacheType() const334 ProfileAdapter::HttpCacheType ProfileAdapter::httpCacheType() const
335 {
336 if (m_httpCacheType == NoCache)
337 return NoCache;
338 if (isOffTheRecord() || httpCachePath().isEmpty())
339 return MemoryHttpCache;
340 return m_httpCacheType;
341 }
342
setHttpCacheType(ProfileAdapter::HttpCacheType newhttpCacheType)343 void ProfileAdapter::setHttpCacheType(ProfileAdapter::HttpCacheType newhttpCacheType)
344 {
345 ProfileAdapter::HttpCacheType oldCacheType = httpCacheType();
346 m_httpCacheType = newhttpCacheType;
347 if (oldCacheType == httpCacheType())
348 return;
349 if (!m_offTheRecord && !m_profile->m_profileIOData->isClearHttpCacheInProgress()) {
350 m_profile->m_profileIOData->resetNetworkContext();
351 if (m_httpCacheType == NoCache)
352 clearHttpCache();
353 }
354 }
355
persistentCookiesPolicy() const356 ProfileAdapter::PersistentCookiesPolicy ProfileAdapter::persistentCookiesPolicy() const
357 {
358 if (isOffTheRecord() || m_name.isEmpty())
359 return NoPersistentCookies;
360 return m_persistentCookiesPolicy;
361 }
362
setPersistentCookiesPolicy(ProfileAdapter::PersistentCookiesPolicy newPersistentCookiesPolicy)363 void ProfileAdapter::setPersistentCookiesPolicy(ProfileAdapter::PersistentCookiesPolicy newPersistentCookiesPolicy)
364 {
365 ProfileAdapter::PersistentCookiesPolicy oldPolicy = persistentCookiesPolicy();
366 m_persistentCookiesPolicy = newPersistentCookiesPolicy;
367 if (oldPolicy == persistentCookiesPolicy())
368 return;
369 if (!m_offTheRecord && !m_profile->m_profileIOData->isClearHttpCacheInProgress())
370 m_profile->m_profileIOData->resetNetworkContext();
371 }
372
visitedLinksPolicy() const373 ProfileAdapter::VisitedLinksPolicy ProfileAdapter::visitedLinksPolicy() const
374 {
375 if (isOffTheRecord() || m_visitedLinksPolicy == DoNotTrackVisitedLinks)
376 return DoNotTrackVisitedLinks;
377 if (m_name.isEmpty())
378 return TrackVisitedLinksInMemory;
379 return m_visitedLinksPolicy;
380 }
381
trackVisitedLinks() const382 bool ProfileAdapter::trackVisitedLinks() const
383 {
384 switch (visitedLinksPolicy()) {
385 case DoNotTrackVisitedLinks:
386 return false;
387 default:
388 break;
389 }
390 return true;
391 }
392
persistVisitedLinks() const393 bool ProfileAdapter::persistVisitedLinks() const
394 {
395 switch (visitedLinksPolicy()) {
396 case DoNotTrackVisitedLinks:
397 case TrackVisitedLinksInMemory:
398 return false;
399 default:
400 break;
401 }
402 return true;
403 }
404
setVisitedLinksPolicy(ProfileAdapter::VisitedLinksPolicy visitedLinksPolicy)405 void ProfileAdapter::setVisitedLinksPolicy(ProfileAdapter::VisitedLinksPolicy visitedLinksPolicy)
406 {
407 if (m_visitedLinksPolicy == visitedLinksPolicy)
408 return;
409 m_visitedLinksPolicy = visitedLinksPolicy;
410 if (m_visitedLinksManager)
411 resetVisitedLinksManager();
412 }
413
httpCacheMaxSize() const414 int ProfileAdapter::httpCacheMaxSize() const
415 {
416 return m_httpCacheMaxSize;
417 }
418
setHttpCacheMaxSize(int maxSize)419 void ProfileAdapter::setHttpCacheMaxSize(int maxSize)
420 {
421 if (m_httpCacheMaxSize == maxSize)
422 return;
423 m_httpCacheMaxSize = maxSize;
424 if (!m_offTheRecord && !m_profile->m_profileIOData->isClearHttpCacheInProgress())
425 m_profile->m_profileIOData->resetNetworkContext();
426 }
427
428 enum class SchemeType { Protected, Overridable, Custom, Unknown };
schemeType(const QByteArray & canonicalScheme)429 static SchemeType schemeType(const QByteArray &canonicalScheme)
430 {
431 static const QSet<QByteArray> blacklist{
432 QByteArrayLiteral("about"),
433 QByteArrayLiteral("blob"),
434 QByteArrayLiteral("data"),
435 QByteArrayLiteral("javascript"),
436 QByteArrayLiteral("qrc"),
437 // See also kStandardURLSchemes in url/url_util.cc (through url::IsStandard below)
438 };
439
440 static const QSet<QByteArray> whitelist{
441 QByteArrayLiteral("gopher"),
442 };
443
444 bool standardSyntax = url::IsStandard(canonicalScheme.data(), url::Component(0, canonicalScheme.size()));
445 bool customScheme = QWebEngineUrlScheme::schemeByName(canonicalScheme) != QWebEngineUrlScheme();
446 bool blacklisted = blacklist.contains(canonicalScheme);
447 bool whitelisted = whitelist.contains(canonicalScheme);
448
449 if (whitelisted)
450 return SchemeType::Overridable;
451 if (blacklisted || (standardSyntax && !customScheme))
452 return SchemeType::Protected;
453 if (customScheme)
454 return SchemeType::Custom;
455 return SchemeType::Unknown;
456 }
457
urlSchemeHandler(const QByteArray & scheme)458 QWebEngineUrlSchemeHandler *ProfileAdapter::urlSchemeHandler(const QByteArray &scheme)
459 {
460 return m_customUrlSchemeHandlers.value(scheme.toLower()).data();
461 }
462
customUrlSchemes() const463 const QList<QByteArray> ProfileAdapter::customUrlSchemes() const
464 {
465 return m_customUrlSchemeHandlers.keys();
466 }
467
updateCustomUrlSchemeHandlers()468 void ProfileAdapter::updateCustomUrlSchemeHandlers()
469 {
470 content::BrowserContext::ForEachStoragePartition(
471 m_profile.get(), base::BindRepeating([](content::StoragePartition *storage_partition) {
472 storage_partition->ResetURLLoaderFactories();
473 }));
474 }
475
removeUrlSchemeHandler(QWebEngineUrlSchemeHandler * handler)476 void ProfileAdapter::removeUrlSchemeHandler(QWebEngineUrlSchemeHandler *handler)
477 {
478 Q_ASSERT(handler);
479 bool removedOneOrMore = false;
480 auto it = m_customUrlSchemeHandlers.begin();
481 while (it != m_customUrlSchemeHandlers.end()) {
482 if (it.value() == handler) {
483 if (schemeType(it.key()) == SchemeType::Protected) {
484 qWarning("Cannot remove the URL scheme handler for an internal scheme: %s", it.key().constData());
485 continue;
486 }
487 it = m_customUrlSchemeHandlers.erase(it);
488 removedOneOrMore = true;
489 continue;
490 }
491 ++it;
492 }
493 if (removedOneOrMore)
494 updateCustomUrlSchemeHandlers();
495 }
496
removeUrlScheme(const QByteArray & scheme)497 void ProfileAdapter::removeUrlScheme(const QByteArray &scheme)
498 {
499 QByteArray canonicalScheme = scheme.toLower();
500 if (schemeType(canonicalScheme) == SchemeType::Protected) {
501 qWarning("Cannot remove the URL scheme handler for an internal scheme: %s", scheme.constData());
502 return;
503 }
504 if (m_customUrlSchemeHandlers.remove(canonicalScheme))
505 updateCustomUrlSchemeHandlers();
506 }
507
installUrlSchemeHandler(const QByteArray & scheme,QWebEngineUrlSchemeHandler * handler)508 void ProfileAdapter::installUrlSchemeHandler(const QByteArray &scheme, QWebEngineUrlSchemeHandler *handler)
509 {
510 Q_ASSERT(handler);
511 QByteArray canonicalScheme = scheme.toLower();
512 SchemeType type = schemeType(canonicalScheme);
513
514 if (type == SchemeType::Protected) {
515 qWarning("Cannot install a URL scheme handler overriding internal scheme: %s", scheme.constData());
516 return;
517 }
518
519 if (m_customUrlSchemeHandlers.value(canonicalScheme, handler) != handler) {
520 qWarning("URL scheme handler already installed for the scheme: %s", scheme.constData());
521 return;
522 }
523
524 if (type == SchemeType::Unknown)
525 qWarning("Please register the custom scheme '%s' via QWebEngineUrlScheme::registerScheme() "
526 "before installing the custom scheme handler.", scheme.constData());
527
528 m_customUrlSchemeHandlers.insert(canonicalScheme, handler);
529 updateCustomUrlSchemeHandlers();
530 }
531
removeAllUrlSchemeHandlers()532 void ProfileAdapter::removeAllUrlSchemeHandlers()
533 {
534 if (m_customUrlSchemeHandlers.size() > 1) {
535 m_customUrlSchemeHandlers.clear();
536 m_customUrlSchemeHandlers.insert(QByteArrayLiteral("qrc"), &m_qrcHandler);
537 updateCustomUrlSchemeHandlers();
538 }
539 }
540
userResourceController()541 UserResourceControllerHost *ProfileAdapter::userResourceController()
542 {
543 if (!m_userResourceController)
544 m_userResourceController.reset(new UserResourceControllerHost);
545 return m_userResourceController.data();
546 }
547
permissionRequestReply(const QUrl & origin,PermissionType type,PermissionState reply)548 void ProfileAdapter::permissionRequestReply(const QUrl &origin, PermissionType type, PermissionState reply)
549 {
550 static_cast<PermissionManagerQt*>(profile()->GetPermissionControllerDelegate())->permissionRequestReply(origin, type, reply);
551 }
552
checkPermission(const QUrl & origin,PermissionType type)553 bool ProfileAdapter::checkPermission(const QUrl &origin, PermissionType type)
554 {
555 return static_cast<PermissionManagerQt*>(profile()->GetPermissionControllerDelegate())->checkPermission(origin, type);
556 }
557
httpAcceptLanguageWithoutQualities() const558 QString ProfileAdapter::httpAcceptLanguageWithoutQualities() const
559 {
560 const QStringList list = m_httpAcceptLanguage.split(QLatin1Char(','));
561 QString out;
562 for (const QString &str : list) {
563 if (!out.isEmpty())
564 out.append(QLatin1Char(','));
565 out.append(str.split(QLatin1Char(';')).first());
566 }
567 return out;
568 }
569
httpAcceptLanguage() const570 QString ProfileAdapter::httpAcceptLanguage() const
571 {
572 return m_httpAcceptLanguage;
573 }
574
setHttpAcceptLanguage(const QString & httpAcceptLanguage)575 void ProfileAdapter::setHttpAcceptLanguage(const QString &httpAcceptLanguage)
576 {
577 if (m_httpAcceptLanguage == httpAcceptLanguage)
578 return;
579 m_httpAcceptLanguage = httpAcceptLanguage;
580
581 std::string http_accept_language = httpAcceptLanguageWithoutQualities().toStdString();
582
583 std::vector<content::WebContentsImpl *> list = content::WebContentsImpl::GetAllWebContents();
584 for (content::WebContentsImpl *web_contents : list) {
585 if (web_contents->GetBrowserContext() == m_profile.data()) {
586 blink::mojom::RendererPreferences *rendererPrefs = web_contents->GetMutableRendererPrefs();
587 rendererPrefs->accept_languages = http_accept_language;
588 web_contents->SyncRendererPrefs();
589 }
590 }
591
592 content::BrowserContext::ForEachStoragePartition(
593 m_profile.get(), base::BindRepeating([](std::string accept_language, content::StoragePartition *storage_partition) {
594 storage_partition->GetNetworkContext()->SetAcceptLanguage(accept_language);
595 }, http_accept_language));
596 }
597
clearHttpCache()598 void ProfileAdapter::clearHttpCache()
599 {
600 m_profile->m_profileIOData->clearHttpCache();
601 }
602
setSpellCheckLanguages(const QStringList & languages)603 void ProfileAdapter::setSpellCheckLanguages(const QStringList &languages)
604 {
605 #if QT_CONFIG(webengine_spellchecker)
606 m_profile->prefServiceAdapter().setSpellCheckLanguages(languages);
607 #endif
608 }
609
spellCheckLanguages() const610 QStringList ProfileAdapter::spellCheckLanguages() const
611 {
612 #if QT_CONFIG(webengine_spellchecker)
613 return m_profile->prefServiceAdapter().spellCheckLanguages();
614 #else
615 return QStringList();
616 #endif
617 }
618
setSpellCheckEnabled(bool enabled)619 void ProfileAdapter::setSpellCheckEnabled(bool enabled)
620 {
621 #if QT_CONFIG(webengine_spellchecker)
622 m_profile->prefServiceAdapter().setSpellCheckEnabled(enabled);
623 #endif
624 }
625
isSpellCheckEnabled() const626 bool ProfileAdapter::isSpellCheckEnabled() const
627 {
628 #if QT_CONFIG(webengine_spellchecker)
629 return m_profile->prefServiceAdapter().isSpellCheckEnabled();
630 #else
631 return false;
632 #endif
633 }
634
addWebContentsAdapterClient(WebContentsAdapterClient * client)635 void ProfileAdapter::addWebContentsAdapterClient(WebContentsAdapterClient *client)
636 {
637 m_webContentsAdapterClients.append(client);
638 }
639
removeWebContentsAdapterClient(WebContentsAdapterClient * client)640 void ProfileAdapter::removeWebContentsAdapterClient(WebContentsAdapterClient *client)
641 {
642 m_webContentsAdapterClients.removeAll(client);
643 }
644
resetVisitedLinksManager()645 void ProfileAdapter::resetVisitedLinksManager()
646 {
647 m_visitedLinksManager.reset(new VisitedLinksManagerQt(m_profile.data(), persistVisitedLinks()));
648 }
649
setUseForGlobalCertificateVerification(bool enable)650 void ProfileAdapter::setUseForGlobalCertificateVerification(bool enable)
651 {
652 if (m_usedForGlobalCertificateVerification == enable)
653 return;
654
655 static QPointer<ProfileAdapter> profileForglobalCertificateVerification;
656
657 m_usedForGlobalCertificateVerification = enable;
658 if (enable) {
659 if (profileForglobalCertificateVerification) {
660 profileForglobalCertificateVerification->m_usedForGlobalCertificateVerification = false;
661 if (!m_profile->m_profileIOData->isClearHttpCacheInProgress())
662 profileForglobalCertificateVerification->m_profile->m_profileIOData->resetNetworkContext();
663 for (auto *client : qAsConst(profileForglobalCertificateVerification->m_clients))
664 client->useForGlobalCertificateVerificationChanged();
665 }
666 profileForglobalCertificateVerification = this;
667 } else {
668 Q_ASSERT(profileForglobalCertificateVerification);
669 Q_ASSERT(profileForglobalCertificateVerification == this);
670 profileForglobalCertificateVerification = nullptr;
671 }
672
673 if (!m_profile->m_profileIOData->isClearHttpCacheInProgress())
674 m_profile->m_profileIOData->resetNetworkContext();
675 }
676
isUsedForGlobalCertificateVerification() const677 bool ProfileAdapter::isUsedForGlobalCertificateVerification() const
678 {
679 return m_usedForGlobalCertificateVerification;
680 }
681
determineDownloadPath(const QString & downloadDirectory,const QString & suggestedFilename,const time_t & startTime)682 QString ProfileAdapter::determineDownloadPath(const QString &downloadDirectory, const QString &suggestedFilename, const time_t &startTime)
683 {
684 QFileInfo suggestedFile(QDir(downloadDirectory).absoluteFilePath(suggestedFilename));
685 QString suggestedFilePath = suggestedFile.absoluteFilePath();
686 base::FilePath tmpFilePath(toFilePath(suggestedFilePath).NormalizePathSeparatorsTo('/'));
687
688 int uniquifier = base::GetUniquePathNumber(tmpFilePath);
689 if (uniquifier > 0)
690 suggestedFilePath = toQt(tmpFilePath.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", uniquifier)).AsUTF8Unsafe());
691 else if (uniquifier == -1) {
692 base::Time::Exploded exploded;
693 base::Time::FromTimeT(startTime).LocalExplode(&exploded);
694 std::string suffix = base::StringPrintf(
695 " - %04d-%02d-%02dT%02d%02d%02d.%03d", exploded.year, exploded.month,
696 exploded.day_of_month, exploded.hour, exploded.minute,
697 exploded.second, exploded.millisecond);
698 suggestedFilePath = toQt(tmpFilePath.InsertBeforeExtensionASCII(suffix).AsUTF8Unsafe());
699 }
700 return suggestedFilePath;
701 }
702
703 #if QT_CONFIG(ssl)
clientCertificateStore()704 QWebEngineClientCertificateStore *ProfileAdapter::clientCertificateStore()
705 {
706 if (!m_clientCertificateStore)
707 m_clientCertificateStore = new QWebEngineClientCertificateStore(m_profile->m_profileIOData->clientCertificateStoreData());
708 return m_clientCertificateStore;
709 }
710 #endif
711
712 } // namespace QtWebEngineCore
713