summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSzabolcs David <davidsz@inf.u-szeged.hu>2022-05-09 13:06:06 +0200
committerSzabolcs David <davidsz@inf.u-szeged.hu>2022-05-26 12:10:35 +0200
commit567739fda232c28992962f32a9e652eab723a4d4 (patch)
treecb933c189d87ed104f71ad8393d9e93d0eec193a
parent2ba1f04b4589e5883a399b022b7795266c4d4646 (diff)
Implement File System Access permission API
Allow web pages to safely access the local file system by exposing a permission API. Permissions are stored in-memory. The built-in access rules are the same as the behavior of Chrome: JS can't request access to system libraries, sensitive directories and the application itself. Task-number: QTBUG-97829 Change-Id: Ic675422cafbad5a90243b4fa8f0749c46afa192c Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
-rw-r--r--examples/webenginewidgets/simplebrowser/webview.cpp32
-rw-r--r--examples/webenginewidgets/simplebrowser/webview.h2
-rw-r--r--src/core/CMakeLists.txt6
-rw-r--r--src/core/api/CMakeLists.txt1
-rw-r--r--src/core/api/qwebenginefilesystemaccessrequest.cpp155
-rw-r--r--src/core/api/qwebenginefilesystemaccessrequest.h99
-rw-r--r--src/core/api/qwebenginepage.cpp8
-rw-r--r--src/core/api/qwebenginepage.h2
-rw-r--r--src/core/api/qwebenginepage_p.h1
-rw-r--r--src/core/content_browser_client_qt.cpp2
-rw-r--r--src/core/file_system_access/file_system_access_permission_context_factory_qt.cpp97
-rw-r--r--src/core/file_system_access/file_system_access_permission_context_factory_qt.h73
-rw-r--r--src/core/file_system_access/file_system_access_permission_context_qt.cpp432
-rw-r--r--src/core/file_system_access/file_system_access_permission_context_qt.h114
-rw-r--r--src/core/file_system_access/file_system_access_permission_grant_qt.cpp178
-rw-r--r--src/core/file_system_access/file_system_access_permission_grant_qt.h94
-rw-r--r--src/core/file_system_access/file_system_access_permission_request_controller.h75
-rw-r--r--src/core/file_system_access/file_system_access_permission_request_controller_impl.cpp84
-rw-r--r--src/core/file_system_access/file_system_access_permission_request_controller_impl.h68
-rw-r--r--src/core/file_system_access/file_system_access_permission_request_manager_qt.cpp231
-rw-r--r--src/core/file_system_access/file_system_access_permission_request_manager_qt.h115
-rw-r--r--src/core/profile_qt.cpp6
-rw-r--r--src/core/profile_qt.h1
-rw-r--r--src/core/web_contents_adapter_client.h2
-rw-r--r--src/webenginequick/api/qquickwebengineview.cpp8
-rw-r--r--src/webenginequick/api/qquickwebengineview_p.h2
-rw-r--r--src/webenginequick/api/qquickwebengineview_p_p.h1
-rw-r--r--tests/auto/quick/publicapi/tst_publicapi.cpp13
-rw-r--r--tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp33
29 files changed, 1929 insertions, 6 deletions
diff --git a/examples/webenginewidgets/simplebrowser/webview.cpp b/examples/webenginewidgets/simplebrowser/webview.cpp
index 31be9f34c..661dd5955 100644
--- a/examples/webenginewidgets/simplebrowser/webview.cpp
+++ b/examples/webenginewidgets/simplebrowser/webview.cpp
@@ -144,6 +144,8 @@ void WebView::setPage(WebPage *page)
&WebView::handleProxyAuthenticationRequired);
disconnect(oldPage, &QWebEnginePage::registerProtocolHandlerRequested, this,
&WebView::handleRegisterProtocolHandlerRequested);
+ disconnect(oldPage, &QWebEnginePage::fileSystemAccessRequested, this,
+ &WebView::handleFileSystemAccessRequested);
}
createWebActionTrigger(page,QWebEnginePage::Forward);
createWebActionTrigger(page,QWebEnginePage::Back);
@@ -159,6 +161,8 @@ void WebView::setPage(WebPage *page)
&WebView::handleProxyAuthenticationRequired);
connect(page, &QWebEnginePage::registerProtocolHandlerRequested, this,
&WebView::handleRegisterProtocolHandlerRequested);
+ connect(page, &QWebEnginePage::fileSystemAccessRequested, this,
+ &WebView::handleFileSystemAccessRequested);
}
int WebView::loadProgress() const
@@ -347,3 +351,31 @@ void WebView::handleRegisterProtocolHandlerRequested(
request.reject();
}
//! [registerProtocolHandlerRequested]
+
+void WebView::handleFileSystemAccessRequested(QWebEngineFileSystemAccessRequest request)
+{
+ QString accessType;
+ switch (request.accessFlags()) {
+ case QWebEngineFileSystemAccessRequest::Read:
+ accessType = "read";
+ break;
+ case QWebEngineFileSystemAccessRequest::Write:
+ accessType = "write";
+ break;
+ case QWebEngineFileSystemAccessRequest::Read | QWebEngineFileSystemAccessRequest::Write:
+ accessType = "read and write";
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+
+ auto answer = QMessageBox::question(window(), tr("File system access reques"),
+ tr("Give %1 %2 access to %3?")
+ .arg(request.origin().host())
+ .arg(accessType)
+ .arg(request.filePath().toString()));
+ if (answer == QMessageBox::Yes)
+ request.accept();
+ else
+ request.reject();
+}
diff --git a/examples/webenginewidgets/simplebrowser/webview.h b/examples/webenginewidgets/simplebrowser/webview.h
index 0dc7c33ad..7d8ff4e59 100644
--- a/examples/webenginewidgets/simplebrowser/webview.h
+++ b/examples/webenginewidgets/simplebrowser/webview.h
@@ -54,6 +54,7 @@
#include <QIcon>
#include <QWebEngineView>
#include <QWebEngineCertificateError>
+#include <QWebEngineFileSystemAccessRequest>
#include <QWebEnginePage>
#include <QWebEngineRegisterProtocolHandlerRequest>
@@ -87,6 +88,7 @@ private slots:
void handleProxyAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth,
const QString &proxyHost);
void handleRegisterProtocolHandlerRequested(QWebEngineRegisterProtocolHandlerRequest request);
+ void handleFileSystemAccessRequested(QWebEngineFileSystemAccessRequest request);
private:
void createWebActionTrigger(QWebEnginePage *page, QWebEnginePage::WebAction);
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 83f914856..94ebe0b9b 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -110,6 +110,12 @@ foreach(arch ${archs})
favicon_driver_qt.cpp favicon_driver_qt.h
favicon_service_factory_qt.cpp favicon_service_factory_qt.h
file_picker_controller.cpp file_picker_controller.h
+ file_system_access/file_system_access_permission_context_factory_qt.cpp file_system_access/file_system_access_permission_context_factory_qt.h
+ file_system_access/file_system_access_permission_context_qt.cpp file_system_access/file_system_access_permission_context_qt.h
+ file_system_access/file_system_access_permission_grant_qt.cpp file_system_access/file_system_access_permission_grant_qt.h
+ file_system_access/file_system_access_permission_request_controller.h
+ file_system_access/file_system_access_permission_request_controller_impl.cpp file_system_access/file_system_access_permission_request_controller_impl.h
+ file_system_access/file_system_access_permission_request_manager_qt.cpp file_system_access/file_system_access_permission_request_manager_qt.h
find_text_helper.cpp find_text_helper.h
global_descriptors_qt.h
javascript_dialog_controller.cpp javascript_dialog_controller.h javascript_dialog_controller_p.h
diff --git a/src/core/api/CMakeLists.txt b/src/core/api/CMakeLists.txt
index e46c95be3..2d493c04c 100644
--- a/src/core/api/CMakeLists.txt
+++ b/src/core/api/CMakeLists.txt
@@ -12,6 +12,7 @@ qt_internal_add_module(WebEngineCore
qwebenginecontextmenurequest.cpp qwebenginecontextmenurequest.h qwebenginecontextmenurequest_p.h
qwebenginecookiestore.cpp qwebenginecookiestore.h qwebenginecookiestore_p.h
qwebenginedownloadrequest.cpp qwebenginedownloadrequest.h qwebenginedownloadrequest_p.h
+ qwebenginefilesystemaccessrequest.cpp qwebenginefilesystemaccessrequest.h
qwebenginefindtextresult.cpp qwebenginefindtextresult.h
qwebenginefullscreenrequest.cpp qwebenginefullscreenrequest.h
qwebenginehistory.cpp qwebenginehistory.h qwebenginehistory_p.h
diff --git a/src/core/api/qwebenginefilesystemaccessrequest.cpp b/src/core/api/qwebenginefilesystemaccessrequest.cpp
new file mode 100644
index 000000000..7602d69bb
--- /dev/null
+++ b/src/core/api/qwebenginefilesystemaccessrequest.cpp
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 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$
+**
+****************************************************************************/
+
+#include "qwebenginefilesystemaccessrequest.h"
+
+#include "file_system_access/file_system_access_permission_request_controller.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QWebEngineFileSystemAccessRequest
+ \brief The QWebEngineFileSystemAccessRequest class enables accepting or rejecting
+ requests for local file system access from JavaScript applications.
+
+ \since 6.4
+
+ \inmodule QtWebEngineCore
+
+ To allow web applications to access local files of the computer,
+ applications must connect to QWebEnginePage::fileSystemAccessRequested, which takes a
+ QWebEngineFileSystemAccessRequest instance as an argument.
+
+ If a web applications requests access to local files or directories,
+ QWebEnginePage::fileSystemAccessRequested will be emitted with an
+ QWebEngineFileSystemAccessRequest instance as an argument where accessFlags() indicates
+ the type of the requested access: read, write or both. The signal handler needs to then
+ either call accept() or reject().
+*/
+
+QWebEngineFileSystemAccessRequest::QWebEngineFileSystemAccessRequest(
+ const QWebEngineFileSystemAccessRequest &other) = default;
+QWebEngineFileSystemAccessRequest &QWebEngineFileSystemAccessRequest::operator=(
+ const QWebEngineFileSystemAccessRequest &other) = default;
+QWebEngineFileSystemAccessRequest::QWebEngineFileSystemAccessRequest(
+ QWebEngineFileSystemAccessRequest &&other) = default;
+QWebEngineFileSystemAccessRequest &
+QWebEngineFileSystemAccessRequest::operator=(QWebEngineFileSystemAccessRequest &&other) = default;
+QWebEngineFileSystemAccessRequest::~QWebEngineFileSystemAccessRequest() = default;
+
+/*! \fn bool QWebEngineFileSystemAccessRequest::operator==(const QWebEngineFileSystemAccessRequest &that) const
+ Returns \c true if \a that points to the same object as this request.
+*/
+bool QWebEngineFileSystemAccessRequest::operator==(
+ const QWebEngineFileSystemAccessRequest &that) const
+{
+ return d_ptr == that.d_ptr;
+}
+
+/*! \fn bool QWebEngineFileSystemAccessRequest::operator!=(const QWebEngineFileSystemAccessRequest &that) const
+ Returns \c true if \a that points to a different object than this request.
+*/
+bool QWebEngineFileSystemAccessRequest::operator!=(
+ const QWebEngineFileSystemAccessRequest &that) const
+{
+ return d_ptr != that.d_ptr;
+}
+
+/*! \internal */
+QWebEngineFileSystemAccessRequest::QWebEngineFileSystemAccessRequest(
+ QSharedPointer<QtWebEngineCore::FileSystemAccessPermissionRequestController> controller)
+ : d_ptr(controller)
+{
+}
+
+/*!
+ Rejects a request to access local files.
+*/
+void QWebEngineFileSystemAccessRequest::reject()
+{
+ d_ptr->reject();
+}
+
+/*!
+ Accepts the request to access local files.
+*/
+void QWebEngineFileSystemAccessRequest::accept()
+{
+ d_ptr->accept();
+}
+
+/*!
+ \property QWebEngineFileSystemAccessRequest::origin
+ \brief The URL of the web page that issued the file system access request.
+*/
+
+QUrl QWebEngineFileSystemAccessRequest::origin() const
+{
+ return d_ptr->origin();
+}
+
+/*!
+ \property QWebEngineFileSystemAccessRequest::filePath
+ \brief Returns the file path this file system access request is referring to.
+*/
+
+QUrl QWebEngineFileSystemAccessRequest::filePath() const
+{
+ return d_ptr->filePath();
+}
+
+/*!
+ \property QWebEngineFileSystemAccessRequest::handleType
+ \brief Returns the type of the requested file system entry. (File or directory)
+ */
+HandleType QWebEngineFileSystemAccessRequest::handleType() const
+{
+ return d_ptr->handleType();
+}
+
+/*!
+ \property QWebEngineFileSystemAccessRequest::accessFlags
+ \brief Contains the requested file access rights.
+ */
+AccessFlags QWebEngineFileSystemAccessRequest::accessFlags() const
+{
+ return d_ptr->accessFlags();
+}
+
+QT_END_NAMESPACE
diff --git a/src/core/api/qwebenginefilesystemaccessrequest.h b/src/core/api/qwebenginefilesystemaccessrequest.h
new file mode 100644
index 000000000..84bcf0f90
--- /dev/null
+++ b/src/core/api/qwebenginefilesystemaccessrequest.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 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$
+**
+****************************************************************************/
+
+#ifndef QWEBENGINEFILESYSTEMACCESSREQUEST_H
+#define QWEBENGINEFILESYSTEMACCESSREQUEST_H
+
+#include <QtWebEngineCore/qtwebenginecoreglobal.h>
+
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/qurl.h>
+
+namespace QtWebEngineCore {
+class FileSystemAccessPermissionRequestController;
+class FileSystemAccessPermissionRequestManagerQt;
+}
+
+QT_BEGIN_NAMESPACE
+
+class Q_WEBENGINECORE_EXPORT QWebEngineFileSystemAccessRequest
+{
+ Q_GADGET
+ Q_PROPERTY(QUrl origin READ origin CONSTANT FINAL)
+ Q_PROPERTY(QUrl filePath READ filePath CONSTANT FINAL)
+ Q_PROPERTY(HandleType handleType READ handleType CONSTANT FINAL)
+ Q_PROPERTY(AccessFlags accessFlags READ accessFlags CONSTANT FINAL)
+
+public:
+ QWebEngineFileSystemAccessRequest(const QWebEngineFileSystemAccessRequest &other);
+ QWebEngineFileSystemAccessRequest &operator=(const QWebEngineFileSystemAccessRequest &other);
+ QWebEngineFileSystemAccessRequest(QWebEngineFileSystemAccessRequest &&other);
+ QWebEngineFileSystemAccessRequest &operator=(QWebEngineFileSystemAccessRequest &&other);
+ ~QWebEngineFileSystemAccessRequest();
+
+ enum HandleType { File, Directory };
+ Q_ENUM(HandleType)
+
+ enum AccessFlag { Read = 0x1, Write = 0x2 };
+ Q_DECLARE_FLAGS(AccessFlags, AccessFlag)
+ Q_FLAG(AccessFlags)
+
+ Q_INVOKABLE void accept();
+ Q_INVOKABLE void reject();
+ QUrl origin() const;
+ QUrl filePath() const;
+ HandleType handleType() const;
+ AccessFlags accessFlags() const;
+
+ bool operator==(const QWebEngineFileSystemAccessRequest &that) const;
+ bool operator!=(const QWebEngineFileSystemAccessRequest &that) const;
+
+private:
+ QWebEngineFileSystemAccessRequest(
+ QSharedPointer<QtWebEngineCore::FileSystemAccessPermissionRequestController>);
+ friend QtWebEngineCore::FileSystemAccessPermissionRequestManagerQt;
+
+ QSharedPointer<QtWebEngineCore::FileSystemAccessPermissionRequestController> d_ptr;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QWebEngineFileSystemAccessRequest::AccessFlags)
+
+QT_END_NAMESPACE
+
+#endif // QWEBENGINEFILESYSTEMACCESSREQUEST_H
diff --git a/src/core/api/qwebenginepage.cpp b/src/core/api/qwebenginepage.cpp
index 57d66f7fa..0b3cba785 100644
--- a/src/core/api/qwebenginepage.cpp
+++ b/src/core/api/qwebenginepage.cpp
@@ -41,6 +41,7 @@
#include "qwebenginepage_p.h"
#include "qwebenginecertificateerror.h"
+#include "qwebenginefilesystemaccessrequest.h"
#include "qwebenginefindtextresult.h"
#include "qwebenginefullscreenrequest.h"
#include "qwebenginehistory.h"
@@ -180,6 +181,7 @@ QWebEnginePagePrivate::QWebEnginePagePrivate(QWebEngineProfile *_profile)
qRegisterMetaType<QWebEngineQuotaRequest>();
qRegisterMetaType<QWebEngineRegisterProtocolHandlerRequest>();
+ qRegisterMetaType<QWebEngineFileSystemAccessRequest>();
qRegisterMetaType<QWebEngineFindTextResult>();
// See setVisible().
@@ -578,6 +580,12 @@ void QWebEnginePagePrivate::runRegisterProtocolHandlerRequest(QWebEngineRegister
Q_EMIT q->registerProtocolHandlerRequested(request);
}
+void QWebEnginePagePrivate::runFileSystemAccessRequest(QWebEngineFileSystemAccessRequest request)
+{
+ Q_Q(QWebEnginePage);
+ Q_EMIT q->fileSystemAccessRequested(request);
+}
+
QObject *QWebEnginePagePrivate::accessibilityParentObject()
{
return view ? view->accessibilityParentObject() : nullptr;
diff --git a/src/core/api/qwebenginepage.h b/src/core/api/qwebenginepage.h
index 45829f603..68fee0f84 100644
--- a/src/core/api/qwebenginepage.h
+++ b/src/core/api/qwebenginepage.h
@@ -61,6 +61,7 @@ class QContextMenuBuilder;
class QWebChannel;
class QWebEngineCertificateError;
class QWebEngineClientCertificateSelection;
+class QWebEngineFileSystemAccessRequest;
class QWebEngineFindTextResult;
class QWebEngineFullScreenRequest;
class QWebEngineHistory;
@@ -345,6 +346,7 @@ Q_SIGNALS:
void fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest);
void quotaRequested(QWebEngineQuotaRequest quotaRequest);
void registerProtocolHandlerRequested(QWebEngineRegisterProtocolHandlerRequest request);
+ void fileSystemAccessRequested(QWebEngineFileSystemAccessRequest request);
void selectClientCertificate(QWebEngineClientCertificateSelection clientCertSelection);
void authenticationRequired(const QUrl &requestUrl, QAuthenticator *authenticator);
void proxyAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *authenticator, const QString &proxyHost);
diff --git a/src/core/api/qwebenginepage_p.h b/src/core/api/qwebenginepage_p.h
index 29b253755..785930127 100644
--- a/src/core/api/qwebenginepage_p.h
+++ b/src/core/api/qwebenginepage_p.h
@@ -169,6 +169,7 @@ public:
void runMouseLockPermissionRequest(const QUrl &securityOrigin) override;
void runQuotaRequest(QWebEngineQuotaRequest) override;
void runRegisterProtocolHandlerRequest(QWebEngineRegisterProtocolHandlerRequest) override;
+ void runFileSystemAccessRequest(QWebEngineFileSystemAccessRequest) override;
QObject *accessibilityParentObject() override;
QWebEngineSettings *webEngineSettings() const override;
void allowCertificateError(const QWebEngineCertificateError &error) override;
diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp
index bede258f3..01b4fa1f3 100644
--- a/src/core/content_browser_client_qt.cpp
+++ b/src/core/content_browser_client_qt.cpp
@@ -92,6 +92,7 @@
#include "client_cert_select_controller.h"
#include "custom_handlers/protocol_handler_registry_factory.h"
#include "devtools_manager_delegate_qt.h"
+#include "file_system_access/file_system_access_permission_request_manager_qt.h"
#include "login_delegate_qt.h"
#include "media_capture_devices_dispatcher.h"
#include "net/cookie_monster_delegate_qt.h"
@@ -1250,6 +1251,7 @@ void ContentBrowserClientQt::SiteInstanceDeleting(content::SiteInstance *site_in
content::WebContentsViewDelegate *ContentBrowserClientQt::GetWebContentsViewDelegate(content::WebContents *web_contents)
{
FormInteractionTabHelper::CreateForWebContents(web_contents);
+ FileSystemAccessPermissionRequestManagerQt::CreateForWebContents(web_contents);
if (auto *registry = performance_manager::PerformanceManagerRegistry::GetInstance())
registry->MaybeCreatePageNodeForWebContents(web_contents);
diff --git a/src/core/file_system_access/file_system_access_permission_context_factory_qt.cpp b/src/core/file_system_access/file_system_access_permission_context_factory_qt.cpp
new file mode 100644
index 000000000..3640cb1e2
--- /dev/null
+++ b/src/core/file_system_access/file_system_access_permission_context_factory_qt.cpp
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 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$
+**
+****************************************************************************/
+
+#include "file_system_access_permission_context_factory_qt.h"
+
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+
+#include <QtGlobal>
+
+namespace QtWebEngineCore {
+
+// static
+FileSystemAccessPermissionContextQt *
+FileSystemAccessPermissionContextFactoryQt::GetForProfile(content::BrowserContext *profile)
+{
+ return static_cast<FileSystemAccessPermissionContextQt *>(
+ GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+// static
+FileSystemAccessPermissionContextQt *
+FileSystemAccessPermissionContextFactoryQt::GetForProfileIfExists(content::BrowserContext *profile)
+{
+ return static_cast<FileSystemAccessPermissionContextQt *>(
+ GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+// static
+FileSystemAccessPermissionContextFactoryQt *
+FileSystemAccessPermissionContextFactoryQt::GetInstance()
+{
+ return base::Singleton<FileSystemAccessPermissionContextFactoryQt>::get();
+}
+
+FileSystemAccessPermissionContextFactoryQt::FileSystemAccessPermissionContextFactoryQt()
+ : BrowserContextKeyedServiceFactory("FileSystemAccessPermissionContext",
+ BrowserContextDependencyManager::GetInstance())
+{
+}
+
+FileSystemAccessPermissionContextFactoryQt::~FileSystemAccessPermissionContextFactoryQt() = default;
+
+content::BrowserContext *FileSystemAccessPermissionContextFactoryQt::GetBrowserContextToUse(
+ content::BrowserContext *context) const
+{
+ return context;
+}
+
+KeyedService *FileSystemAccessPermissionContextFactoryQt::BuildServiceInstanceFor(
+ content::BrowserContext *context) const
+{
+ return new FileSystemAccessPermissionContextQt(context);
+}
+
+void FileSystemAccessPermissionContextFactoryQt::BrowserContextShutdown(
+ content::BrowserContext *context)
+{
+ Q_UNUSED(context);
+}
+
+} // namespace QtWebEngineCore
diff --git a/src/core/file_system_access/file_system_access_permission_context_factory_qt.h b/src/core/file_system_access/file_system_access_permission_context_factory_qt.h
new file mode 100644
index 000000000..3dfc5c64a
--- /dev/null
+++ b/src/core/file_system_access/file_system_access_permission_context_factory_qt.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 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$
+**
+****************************************************************************/
+
+#ifndef FILE_SYSTEM_ACCESS_PERMISSION_CONTEXT_FACTORY_QT_H
+#define FILE_SYSTEM_ACCESS_PERMISSION_CONTEXT_FACTORY_QT_H
+
+#include "base/memory/singleton.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+#include "file_system_access_permission_context_qt.h"
+
+namespace QtWebEngineCore {
+
+class FileSystemAccessPermissionContextFactoryQt : public BrowserContextKeyedServiceFactory
+{
+public:
+ static FileSystemAccessPermissionContextQt *GetForProfile(content::BrowserContext *profile);
+ static FileSystemAccessPermissionContextQt *
+ GetForProfileIfExists(content::BrowserContext *profile);
+ static FileSystemAccessPermissionContextFactoryQt *GetInstance();
+
+private:
+ friend struct base::DefaultSingletonTraits<FileSystemAccessPermissionContextFactoryQt>;
+
+ FileSystemAccessPermissionContextFactoryQt();
+ ~FileSystemAccessPermissionContextFactoryQt() override;
+
+ // BrowserContextKeyedServiceFactory
+ content::BrowserContext *
+ GetBrowserContextToUse(content::BrowserContext *context) const override;
+ KeyedService *BuildServiceInstanceFor(content::BrowserContext *profile) const override;
+ void BrowserContextShutdown(content::BrowserContext *context) override;
+};
+
+} // namespace QtWebEngineCore
+
+#endif // FILE_SYSTEM_ACCESS_PERMISSION_CONTEXT_FACTORY_QT_H
diff --git a/src/core/file_system_access/file_system_access_permission_context_qt.cpp b/src/core/file_system_access/file_system_access_permission_context_qt.cpp
new file mode 100644
index 000000000..215fcf4a4
--- /dev/null
+++ b/src/core/file_system_access/file_system_access_permission_context_qt.cpp
@@ -0,0 +1,432 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 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$
+**
+****************************************************************************/
+
+// This file is based on chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc:
+// Copyright 2019 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 "file_system_access_permission_context_qt.h"
+
+#include "base/base_paths.h"
+#include "base/path_service.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "chrome/common/chrome_paths.h"
+#include "components/content_settings/core/common/content_settings_types.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+
+#include "file_system_access_permission_grant_qt.h"
+#include "type_conversion.h"
+
+#include <QCoreApplication>
+#include <QStandardPaths>
+
+namespace QtWebEngineCore {
+
+// Sentinel used to indicate that no PathService key is specified for a path in
+// the struct below.
+constexpr const int kNoBasePathKey = -1;
+
+enum BlockType { kBlockAllChildren, kBlockNestedDirectories, kDontBlockChildren, kDontBlockAppFolder };
+
+const struct
+{
+ // base::BasePathKey value (or one of the platform specific extensions to it)
+ // for a path that should be blocked. Specify kNoBasePathKey if |path| should
+ // be used instead.
+ int base_path_key;
+
+ // Explicit path to block instead of using |base_path_key|. Set to nullptr to
+ // use |base_path_key| on its own. If both |base_path_key| and |path| are set,
+ // |path| is treated relative to the path |base_path_key| resolves to.
+ const base::FilePath::CharType *path;
+
+ // If this is set to kDontBlockChildren, only the given path and its parents
+ // are blocked. If this is set to kBlockAllChildren, all children of the given
+ // path are blocked as well. Finally if this is set to kBlockNestedDirectories
+ // access is allowed to individual files in the directory, but nested
+ // directories are still blocked.
+ // The BlockType of the nearest ancestor of a path to check is what ultimately
+ // determines if a path is blocked or not. If a blocked path is a descendent
+ // of another blocked path, then it may override the child-blocking policy of
+ // its ancestor. For example, if /home blocks all children, but
+ // /home/downloads does not, then /home/downloads/file.ext will *not* be
+ // blocked.
+ BlockType type;
+} kBlockedPaths[] = {
+ // Don't allow users to share their entire home directory, entire desktop or
+ // entire documents folder, but do allow sharing anything inside those
+ // directories not otherwise blocked.
+ { base::DIR_HOME, nullptr, kDontBlockChildren },
+ { base::DIR_USER_DESKTOP, nullptr, kDontBlockChildren },
+ { chrome::DIR_USER_DOCUMENTS, nullptr, kDontBlockChildren },
+ // Similar restrictions for the downloads directory.
+ { chrome::DIR_DEFAULT_DOWNLOADS, nullptr, kDontBlockChildren },
+ { chrome::DIR_DEFAULT_DOWNLOADS_SAFE, nullptr, kDontBlockChildren },
+ // The Chrome installation itself should not be modified by the web.
+ { base::DIR_EXE, nullptr, kBlockAllChildren },
+ { base::DIR_MODULE, nullptr, kBlockAllChildren },
+ { base::DIR_ASSETS, nullptr, kBlockAllChildren },
+ // And neither should the configuration of at least the currently running
+ // Chrome instance (note that this does not take --user-data-dir command
+ // line overrides into account).
+ { chrome::DIR_USER_DATA, nullptr, kBlockAllChildren },
+ // ~/.ssh is pretty sensitive on all platforms, so block access to that.
+ { base::DIR_HOME, FILE_PATH_LITERAL(".ssh"), kBlockAllChildren },
+ // And limit access to ~/.gnupg as well.
+ { base::DIR_HOME, FILE_PATH_LITERAL(".gnupg"), kBlockAllChildren },
+#if defined(OS_WIN)
+ // Some Windows specific directories to block, basically all apps, the
+ // operating system itself, as well as configuration data for apps.
+ { base::DIR_PROGRAM_FILES, nullptr, kBlockAllChildren },
+ { base::DIR_PROGRAM_FILESX86, nullptr, kBlockAllChildren },
+ { base::DIR_PROGRAM_FILES6432, nullptr, kBlockAllChildren },
+ { base::DIR_WINDOWS, nullptr, kBlockAllChildren },
+ { base::DIR_ROAMING_APP_DATA, nullptr, kBlockAllChildren },
+ { base::DIR_LOCAL_APP_DATA, nullptr, kBlockAllChildren },
+ // Whitelist AppData\Local\Temp to make the default location of QDir::tempPath(),
+ // QTemporaryFile and QTemporaryDir working on Windows.
+ { base::DIR_LOCAL_APP_DATA, FILE_PATH_LITERAL("Temp"), kDontBlockAppFolder },
+ { base::DIR_COMMON_APP_DATA, nullptr, kBlockAllChildren },
+ // Opening a file from an MTP device, such as a smartphone or a camera, is
+ // implemented by Windows as opening a file in the temporary internet files
+ // directory. To support that, allow opening files in that directory, but
+ // not whole directories.
+ { base::DIR_IE_INTERNET_CACHE, nullptr, kBlockNestedDirectories },
+#endif
+#if defined(OS_MAC)
+ // Similar Mac specific blocks.
+ { base::DIR_APP_DATA, nullptr, kBlockAllChildren },
+ { base::DIR_HOME, FILE_PATH_LITERAL("Library"), kBlockAllChildren },
+ // Allow access to iCloud files.
+ { base::DIR_HOME, FILE_PATH_LITERAL("Library/Mobile Documents"), kDontBlockChildren },
+#endif
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+ // On Linux also block access to devices via /dev, as well as security
+ // sensitive data in /sys and /proc.
+ { kNoBasePathKey, FILE_PATH_LITERAL("/dev"), kBlockAllChildren },
+ { kNoBasePathKey, FILE_PATH_LITERAL("/sys"), kBlockAllChildren },
+ { kNoBasePathKey, FILE_PATH_LITERAL("/proc"), kBlockAllChildren },
+ // And block all of ~/.config, matching the similar restrictions on mac
+ // and windows.
+ { base::DIR_HOME, FILE_PATH_LITERAL(".config"), kBlockAllChildren },
+ // Block ~/.dbus as well, just in case, although there probably isn't much a
+ // website can do with access to that directory and its contents.
+ { base::DIR_HOME, FILE_PATH_LITERAL(".dbus"), kBlockAllChildren },
+#endif
+ // TODO(https://crbug.com/984641): Refine this list, for example add
+ // XDG_CONFIG_HOME when it is not set ~/.config?
+};
+
+bool ShouldBlockAccessToPath(const base::FilePath &check_path, HandleType handle_type)
+{
+ DCHECK(!check_path.empty());
+ DCHECK(check_path.IsAbsolute());
+
+ base::FilePath nearest_ancestor;
+ int nearest_ancestor_path_key = kNoBasePathKey;
+ BlockType nearest_ancestor_block_type = kDontBlockChildren;
+ for (const auto &block : kBlockedPaths) {
+ base::FilePath blocked_path;
+ if (block.base_path_key != kNoBasePathKey) {
+ if (!base::PathService::Get(block.base_path_key, &blocked_path))
+ continue;
+ if (block.path)
+ blocked_path = blocked_path.Append(block.path);
+ } else {
+ DCHECK(block.path);
+ blocked_path = base::FilePath(block.path);
+ }
+
+ if (check_path == blocked_path || check_path.IsParent(blocked_path)) {
+ VLOG(1) << "Blocking access to " << check_path << " because it is a parent of "
+ << blocked_path << " (" << block.base_path_key << ")";
+ return true;
+ }
+
+ if (blocked_path.IsParent(check_path)
+ && (nearest_ancestor.empty() || nearest_ancestor.IsParent(blocked_path))) {
+ nearest_ancestor = blocked_path;
+ nearest_ancestor_path_key = block.base_path_key;
+ nearest_ancestor_block_type = block.type;
+ }
+ }
+
+ // The path we're checking is not in a potentially blocked directory, or the
+ // nearest ancestor does not block access to its children. Grant access.
+ if (nearest_ancestor.empty() || nearest_ancestor_block_type == kDontBlockChildren)
+ return false;
+
+ // The path we're checking is a file, and the nearest ancestor only blocks
+ // access to directories. Grant access.
+ if (handle_type == HandleType::kFile && nearest_ancestor_block_type == kBlockNestedDirectories)
+ return false;
+
+ if (nearest_ancestor_block_type == kDontBlockAppFolder) {
+ // Relative path from the nearest blocklisted ancestor
+ base::FilePath diff;
+ nearest_ancestor.AppendRelativePath(check_path, &diff);
+
+ std::vector<base::FilePath::StringType> diff_components;
+ diff.GetComponents(&diff_components);
+ if (diff_components.size() > 0 && toQt(diff_components[0]).contains(QCoreApplication::applicationName())) {
+ // The relative path contains the application name. Grant access.
+ return false;
+ }
+ }
+
+ // The nearest ancestor blocks access to its children, so block access.
+ VLOG(1) << "Blocking access to " << check_path << " because it is inside " << nearest_ancestor
+ << " (" << nearest_ancestor_path_key << ")";
+ return true;
+}
+
+struct FileSystemAccessPermissionContextQt::OriginState
+{
+ // Raw pointers, owned collectively by all the handles that reference this
+ // grant. When last reference goes away this state is cleared as well by
+ // PermissionGrantDestroyed().
+ std::map<base::FilePath, FileSystemAccessPermissionGrantQt *> read_grants;
+ std::map<base::FilePath, FileSystemAccessPermissionGrantQt *> write_grants;
+};
+
+FileSystemAccessPermissionContextQt::FileSystemAccessPermissionContextQt(
+ content::BrowserContext *context)
+ : m_profile(context)
+{
+}
+
+FileSystemAccessPermissionContextQt::~FileSystemAccessPermissionContextQt() = default;
+
+scoped_refptr<content::FileSystemAccessPermissionGrant>
+FileSystemAccessPermissionContextQt::GetReadPermissionGrant(const url::Origin &origin,
+ const base::FilePath &path,
+ HandleType handle_type,
+ UserAction user_action)
+{
+ Q_UNUSED(user_action);
+
+ auto &origin_state = m_origins[origin];
+ auto *&existing_grant = origin_state.read_grants[path];
+ scoped_refptr<FileSystemAccessPermissionGrantQt> new_grant;
+
+ if (existing_grant && existing_grant->handleType() != handle_type) {
+ // |path| changed from being a directory to being a file or vice versa,
+ // don't just re-use the existing grant but revoke the old grant before
+ // creating a new grant.
+ existing_grant->SetStatus(PermissionStatus::DENIED);
+ existing_grant = nullptr;
+ }
+
+ if (!existing_grant) {
+ new_grant = base::MakeRefCounted<FileSystemAccessPermissionGrantQt>(
+ m_weakFactory.GetWeakPtr(), origin, path, handle_type, GrantType::kRead);
+ existing_grant = new_grant.get();
+ }
+
+ return existing_grant;
+}
+
+scoped_refptr<content::FileSystemAccessPermissionGrant>
+FileSystemAccessPermissionContextQt::GetWritePermissionGrant(const url::Origin &origin,
+ const base::FilePath &path,
+ HandleType handle_type,
+ UserAction user_action)
+{
+ Q_UNUSED(user_action);
+
+ auto &origin_state = m_origins[origin];
+ auto *&existing_grant = origin_state.write_grants[path];
+ scoped_refptr<FileSystemAccessPermissionGrantQt> new_grant;
+
+ if (existing_grant && existing_grant->handleType() != handle_type) {
+ // |path| changed from being a directory to being a file or vice versa,
+ // don't just re-use the existing grant but revoke the old grant before
+ // creating a new grant.
+ existing_grant->SetStatus(PermissionStatus::DENIED);
+ existing_grant = nullptr;
+ }
+
+ if (!existing_grant) {
+ new_grant = base::MakeRefCounted<FileSystemAccessPermissionGrantQt>(
+ m_weakFactory.GetWeakPtr(), origin, path, handle_type, GrantType::kWrite);
+ existing_grant = new_grant.get();
+ }
+
+ return existing_grant;
+}
+
+void FileSystemAccessPermissionContextQt::ConfirmSensitiveDirectoryAccess(
+ const url::Origin &origin, PathType path_type, const base::FilePath &path,
+ HandleType handle_type, content::GlobalRenderFrameHostId frame_id,
+ base::OnceCallback<void(SensitiveDirectoryResult)> callback)
+{
+ if (path_type == PathType::kExternal) {
+ std::move(callback).Run(SensitiveDirectoryResult::kAllowed);
+ return;
+ }
+
+ base::ThreadPool::PostTaskAndReplyWithResult(
+ FROM_HERE, { base::MayBlock(), base::TaskPriority::USER_VISIBLE },
+ base::BindOnce(&ShouldBlockAccessToPath, path, handle_type),
+ base::BindOnce(&FileSystemAccessPermissionContextQt::DidConfirmSensitiveDirectoryAccess,
+ m_weakFactory.GetWeakPtr(), origin, path, handle_type, frame_id,
+ std::move(callback)));
+}
+
+void FileSystemAccessPermissionContextQt::PerformAfterWriteChecks(
+ std::unique_ptr<content::FileSystemAccessWriteItem> item,
+ content::GlobalRenderFrameHostId frame_id,
+ base::OnceCallback<void(AfterWriteCheckResult)> callback)
+{
+ Q_UNUSED(item);
+ Q_UNUSED(frame_id);
+ std::move(callback).Run(AfterWriteCheckResult::kAllow);
+}
+
+bool FileSystemAccessPermissionContextQt::CanObtainReadPermission(const url::Origin &origin)
+{
+ Q_UNUSED(origin);
+ return true;
+}
+
+bool FileSystemAccessPermissionContextQt::CanObtainWritePermission(const url::Origin &origin)
+{
+ Q_UNUSED(origin);
+ return true;
+}
+
+void FileSystemAccessPermissionContextQt::SetLastPickedDirectory(const url::Origin &origin,
+ const std::string &id,
+ const base::FilePath &path,
+ const PathType type)
+{
+ Q_UNUSED(origin);
+
+ FileSystemAccessPermissionContextQt::PathInfo info;
+ info.path = path;
+ info.type = type;
+ m_lastPickedDirectories.insert({ id, info });
+}
+
+FileSystemAccessPermissionContextQt::PathInfo
+FileSystemAccessPermissionContextQt::GetLastPickedDirectory(const url::Origin &origin,
+ const std::string &id)
+{
+ Q_UNUSED(origin);
+
+ return m_lastPickedDirectories.find(id) != m_lastPickedDirectories.end()
+ ? m_lastPickedDirectories[id]
+ : FileSystemAccessPermissionContextQt::PathInfo();
+}
+
+base::FilePath FileSystemAccessPermissionContextQt::GetWellKnownDirectoryPath(
+ blink::mojom::WellKnownDirectory directory)
+{
+ QStandardPaths::StandardLocation location = QStandardPaths::DocumentsLocation;
+ switch (directory) {
+ case blink::mojom::WellKnownDirectory::kDefault:
+ location = QStandardPaths::DocumentsLocation;
+ break;
+ case blink::mojom::WellKnownDirectory::kDirDesktop:
+ location = QStandardPaths::DesktopLocation;
+ break;
+ case blink::mojom::WellKnownDirectory::kDirDocuments:
+ location = QStandardPaths::DocumentsLocation;
+ break;
+ case blink::mojom::WellKnownDirectory::kDirDownloads:
+ location = QStandardPaths::DownloadLocation;
+ break;
+ case blink::mojom::WellKnownDirectory::kDirMusic:
+ location = QStandardPaths::MusicLocation;
+ break;
+ case blink::mojom::WellKnownDirectory::kDirPictures:
+ location = QStandardPaths::PicturesLocation;
+ break;
+ case blink::mojom::WellKnownDirectory::kDirVideos:
+ location = QStandardPaths::MoviesLocation;
+ break;
+ }
+
+ return toFilePath(QStandardPaths::writableLocation(location));
+}
+
+void FileSystemAccessPermissionContextQt::NavigatedAwayFromOrigin(const url::Origin &origin)
+{
+ // If the last top-level WebContents for an origin is closed (or is navigated to another
+ // origin), all the permissions for that origin will be revoked.
+
+ auto it = m_origins.find(origin);
+ // If we have no permissions for the origin, there is nothing to do.
+ if (it == m_origins.end())
+ return;
+
+ std::vector<content::WebContentsImpl *> list = content::WebContentsImpl::GetAllWebContents();
+ for (content::WebContentsImpl *web_contents : list) {
+ url::Origin web_contents_origin = url::Origin::Create(web_contents->GetLastCommittedURL());
+ // Found a tab for this origin, so early exit and don't revoke grants.
+ if (web_contents_origin == origin)
+ return;
+ }
+
+ OriginState &origin_state = it->second;
+ for (auto &grant : origin_state.read_grants)
+ grant.second->SetStatus(PermissionStatus::ASK);
+ for (auto &grant : origin_state.write_grants)
+ grant.second->SetStatus(PermissionStatus::ASK);
+}
+
+void FileSystemAccessPermissionContextQt::DidConfirmSensitiveDirectoryAccess(
+ const url::Origin &origin, const base::FilePath &path, HandleType handle_type,
+ content::GlobalRenderFrameHostId frame_id,
+ base::OnceCallback<void(SensitiveDirectoryResult)> callback, bool should_block)
+{
+ Q_UNUSED(origin);
+ Q_UNUSED(path);
+ Q_UNUSED(handle_type);
+ Q_UNUSED(frame_id);
+
+ if (should_block)
+ std::move(callback).Run(SensitiveDirectoryResult::kAbort);
+ else
+ std::move(callback).Run(SensitiveDirectoryResult::kAllowed);
+}
+
+} // namespace QtWebEngineCore
diff --git a/src/core/file_system_access/file_system_access_permission_context_qt.h b/src/core/file_system_access/file_system_access_permission_context_qt.h
new file mode 100644
index 000000000..36aea7376
--- /dev/null
+++ b/src/core/file_system_access/file_system_access_permission_context_qt.h
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 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$
+**
+****************************************************************************/
+
+// This file is based on chrome/browser/file_system_access/chrome_file_system_access_permission_context.h:
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef FILE_SYSTEM_ACCESS_PERMISSION_CONTEXT_QT_H
+#define FILE_SYSTEM_ACCESS_PERMISSION_CONTEXT_QT_H
+
+#include "base/files/file_path.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "content/public/browser/file_system_access_permission_context.h"
+#include "content/public/browser/global_routing_id.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace QtWebEngineCore {
+
+class FileSystemAccessPermissionContextQt : public content::FileSystemAccessPermissionContext,
+ public KeyedService
+{
+public:
+ explicit FileSystemAccessPermissionContextQt(content::BrowserContext *context);
+ ~FileSystemAccessPermissionContextQt() override;
+
+ enum class GrantType { kRead, kWrite };
+
+ // content::FileSystemAccessPermissionContext:
+ scoped_refptr<content::FileSystemAccessPermissionGrant>
+ GetReadPermissionGrant(const url::Origin &origin, const base::FilePath &path,
+ HandleType handle_type, UserAction user_action) override;
+ scoped_refptr<content::FileSystemAccessPermissionGrant>
+ GetWritePermissionGrant(const url::Origin &origin, const base::FilePath &path,
+ HandleType handle_type, UserAction user_action) override;
+ void ConfirmSensitiveDirectoryAccess(
+ const url::Origin &origin, PathType path_type, const base::FilePath &path,
+ HandleType handle_type, content::GlobalRenderFrameHostId frame_id,
+ base::OnceCallback<void(SensitiveDirectoryResult)> callback) override;
+ void PerformAfterWriteChecks(std::unique_ptr<content::FileSystemAccessWriteItem> item,
+ content::GlobalRenderFrameHostId frame_id,
+ base::OnceCallback<void(AfterWriteCheckResult)> callback) override;
+ bool CanObtainReadPermission(const url::Origin &origin) override;
+ bool CanObtainWritePermission(const url::Origin &origin) override;
+ void SetLastPickedDirectory(const url::Origin &origin, const std::string &id,
+ const base::FilePath &path, const PathType type) override;
+ FileSystemAccessPermissionContextQt::PathInfo
+ GetLastPickedDirectory(const url::Origin &origin, const std::string &id) override;
+ base::FilePath GetWellKnownDirectoryPath(blink::mojom::WellKnownDirectory directory) override;
+
+ void NavigatedAwayFromOrigin(const url::Origin &origin);
+ content::BrowserContext *profile() const { return m_profile; }
+
+private:
+ class PermissionGrantImpl;
+
+ void DidConfirmSensitiveDirectoryAccess(
+ const url::Origin &origin, const base::FilePath &path, HandleType handle_type,
+ content::GlobalRenderFrameHostId frame_id,
+ base::OnceCallback<void(SensitiveDirectoryResult)> callback, bool should_block);
+
+ content::BrowserContext *m_profile;
+
+ // Permission state per origin.
+ struct OriginState;
+ std::map<url::Origin, OriginState> m_origins;
+
+ std::map<std::string, FileSystemAccessPermissionContextQt::PathInfo> m_lastPickedDirectories;
+
+ base::WeakPtrFactory<FileSystemAccessPermissionContextQt> m_weakFactory { this };
+};
+
+} // namespace QtWebEngineCore
+
+#endif // FILE_SYSTEM_ACCESS_PERMISSION_CONTEXT_QT_H
diff --git a/src/core/file_system_access/file_system_access_permission_grant_qt.cpp b/src/core/file_system_access/file_system_access_permission_grant_qt.cpp
new file mode 100644
index 000000000..f5ee4423f
--- /dev/null
+++ b/src/core/file_system_access/file_system_access_permission_grant_qt.cpp
@@ -0,0 +1,178 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 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$
+**
+****************************************************************************/
+
+#include "file_system_access_permission_grant_qt.h"
+
+#include "file_system_access_permission_request_manager_qt.h"
+
+#include "components/permissions/permission_util.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/disallow_activation_reason.h"
+#include "url/origin.h"
+
+namespace QtWebEngineCore {
+
+FileSystemAccessPermissionGrantQt::FileSystemAccessPermissionGrantQt(
+ base::WeakPtr<FileSystemAccessPermissionContextQt> context, const url::Origin &origin,
+ const base::FilePath &path, HandleType handle_type, GrantType type)
+ : m_context(context), m_origin(origin), m_path(path), m_handleType(handle_type), m_type(type)
+{
+}
+
+void FileSystemAccessPermissionGrantQt::RequestPermission(
+ content::GlobalRenderFrameHostId frame_id, UserActivationState user_activation_state,
+ base::OnceCallback<void(PermissionRequestOutcome)> callback)
+{
+ // Check if a permission request has already been processed previously. This
+ // check is done first because we don't want to reset the status of a
+ // permission if it has already been granted.
+ if (GetStatus() != PermissionStatus::ASK || !m_context) {
+ if (GetStatus() == PermissionStatus::GRANTED)
+ SetStatus(PermissionStatus::GRANTED);
+ std::move(callback).Run(PermissionRequestOutcome::kRequestAborted);
+ return;
+ }
+
+ // Otherwise, perform checks and ask the user for permission.
+
+ content::RenderFrameHost *rfh = content::RenderFrameHost::FromID(frame_id);
+ if (!rfh) {
+ // Requested from a no longer valid render frame host.
+ std::move(callback).Run(PermissionRequestOutcome::kInvalidFrame);
+ return;
+ }
+
+ // Don't show request permission UI for an inactive RenderFrameHost as the
+ // page might not distinguish properly between user denying the permission
+ // and automatic rejection, leading to an inconsistent UX once the page
+ // becomes active again.
+ // - If this is called when RenderFrameHost is in BackForwardCache, evict
+ // the document from the cache.
+ // - If this is called when RenderFrameHost is in prerendering, cancel
+ // prerendering.
+ if (rfh->IsInactiveAndDisallowActivation(
+ content::DisallowActivationReasonId::kFileSystemAccessPermissionRequest)) {
+ std::move(callback).Run(PermissionRequestOutcome::kInvalidFrame);
+ return;
+ }
+
+ if (user_activation_state == UserActivationState::kRequired
+ && !rfh->HasTransientUserActivation()) {
+ // No permission prompts without user activation.
+ std::move(callback).Run(PermissionRequestOutcome::kNoUserActivation);
+ return;
+ }
+
+ content::WebContents *web_contents = content::WebContents::FromRenderFrameHost(rfh);
+ if (!web_contents) {
+ // Requested from a worker, or a no longer existing tab.
+ std::move(callback).Run(PermissionRequestOutcome::kInvalidFrame);
+ return;
+ }
+
+ url::Origin embedding_origin = url::Origin::Create(web_contents->GetLastCommittedURL());
+ if (embedding_origin != m_origin) {
+ // Third party iframes are not allowed to request more permissions.
+ std::move(callback).Run(PermissionRequestOutcome::kThirdPartyContext);
+ return;
+ }
+
+ auto *request_manager =
+ FileSystemAccessPermissionRequestManagerQt::FromWebContents(web_contents);
+ if (!request_manager) {
+ std::move(callback).Run(PermissionRequestOutcome::kRequestAborted);
+ return;
+ }
+
+ // Drop fullscreen mode so that the user sees the URL bar.
+ base::ScopedClosureRunner fullscreen_block = web_contents->ForSecurityDropFullscreen();
+
+ FileSystemAccessPermissionRequestManagerQt::Access access = m_type == GrantType::kRead
+ ? FileSystemAccessPermissionRequestManagerQt::Access::kRead
+ : FileSystemAccessPermissionRequestManagerQt::Access::kWrite;
+
+ // If a website wants both read and write access, code in content will
+ // request those as two separate requests. The |request_manager| will then
+ // detect this and combine the two requests into one prompt. As such this
+ // code does not have to have any way to request Access::kReadWrite.
+
+ request_manager->AddRequest(
+ { m_origin, m_path, m_handleType, access },
+ base::BindOnce(&FileSystemAccessPermissionGrantQt::OnPermissionRequestResult, this,
+ std::move(callback)),
+ std::move(fullscreen_block));
+}
+
+void FileSystemAccessPermissionGrantQt::SetStatus(PermissionStatus status)
+{
+ bool should_notify = m_status != status;
+ m_status = status;
+ if (should_notify)
+ NotifyPermissionStatusChanged();
+}
+
+void FileSystemAccessPermissionGrantQt::OnPermissionRequestResult(
+ base::OnceCallback<void(PermissionRequestOutcome)> callback, PermissionAction result)
+{
+ switch (result) {
+ case PermissionAction::GRANTED:
+ SetStatus(PermissionStatus::GRANTED);
+ std::move(callback).Run(PermissionRequestOutcome::kUserGranted);
+ break;
+ case PermissionAction::DENIED:
+ SetStatus(PermissionStatus::DENIED);
+ std::move(callback).Run(PermissionRequestOutcome::kUserDenied);
+ break;
+ case PermissionAction::DISMISSED:
+ case PermissionAction::IGNORED:
+ std::move(callback).Run(PermissionRequestOutcome::kUserDismissed);
+ break;
+ case PermissionAction::REVOKED:
+ case PermissionAction::GRANTED_ONCE:
+ case PermissionAction::NUM:
+ NOTREACHED();
+ break;
+ }
+}
+
+} // namespace QtWebEngineCore
diff --git a/src/core/file_system_access/file_system_access_permission_grant_qt.h b/src/core/file_system_access/file_system_access_permission_grant_qt.h
new file mode 100644
index 000000000..c7ea1b331
--- /dev/null
+++ b/src/core/file_system_access/file_system_access_permission_grant_qt.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 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$
+**
+****************************************************************************/
+
+#ifndef FILE_SYSTEM_ACCESS_PERMISSION_GRANT_QT_H
+#define FILE_SYSTEM_ACCESS_PERMISSION_GRANT_QT_H
+
+#include "content/public/browser/file_system_access_permission_grant.h"
+#include "url/origin.h"
+#include "file_system_access_permission_context_qt.h"
+#include "content/public/browser/global_routing_id.h"
+#include "components/permissions/permission_util.h"
+
+namespace QtWebEngineCore {
+
+using HandleType = content::FileSystemAccessPermissionContext::HandleType;
+using GrantType = FileSystemAccessPermissionContextQt::GrantType;
+using blink::mojom::PermissionStatus;
+using permissions::PermissionAction;
+
+class FileSystemAccessPermissionGrantQt : public content::FileSystemAccessPermissionGrant
+{
+public:
+ FileSystemAccessPermissionGrantQt(base::WeakPtr<FileSystemAccessPermissionContextQt> context,
+ const url::Origin &origin, const base::FilePath &path,
+ HandleType handle_type, GrantType type);
+
+ // content::FileSystemAccessPermissionGrant:
+ PermissionStatus GetStatus() override { return m_status; }
+ base::FilePath GetPath() override { return m_path; }
+ void RequestPermission(content::GlobalRenderFrameHostId frame_id,
+ UserActivationState user_activation_state,
+ base::OnceCallback<void(PermissionRequestOutcome)> callback) override;
+
+ const url::Origin &origin() const { return m_origin; }
+ HandleType handleType() const { return m_handleType; }
+ const base::FilePath &path() const { return m_path; }
+ GrantType type() const { return m_type; }
+
+ void SetStatus(PermissionStatus status);
+
+private:
+ void OnPermissionRequestResult(base::OnceCallback<void(PermissionRequestOutcome)> callback,
+ PermissionAction result);
+
+ base::WeakPtr<FileSystemAccessPermissionContextQt> const m_context;
+ const url::Origin m_origin;
+ const base::FilePath m_path;
+ const HandleType m_handleType;
+ const GrantType m_type;
+
+ // This member should only be updated via SetStatus(), to make sure
+ // observers are properly notified about any change in status.
+ PermissionStatus m_status = PermissionStatus::ASK;
+};
+
+} // namespace QtWebEngineCore
+
+#endif // FILE_SYSTEM_ACCESS_PERMISSION_GRANT_QT_H
diff --git a/src/core/file_system_access/file_system_access_permission_request_controller.h b/src/core/file_system_access/file_system_access_permission_request_controller.h
new file mode 100644
index 000000000..65610dff9
--- /dev/null
+++ b/src/core/file_system_access/file_system_access_permission_request_controller.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 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$
+**
+****************************************************************************/
+
+#ifndef FILE_SYSTEM_ACCESS_PERMISSION_REQUEST_CONTROLLER_H
+#define FILE_SYSTEM_ACCESS_PERMISSION_REQUEST_CONTROLLER_H
+
+#include "api/qwebenginefilesystemaccessrequest.h"
+#include "request_controller.h"
+
+using HandleType = QWebEngineFileSystemAccessRequest::HandleType;
+using AccessFlags = QWebEngineFileSystemAccessRequest::AccessFlags;
+
+namespace QtWebEngineCore {
+
+class FileSystemAccessPermissionRequestController : public RequestController
+{
+public:
+ FileSystemAccessPermissionRequestController(const QUrl &origin, const QUrl &filePath,
+ HandleType handleType, AccessFlags accessType)
+ : RequestController(std::move(origin))
+ , m_filePath(filePath)
+ , m_handleType(handleType)
+ , m_accessType(accessType)
+ {
+ }
+
+ QUrl filePath() const { return m_filePath; }
+ HandleType handleType() const { return m_handleType; }
+ AccessFlags accessFlags() const { return m_accessType; }
+
+private:
+ QUrl m_filePath;
+ HandleType m_handleType;
+ AccessFlags m_accessType;
+};
+
+} // namespace QtWebEngineCore
+
+#endif // FILE_SYSTEM_ACCESS_PERMISSION_REQUEST_CONTROLLER_H
diff --git a/src/core/file_system_access/file_system_access_permission_request_controller_impl.cpp b/src/core/file_system_access/file_system_access_permission_request_controller_impl.cpp
new file mode 100644
index 000000000..d5caa37b7
--- /dev/null
+++ b/src/core/file_system_access/file_system_access_permission_request_controller_impl.cpp
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 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$
+**
+****************************************************************************/
+
+#include "file_system_access_permission_request_controller_impl.h"
+
+#include "components/permissions/permission_util.h"
+#include "content/public/browser/file_system_access_permission_context.h"
+#include "type_conversion.h"
+
+namespace QtWebEngineCore {
+
+ASSERT_ENUMS_MATCH(content::FileSystemAccessPermissionContext::HandleType::kFile,
+ QWebEngineFileSystemAccessRequest::HandleType::File);
+ASSERT_ENUMS_MATCH(content::FileSystemAccessPermissionContext::HandleType::kDirectory,
+ QWebEngineFileSystemAccessRequest::HandleType::Directory);
+
+ASSERT_ENUMS_MATCH(FileSystemAccessPermissionRequestManagerQt::Access::kRead,
+ QWebEngineFileSystemAccessRequest::AccessFlag::Read);
+ASSERT_ENUMS_MATCH(FileSystemAccessPermissionRequestManagerQt::Access::kWrite,
+ QWebEngineFileSystemAccessRequest::AccessFlag::Write);
+
+FileSystemAccessPermissionRequestControllerImpl::FileSystemAccessPermissionRequestControllerImpl(
+ const FileSystemAccessPermissionRequestManagerQt::RequestData &request,
+ base::OnceCallback<void(permissions::PermissionAction result)> callback)
+ : FileSystemAccessPermissionRequestController(
+ toQt(request.origin.GetURL()), toQt(request.path.value()),
+ (HandleType)request.handle_type, AccessFlags((int)request.access))
+ , m_callback(std::move(callback))
+{
+}
+
+FileSystemAccessPermissionRequestControllerImpl::~FileSystemAccessPermissionRequestControllerImpl()
+{
+ if (m_callback)
+ std::move(m_callback).Run(permissions::PermissionAction::IGNORED);
+}
+
+void FileSystemAccessPermissionRequestControllerImpl::accepted()
+{
+ std::move(m_callback).Run(permissions::PermissionAction::GRANTED);
+}
+
+void FileSystemAccessPermissionRequestControllerImpl::rejected()
+{
+ std::move(m_callback).Run(permissions::PermissionAction::DENIED);
+}
+
+} // namespace QtWebEngineCore
diff --git a/src/core/file_system_access/file_system_access_permission_request_controller_impl.h b/src/core/file_system_access/file_system_access_permission_request_controller_impl.h
new file mode 100644
index 000000000..d2cc5ba2b
--- /dev/null
+++ b/src/core/file_system_access/file_system_access_permission_request_controller_impl.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 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$
+**
+****************************************************************************/
+
+#ifndef FILE_SYSTEM_ACCESS_PERMISSION_REQUEST_CONTROLLER_IMPL_H
+#define FILE_SYSTEM_ACCESS_PERMISSION_REQUEST_CONTROLLER_IMPL_H
+
+#include "file_system_access_permission_request_controller.h"
+#include "file_system_access_permission_request_manager_qt.h"
+
+namespace QtWebEngineCore {
+
+class FileSystemAccessPermissionRequestControllerImpl final
+ : public FileSystemAccessPermissionRequestController
+{
+public:
+ FileSystemAccessPermissionRequestControllerImpl(
+ const FileSystemAccessPermissionRequestManagerQt::RequestData &request,
+ base::OnceCallback<void(permissions::PermissionAction result)> callback);
+
+ ~FileSystemAccessPermissionRequestControllerImpl();
+
+protected:
+ void accepted() override;
+ void rejected() override;
+
+private:
+ base::OnceCallback<void(permissions::PermissionAction result)> m_callback;
+};
+
+} // namespace QtWebEngineCore
+
+#endif // FILE_SYSTEM_ACCESS_PERMISSION_REQUEST_CONTROLLER_IMPL_H
diff --git a/src/core/file_system_access/file_system_access_permission_request_manager_qt.cpp b/src/core/file_system_access/file_system_access_permission_request_manager_qt.cpp
new file mode 100644
index 000000000..594c879f2
--- /dev/null
+++ b/src/core/file_system_access/file_system_access_permission_request_manager_qt.cpp
@@ -0,0 +1,231 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 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$
+**
+****************************************************************************/
+
+#include "file_system_access_permission_request_manager_qt.h"
+
+#include "components/permissions/permission_util.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/navigation_handle.h"
+
+#include "api/qwebenginefilesystemaccessrequest.h"
+#include "file_system_access_permission_context_factory_qt.h"
+#include "file_system_access_permission_request_controller_impl.h"
+#include "web_contents_adapter_client.h"
+#include "web_contents_view_qt.h"
+
+namespace QtWebEngineCore {
+
+bool RequestsAreIdentical(const FileSystemAccessPermissionRequestManagerQt::RequestData &a,
+ const FileSystemAccessPermissionRequestManagerQt::RequestData &b)
+{
+ return a.origin == b.origin && a.path == b.path && a.handle_type == b.handle_type
+ && a.access == b.access;
+}
+
+bool RequestsAreForSamePath(const FileSystemAccessPermissionRequestManagerQt::RequestData &a,
+ const FileSystemAccessPermissionRequestManagerQt::RequestData &b)
+{
+ return a.origin == b.origin && a.path == b.path && a.handle_type == b.handle_type;
+}
+
+struct FileSystemAccessPermissionRequestManagerQt::Request
+{
+ Request(RequestData data,
+ base::OnceCallback<void(permissions::PermissionAction result)> callback,
+ base::ScopedClosureRunner fullscreen_block)
+ : data(std::move(data))
+ {
+ callbacks.push_back(std::move(callback));
+ fullscreen_blocks.push_back(std::move(fullscreen_block));
+ }
+
+ RequestData data;
+ std::vector<base::OnceCallback<void(permissions::PermissionAction result)>> callbacks;
+ std::vector<base::ScopedClosureRunner> fullscreen_blocks;
+};
+
+FileSystemAccessPermissionRequestManagerQt::~FileSystemAccessPermissionRequestManagerQt() = default;
+
+void FileSystemAccessPermissionRequestManagerQt::AddRequest(
+ RequestData data, base::OnceCallback<void(permissions::PermissionAction result)> callback,
+ base::ScopedClosureRunner fullscreen_block)
+{
+ // Check if any pending requests are identical to the new request.
+ if (m_currentRequest && RequestsAreIdentical(m_currentRequest->data, data)) {
+ m_currentRequest->callbacks.push_back(std::move(callback));
+ m_currentRequest->fullscreen_blocks.push_back(std::move(fullscreen_block));
+ return;
+ }
+ for (const auto &request : m_queuedRequests) {
+ if (RequestsAreIdentical(request->data, data)) {
+ request->callbacks.push_back(std::move(callback));
+ request->fullscreen_blocks.push_back(std::move(fullscreen_block));
+ return;
+ }
+ if (RequestsAreForSamePath(request->data, data)) {
+ // This means access levels are different. Change the existing request
+ // to kReadWrite, and add the new callback.
+ request->data.access = Access::kReadWrite;
+ request->callbacks.push_back(std::move(callback));
+ request->fullscreen_blocks.push_back(std::move(fullscreen_block));
+ return;
+ }
+ }
+
+ m_queuedRequests.push_back(std::make_unique<Request>(std::move(data), std::move(callback),
+ std::move(fullscreen_block)));
+ if (!IsShowingRequest())
+ ScheduleShowRequest();
+}
+
+FileSystemAccessPermissionRequestManagerQt::FileSystemAccessPermissionRequestManagerQt(
+ content::WebContents *web_contents)
+ : content::WebContentsObserver(web_contents)
+{
+}
+
+bool FileSystemAccessPermissionRequestManagerQt::CanShowRequest() const
+{
+ // Delay showing requests until the main frame is fully loaded.
+ // ScheduleShowRequest() will be called again when that happens.
+ return web_contents()->IsDocumentOnLoadCompletedInMainFrame() && !m_queuedRequests.empty()
+ && !m_currentRequest;
+}
+
+void FileSystemAccessPermissionRequestManagerQt::ScheduleShowRequest()
+{
+ if (!CanShowRequest())
+ return;
+
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
+ base::BindOnce(&FileSystemAccessPermissionRequestManagerQt::DequeueAndShowRequest,
+ m_weakFactory.GetWeakPtr()));
+}
+
+void FileSystemAccessPermissionRequestManagerQt::DequeueAndShowRequest()
+{
+ if (!CanShowRequest())
+ return;
+
+ m_currentRequest = std::move(m_queuedRequests.front());
+ m_queuedRequests.pop_front();
+
+ WebContentsAdapterClient *client =
+ WebContentsViewQt::from(
+ static_cast<content::WebContentsImpl *>(web_contents())->GetView())
+ ->client();
+ if (!client) {
+ LOG(ERROR)
+ << "Attempt to request file system access from content missing WebContents client";
+ for (auto &callback : m_currentRequest->callbacks)
+ std::move(callback).Run(permissions::PermissionAction::DENIED);
+ return;
+ }
+
+ QWebEngineFileSystemAccessRequest request(
+ QSharedPointer<FileSystemAccessPermissionRequestControllerImpl>::create(
+ m_currentRequest->data,
+ base::BindOnce(
+ &FileSystemAccessPermissionRequestManagerQt::OnPermissionDialogResult,
+ m_weakFactory.GetWeakPtr())));
+ client->runFileSystemAccessRequest(std::move(request));
+}
+
+void FileSystemAccessPermissionRequestManagerQt::DocumentOnLoadCompletedInMainFrame(
+ content::RenderFrameHost *)
+{
+ // This is scheduled because while all calls to the browser have been
+ // issued at DOMContentLoaded, they may be bouncing around in scheduled
+ // callbacks finding the UI thread still. This makes sure we allow those
+ // scheduled calls to AddRequest to complete before we show the page-load
+ // permissions bubble.
+ if (!m_queuedRequests.empty())
+ ScheduleShowRequest();
+}
+
+void FileSystemAccessPermissionRequestManagerQt::DidFinishNavigation(
+ content::NavigationHandle *navigation)
+{
+ // We only care about top-level navigations that actually committed.
+ if (!navigation->IsInMainFrame() || !navigation->HasCommitted())
+ return;
+
+ auto src_origin = url::Origin::Create(navigation->GetPreviousMainFrameURL());
+ auto dest_origin = url::Origin::Create(navigation->GetURL());
+ if (src_origin == dest_origin)
+ return;
+
+ // Navigated away from |src_origin|, tell permission context to check if
+ // permissions need to be revoked.
+ auto *context = FileSystemAccessPermissionContextFactoryQt::GetForProfileIfExists(
+ web_contents()->GetBrowserContext());
+ if (context)
+ context->NavigatedAwayFromOrigin(src_origin);
+}
+
+void FileSystemAccessPermissionRequestManagerQt::WebContentsDestroyed()
+{
+ auto src_origin = web_contents()->GetMainFrame()->GetLastCommittedOrigin();
+
+ // Navigated away from |src_origin|, tell permission context to check if
+ // permissions need to be revoked.
+ auto *context = FileSystemAccessPermissionContextFactoryQt::GetForProfileIfExists(
+ web_contents()->GetBrowserContext());
+ if (context)
+ context->NavigatedAwayFromOrigin(src_origin);
+}
+
+void FileSystemAccessPermissionRequestManagerQt::OnPermissionDialogResult(
+ permissions::PermissionAction result)
+{
+ DCHECK(m_currentRequest);
+ for (auto &callback : m_currentRequest->callbacks)
+ std::move(callback).Run(result);
+
+ m_currentRequest = nullptr;
+ if (!m_queuedRequests.empty())
+ ScheduleShowRequest();
+}
+
+WEB_CONTENTS_USER_DATA_KEY_IMPL(FileSystemAccessPermissionRequestManagerQt);
+
+} // namespace QtWebEngineCore
diff --git a/src/core/file_system_access/file_system_access_permission_request_manager_qt.h b/src/core/file_system_access/file_system_access_permission_request_manager_qt.h
new file mode 100644
index 000000000..6746899b6
--- /dev/null
+++ b/src/core/file_system_access/file_system_access_permission_request_manager_qt.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 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$
+**
+****************************************************************************/
+
+#ifndef FILE_SYSTEM_ACCESS_PERMISSION_REQUEST_MANAGER_QT_H
+#define FILE_SYSTEM_ACCESS_PERMISSION_REQUEST_MANAGER_QT_H
+
+#include "base/callback_helpers.h"
+#include "base/containers/circular_deque.h"
+#include "base/files/file_path.h"
+#include "base/memory/weak_ptr.h"
+#include "content/public/browser/file_system_access_permission_context.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+#include "url/origin.h"
+
+namespace permissions {
+enum class PermissionAction;
+}
+
+namespace QtWebEngineCore {
+
+class FileSystemAccessPermissionRequestManagerQt
+ : public content::WebContentsObserver,
+ public content::WebContentsUserData<FileSystemAccessPermissionRequestManagerQt>
+{
+public:
+ ~FileSystemAccessPermissionRequestManagerQt() override;
+
+ enum class Access {
+ // Only ask for read access.
+ kRead = 0x1,
+ // Only ask for write access, assuming read access has already been granted.
+ kWrite = 0x2,
+ // Ask for both read and write access.
+ kReadWrite = 0x3
+ };
+
+ struct RequestData
+ {
+ url::Origin origin;
+ base::FilePath path;
+ content::FileSystemAccessPermissionContext::HandleType handle_type;
+ Access access;
+ };
+
+ void AddRequest(RequestData request,
+ base::OnceCallback<void(permissions::PermissionAction result)> callback,
+ base::ScopedClosureRunner fullscreen_block);
+
+private:
+ friend class content::WebContentsUserData<FileSystemAccessPermissionRequestManagerQt>;
+
+ explicit FileSystemAccessPermissionRequestManagerQt(content::WebContents *web_contents);
+
+ bool IsShowingRequest() const { return m_currentRequest != nullptr; }
+ bool CanShowRequest() const;
+ void ScheduleShowRequest();
+ void DequeueAndShowRequest();
+
+ // content::WebContentsObserver
+ void DocumentOnLoadCompletedInMainFrame(content::RenderFrameHost *) override;
+ void DidFinishNavigation(content::NavigationHandle *navigation_handle) override;
+ void WebContentsDestroyed() override;
+
+ void OnPermissionDialogResult(permissions::PermissionAction result);
+
+ struct Request;
+ // Request currently being shown in prompt.
+ std::unique_ptr<Request> m_currentRequest;
+ // Queued up requests.
+ base::circular_deque<std::unique_ptr<Request>> m_queuedRequests;
+
+ base::WeakPtrFactory<FileSystemAccessPermissionRequestManagerQt> m_weakFactory { this };
+ WEB_CONTENTS_USER_DATA_KEY_DECL();
+};
+
+} // namespace QtWebEngineCore
+
+#endif // FILE_SYSTEM_ACCESS_PERMISSION_REQUEST_MANAGER_QT_H
diff --git a/src/core/profile_qt.cpp b/src/core/profile_qt.cpp
index 71198b2fc..829f96249 100644
--- a/src/core/profile_qt.cpp
+++ b/src/core/profile_qt.cpp
@@ -42,6 +42,7 @@
#include "profile_adapter.h"
#include "browsing_data_remover_delegate_qt.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"
#include "permission_manager_qt.h"
#include "platform_notification_service_qt.h"
@@ -240,6 +241,11 @@ std::string ProfileQt::GetMediaDeviceIDSalt()
return m_prefServiceAdapter.mediaDeviceIdSalt();
}
+content::FileSystemAccessPermissionContext *ProfileQt::GetFileSystemAccessPermissionContext()
+{
+ return FileSystemAccessPermissionContextFactoryQt::GetForProfile(this);
+}
+
void ProfileQt::setupPrefService()
{
// Remove previous handler before we set a new one or we will assert
diff --git a/src/core/profile_qt.h b/src/core/profile_qt.h
index b9c2e0489..9fb1e7f04 100644
--- a/src/core/profile_qt.h
+++ b/src/core/profile_qt.h
@@ -91,6 +91,7 @@ public:
content::StorageNotificationService *GetStorageNotificationService() override;
content::PlatformNotificationService *GetPlatformNotificationService() override;
std::string GetMediaDeviceIDSalt() override;
+ content::FileSystemAccessPermissionContext *GetFileSystemAccessPermissionContext() override;
// Profile implementation:
PrefService *GetPrefs() override;
diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h
index b8d91af2d..2729e7beb 100644
--- a/src/core/web_contents_adapter_client.h
+++ b/src/core/web_contents_adapter_client.h
@@ -63,6 +63,7 @@
QT_FORWARD_DECLARE_CLASS(QKeyEvent)
QT_FORWARD_DECLARE_CLASS(QVariant)
+QT_FORWARD_DECLARE_CLASS(QWebEngineFileSystemAccessRequest)
QT_FORWARD_DECLARE_CLASS(QWebEngineFindTextResult)
QT_FORWARD_DECLARE_CLASS(QWebEngineLoadingInfo)
QT_FORWARD_DECLARE_CLASS(QWebEngineQuotaRequest)
@@ -223,6 +224,7 @@ public:
virtual void runMouseLockPermissionRequest(const QUrl &securityOrigin) = 0;
virtual void runQuotaRequest(QWebEngineQuotaRequest) = 0;
virtual void runRegisterProtocolHandlerRequest(QWebEngineRegisterProtocolHandlerRequest) = 0;
+ virtual void runFileSystemAccessRequest(QWebEngineFileSystemAccessRequest) = 0;
virtual QWebEngineSettings *webEngineSettings() const = 0;
RenderProcessTerminationStatus renderProcessExitStatus(int);
virtual void renderProcessTerminated(RenderProcessTerminationStatus terminationStatus, int exitCode) = 0;
diff --git a/src/webenginequick/api/qquickwebengineview.cpp b/src/webenginequick/api/qquickwebengineview.cpp
index 5d73f55bc..d2e5f9761 100644
--- a/src/webenginequick/api/qquickwebengineview.cpp
+++ b/src/webenginequick/api/qquickwebengineview.cpp
@@ -66,6 +66,7 @@
#include "web_contents_adapter.h"
#include <QtWebEngineCore/qwebenginecertificateerror.h>
+#include <QtWebEngineCore/qwebenginefilesystemaccessrequest.h>
#include <QtWebEngineCore/qwebenginefindtextresult.h>
#include <QtWebEngineCore/qwebenginefullscreenrequest.h>
#include <QtWebEngineCore/qwebengineloadinginfo.h>
@@ -647,6 +648,13 @@ void QQuickWebEngineViewPrivate::runRegisterProtocolHandlerRequest(QWebEngineReg
Q_EMIT q->registerProtocolHandlerRequested(request);
}
+void QQuickWebEngineViewPrivate::runFileSystemAccessRequest(
+ QWebEngineFileSystemAccessRequest request)
+{
+ Q_Q(QQuickWebEngineView);
+ Q_EMIT q->fileSystemAccessRequested(request);
+}
+
QObject *QQuickWebEngineViewPrivate::accessibilityParentObject()
{
Q_Q(QQuickWebEngineView);
diff --git a/src/webenginequick/api/qquickwebengineview_p.h b/src/webenginequick/api/qquickwebengineview_p.h
index 867e37d06..fb736085b 100644
--- a/src/webenginequick/api/qquickwebengineview_p.h
+++ b/src/webenginequick/api/qquickwebengineview_p.h
@@ -79,6 +79,7 @@ class QQuickWebEngineTooltipRequest;
class QQuickWebEngineViewPrivate;
class QWebEngineCertificateError;
class QWebEngineContextMenuRequest;
+class QWebEngineFileSystemAccessRequest;
class QWebEngineFindTextResult;
class QWebEngineFullScreenRequest;
class QWebEngineHistory;
@@ -572,6 +573,7 @@ Q_SIGNALS:
Q_REVISION(1,12) void newWindowRequested(QQuickWebEngineNewWindowRequest *request);
Q_REVISION(6,3) void touchSelectionMenuRequested(QQuickWebEngineTouchSelectionMenuRequest *request);
Q_REVISION(6,4) void touchHandleDelegateChanged();
+ Q_REVISION(6,4) void fileSystemAccessRequested(const QWebEngineFileSystemAccessRequest &request);
protected:
void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
diff --git a/src/webenginequick/api/qquickwebengineview_p_p.h b/src/webenginequick/api/qquickwebengineview_p_p.h
index 073d0180c..2096f79c6 100644
--- a/src/webenginequick/api/qquickwebengineview_p_p.h
+++ b/src/webenginequick/api/qquickwebengineview_p_p.h
@@ -141,6 +141,7 @@ public:
void runMouseLockPermissionRequest(const QUrl &securityOrigin) override;
void runQuotaRequest(QWebEngineQuotaRequest) override;
void runRegisterProtocolHandlerRequest(QWebEngineRegisterProtocolHandlerRequest) override;
+ void runFileSystemAccessRequest(QWebEngineFileSystemAccessRequest) override;
QObject *accessibilityParentObject() override;
QWebEngineSettings *webEngineSettings() const override;
void allowCertificateError(const QWebEngineCertificateError &error) override;
diff --git a/tests/auto/quick/publicapi/tst_publicapi.cpp b/tests/auto/quick/publicapi/tst_publicapi.cpp
index edec675f6..3b7da9759 100644
--- a/tests/auto/quick/publicapi/tst_publicapi.cpp
+++ b/tests/auto/quick/publicapi/tst_publicapi.cpp
@@ -35,6 +35,7 @@
#include <QtTest/QtTest>
#include <QtWebEngineQuick/QQuickWebEngineProfile>
#include <QtWebEngineCore/QWebEngineCertificateError>
+#include <QtWebEngineCore/QWebEngineFileSystemAccessRequest>
#include <QtWebEngineCore/QWebEngineFindTextResult>
#include <QtWebEngineCore/QWebEngineFullScreenRequest>
#include <QtWebEngineCore/QWebEngineHistory>
@@ -85,6 +86,7 @@ static const QList<const QMetaObject *> typesToCheck = QList<const QMetaObject *
<< &QQuickWebEngineTooltipRequest::staticMetaObject
<< &QWebEngineContextMenuRequest::staticMetaObject
<< &QWebEngineCertificateError::staticMetaObject
+ << &QWebEngineFileSystemAccessRequest::staticMetaObject
<< &QWebEngineFindTextResult::staticMetaObject
<< &QWebEngineLoadingInfo::staticMetaObject
<< &QWebEngineNavigationRequest::staticMetaObject
@@ -288,6 +290,16 @@ static const QStringList expectedAPI = QStringList()
<< "QWebEngineFullScreenRequest.origin --> QUrl"
<< "QWebEngineFullScreenRequest.reject() --> void"
<< "QWebEngineFullScreenRequest.toggleOn --> bool"
+ << "QWebEngineFileSystemAccessRequest.File --> HandleType"
+ << "QWebEngineFileSystemAccessRequest.Directory --> HandleType"
+ << "QWebEngineFileSystemAccessRequest.Read --> AccessFlags"
+ << "QWebEngineFileSystemAccessRequest.Write --> AccessFlags"
+ << "QWebEngineFileSystemAccessRequest.origin --> QUrl"
+ << "QWebEngineFileSystemAccessRequest.filePath --> QUrl"
+ << "QWebEngineFileSystemAccessRequest.handleType --> QWebEngineFileSystemAccessRequest::HandleType"
+ << "QWebEngineFileSystemAccessRequest.accessFlags --> QFlags<QWebEngineFileSystemAccessRequest::AccessFlag>"
+ << "QWebEngineFileSystemAccessRequest.accept() --> void"
+ << "QWebEngineFileSystemAccessRequest.reject() --> void"
<< "QWebEngineHistory.backItems --> QWebEngineHistoryModel*"
<< "QWebEngineHistory.clear() --> void"
<< "QWebEngineHistory.forwardItems --> QWebEngineHistoryModel*"
@@ -697,6 +709,7 @@ static const QStringList expectedAPI = QStringList()
<< "QQuickWebEngineView.devToolsViewChanged() --> void"
<< "QQuickWebEngineView.featurePermissionRequested(QUrl,Feature) --> void"
<< "QQuickWebEngineView.fileDialogRequested(QQuickWebEngineFileDialogRequest*) --> void"
+ << "QQuickWebEngineView.fileSystemAccessRequested(QWebEngineFileSystemAccessRequest) --> void"
<< "QQuickWebEngineView.findText(QString) --> void"
<< "QQuickWebEngineView.findText(QString,FindFlags) --> void"
<< "QQuickWebEngineView.findText(QString,FindFlags,QJSValue) --> void"
diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
index b16e9fa62..57f6b24a8 100644
--- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
+++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
@@ -48,6 +48,7 @@
#include <qnetworkreply.h>
#include <qnetworkrequest.h>
#include <qwebenginedownloadrequest.h>
+#include <qwebenginefilesystemaccessrequest.h>
#include <qwebenginefindtextresult.h>
#include <qwebenginefullscreenrequest.h>
#include <qwebenginehistory.h>
@@ -4794,17 +4795,17 @@ void tst_QWebEnginePage::renderProcessPid()
class FileSelectionTestPage : public QWebEnginePage {
public:
- FileSelectionTestPage()
- { }
+ FileSelectionTestPage() : m_tempDir(QDir::tempPath() + "/tst_qwebenginepage-XXXXXX") { }
QStringList chooseFiles(FileSelectionMode mode, const QStringList &oldFiles, const QStringList &acceptedMimeTypes) override
{
Q_UNUSED(oldFiles);
chosenFileSelectionMode = mode;
chosenAcceptedMimeTypes = acceptedMimeTypes;
- return QStringList();
+ return QStringList() << (m_tempDir.path() + "/file.txt");
}
+ QTemporaryDir m_tempDir;
int chosenFileSelectionMode = -1;
QStringList chosenAcceptedMimeTypes;
};
@@ -4890,9 +4891,27 @@ void tst_QWebEnginePage::fileSystemAccessDialog()
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
- page.setHtml(QString("<html><body>"
+ connect(&page, &QWebEnginePage::fileSystemAccessRequested,
+ [](QWebEngineFileSystemAccessRequest request) {
+ QCOMPARE(request.accessFlags(),
+ QWebEngineFileSystemAccessRequest::Read
+ | QWebEngineFileSystemAccessRequest::Write);
+ request.accept();
+ });
+
+ page.setHtml(QString("<html><head><script>"
+ "async function getTemporaryDir() {"
+ " const newHandle = await window.showSaveFilePicker();"
+ " const writable = await newHandle.createWritable();"
+ " await writable.write(new Blob(['New value']));"
+ " await writable.close();"
+ ""
+ " const fileData = await newHandle.getFile();"
+ " document.title = await fileData.text();"
+ "}"
+ "</script></head><body>"
"<button id='triggerDialog' value='trigger' "
- "onclick='window.showDirectoryPicker()'>"
+ "onclick='getTemporaryDir()'"
"</body></html>"),
QString("qrc:/"));
QVERIFY(spyFinished.wait());
@@ -4903,7 +4922,9 @@ void tst_QWebEnginePage::fileSystemAccessDialog()
QStringLiteral("triggerDialog"));
QTest::keyClick(view.focusProxy(), Qt::Key_Enter);
- QTRY_COMPARE(page.chosenFileSelectionMode, QWebEnginePage::FileSelectUploadFolder);
+ QTRY_COMPARE(page.title(), "New value");
+
+ QTRY_COMPARE(page.chosenFileSelectionMode, QWebEnginePage::FileSelectSave);
QTRY_COMPARE(page.chosenAcceptedMimeTypes, QStringList());
}