summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-05-28 09:55:20 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-05-28 12:02:27 +0200
commitcdfa08e44b416aebaf5a5e4762ed759062a10e88 (patch)
tree03b97f5b8a85514b4344b7dad015e359d5e19e4c
parentd927e9a0b45a79bc49f7e80f6c05ac20617902ad (diff)
parent5087a4eaa32e08fe59f1f5b71dc21dda0876a759 (diff)
downloadqtwebengine-cdfa08e44b416aebaf5a5e4762ed759062a10e88.tar.gz
Merge "Merge remote-tracking branch 'origin/5.15' into dev"
-rw-r--r--mkspecs/features/gn_generator.prf3
m---------src/3rdparty0
-rw-r--r--src/core/compositor/chromium_gpu_helper.cpp16
-rw-r--r--src/core/compositor/chromium_gpu_helper.h16
-rw-r--r--src/core/compositor/delegated_frame_node.cpp17
-rw-r--r--src/core/content_client_qt.cpp8
-rw-r--r--src/core/extensions/component_extension_resource_manager_qt.cpp19
-rw-r--r--src/core/file_picker_controller.cpp72
-rw-r--r--src/core/gn_run.pro5
-rw-r--r--src/core/permission_manager_qt.cpp26
-rw-r--r--src/core/permission_manager_qt.h11
-rw-r--r--src/core/profile_adapter.cpp2
-rw-r--r--src/core/profile_adapter.h8
-rw-r--r--src/core/web_contents_adapter.cpp8
-rw-r--r--src/core/web_contents_adapter.h2
-rw-r--r--src/core/web_contents_delegate_qt.cpp3
-rw-r--r--src/webengine/api/qquickwebengineview.cpp10
-rw-r--r--src/webengine/doc/src/qtwebengine-debugging.qdoc8
-rw-r--r--src/webenginewidgets/api/qwebenginepage.cpp30
-rw-r--r--tests/auto/core/qwebengineurlrequestinterceptor/resources/sw.html16
-rw-r--r--tests/auto/core/qwebengineurlrequestinterceptor/resources/sw.js3
-rw-r--r--tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp88
-rw-r--r--tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.qrc2
-rw-r--r--tests/auto/quick/qmltests/data/TestWebEngineView.qml7
-rw-r--r--tests/auto/quick/qmltests/data/tst_certificateError.qml114
-rw-r--r--tests/auto/quick/qmltests/qmltests.pro1
-rw-r--r--tests/auto/quick/qmltests/tst_qmltests.cpp4
-rw-r--r--tests/auto/quick/qmltests2/data/tst_filePicker.qml40
-rw-r--r--tests/auto/shared/httpreqrep.h4
-rw-r--r--tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp6
-rw-r--r--tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp88
-rw-r--r--tests/manual/quick/faviconbrowser/faviconbrowser.qrc16
32 files changed, 503 insertions, 150 deletions
diff --git a/mkspecs/features/gn_generator.prf b/mkspecs/features/gn_generator.prf
index 6ff09d851..a83b59847 100644
--- a/mkspecs/features/gn_generator.prf
+++ b/mkspecs/features/gn_generator.prf
@@ -230,6 +230,9 @@ win32 {
CONFIG(rtti_off): GN_CONTENTS += " configs += [\"//build/config/compiler:no_rtti\"]"
CONFIG(rtti): GN_CONTENTS += " configs += [\"//build/config/compiler:rtti\"]"
}
+gcc:!qtConfig(reduce_exports) {
+ GN_CONTENTS += " configs -= [\"//build/config/gcc:symbol_visibility_hidden\"]"
+}
GN_CONTENTS += " if (moc_source_h_files != []) {"
GN_CONTENTS += " deps += ["
diff --git a/src/3rdparty b/src/3rdparty
-Subproject 623647821aa7c7565ed5153a27c5a1bb088efbe
+Subproject 7b2f027ea83c372c33d5b50deb65a2d98244aa0
diff --git a/src/core/compositor/chromium_gpu_helper.cpp b/src/core/compositor/chromium_gpu_helper.cpp
index 71d0f3687..1ddbf75e5 100644
--- a/src/core/compositor/chromium_gpu_helper.cpp
+++ b/src/core/compositor/chromium_gpu_helper.cpp
@@ -57,9 +57,7 @@
#include "content/gpu/gpu_child_thread.h"
#include "gpu/ipc/service/gpu_channel_manager.h"
-#ifdef Q_OS_QNX
-#include "content/common/gpu/stream_texture_qnx.h"
-#endif
+#include <QtGlobal> // We need this for Q_UNUSED
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner()
{
@@ -87,15 +85,3 @@ void ProgressFlingIfNeeded(content::RenderWidgetHost *host, const base::TimeTick
{
content::RenderWidgetHostImpl::From(host)->ProgressFlingIfNeeded(current_time);
}
-
-#ifdef Q_OS_QNX
-EGLStreamData eglstream_connect_consumer(gpu::Texture *tex)
-{
- EGLStreamData egl_stream;
- content::StreamTexture* image = static_cast<content::StreamTexture *>(tex->GetLevelImage(GL_TEXTURE_EXTERNAL_OES, 0));
- if (image) {
- image->ConnectConsumerIfNeeded(&egl_stream.egl_display, &egl_stream.egl_str_handle);
- }
- return egl_stream;
-}
-#endif
diff --git a/src/core/compositor/chromium_gpu_helper.h b/src/core/compositor/chromium_gpu_helper.h
index 4086d12ab..e692b9b85 100644
--- a/src/core/compositor/chromium_gpu_helper.h
+++ b/src/core/compositor/chromium_gpu_helper.h
@@ -40,8 +40,6 @@
#ifndef CHROMIUM_GPU_HELPER_H
#define CHROMIUM_GPU_HELPER_H
-#include <QtGlobal> // We need this for the Q_OS_QNX define.
-
#include "base/memory/scoped_refptr.h"
namespace base {
@@ -72,18 +70,4 @@ unsigned int service_id(gpu::TextureBase *tex);
void ProgressFlingIfNeeded(content::RenderWidgetHost *host, const base::TimeTicks &current_time);
-#ifdef Q_OS_QNX
-typedef void* EGLDisplay;
-typedef void* EGLStreamKHR;
-
-struct EGLStreamData {
- EGLDisplay egl_display;
- EGLStreamKHR egl_str_handle;
-
- EGLStreamData(): egl_display(NULL), egl_str_handle(NULL) {}
-};
-
-EGLStreamData eglstream_connect_consumer(gpu::Texture *tex);
-#endif
-
#endif // CHROMIUM_GPU_HELPER_H
diff --git a/src/core/compositor/delegated_frame_node.cpp b/src/core/compositor/delegated_frame_node.cpp
index c20069558..de79ba514 100644
--- a/src/core/compositor/delegated_frame_node.cpp
+++ b/src/core/compositor/delegated_frame_node.cpp
@@ -142,9 +142,6 @@ private:
#if defined(USE_OZONE)
bool m_ownsTexture;
#endif
-#ifdef Q_OS_QNX
- EGLStreamData m_eglStreamData;
-#endif
friend class DelegatedFrameNode;
};
#endif // QT_CONFIG(opengl)
@@ -467,20 +464,6 @@ void MailboxTexture::bind()
if (m_fence)
m_fence->wait();
glBindTexture(m_target, m_textureId);
-#ifdef Q_OS_QNX
- if (m_target == GL_TEXTURE_EXTERNAL_OES) {
- static bool resolved = false;
- static PFNEGLSTREAMCONSUMERACQUIREKHRPROC eglStreamConsumerAcquire = 0;
-
- if (!resolved) {
- QOpenGLContext *context = QOpenGLContext::currentContext();
- eglStreamConsumerAcquire = (PFNEGLSTREAMCONSUMERACQUIREKHRPROC)context->getProcAddress("eglStreamConsumerAcquireKHR");
- resolved = true;
- }
- if (eglStreamConsumerAcquire)
- eglStreamConsumerAcquire(m_eglStreamData.egl_display, m_eglStreamData.egl_str_handle);
- }
-#endif
}
#endif // QT_CONFIG(opengl)
diff --git a/src/core/content_client_qt.cpp b/src/core/content_client_qt.cpp
index 80eb9ceb1..083e10f2a 100644
--- a/src/core/content_client_qt.cpp
+++ b/src/core/content_client_qt.cpp
@@ -54,7 +54,7 @@
#include "ui/base/layout.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
-
+#include "services/service_manager/embedder/switches.h"
#include "type_conversion.h"
#include <QCoreApplication>
@@ -68,9 +68,7 @@
#include "third_party/widevine/cdm/widevine_cdm_common.h"
#if BUILDFLAG(ENABLE_WIDEVINE) && !BUILDFLAG(ENABLE_WIDEVINE_CDM_COMPONENT)
#define WIDEVINE_CDM_AVAILABLE_NOT_COMPONENT
-namespace switches {
-const char kCdmWidevinePath[] = "widevine-path";
-}
+
// File name of the CDM on different platforms.
const char kWidevineCdmFileName[] =
#if defined(OS_MACOSX)
@@ -287,7 +285,7 @@ static bool IsWidevineAvailable(base::FilePath *cdm_path,
content::CdmCapability *capability)
{
QStringList pluginPaths;
- const base::CommandLine::StringType widevine_argument = base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(switches::kCdmWidevinePath);
+ const base::CommandLine::StringType widevine_argument = base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(service_manager::switches::kCdmWidevinePath);
if (!widevine_argument.empty())
pluginPaths << QtWebEngineCore::toQt(widevine_argument);
else {
diff --git a/src/core/extensions/component_extension_resource_manager_qt.cpp b/src/core/extensions/component_extension_resource_manager_qt.cpp
index bb1dd045c..1f58de151 100644
--- a/src/core/extensions/component_extension_resource_manager_qt.cpp
+++ b/src/core/extensions/component_extension_resource_manager_qt.cpp
@@ -92,12 +92,27 @@ const ui::TemplateReplacements *ComponentExtensionResourceManagerQt::GetTemplate
void ComponentExtensionResourceManagerQt::AddComponentResourceEntries(const GritResourceMap *entries, size_t size)
{
+ base::FilePath gen_folder_path = base::FilePath().AppendASCII("@out_folder@/gen/chrome/browser/resources/");
+ gen_folder_path = gen_folder_path.NormalizePathSeparators();
+
for (size_t i = 0; i < size; ++i) {
base::FilePath resource_path = base::FilePath().AppendASCII(entries[i].name);
resource_path = resource_path.NormalizePathSeparators();
- DCHECK(!base::Contains(path_to_resource_id_, resource_path));
- path_to_resource_id_[resource_path] = entries[i].value;
+
+ if (!gen_folder_path.IsParent(resource_path)) {
+ DCHECK(!base::Contains(path_to_resource_id_, resource_path));
+ path_to_resource_id_[resource_path] = entries[i].value;
+ } else {
+ // If the resource is a generated file, strip the generated folder's path,
+ // so that it can be served from a normal URL (as if it were not
+ // generated).
+ base::FilePath effective_path =
+ base::FilePath().AppendASCII(resource_path.AsUTF8Unsafe().substr(
+ gen_folder_path.value().length()));
+ DCHECK(!base::Contains(path_to_resource_id_, effective_path));
+ path_to_resource_id_[effective_path] = entries[i].value;
+ }
}
}
diff --git a/src/core/file_picker_controller.cpp b/src/core/file_picker_controller.cpp
index 3c81a977c..01a6d0746 100644
--- a/src/core/file_picker_controller.cpp
+++ b/src/core/file_picker_controller.cpp
@@ -39,9 +39,8 @@
#include "file_picker_controller.h"
#include "type_conversion.h"
-#if defined(OS_WIN)
+
#include "base/files/file_path.h"
-#endif
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/file_select_listener.h"
@@ -72,27 +71,64 @@ void FilePickerController::accepted(const QStringList &files)
for (const QString &urlString : files) {
// We accept strings on both absolute-path and file-URL form:
- if (QDir::isAbsolutePath(urlString)) {
- QString absolutePath = QDir::fromNativeSeparators(urlString);
-#if defined(OS_WIN)
- if (absolutePath.at(0).isLetter() && absolutePath.at(1) == QLatin1Char(':') && !base::FilePath::IsSeparator(absolutePath.at(2).toLatin1()))
- qWarning("Ignoring invalid item in FilePickerController::accepted(QStringList): %s", qPrintable(urlString));
- else
+ if (toFilePath(urlString).IsAbsolute()) {
+ stringList.append(urlString);
+ continue;
+ }
+
+ if (urlString.startsWith("file:")) {
+ base::FilePath filePath = toFilePath(urlString).NormalizePathSeparators();
+ std::vector<base::FilePath::StringType> pathComponents;
+ // Splits the file URL into host name, path and file name.
+ filePath.GetComponents(&pathComponents);
+
+ QString absolutePath;
+#if !defined(OS_WIN)
+ absolutePath = "/";
#endif
- stringList.append(absolutePath);
- } else {
- QUrl url(urlString, QUrl::StrictMode);
- if (url.isLocalFile() && QDir::isAbsolutePath(url.toLocalFile())) {
- QString absolutePath = url.toLocalFile();
+
+ QString scheme = toQt(pathComponents[0]);
+ if (scheme.size() > 5) {
#if defined(OS_WIN)
- if (absolutePath.at(0).isLetter() && absolutePath.at(1) == QLatin1Char(':') && !base::FilePath::IsSeparator(absolutePath.at(2).toLatin1()))
+ // There is no slash at the end of the file scheme and it is valid on Windows: file:C:/
+ if (scheme.at(5).isLetter() && scheme.at(6) != ':') {
+ absolutePath += scheme.at(5) + ":/";
+ } else {
+#endif
qWarning("Ignoring invalid item in FilePickerController::accepted(QStringList): %s", qPrintable(urlString));
- else
+ continue;
+#if defined(OS_WIN)
+ }
+#endif
+ }
+
+ // Non-local file and UNC Path validation: file://path/file
+ if (base::FilePath::IsSeparator(urlString.at(5).toLatin1())
+ && base::FilePath::IsSeparator(urlString.at(6).toLatin1())
+ && !base::FilePath::IsSeparator(urlString.at(7).toLatin1())) {
+#if defined(OS_WIN)
+ if (urlString.at(8) != ':' && pathComponents.size() > 2) {
+ absolutePath += "//";
+#else
+ if (pathComponents.size() > 2) {
+ absolutePath += "/";
#endif
- stringList.append(absolutePath);
- } else
- qWarning("Ignoring invalid item in FilePickerController::accepted(QStringList): %s", qPrintable(urlString));
+ } else {
+ qWarning("Ignoring invalid item in FilePickerController::accepted(QStringList): %s", qPrintable(urlString));
+ continue;
+ }
+ }
+
+ // Build absolute path from file URI componenets.
+ for (int j = 1; j < pathComponents.size(); j++)
+ absolutePath += toQt(pathComponents[j]) + (j != pathComponents.size()-1 ? "/" : "");
+
+ if (toFilePath(absolutePath).IsAbsolute()) {
+ stringList.append(absolutePath);
+ continue;
+ }
}
+ qWarning("Ignoring invalid item in FilePickerController::accepted(QStringList): %s", qPrintable(urlString));
}
FilePickerController::filesSelectedInChooser(stringList);
diff --git a/src/core/gn_run.pro b/src/core/gn_run.pro
index 4f1ccce43..f72efc8d5 100644
--- a/src/core/gn_run.pro
+++ b/src/core/gn_run.pro
@@ -61,3 +61,8 @@ build_pass|!debug_and_release {
notParallel.target = .NOTPARALLEL
QMAKE_EXTRA_TARGETS += notParallel
}
+
+build_pass:CONFIG(debug, debug|release) {
+ TARGET = gn_run_debug
+}
+
diff --git a/src/core/permission_manager_qt.cpp b/src/core/permission_manager_qt.cpp
index 2f9543769..862a1c262 100644
--- a/src/core/permission_manager_qt.cpp
+++ b/src/core/permission_manager_qt.cpp
@@ -102,6 +102,18 @@ static bool canRequestPermissionFor(ProfileAdapter::PermissionType type)
return false;
}
+static blink::mojom::PermissionStatus toBlink(ProfileAdapter::PermissionState reply)
+{
+ switch (reply) {
+ case ProfileAdapter::AskPermission:
+ return blink::mojom::PermissionStatus::ASK;
+ case ProfileAdapter::AllowedPermission:
+ return blink::mojom::PermissionStatus::GRANTED;
+ case ProfileAdapter::DeniedPermission:
+ return blink::mojom::PermissionStatus::DENIED;
+ }
+}
+
PermissionManagerQt::PermissionManagerQt()
: m_requestIdCount(0)
, m_subscriberIdCount(0)
@@ -112,7 +124,7 @@ PermissionManagerQt::~PermissionManagerQt()
{
}
-void PermissionManagerQt::permissionRequestReply(const QUrl &url, ProfileAdapter::PermissionType type, bool reply)
+void PermissionManagerQt::permissionRequestReply(const QUrl &url, ProfileAdapter::PermissionType type, ProfileAdapter::PermissionState reply)
{
// Normalize the QUrl to GURL origin form.
const GURL gorigin = toGurl(url).GetOrigin();
@@ -120,9 +132,12 @@ void PermissionManagerQt::permissionRequestReply(const QUrl &url, ProfileAdapter
if (origin.isEmpty())
return;
QPair<QUrl, ProfileAdapter::PermissionType> key(origin, type);
- m_permissions[key] = reply;
- blink::mojom::PermissionStatus status = reply ? blink::mojom::PermissionStatus::GRANTED : blink::mojom::PermissionStatus::DENIED;
- {
+ if (reply == ProfileAdapter::AskPermission)
+ m_permissions.remove(key);
+ else
+ m_permissions[key] = (reply == ProfileAdapter::AllowedPermission);
+ blink::mojom::PermissionStatus status = toBlink(reply);
+ if (reply != ProfileAdapter::AskPermission) {
auto it = m_requests.begin();
while (it != m_requests.end()) {
if (it->origin == origin && it->type == type) {
@@ -137,6 +152,9 @@ void PermissionManagerQt::permissionRequestReply(const QUrl &url, ProfileAdapter
it.second.callback.Run(status);
}
+ if (reply == ProfileAdapter::AskPermission)
+ return;
+
auto it = m_multiRequests.begin();
while (it != m_multiRequests.end()) {
if (it->origin == origin) {
diff --git a/src/core/permission_manager_qt.h b/src/core/permission_manager_qt.h
index 6ab071237..e046174df 100644
--- a/src/core/permission_manager_qt.h
+++ b/src/core/permission_manager_qt.h
@@ -54,10 +54,9 @@ class PermissionManagerQt : public content::PermissionControllerDelegate {
public:
PermissionManagerQt();
~PermissionManagerQt();
- typedef ProfileAdapter::PermissionType PermissionType;
- void permissionRequestReply(const QUrl &origin, PermissionType type, bool reply);
- bool checkPermission(const QUrl &origin, PermissionType type);
+ void permissionRequestReply(const QUrl &origin, ProfileAdapter::PermissionType type, ProfileAdapter::PermissionState reply);
+ bool checkPermission(const QUrl &origin, ProfileAdapter::PermissionType type);
// content::PermissionManager implementation:
int RequestPermission(
@@ -99,10 +98,10 @@ public:
void UnsubscribePermissionStatusChange(int subscription_id) override;
private:
- QHash<QPair<QUrl, PermissionType>, bool> m_permissions;
+ QHash<QPair<QUrl, ProfileAdapter::PermissionType>, bool> m_permissions;
struct Request {
int id;
- PermissionType type;
+ ProfileAdapter::PermissionType type;
QUrl origin;
base::OnceCallback<void(blink::mojom::PermissionStatus)> callback;
};
@@ -113,7 +112,7 @@ private:
base::OnceCallback<void(const std::vector<blink::mojom::PermissionStatus>&)> callback;
};
struct Subscription {
- PermissionType type;
+ ProfileAdapter::PermissionType type;
QUrl origin;
base::RepeatingCallback<void(blink::mojom::PermissionStatus)> callback;
};
diff --git a/src/core/profile_adapter.cpp b/src/core/profile_adapter.cpp
index b87591c97..4557ad7a4 100644
--- a/src/core/profile_adapter.cpp
+++ b/src/core/profile_adapter.cpp
@@ -543,7 +543,7 @@ UserResourceControllerHost *ProfileAdapter::userResourceController()
return m_userResourceController.data();
}
-void ProfileAdapter::permissionRequestReply(const QUrl &origin, PermissionType type, bool reply)
+void ProfileAdapter::permissionRequestReply(const QUrl &origin, PermissionType type, PermissionState reply)
{
static_cast<PermissionManagerQt*>(profile()->GetPermissionControllerDelegate())->permissionRequestReply(origin, type, reply);
}
diff --git a/src/core/profile_adapter.h b/src/core/profile_adapter.h
index 1e5a3e21f..efd56e50e 100644
--- a/src/core/profile_adapter.h
+++ b/src/core/profile_adapter.h
@@ -164,6 +164,12 @@ public:
ClipboardWrite = 6,
};
+ enum PermissionState {
+ AskPermission = 0,
+ AllowedPermission = 1,
+ DeniedPermission = 2
+ };
+
HttpCacheType httpCacheType() const;
void setHttpCacheType(ProfileAdapter::HttpCacheType);
@@ -187,7 +193,7 @@ public:
const QList<QByteArray> customUrlSchemes() const;
UserResourceControllerHost *userResourceController();
- void permissionRequestReply(const QUrl &origin, PermissionType type, bool reply);
+ void permissionRequestReply(const QUrl &origin, PermissionType type, PermissionState reply);
bool checkPermission(const QUrl &origin, PermissionType type);
QString httpAcceptLanguageWithoutQualities() const;
diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp
index 0f2f21f83..ef482ef08 100644
--- a/src/core/web_contents_adapter.cpp
+++ b/src/core/web_contents_adapter.cpp
@@ -1360,15 +1360,15 @@ void WebContentsAdapter::grantMediaAccessPermission(const QUrl &securityOrigin,
CHECK_INITIALIZED();
// Let the permission manager remember the reply.
if (flags & WebContentsAdapterClient::MediaAudioCapture)
- m_profileAdapter->permissionRequestReply(securityOrigin, ProfileAdapter::AudioCapturePermission, true);
+ m_profileAdapter->permissionRequestReply(securityOrigin, ProfileAdapter::AudioCapturePermission, ProfileAdapter::AllowedPermission);
if (flags & WebContentsAdapterClient::MediaVideoCapture)
- m_profileAdapter->permissionRequestReply(securityOrigin, ProfileAdapter::VideoCapturePermission, true);
+ m_profileAdapter->permissionRequestReply(securityOrigin, ProfileAdapter::VideoCapturePermission, ProfileAdapter::AllowedPermission);
MediaCaptureDevicesDispatcher::GetInstance()->handleMediaAccessPermissionResponse(m_webContents.get(), securityOrigin, flags);
}
-void WebContentsAdapter::runFeatureRequestCallback(const QUrl &securityOrigin, ProfileAdapter::PermissionType feature, bool allowed)
+void WebContentsAdapter::grantFeaturePermission(const QUrl &securityOrigin, ProfileAdapter::PermissionType feature, ProfileAdapter::PermissionState allowed)
{
- CHECK_INITIALIZED();
+ Q_ASSERT(m_profileAdapter);
m_profileAdapter->permissionRequestReply(securityOrigin, feature, allowed);
}
diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h
index 66808ce5e..d833314f2 100644
--- a/src/core/web_contents_adapter.h
+++ b/src/core/web_contents_adapter.h
@@ -196,7 +196,7 @@ public:
void grantMediaAccessPermission(const QUrl &securityOrigin, WebContentsAdapterClient::MediaRequestFlags flags);
void grantMouseLockPermission(const QUrl &securityOrigin, bool granted);
void handlePendingMouseLockPermission();
- void runFeatureRequestCallback(const QUrl &securityOrigin, ProfileAdapter::PermissionType feature, bool allowed);
+ void grantFeaturePermission(const QUrl &securityOrigin, ProfileAdapter::PermissionType feature, ProfileAdapter::PermissionState allowed);
void setBackgroundColor(const QColor &color);
QAccessibleInterface *browserAccessible();
diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp
index bf0254e82..63f52433e 100644
--- a/src/core/web_contents_delegate_qt.cpp
+++ b/src/core/web_contents_delegate_qt.cpp
@@ -251,8 +251,9 @@ void WebContentsDelegateQt::AddNewContents(content::WebContents* source, std::un
void WebContentsDelegateQt::CloseContents(content::WebContents *source)
{
- m_viewClient->close();
GetJavaScriptDialogManager(source)->CancelDialogs(source, /* whatever?: */false);
+ // Must be the last call because close() might trigger the destruction of this object.
+ m_viewClient->close();
}
void WebContentsDelegateQt::LoadProgressChanged(double progress)
diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp
index 6e5469ab4..f659d15ca 100644
--- a/src/webengine/api/qquickwebengineview.cpp
+++ b/src/webengine/api/qquickwebengineview.cpp
@@ -1644,9 +1644,6 @@ void QQuickWebEngineView::grantFeaturePermission(const QUrl &securityOrigin, QQu
case MediaAudioVideoCapture:
d_ptr->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaRequestFlags(WebContentsAdapterClient::MediaAudioCapture | WebContentsAdapterClient::MediaVideoCapture));
break;
- case Geolocation:
- d_ptr->adapter->runFeatureRequestCallback(securityOrigin, ProfileAdapter::GeolocationPermission, granted);
- break;
case DesktopVideoCapture:
d_ptr->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaDesktopVideoCapture);
break;
@@ -1657,8 +1654,13 @@ void QQuickWebEngineView::grantFeaturePermission(const QUrl &securityOrigin, QQu
WebContentsAdapterClient::MediaDesktopAudioCapture |
WebContentsAdapterClient::MediaDesktopVideoCapture));
break;
+ case Geolocation:
+ d_ptr->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::GeolocationPermission,
+ granted ? ProfileAdapter::AllowedPermission : ProfileAdapter::DeniedPermission);
+ break;
case Notifications:
- d_ptr->adapter->runFeatureRequestCallback(securityOrigin, ProfileAdapter::NotificationPermission, granted);
+ d_ptr->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::NotificationPermission,
+ granted ? ProfileAdapter::AllowedPermission : ProfileAdapter::DeniedPermission);
break;
default:
Q_UNREACHABLE();
diff --git a/src/webengine/doc/src/qtwebengine-debugging.qdoc b/src/webengine/doc/src/qtwebengine-debugging.qdoc
index 088db5f87..0db35c85c 100644
--- a/src/webengine/doc/src/qtwebengine-debugging.qdoc
+++ b/src/webengine/doc/src/qtwebengine-debugging.qdoc
@@ -97,6 +97,11 @@
\li \c {--single-process} runs the renderer and plugins in the same
process as the browser. This is useful for getting stack traces for
renderer crashes.
+ \li \c {--enable-features=NetworkServiceInProcess} runs networking in
+ the main process. This may help firewall management, since only the
+ application executable will need to be whitelisted and
+ not QtWebEngineProcess. It means losing the security of
+ sandboxing of the network service though.
\endlist
Alternatively, the environment variable QTWEBENGINE_CHROMIUM_FLAGS can be
@@ -106,4 +111,7 @@
\code
QTWEBENGINE_CHROMIUM_FLAGS="--disable-logging" mybrowser
\endcode
+
+ QTWEBENGINE_CHROMIUM_FLAGS can also be set using {qputenv} from within the
+ application if called before QtWebEngine::initialize().
*/
diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp
index 7045fd856..6fb3c5c43 100644
--- a/src/webenginewidgets/api/qwebenginepage.cpp
+++ b/src/webenginewidgets/api/qwebenginepage.cpp
@@ -1910,8 +1910,24 @@ QMenu *QWebEnginePage::createStandardContextMenu()
void QWebEnginePage::setFeaturePermission(const QUrl &securityOrigin, QWebEnginePage::Feature feature, QWebEnginePage::PermissionPolicy policy)
{
Q_D(QWebEnginePage);
- if (policy == PermissionUnknown)
+ if (policy == PermissionUnknown) {
+ switch (feature) {
+ case MediaAudioVideoCapture:
+ case MediaAudioCapture:
+ case MediaVideoCapture:
+ case DesktopAudioVideoCapture:
+ case DesktopVideoCapture:
+ case MouseLock:
+ break;
+ case Geolocation:
+ d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::GeolocationPermission, ProfileAdapter::AskPermission);
+ break;
+ case Notifications:
+ d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::NotificationPermission, ProfileAdapter::AskPermission);
+ break;
+ }
return;
+ }
const WebContentsAdapterClient::MediaRequestFlags audioVideoCaptureFlags(
WebContentsAdapterClient::MediaVideoCapture |
@@ -1937,14 +1953,14 @@ void QWebEnginePage::setFeaturePermission(const QUrl &securityOrigin, QWebEngine
case DesktopVideoCapture:
d->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaDesktopVideoCapture);
break;
- case Geolocation:
- d->adapter->runFeatureRequestCallback(securityOrigin, ProfileAdapter::GeolocationPermission, true);
- break;
case MouseLock:
d->adapter->grantMouseLockPermission(securityOrigin, true);
break;
+ case Geolocation:
+ d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::GeolocationPermission, ProfileAdapter::AllowedPermission);
+ break;
case Notifications:
- d->adapter->runFeatureRequestCallback(securityOrigin, ProfileAdapter::NotificationPermission, true);
+ d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::NotificationPermission, ProfileAdapter::AllowedPermission);
break;
}
} else { // if (policy == PermissionDeniedByUser)
@@ -1957,13 +1973,13 @@ void QWebEnginePage::setFeaturePermission(const QUrl &securityOrigin, QWebEngine
d->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaNone);
break;
case Geolocation:
- d->adapter->runFeatureRequestCallback(securityOrigin, ProfileAdapter::GeolocationPermission, false);
+ d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::GeolocationPermission, ProfileAdapter::DeniedPermission);
break;
case MouseLock:
d->adapter->grantMouseLockPermission(securityOrigin, false);
break;
case Notifications:
- d->adapter->runFeatureRequestCallback(securityOrigin, ProfileAdapter::NotificationPermission, false);
+ d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::NotificationPermission, ProfileAdapter::DeniedPermission);
break;
}
}
diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/resources/sw.html b/tests/auto/core/qwebengineurlrequestinterceptor/resources/sw.html
new file mode 100644
index 000000000..af44b45a2
--- /dev/null
+++ b/tests/auto/core/qwebengineurlrequestinterceptor/resources/sw.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+ <body>
+ <script>
+ if ('serviceWorker' in navigator) {
+ window.addEventListener('load', function() {
+ navigator.serviceWorker.register('/sw.js').then(function(registration) {
+ console.log('ServiceWorker registration successful with scope: ', registration.scope);
+ }, function(err) {
+ console.error('ServiceWorker registration failed: ', err);
+ });
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/resources/sw.js b/tests/auto/core/qwebengineurlrequestinterceptor/resources/sw.js
new file mode 100644
index 000000000..2216e2a07
--- /dev/null
+++ b/tests/auto/core/qwebengineurlrequestinterceptor/resources/sw.js
@@ -0,0 +1,3 @@
+self.addEventListener('install', function(event) {
+ console.log('ServiceWorker installed');
+});
diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp
index b8ecce635..350c15174 100644
--- a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp
+++ b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp
@@ -74,6 +74,8 @@ private Q_SLOTS:
void passRefererHeader();
void initiator_data();
void initiator();
+ void jsServiceWorker_data();
+ void jsServiceWorker();
};
tst_QWebEngineUrlRequestInterceptor::tst_QWebEngineUrlRequestInterceptor()
@@ -186,6 +188,58 @@ public:
}
};
+class TestServer : public HttpServer
+{
+public:
+ TestServer()
+ {
+ connect(this, &HttpServer::newRequest, this, &TestServer::onNewRequest);
+ }
+
+private:
+ void onNewRequest(HttpReqRep *rr)
+ {
+ const QDir resourceDir(TESTS_SOURCE_DIR "qwebengineurlrequestinterceptor/resources");
+ QString path = rr->requestPath();
+ path.remove(0, 1);
+
+ if (rr->requestMethod() != "GET" || !resourceDir.exists(path))
+ {
+ rr->setResponseStatus(404);
+ rr->sendResponse();
+ return;
+ }
+
+ QFile file(resourceDir.filePath(path));
+ file.open(QIODevice::ReadOnly);
+ QByteArray data = file.readAll();
+ rr->setResponseBody(data);
+ QMimeDatabase db;
+ QMimeType mime = db.mimeTypeForFileNameAndData(file.fileName(), data);
+ rr->setResponseHeader(QByteArrayLiteral("content-type"), mime.name().toUtf8());
+ rr->sendResponse();
+ }
+};
+
+class ConsolePage : public QWebEnginePage {
+ Q_OBJECT
+public:
+ ConsolePage(QWebEngineProfile* profile) : QWebEnginePage(profile) {}
+
+ virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID)
+ {
+ levels.append(level);
+ messages.append(message);
+ lineNumbers.append(lineNumber);
+ sourceIDs.append(sourceID);
+ }
+
+ QList<int> levels;
+ QStringList messages;
+ QList<int> lineNumbers;
+ QStringList sourceIDs;
+};
+
void tst_QWebEngineUrlRequestInterceptor::interceptRequest_data()
{
QTest::addColumn<InterceptorSetter>("setter");
@@ -699,5 +753,39 @@ void tst_QWebEngineUrlRequestInterceptor::initiator()
QVERIFY(interceptor.requestInitiatorUrls[info.requestUrl].contains(info.initiator));
}
+void tst_QWebEngineUrlRequestInterceptor::jsServiceWorker_data()
+{
+ interceptRequest_data();
+}
+
+void tst_QWebEngineUrlRequestInterceptor::jsServiceWorker()
+{
+ QFETCH(InterceptorSetter, setter);
+
+ TestServer server;
+ QVERIFY(server.start());
+
+ QWebEngineProfile profile(QStringLiteral("Test"));
+ std::unique_ptr<ConsolePage> page;
+ page.reset(new ConsolePage(&profile));
+ TestRequestInterceptor interceptor(/* intercept */ false);
+ (profile.*setter)(&interceptor);
+ QVERIFY(loadSync(page.get(), server.url("/sw.html")));
+
+ // We expect only one message here, because logging of services workers is not exposed in our API.
+ QTRY_COMPARE(page->messages.count(), 1);
+ QCOMPARE(page->levels.at(0), QWebEnginePage::InfoMessageLevel);
+
+ QUrl firstPartyUrl = QUrl(server.url().toString() + "sw.js");
+ QList<RequestInfo> infos;
+ // Service Worker
+ QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeServiceWorker));
+ infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeServiceWorker);
+ foreach (auto info, infos)
+ QCOMPARE(info.firstPartyUrl, firstPartyUrl);
+
+ QVERIFY(server.stop());
+}
+
QTEST_MAIN(tst_QWebEngineUrlRequestInterceptor)
#include "tst_qwebengineurlrequestinterceptor.moc"
diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.qrc b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.qrc
index 13dbb134e..6a34635f7 100644
--- a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.qrc
+++ b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.qrc
@@ -17,6 +17,8 @@
<file>resources/resource_in_iframe.html</file>
<file>resources/script.js</file>
<file>resources/style.css</file>
+ <file>resources/sw.html</file>
+ <file>resources/sw.js</file>
<file>resources/icons/favicon.png</file>
</qresource>
</RCC>
diff --git a/tests/auto/quick/qmltests/data/TestWebEngineView.qml b/tests/auto/quick/qmltests/data/TestWebEngineView.qml
index f5e83c5d2..6db076ae8 100644
--- a/tests/auto/quick/qmltests/data/TestWebEngineView.qml
+++ b/tests/auto/quick/qmltests/data/TestWebEngineView.qml
@@ -111,5 +111,12 @@ WebEngineView {
onWindowCloseRequested: {
windowCloseRequestedSignalEmitted = true;
}
+
+ function getBodyText() {
+ let text
+ runJavaScript('document.body.innerText', function(t) { text = t })
+ testCase.tryVerify(function() { return text !== undefined })
+ return text
+ }
}
diff --git a/tests/auto/quick/qmltests/data/tst_certificateError.qml b/tests/auto/quick/qmltests/data/tst_certificateError.qml
new file mode 100644
index 000000000..0629be175
--- /dev/null
+++ b/tests/auto/quick/qmltests/data/tst_certificateError.qml
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.2
+import QtTest 1.0
+import QtWebEngine 1.9
+
+import Test.Shared 1.0 as Shared
+
+TestWebEngineView {
+ id: view; width: 320; height: 320
+
+ property bool deferError: false
+ property bool acceptCertificate: false
+
+ onCertificateError: function(error) {
+ if (deferError)
+ error.defer()
+ else if (acceptCertificate)
+ error.ignoreCertificateError()
+ else
+ error.rejectCertificate()
+ }
+
+ SignalSpy {
+ id: spyError
+ target: view
+ signalName: 'certificateError'
+ }
+
+ TestCase {
+ name: 'CertificateError'
+ when: windowShown
+
+ function initTestCase() {
+ Shared.HttpsServer.setExpectError(true)
+ Shared.HttpsServer.newRequest.connect(function (request) {
+ request.setResponseBody('<html><body>Test</body></html>')
+ request.sendResponse()
+ })
+ view.settings.errorPageEnabled = false
+ }
+
+ function init() {
+ verify(Shared.HttpsServer.start())
+ }
+
+ function cleanup() {
+ Shared.HttpsServer.stop()
+ view.deferError = false
+ view.acceptCertificate = false
+ spyError.clear()
+ }
+
+ function test_error_data() {
+ return [
+ { tag: 'reject', deferError: false, acceptCertificate: false, expectedContent: '' },
+ { tag: 'defer_reject', deferError: true, acceptCertificate: false, expectedContent: '' },
+ { tag: 'defer_accept', deferError: true, acceptCertificate: true, expectedContent: 'Test' },
+ ]
+ }
+
+ function test_error(data) {
+ view.deferError = data.deferError
+ view.acceptCertificate = data.acceptCertificate
+ view.url = Shared.HttpsServer.url()
+
+ if (data.deferError) {
+ spyError.wait()
+ compare(spyError.count, 1)
+ compare('', view.getBodyText())
+
+ let error = spyError.signalArguments[0][0]
+ if (data.acceptCertificate)
+ error.ignoreCertificateError()
+ else
+ error.rejectCertificate()
+ }
+
+ if (data.acceptCertificate)
+ verify(view.waitForLoadSucceeded())
+ else
+ verify(view.waitForLoadFailed())
+
+ compare(spyError.count, 1)
+ compare(data.expectedContent, view.getBodyText())
+ }
+ }
+}
diff --git a/tests/auto/quick/qmltests/qmltests.pro b/tests/auto/quick/qmltests/qmltests.pro
index 5c57f7ad9..6bec6dc0d 100644
--- a/tests/auto/quick/qmltests/qmltests.pro
+++ b/tests/auto/quick/qmltests/qmltests.pro
@@ -1,4 +1,5 @@
include(../tests.pri)
+include(../../shared/https.pri)
QT += qmltest
diff --git a/tests/auto/quick/qmltests/tst_qmltests.cpp b/tests/auto/quick/qmltests/tst_qmltests.cpp
index 9e8d25222..0d830931d 100644
--- a/tests/auto/quick/qmltests/tst_qmltests.cpp
+++ b/tests/auto/quick/qmltests/tst_qmltests.cpp
@@ -26,6 +26,8 @@
**
****************************************************************************/
+#include <httpsserver.h>
+
#include <QtCore/QScopedPointer>
#include <QTemporaryDir>
#include <QtQuickTest/quicktest.h>
@@ -144,6 +146,8 @@ int main(int argc, char **argv)
QTEST_SET_MAIN_SOURCE_PATH
+ qmlRegisterSingletonType<HttpsServer>("Test.Shared", 1, 0, "HttpsServer", [&] (QQmlEngine *, QJSEngine *) { return new HttpsServer; });
+
int i = quick_test_main(argc, argv, "qmltests", QUICK_TEST_SOURCE_DIR);
return i;
}
diff --git a/tests/auto/quick/qmltests2/data/tst_filePicker.qml b/tests/auto/quick/qmltests2/data/tst_filePicker.qml
index ffd7ef87b..ab30d9e82 100644
--- a/tests/auto/quick/qmltests2/data/tst_filePicker.qml
+++ b/tests/auto/quick/qmltests2/data/tst_filePicker.qml
@@ -36,6 +36,7 @@ TestWebEngineView {
id: webEngineView
width: 400
height: 300
+ property var titleChanges: []
function driveLetter() {
if (Qt.platform.os !== "windows")
@@ -54,6 +55,8 @@ TestWebEngineView {
signalName: "renderProcessTerminated"
}
+ onTitleChanged: { titleChanges.push(webEngineView.title) }
+
TestCase {
name: "WebEngineViewSingleFileUpload"
when: windowShown
@@ -65,6 +68,7 @@ TestWebEngineView {
FilePickerParams.nameFilters = []
titleSpy.clear()
terminationSpy.clear()
+ titleChanges = []
}
function cleanup() {
@@ -80,14 +84,14 @@ TestWebEngineView {
function test_acceptSingleFileSelection_data() {
return [
+ { tag: "test.txt", input: "test.txt", expected: "Failed to Upload" },
{ tag: driveLetter() + "/test.txt", input: driveLetter() + "/test.txt", expected: "test.txt" },
- { tag: driveLetter() + "test.txt", input: driveLetter() + "test.txt", expected: "Failed to Upload" },
{ tag: driveLetter() + "/tést.txt", input: driveLetter() + "/tést.txt", expected: "tést.txt" },
{ tag: driveLetter() + "/t%65st.txt", input: driveLetter() + "/t%65st.txt", expected: "t%65st.txt" },
{ tag: "file:///" + driveLetter() + "test.txt", input: "file:///" + driveLetter() + "test.txt", expected: "test.txt" },
{ tag: "file:///" + driveLetter() + "tést.txt", input: "file:///" + driveLetter() + "tést.txt", expected: "tést.txt" },
- { tag: "file:///" + driveLetter() + "t%65st.txt", input: "file:///" + driveLetter() + "t%65st.txt", expected: "test.txt" },
- { tag: "file://" + driveLetter() + "test.txt", input: "file://" + driveLetter() + "test.txt", expected: "test.txt" },
+ { tag: "file:///" + driveLetter() + "t%65st.txt", input: "file:///" + driveLetter() + "t%65st.txt", expected: "t%65st.txt" },
+ { tag: "file://" + driveLetter() + "test.txt", input: "file://" + driveLetter() + "test.txt", expected: "Failed to Upload" },
{ tag: "file:/" + driveLetter() + "test.txt", input: "file:/" + driveLetter() + "test.txt", expected: "test.txt"},
{ tag: "file:test//test.txt", input: "file:test//test.txt", expected: "Failed to Upload" },
{ tag: "http://test.txt", input: "http://test.txt", expected: "Failed to Upload" },
@@ -107,7 +111,10 @@ TestWebEngineView {
keyClick(Qt.Key_Enter); // Focus is on the button. Open FileDialog.
tryCompare(FilePickerParams, "filePickerOpened", true);
- tryCompare(webEngineView, "title", row.expected);
+ webEngineView.url = Qt.resolvedUrl("about:blank");
+ verify(webEngineView.waitForLoadSucceeded());
+ tryCompare(webEngineView, "title", "about:blank");
+ compare(titleChanges[titleChanges.length-2], row.expected);
// Custom dialog
@@ -125,7 +132,10 @@ TestWebEngineView {
keyClick(Qt.Key_Enter); // Focus is on the button. Open FileDialog.
tryVerify(function() { return finished; });
- tryCompare(webEngineView, "title", row.expected);
+ webEngineView.url = Qt.resolvedUrl("about:blank");
+ verify(webEngineView.waitForLoadSucceeded());
+ tryCompare(webEngineView, "title", "about:blank");
+ compare(titleChanges[titleChanges.length-2], row.expected);
webEngineView.fileDialogRequested.disconnect(acceptedFileHandler);
}
@@ -212,19 +222,19 @@ TestWebEngineView {
{ tag: "C:/test.txt", input: "C:/test.txt", expected: "test.txt"},
{ tag: "C:\\test.txt", input: "C:\\test.txt", expected: "test.txt"},
{ tag: "C:\\Documents and Settings\\test\\test.txt", input: "C:\\Documents and Settings\\test\\test.txt", expected: "test.txt"},
- { tag: "\\\\applib\\products\\a%2Db\\ abc%5F9\\t.est\\test.txt", input: "file://applib/products/a%2Db/ abc%5F9/4148.920a/media/test.txt", expected: "test.txt"},
- { tag: "file://applib/products/a%2Db/ abc%5F9/t.est/test.txt", input: "file://applib/products/a%2Db/ abc%5F9/4148.920a/media/test.txt", expected: "test.txt"},
+ { tag: "\\\\applib\\products\\a%2Db\\ abc%5F9\\t.est\\test.txt", input: "\\\\applib\\products\\a%2Db\\ abc%5F9\\t.est\\test.txt", expected: "test.txt"},
+ { tag: "file://applib/products/a%2Db/ abc%5F9/4148.920a/media/test.txt", input: "file://applib/products/a%2Db/ abc%5F9/4148.920a/media/test.txt", expected: "test.txt"},
{ tag: "file://applib/products/a-b/abc_1/t.est/test.txt", input: "file://applib/products/a-b/abc_1/t.est/test.txt", expected: "test.txt"},
{ tag: "file:\\\\applib\\products\\a-b\\abc_1\\t:est\\test.txt", input: "file:\\\\applib\\products\\a-b\\abc_1\\t:est\\test.txt", expected: "test.txt"},
- { tag: "file:C:/test.txt", input: "file:C:/test.txt", expected: "Failed to Upload"},
- { tag: "file:/C:/test.txt", input: "file:/C:/test.txt", expected: "Failed to Upload"},
+ { tag: "file:C:/test.txt", input: "file:C:/test.txt", expected: "test.tx"},
+ { tag: "file:/C:/test.txt", input: "file:/C:/test.txt", expected: "test.tx"},
{ tag: "file://C:/test.txt", input: "file://C:/test.txt", expected: "Failed to Upload"},
{ tag: "file:///C:test.txt", input: "file:///C:test.txt", expected: "Failed to Upload"},
{ tag: "file:///C:/test.txt", input: "file:///C:/test.txt", expected: "test.txt"},
{ tag: "file:///C:\\test.txt", input: "file:///C:\\test.txt", expected: "test.txt"},
{ tag: "file:\\//C:/test.txt", input: "file:\\//C:/test.txt", expected: "test.txt"},
{ tag: "file:\\\\/C:\\test.txt", input: "file:\\\\/C:\\test.txt", expected: "test.txt"},
- { tag: "\\\\?\\C:/test.txt", input: "\\\\?\\C:/test.txt", expected: "Failed to Upload"},
+ { tag: "\\\\?\\C:/test.txt", input: "\\\\?\\C:/test.txt", expected: "test.tx"},
];
}
@@ -241,7 +251,10 @@ TestWebEngineView {
keyClick(Qt.Key_Enter); // Focus is on the button. Open FileDialog.
tryCompare(FilePickerParams, "filePickerOpened", true);
- tryCompare(webEngineView, "title", row.expected);
+ webEngineView.url = Qt.resolvedUrl("about:blank");
+ verify(webEngineView.waitForLoadSucceeded());
+ tryCompare(webEngineView, "title", "about:blank");
+ compare(titleChanges[titleChanges.length-2], row.expected);
// Custom dialog
@@ -259,7 +272,10 @@ TestWebEngineView {
keyClick(Qt.Key_Enter); // Focus is on the button. Open FileDialog.
tryVerify(function() { return finished; });
- tryCompare(webEngineView, "title", row.expected);
+ webEngineView.url = Qt.resolvedUrl("about:blank");
+ verify(webEngineView.waitForLoadSucceeded());
+ tryCompare(webEngineView, "title", "about:blank");
+ compare(titleChanges[titleChanges.length-2], row.expected);
webEngineView.fileDialogRequested.disconnect(acceptedFileHandler);
}
diff --git a/tests/auto/shared/httpreqrep.h b/tests/auto/shared/httpreqrep.h
index bee8119eb..1666b17d0 100644
--- a/tests/auto/shared/httpreqrep.h
+++ b/tests/auto/shared/httpreqrep.h
@@ -40,7 +40,7 @@ class HttpReqRep : public QObject
public:
explicit HttpReqRep(QTcpSocket *socket, QObject *parent = nullptr);
- void sendResponse();
+ Q_INVOKABLE void sendResponse();
void close();
// Request parameters (only valid after requestReceived())
@@ -61,7 +61,7 @@ public:
m_responseHeaders[key.toLower()] = std::move(value);
}
QByteArray responseBody() const { return m_responseBody; }
- void setResponseBody(QByteArray content)
+ Q_INVOKABLE void setResponseBody(QByteArray content)
{
m_responseHeaders["content-length"] = QByteArray::number(content.size());
m_responseBody = std::move(content);
diff --git a/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp b/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp
index 55d8ac6e8..39948c211 100644
--- a/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp
+++ b/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp
@@ -1016,8 +1016,10 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilenameWithTimestamp()
QRegularExpressionMatch match = fileNameCheck.match(downloadedFilePath);
QVERIFY(match.hasMatch());
// ISO 8601 Date and time in UTC
- QRegExp timestamp("^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9])([0-5][0-9])([0-5][0-9])([.][0-9]+)?(Z|[+-](?:2[0-3]|[01][0-9])[0-5][0-9])?$");
- QVERIFY(timestamp.exactMatch(match.captured(1)));
+ QRegularExpression timestamp("^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|["
+ "12][0-9])T(2[0-3]|[01][0-9])([0-5][0-9])([0-5][0-9])([.][0-9]"
+ "+)?(Z|[+-](?:2[0-3]|[01][0-9])[0-5][0-9])?$");
+ QVERIFY(timestamp.match(match.captured(1)).hasMatch());
QCOMPARE(suggestedFileName, fileName);
}
}
diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
index 190758ed2..7bd540cc6 100644
--- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
+++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
@@ -200,11 +200,10 @@ private Q_SLOTS:
void triggerActionWithoutMenu();
void dynamicFrame();
- void notificationRequest_data();
- void notificationRequest();
+ void notificationPermission_data();
+ void notificationPermission();
void sendNotification();
void contentsSize();
- void notificationPermission();
void setLifecycleState();
void setVisible();
@@ -229,6 +228,7 @@ private Q_SLOTS:
void renderProcessPid();
void backgroundColor();
void audioMuted();
+ void closeContents();
private:
static QPoint elementCenter(QWebEnginePage *page, const QString &id);
@@ -3575,42 +3575,61 @@ public:
}
};
-void tst_QWebEnginePage::notificationRequest_data()
+void tst_QWebEnginePage::notificationPermission_data()
{
+ QTest::addColumn<bool>("setOnInit");
QTest::addColumn<QWebEnginePage::PermissionPolicy>("policy");
QTest::addColumn<QString>("permission");
- QTest::newRow("deny") << QWebEnginePage::PermissionDeniedByUser << "denied";
- QTest::newRow("grant") << QWebEnginePage::PermissionGrantedByUser << "granted";
+ QTest::newRow("denyOnInit") << true << QWebEnginePage::PermissionDeniedByUser << "denied";
+ QTest::newRow("deny") << false << QWebEnginePage::PermissionDeniedByUser << "denied";
+ QTest::newRow("grant") << false << QWebEnginePage::PermissionGrantedByUser << "granted";
+ QTest::newRow("grantOnInit") << true << QWebEnginePage::PermissionGrantedByUser << "granted";
}
-void tst_QWebEnginePage::notificationRequest()
+void tst_QWebEnginePage::notificationPermission()
{
+ QFETCH(bool, setOnInit);
QFETCH(QWebEnginePage::PermissionPolicy, policy);
QFETCH(QString, permission);
- NotificationPage page(policy);
- QVERIFY(page.spyLoad.waitForResult());
+ QWebEngineProfile otr;
+ QWebEnginePage page(&otr, nullptr);
- page.resetPermission();
- QCOMPARE(page.getPermission(), "default");
+ QUrl baseUrl("https://www.example.com/somepage.html");
- page.requestPermission();
- page.spyRequest.waitForResult();
- QVERIFY(page.spyRequest.wasCalled());
+ bool permissionRequested = false, errorState = false;
+ connect(&page, &QWebEnginePage::featurePermissionRequested, &page, [&] (const QUrl &o, QWebEnginePage::Feature f) {
+ if (f != QWebEnginePage::Notifications)
+ return;
+ if (permissionRequested || o != baseUrl.url(QUrl::RemoveFilename)) {
+ qWarning() << "Unexpected case. Can't proceed." << setOnInit << permissionRequested << o;
+ errorState = true;
+ return;
+ }
+ permissionRequested = true;
+ page.setFeaturePermission(o, f, policy);
+ });
- QCOMPARE(page.getPermission(), permission);
-}
+ if (setOnInit)
+ page.setFeaturePermission(baseUrl, QWebEnginePage::Notifications, policy);
-void tst_QWebEnginePage::notificationPermission()
-{
- QWebEngineProfile otr;
- QWebEnginePage page(&otr, nullptr);
QSignalSpy spy(&page, &QWebEnginePage::loadFinished);
- page.setHtml(QString("<html><body>Test</body></html>"), QUrl("https://www.example.com"));
+ page.setHtml(QString("<html><body>Test</body></html>"), baseUrl);
QTRY_COMPARE(spy.count(), 1);
- QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("Notification.permission")), QLatin1String("default"));
- page.setFeaturePermission(QUrl("https://www.example.com"), QWebEnginePage::Notifications, QWebEnginePage::PermissionGrantedByUser);
- QTRY_COMPARE(evaluateJavaScriptSync(&page, QStringLiteral("Notification.permission")), QLatin1String("granted"));
+
+ QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("Notification.permission")), setOnInit ? permission : QLatin1String("default"));
+
+ if (!setOnInit) {
+ page.setFeaturePermission(baseUrl, QWebEnginePage::Notifications, policy);
+ QTRY_COMPARE(evaluateJavaScriptSync(&page, QStringLiteral("Notification.permission")), permission);
+ }
+
+ auto js = QStringLiteral("var permission; Notification.requestPermission().then(p => { permission = p })");
+ evaluateJavaScriptSync(&page, js);
+ QTRY_COMPARE(evaluateJavaScriptSync(&page, "permission").toString(), permission);
+ // permission is not 'remembered' from api standpoint, hence is not suppressed on explicit call from JS
+ QVERIFY(permissionRequested);
+ QVERIFY(!errorState);
}
void tst_QWebEnginePage::sendNotification()
@@ -4608,6 +4627,27 @@ void tst_QWebEnginePage::audioMuted()
QCOMPARE(spy[1][0], QVariant(false));
}
+void tst_QWebEnginePage::closeContents()
+{
+ TestPage page;
+ QSignalSpy windowCreatedSpy(&page, &TestPage::windowCreated);
+ page.runJavaScript("var dialog = window.open('', '', 'width=100, height=100');");
+ QTRY_COMPARE(windowCreatedSpy.count(), 1);
+
+ QWebEngineView *dialogView = new QWebEngineView;
+ QWebEnginePage *dialogPage = page.createdWindows[0];
+ dialogPage->setView(dialogView);
+ QCOMPARE(dialogPage->lifecycleState(), QWebEnginePage::LifecycleState::Active);
+
+ // This should not crash.
+ connect(dialogPage, &QWebEnginePage::windowCloseRequested, dialogView, &QWebEngineView::close);
+ page.runJavaScript("dialog.close();");
+
+ // QWebEngineView::closeEvent() sets the life cycle state to discarded.
+ QTRY_COMPARE(dialogPage->lifecycleState(), QWebEnginePage::LifecycleState::Discarded);
+ delete dialogView;
+}
+
static QByteArrayList params = {QByteArrayLiteral("--use-fake-device-for-media-stream")};
W_QTEST_MAIN(tst_QWebEnginePage, params)
diff --git a/tests/manual/quick/faviconbrowser/faviconbrowser.qrc b/tests/manual/quick/faviconbrowser/faviconbrowser.qrc
index 95d0dc2c4..b641fa2fa 100644
--- a/tests/manual/quick/faviconbrowser/faviconbrowser.qrc
+++ b/tests/manual/quick/faviconbrowser/faviconbrowser.qrc
@@ -5,13 +5,13 @@
<file>FaviconPanel.qml</file>
</qresource>
<qresource prefix="test">
- <file alias="favicon-multi-gray.html">../../../auto/quick/qmltests/data/favicon-multi-gray.html</file>
- <file alias="favicon-candidates-gray.html">../../../auto/quick/qmltests/data/favicon-candidates-gray.html</file>
- <file alias="icons/grayicons.ico">../../../auto/quick/qmltests/data/icons/grayicons.ico</file>
- <file alias="icons/gray16.png">../../../auto/quick/qmltests/data/icons/gray16.png</file>
- <file alias="icons/gray32.png">../../../auto/quick/qmltests/data/icons/gray32.png</file>
- <file alias="icons/gray64.png">../../../auto/quick/qmltests/data/icons/gray64.png</file>
- <file alias="icons/gray128.png">../../../auto/quick/qmltests/data/icons/gray128.png</file>
- <file alias="icons/gray255.png">../../../auto/quick/qmltests/data/icons/gray255.png</file>
+ <file alias="favicon-multi-gray.html">../../../auto/quick/qmltests2/data/favicon-multi-gray.html</file>
+ <file alias="favicon-candidates-gray.html">../../../auto/quick/qmltests2/data/favicon-candidates-gray.html</file>
+ <file alias="icons/grayicons.ico">../../../auto/quick/qmltests2/data/icons/grayicons.ico</file>
+ <file alias="icons/gray16.png">../../../auto/quick/qmltests2/data/icons/gray16.png</file>
+ <file alias="icons/gray32.png">../../../auto/quick/qmltests2/data/icons/gray32.png</file>
+ <file alias="icons/gray64.png">../../../auto/quick/qmltests2/data/icons/gray64.png</file>
+ <file alias="icons/gray128.png">../../../auto/quick/qmltests2/data/icons/gray128.png</file>
+ <file alias="icons/gray255.png">../../../auto/quick/qmltests2/data/icons/gray255.png</file>
</qresource>
</RCC>