summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-09-01 13:10:34 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-01-19 07:42:58 +0000
commit757004ecf484289f576870b4f251c3e7551294c5 (patch)
tree3f45d9230b87239d16ca7584c07b54b068c11697
parent71d6dc0c326523103dff867d7184e7bc7e49c71d (diff)
Reinstate cookie filter API
Expose API to block cookies for specific domains, or third party cookies in general. Task-number: QTBUG-62897 Change-Id: I7f0e3f346368a2ef2fbd77f3197ee2dea50d57ce Reviewed-by: Peter Varga <pvarga@inf.u-szeged.hu>
-rw-r--r--src/core/api/core_api.pro4
-rw-r--r--src/core/api/qwebenginecallback_p.h10
-rw-r--r--src/core/api/qwebenginecookiestore.cpp90
-rw-r--r--src/core/api/qwebenginecookiestore.h12
-rw-r--r--src/core/api/qwebenginecookiestore_p.h3
-rw-r--r--src/core/content_browser_client_qt.cpp26
-rw-r--r--src/core/content_browser_client_qt.h15
-rw-r--r--src/core/cookie_monster_delegate_qt.cpp16
-rw-r--r--src/core/cookie_monster_delegate_qt.h1
-rw-r--r--src/core/network_delegate_qt.cpp22
-rw-r--r--src/core/network_delegate_qt.h3
-rw-r--r--tests/auto/core/qwebenginecookiestore/tst_qwebenginecookiestore.cpp33
-rw-r--r--tests/quicktestbrowser/BrowserWindow.qml8
-rw-r--r--tests/quicktestbrowser/main.cpp22
14 files changed, 250 insertions, 15 deletions
diff --git a/src/core/api/core_api.pro b/src/core/api/core_api.pro
index 93eebbc45..0fea312f4 100644
--- a/src/core/api/core_api.pro
+++ b/src/core/api/core_api.pro
@@ -24,7 +24,9 @@ DEFINES += \
CHROMIUM_SRC_DIR = $$QTWEBENGINE_ROOT/$$getChromiumSrcDir()
INCLUDEPATH += $$QTWEBENGINE_ROOT/src/core \
- $$CHROMIUM_SRC_DIR
+ $$CHROMIUM_SRC_DIR \
+ $$CHROMIUM_SRC_DIR/third_party/skia/include/core \
+ $$CHROMIUM_SRC_DIR/third_party/skia/include/config
linux-g++*: QMAKE_CXXFLAGS += -Wno-unused-parameter
diff --git a/src/core/api/qwebenginecallback_p.h b/src/core/api/qwebenginecallback_p.h
index fdaf84d21..24b4495df 100644
--- a/src/core/api/qwebenginecallback_p.h
+++ b/src/core/api/qwebenginecallback_p.h
@@ -114,9 +114,15 @@ public:
#undef DEFINE_INVOKE_FOR_TYPE
template <typename A>
- void invokeDirectly(const QWebEngineCallback<A> &callback, const A &argument)
+ void invokeDirectly(const QWebEngineCallback<typename std::remove_reference<A>::type &> &callback, A &argument)
{
- return callback.d.data()->operator()(std::forward<const A&>(argument));
+ return callback.d.data()->operator()(argument);
+ }
+
+ template <typename A>
+ void invokeDirectly(const QWebEngineCallback<typename std::remove_reference<A>::type> &callback, const A &argument)
+ {
+ return callback.d.data()->operator()(std::forward<const A &>(argument));
}
private:
diff --git a/src/core/api/qwebenginecookiestore.cpp b/src/core/api/qwebenginecookiestore.cpp
index 031eb8d3d..e034e08ea 100644
--- a/src/core/api/qwebenginecookiestore.cpp
+++ b/src/core/api/qwebenginecookiestore.cpp
@@ -40,7 +40,10 @@
#include "qwebenginecookiestore.h"
#include "qwebenginecookiestore_p.h"
-#include <cookie_monster_delegate_qt.h>
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+
+#include "cookie_monster_delegate_qt.h"
+#include "type_conversion.h"
#include <QByteArray>
#include <QUrl>
@@ -179,6 +182,21 @@ void QWebEngineCookieStorePrivate::onCookieChanged(const QNetworkCookie &cookie,
Q_EMIT q->cookieAdded(cookie);
}
+bool QWebEngineCookieStorePrivate::canAccessCookies(const QUrl &firstPartyUrl, const QUrl &url)
+{
+ if (!filterCallback)
+ return true;
+
+ bool thirdParty =
+ !net::registry_controlled_domains::SameDomainOrHost(toGurl(url),
+ toGurl(firstPartyUrl),
+ net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
+
+ QWebEngineCookieStore::FilterRequest request = { true, thirdParty, firstPartyUrl, url };
+ callbackDirectory.invokeDirectly<QWebEngineCookieStore::FilterRequest&>(filterCallback, request);
+ return request.accepted;
+}
+
/*!
\class QWebEngineCookieStore
\inmodule QtWebEngineCore
@@ -314,4 +332,74 @@ void QWebEngineCookieStore::deleteAllCookies()
d->deleteAllCookies();
}
+/*!
+ \fn void QWebEngineCookieStore::setCookieFilter(FunctorOrLambda filterCallback)
+ \since 5.11
+
+ Installs a cookie filter that can prevent sites and resources from using cookies.
+ The \a filterCallback must be a lambda or functor taking a FilterRequest structure. If the
+ cookie is to be rejected, the filter can set FilterRequest::accepted to \c false.
+
+ The callback should not be used to execute heavy tasks since it is running on the
+ IO thread and therefore blocks the Chromium networking.
+
+ \sa deleteAllCookies(), loadAllCookies()
+*/
+void QWebEngineCookieStore::setCookieFilter(const QWebEngineCallback<QWebEngineCookieStore::FilterRequest&> &filter)
+{
+ Q_D(QWebEngineCookieStore);
+ d->filterCallback = filter;
+}
+
+/*!
+ \class QWebEngineCookieStore::FilterRequest
+ \inmodule QtWebEngineCore
+ \since 5.11
+
+ \brief This struct is used in conjunction with QWebEngineCookieStore::setCookieFilter() and is
+ the type \a filterCallback operates on.
+
+ \sa QWebEngineCookieStore::setCookieFilter()
+*/
+
+/*!
+ \variable QWebEngineCookieStore::FilterRequest::accepted
+ \brief Whether the cookie access should be accepted or not. Defaults to \c true.
+
+ Can be set to \c false by the filter to block the cookie access.
+*/
+
+/*!
+ \variable QWebEngineCookieStore::FilterRequest::firstPartyUrl
+ \brief The URL that was navigated to.
+
+ The site that would be showing in the location bar if the application has one.
+
+ Can be used to white-list or black-list cookie access or third-party cookie access
+ for specific sites visited.
+
+ \sa origin, thirdParty
+*/
+
+/*!
+ \variable QWebEngineCookieStore::FilterRequest::origin
+ \brief The URL of the script or content accessing a cookie
+
+ Can be used to white-list or black-list third-party cookie access
+ for specific services.
+
+ \sa firstPartyUrl, thirdParty
+*/
+
+/*!
+ \variable QWebEngineCookieStore::FilterRequest::thirdParty
+ \brief Whether this is considered a third-party access
+
+ This is calculated by comparing FilterRequest::origin and FilterRequest::firstPartyUrl and
+ checking if they share a common origin that is not a top-domain (like .com or .co.uk),
+ or a known hosting site with independently owned subdomains.
+
+ \sa firstPartyUrl, origin
+*/
+
QT_END_NAMESPACE
diff --git a/src/core/api/qwebenginecookiestore.h b/src/core/api/qwebenginecookiestore.h
index c05a72cf1..d3feacefe 100644
--- a/src/core/api/qwebenginecookiestore.h
+++ b/src/core/api/qwebenginecookiestore.h
@@ -60,8 +60,20 @@ class QWEBENGINE_EXPORT QWebEngineCookieStore : public QObject {
Q_OBJECT
public:
+ struct FilterRequest {
+ bool accepted;
+ const bool thirdParty;
+
+ const QUrl firstPartyUrl;
+ const QUrl origin;
+ };
virtual ~QWebEngineCookieStore();
+#ifdef Q_QDOC
+ void setCookieFilter(FunctorOrLambda filterCallback);
+#else
+ void setCookieFilter(const QWebEngineCallback<FilterRequest&> &filterCallback);
+#endif
void setCookie(const QNetworkCookie &cookie, const QUrl &origin = QUrl());
void deleteCookie(const QNetworkCookie &cookie, const QUrl &origin = QUrl());
void deleteSessionCookies();
diff --git a/src/core/api/qwebenginecookiestore_p.h b/src/core/api/qwebenginecookiestore_p.h
index 582c0712a..809aa39b0 100644
--- a/src/core/api/qwebenginecookiestore_p.h
+++ b/src/core/api/qwebenginecookiestore_p.h
@@ -78,6 +78,7 @@ class QWEBENGINE_PRIVATE_EXPORT QWebEngineCookieStorePrivate
QWebEngineCookieStore *q_ptr;
public:
QtWebEngineCore::CallbackDirectory callbackDirectory;
+ QWebEngineCallback<QWebEngineCookieStore::FilterRequest&> filterCallback;
QVector<CookieData> m_pendingUserCookies;
quint64 m_nextCallbackId;
bool m_deleteSessionCookiesPending;
@@ -96,6 +97,8 @@ public:
void deleteAllCookies();
void getAllCookies();
+ bool canAccessCookies(const QUrl &firstPartyUrl, const QUrl &url);
+
void onGetAllCallbackResult(qint64 callbackId, const QByteArray &cookieList);
void onSetCallbackResult(qint64 callbackId, bool success);
void onDeleteCallbackResult(qint64 callbackId, int numCookies);
diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp
index d0019e4f3..5689a4fb8 100644
--- a/src/core/content_browser_client_qt.cpp
+++ b/src/core/content_browser_client_qt.cpp
@@ -68,6 +68,7 @@
#include "device/geolocation/geolocation_provider.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/binding_set.h"
+#include "printing/features/features.h"
#include "net/ssl/client_cert_identity.h"
#include "services/service_manager/public/cpp/bind_source_info.h"
#include "services/service_manager/public/cpp/binder_registry.h"
@@ -93,7 +94,7 @@
#include "device/geolocation/location_provider.h"
#endif
#include "media_capture_devices_dispatcher.h"
-#include "printing/features/features.h"
+#include "network_delegate_qt.h"
#if BUILDFLAG(ENABLE_BASIC_PRINTING)
#include "printing_message_filter_qt.h"
#endif // BUILDFLAG(ENABLE_BASIC_PRINTING)
@@ -660,6 +661,29 @@ bool ContentBrowserClientQt::CanCreateWindow(
return (settings && settings->getJavaScriptCanOpenWindowsAutomatically()) || user_gesture;
}
+bool ContentBrowserClientQt::AllowGetCookie(const GURL &url,
+ const GURL &first_party,
+ const net::CookieList & /*cookie_list*/,
+ content::ResourceContext *context,
+ int /*render_process_id*/,
+ int /*render_frame_id*/)
+{
+ NetworkDelegateQt *networkDelegate = static_cast<NetworkDelegateQt *>(context->GetRequestContext()->network_delegate());
+ return networkDelegate->canGetCookies(first_party, url);
+}
+
+bool ContentBrowserClientQt::AllowSetCookie(const GURL &url,
+ const GURL &first_party,
+ const std::string &cookie_line,
+ content::ResourceContext *context,
+ int /*render_process_id*/,
+ int /*render_frame_id*/,
+ const net::CookieOptions& /*options*/)
+{
+ NetworkDelegateQt *networkDelegate = static_cast<NetworkDelegateQt *>(context->GetRequestContext()->network_delegate());
+ return networkDelegate->canSetCookies(first_party, url, cookie_line);
+}
+
} // namespace QtWebEngineCore
DEFINE_WEB_CONTENTS_USER_DATA_KEY(QtWebEngineCore::ServiceDriver);
diff --git a/src/core/content_browser_client_qt.h b/src/core/content_browser_client_qt.h
index d810fc08a..db5cbd191 100644
--- a/src/core/content_browser_client_qt.h
+++ b/src/core/content_browser_client_qt.h
@@ -137,6 +137,21 @@ public:
bool opener_suppressed,
bool* no_javascript_access) override;
+ bool AllowGetCookie(const GURL& url,
+ const GURL& first_party,
+ const net::CookieList& cookie_list,
+ content::ResourceContext* context,
+ int render_process_id,
+ int render_frame_id) override;
+
+ bool AllowSetCookie(const GURL& url,
+ const GURL& first_party,
+ const std::string& cookie_line,
+ content::ResourceContext* context,
+ int render_process_id,
+ int render_frame_id,
+ const net::CookieOptions& options) override;
+
#if defined(Q_OS_LINUX)
void GetAdditionalMappedFilesForChildProcess(const base::CommandLine& command_line, int child_process_id, content::FileDescriptorInfo* mappings) override;
#endif
diff --git a/src/core/cookie_monster_delegate_qt.cpp b/src/core/cookie_monster_delegate_qt.cpp
index 0fa8dead0..58cd481dc 100644
--- a/src/core/cookie_monster_delegate_qt.cpp
+++ b/src/core/cookie_monster_delegate_qt.cpp
@@ -211,10 +211,20 @@ void CookieMonsterDelegateQt::setClient(QWebEngineCookieStore *client)
m_client->d_func()->processPendingUserCookies();
}
-bool CookieMonsterDelegateQt::canSetCookie(const QUrl &firstPartyUrl, const QByteArray &cookieLine, const QUrl &url)
+bool CookieMonsterDelegateQt::canSetCookie(const QUrl &firstPartyUrl, const QByteArray &/*cookieLine*/, const QUrl &url)
{
- // TODO: should be used for FilterRequest implementation
- return true;
+ if (!m_client)
+ return true;
+
+ return m_client->d_func()->canAccessCookies(firstPartyUrl, url);
+}
+
+bool CookieMonsterDelegateQt::canGetCookies(const QUrl &firstPartyUrl, const QUrl &url)
+{
+ if (!m_client)
+ return true;
+
+ return m_client->d_func()->canAccessCookies(firstPartyUrl, url);
}
void CookieMonsterDelegateQt::OnCookieChanged(const net::CanonicalCookie& cookie, bool removed, net::CookieStore::ChangeCause cause)
diff --git a/src/core/cookie_monster_delegate_qt.h b/src/core/cookie_monster_delegate_qt.h
index 4625eb264..941992a7b 100644
--- a/src/core/cookie_monster_delegate_qt.h
+++ b/src/core/cookie_monster_delegate_qt.h
@@ -83,6 +83,7 @@ public:
void setClient(QWebEngineCookieStore *client);
bool canSetCookie(const QUrl &firstPartyUrl, const QByteArray &cookieLine, const QUrl &url);
+ bool canGetCookies(const QUrl &firstPartyUrl, const QUrl &url);
void OnCookieChanged(const net::CanonicalCookie& cookie, bool removed, net::CookieStore::ChangeCause cause) override;
private:
diff --git a/src/core/network_delegate_qt.cpp b/src/core/network_delegate_qt.cpp
index 90d4e6ce2..f82d47fa1 100644
--- a/src/core/network_delegate_qt.cpp
+++ b/src/core/network_delegate_qt.cpp
@@ -238,10 +238,25 @@ bool NetworkDelegateQt::OnCanSetCookie(const net::URLRequest& request,
const std::string& cookie_line,
net::CookieOptions*)
{
+ return canSetCookies(request.first_party_for_cookies(), request.url(), cookie_line);
+}
+
+bool NetworkDelegateQt::OnCanGetCookies(const net::URLRequest& request, const net::CookieList&)
+{
+ return canGetCookies(request.first_party_for_cookies(), request.url());
+}
+
+bool NetworkDelegateQt::canSetCookies(const GURL &first_party, const GURL &url, const std::string &cookie_line) const
+{
Q_ASSERT(m_requestContextGetter);
- return m_requestContextGetter->m_cookieDelegate->canSetCookie(toQt(request.first_party_for_cookies()), QByteArray::fromStdString(cookie_line), toQt(request.url()));
+ return m_requestContextGetter->m_cookieDelegate->canSetCookie(toQt(first_party), QByteArray::fromStdString(cookie_line), toQt(url));
}
+bool NetworkDelegateQt::canGetCookies(const GURL &first_party, const GURL &url) const
+{
+ Q_ASSERT(m_requestContextGetter);
+ return m_requestContextGetter->m_cookieDelegate->canGetCookies(toQt(first_party), toQt(url));
+}
int NetworkDelegateQt::OnBeforeStartTransaction(net::URLRequest *request, const net::CompletionCallback &callback, net::HttpRequestHeaders *headers)
{
@@ -291,11 +306,6 @@ net::NetworkDelegate::AuthRequiredResponse NetworkDelegateQt::OnAuthRequired(net
return AUTH_REQUIRED_RESPONSE_NO_ACTION;
}
-bool NetworkDelegateQt::OnCanGetCookies(const net::URLRequest&, const net::CookieList&)
-{
- return true;
-}
-
bool NetworkDelegateQt::OnCanAccessFile(const net::URLRequest&, const base::FilePath&, const base::FilePath&) const
{
return true;
diff --git a/src/core/network_delegate_qt.h b/src/core/network_delegate_qt.h
index b0a8e1ef9..452d1dd77 100644
--- a/src/core/network_delegate_qt.h
+++ b/src/core/network_delegate_qt.h
@@ -100,6 +100,9 @@ public:
const GURL& endpoint) const override;
virtual bool OnCanUseReportingClient(const url::Origin& origin,
const GURL& endpoint) const override;
+
+ bool canSetCookies(const GURL &first_party, const GURL &url, const std::string &cookie_line) const;
+ bool canGetCookies(const GURL &first_party, const GURL &url) const;
};
} // namespace QtWebEngineCore
diff --git a/tests/auto/core/qwebenginecookiestore/tst_qwebenginecookiestore.cpp b/tests/auto/core/qwebenginecookiestore/tst_qwebenginecookiestore.cpp
index 930c208ee..913614df2 100644
--- a/tests/auto/core/qwebenginecookiestore/tst_qwebenginecookiestore.cpp
+++ b/tests/auto/core/qwebenginecookiestore/tst_qwebenginecookiestore.cpp
@@ -51,6 +51,7 @@ private Q_SLOTS:
void cookieSignals();
void setAndDeleteCookie();
void batchCookieTasks();
+ void basicFilter();
private:
QWebEngineProfile m_profile;
@@ -186,5 +187,37 @@ void tst_QWebEngineCookieStore::batchCookieTasks()
QTRY_COMPARE(cookieRemovedSpy.count(), 4);
}
+void tst_QWebEngineCookieStore::basicFilter()
+{
+ QWebEnginePage page(&m_profile);
+ QWebEngineCookieStore *client = m_profile.cookieStore();
+
+ QAtomicInt accessTested = 0;
+ client->setCookieFilter([&](QWebEngineCookieStore::FilterRequest &){ ++accessTested; });
+
+ QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool)));
+ QSignalSpy cookieAddedSpy(client, SIGNAL(cookieAdded(const QNetworkCookie &)));
+ QSignalSpy cookieRemovedSpy(client, SIGNAL(cookieRemoved(const QNetworkCookie &)));
+
+ page.load(QUrl("qrc:///resources/index.html"));
+
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QVERIFY(loadSpy.takeFirst().takeFirst().toBool());
+ QTRY_COMPARE(cookieAddedSpy.count(), 2);
+ QTRY_COMPARE(accessTested.loadAcquire(), 2);
+
+ client->deleteAllCookies();
+ QTRY_COMPARE(cookieRemovedSpy.count(), 2);
+
+ client->setCookieFilter([&](QWebEngineCookieStore::FilterRequest &request){ ++accessTested; request.accepted = false; });
+ page.triggerAction(QWebEnginePage::ReloadAndBypassCache);
+ QTRY_COMPARE(loadSpy.count(), 1);
+ QVERIFY(loadSpy.takeFirst().takeFirst().toBool());
+ QTRY_COMPARE(accessTested.loadAcquire(), 4);
+ // Test cookies are NOT added:
+ QTest::qWait(100);
+ QCOMPARE(cookieAddedSpy.count(), 2);
+}
+
QTEST_MAIN(tst_QWebEngineCookieStore)
#include "tst_qwebenginecookiestore.moc"
diff --git a/tests/quicktestbrowser/BrowserWindow.qml b/tests/quicktestbrowser/BrowserWindow.qml
index 2d8807e8c..22f98e1c5 100644
--- a/tests/quicktestbrowser/BrowserWindow.qml
+++ b/tests/quicktestbrowser/BrowserWindow.qml
@@ -66,6 +66,7 @@ ApplicationWindow {
property alias javaScriptEnabled: javaScriptEnabled.checked;
property alias errorPageEnabled: errorPageEnabled.checked;
property alias pluginsEnabled: pluginsEnabled.checked;
+ property alias thirdPartyCookiesEnabled: thirdPartyCookiesEnabled.checked;
}
// Make sure the Qt.WindowFullscreenButtonHint is set on OS X.
@@ -241,6 +242,13 @@ ApplicationWindow {
checked: true
}
MenuItem {
+ id: thirdPartyCookiesEnabled
+ text: "Third party cookies enabled"
+ checkable: true
+ checked: true
+ onToggled: applicationRoot.thirdPartyCookiesEnabled = checked
+ }
+ MenuItem {
id: offTheRecordEnabled
text: "Off The Record"
checkable: true
diff --git a/tests/quicktestbrowser/main.cpp b/tests/quicktestbrowser/main.cpp
index 3f513f6a6..d56841974 100644
--- a/tests/quicktestbrowser/main.cpp
+++ b/tests/quicktestbrowser/main.cpp
@@ -70,7 +70,27 @@ int main(int argc, char **argv)
Utils utils;
appEngine.rootContext()->setContextProperty("utils", &utils);
appEngine.load(QUrl("qrc:/ApplicationRoot.qml"));
- QMetaObject::invokeMethod(appEngine.rootObjects().first(), "load", Q_ARG(QVariant, startupUrl()));
+
+ QObject *rootObject = appEngine.rootObjects().first();
+
+ QQuickWebEngineProfile *profile = new QQuickWebEngineProfile(rootObject);
+
+ const QMetaObject *rootMeta = rootObject->metaObject();
+ int index = rootMeta->indexOfProperty("thirdPartyCookiesEnabled");
+ Q_ASSERT(index != -1);
+ QMetaProperty thirdPartyCookiesProperty = rootMeta->property(index);
+ profile->cookieStore()->setCookieFilter(
+ [rootObject,&thirdPartyCookiesProperty](QWebEngineCookieStore::FilterRequest &request)
+ {
+ request.accepted = !request.thirdParty || thirdPartyCookiesProperty.read(rootObject).toBool();
+ });
+
+ index = rootMeta->indexOfProperty("testProfile");
+ Q_ASSERT(index != -1);
+ QMetaProperty profileProperty = rootMeta->property(index);
+ profileProperty.write(rootObject, qVariantFromValue(profile));
+
+ QMetaObject::invokeMethod(rootObject, "load", Q_ARG(QVariant, startupUrl()));
return app.exec();
}