summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/webenginewidgets/simplebrowser/webpage.cpp42
-rw-r--r--src/webenginewidgets/api/qwebenginecertificateerror.cpp97
-rw-r--r--src/webenginewidgets/api/qwebenginecertificateerror.h19
-rw-r--r--src/webenginewidgets/api/qwebenginepage.cpp8
-rw-r--r--src/webenginewidgets/api/qwebenginepage_p.h2
-rw-r--r--src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc2
-rw-r--r--tests/auto/shared/https.pri4
-rw-r--r--tests/auto/shared/httpserver.cpp31
-rw-r--r--tests/auto/shared/httpserver.h13
-rw-r--r--tests/auto/shared/httpsserver.h81
-rw-r--r--tests/auto/shared/httpsserver.qrc6
-rw-r--r--tests/auto/shared/resources/cert.pem34
-rw-r--r--tests/auto/shared/resources/key.pem52
-rw-r--r--tests/auto/widgets/certificateerror/certificateerror.pro3
-rw-r--r--tests/auto/widgets/certificateerror/tst_certificateerror.cpp122
-rw-r--r--tests/auto/widgets/widgets.pro1
16 files changed, 472 insertions, 45 deletions
diff --git a/examples/webenginewidgets/simplebrowser/webpage.cpp b/examples/webenginewidgets/simplebrowser/webpage.cpp
index 99849c77d..2e49f651f 100644
--- a/examples/webenginewidgets/simplebrowser/webpage.cpp
+++ b/examples/webenginewidgets/simplebrowser/webpage.cpp
@@ -57,6 +57,7 @@
#include <QAuthenticator>
#include <QMessageBox>
#include <QStyle>
+#include <QTimer>
#include <QWebEngineCertificateError>
WebPage::WebPage(QWebEngineProfile *profile, QObject *parent)
@@ -74,22 +75,33 @@ WebPage::WebPage(QWebEngineProfile *profile, QObject *parent)
bool WebPage::certificateError(const QWebEngineCertificateError &error)
{
QWidget *mainWindow = view()->window();
- if (error.isOverridable()) {
- QDialog dialog(mainWindow);
- dialog.setModal(true);
- dialog.setWindowFlags(dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint);
- Ui::CertificateErrorDialog certificateDialog;
- certificateDialog.setupUi(&dialog);
- certificateDialog.m_iconLabel->setText(QString());
- QIcon icon(mainWindow->style()->standardIcon(QStyle::SP_MessageBoxWarning, 0, mainWindow));
- certificateDialog.m_iconLabel->setPixmap(icon.pixmap(32, 32));
- certificateDialog.m_errorLabel->setText(error.errorDescription());
- dialog.setWindowTitle(tr("Certificate Error"));
- return dialog.exec() == QDialog::Accepted;
- }
- QMessageBox::critical(mainWindow, tr("Certificate Error"), error.errorDescription());
- return false;
+ QWebEngineCertificateError deferredError = error;
+ deferredError.defer();
+
+ QTimer::singleShot(0, mainWindow, [mainWindow, error = std::move(deferredError)] () mutable {
+ if (!error.deferred()) {
+ QMessageBox::critical(mainWindow, tr("Certificate Error"), error.errorDescription());
+ } else {
+ QDialog dialog(mainWindow);
+ dialog.setModal(true);
+ dialog.setWindowFlags(dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ Ui::CertificateErrorDialog certificateDialog;
+ certificateDialog.setupUi(&dialog);
+ certificateDialog.m_iconLabel->setText(QString());
+ QIcon icon(mainWindow->style()->standardIcon(QStyle::SP_MessageBoxWarning, 0, mainWindow));
+ certificateDialog.m_iconLabel->setPixmap(icon.pixmap(32, 32));
+ certificateDialog.m_errorLabel->setText(error.errorDescription());
+ dialog.setWindowTitle(tr("Certificate Error"));
+
+ if (dialog.exec() == QDialog::Accepted)
+ error.ignoreCertificateError();
+ else
+ error.rejectCertificate();
+ }
+ });
+ return true;
}
void WebPage::handleAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth)
diff --git a/src/webenginewidgets/api/qwebenginecertificateerror.cpp b/src/webenginewidgets/api/qwebenginecertificateerror.cpp
index f04b73615..e8c7a4245 100644
--- a/src/webenginewidgets/api/qwebenginecertificateerror.cpp
+++ b/src/webenginewidgets/api/qwebenginecertificateerror.cpp
@@ -39,6 +39,8 @@
#include "qwebenginecertificateerror.h"
+#include "certificate_error_controller.h"
+
QT_BEGIN_NAMESPACE
/*!
@@ -51,14 +53,37 @@ QT_BEGIN_NAMESPACE
QWebEnginePage::certificateError().
*/
-class QWebEngineCertificateErrorPrivate {
+class QWebEngineCertificateErrorPrivate : public QSharedData {
public:
QWebEngineCertificateErrorPrivate(int error, QUrl url, bool overridable, QString errorDescription);
+ ~QWebEngineCertificateErrorPrivate() {
+ if (deferred && !answered)
+ rejectCertificate();
+ }
+
+ void resolveError(bool accept) {
+ if (answered)
+ return;
+ answered = true;
+ if (overridable) {
+ if (auto ctl = controller.lock())
+ ctl->accept(accept);
+ }
+ }
+
+ void ignoreCertificateError() { resolveError(true); }
+ void rejectCertificate() { resolveError(false); }
+
QWebEngineCertificateError::Error error;
QUrl url;
bool overridable;
QString errorDescription;
+
+ bool answered = false, deferred = false;
+ QWeakPointer<CertificateErrorController> controller;
+
+ Q_DISABLE_COPY(QWebEngineCertificateErrorPrivate)
};
QWebEngineCertificateErrorPrivate::QWebEngineCertificateErrorPrivate(int error, QUrl url, bool overridable, QString errorDescription)
@@ -68,17 +93,30 @@ QWebEngineCertificateErrorPrivate::QWebEngineCertificateErrorPrivate(int error,
, errorDescription(errorDescription)
{ }
-
/*! \internal
*/
QWebEngineCertificateError::QWebEngineCertificateError(int error, QUrl url, bool overridable, QString errorDescription)
- : d_ptr(new QWebEngineCertificateErrorPrivate(error, url, overridable, errorDescription))
+ : d(new QWebEngineCertificateErrorPrivate(error, url, overridable, errorDescription))
{ }
/*! \internal
*/
+QWebEngineCertificateError::QWebEngineCertificateError(const QSharedPointer<CertificateErrorController> &controller)
+ : d(new QWebEngineCertificateErrorPrivate(controller->error(), controller->url(),
+ controller->overridable(), controller->errorString()))
+{
+ d->controller = controller;
+}
+
+QWebEngineCertificateError::QWebEngineCertificateError(const QWebEngineCertificateError &other) = default;
+
+QWebEngineCertificateError& QWebEngineCertificateError::operator=(const QWebEngineCertificateError &other) = default;
+
+/*! \internal
+*/
QWebEngineCertificateError::~QWebEngineCertificateError()
{
+
}
/*!
@@ -116,7 +154,6 @@ QWebEngineCertificateError::~QWebEngineCertificateError()
*/
bool QWebEngineCertificateError::isOverridable() const
{
- const Q_D(QWebEngineCertificateError);
return d->overridable;
}
@@ -127,7 +164,6 @@ bool QWebEngineCertificateError::isOverridable() const
*/
QUrl QWebEngineCertificateError::url() const
{
- const Q_D(QWebEngineCertificateError);
return d->url;
}
@@ -138,7 +174,6 @@ QUrl QWebEngineCertificateError::url() const
*/
QWebEngineCertificateError::Error QWebEngineCertificateError::error() const
{
- const Q_D(QWebEngineCertificateError);
return d->error;
}
@@ -149,8 +184,56 @@ QWebEngineCertificateError::Error QWebEngineCertificateError::error() const
*/
QString QWebEngineCertificateError::errorDescription() const
{
- const Q_D(QWebEngineCertificateError);
return d->errorDescription;
}
+/*!
+ Marks the certificate error for delayed handling.
+
+ This function should be called when there is a need to postpone the decision whether to ignore a
+ certificate error, for example, while waiting for user input. When called, the function pauses the
+ URL request until ignoreCertificateError() or rejectCertificate() is called.
+
+ \note It is only possible to defer overridable certificate errors.
+
+ \sa isOverridable(), deferred()
+*/
+void QWebEngineCertificateError::defer()
+{
+ if (isOverridable())
+ d->deferred = true;
+}
+
+/*!
+ Returns whether the decision for error handling was delayed and the URL load was halted.
+*/
+bool QWebEngineCertificateError::deferred() const
+{
+ return d->deferred;
+}
+
+/*!
+ Ignores the certificate error and continues the loading of the requested URL.
+*/
+void QWebEngineCertificateError::ignoreCertificateError()
+{
+ d->ignoreCertificateError();
+}
+
+/*!
+ Rejects the certificate and aborts the loading of the requested URL.
+*/
+void QWebEngineCertificateError::rejectCertificate()
+{
+ d->rejectCertificate();
+}
+
+/*!
+ Returns \c true if the error was explicitly rejected or accepted.
+*/
+bool QWebEngineCertificateError::answered() const
+{
+ return d->answered;
+}
+
QT_END_NAMESPACE
diff --git a/src/webenginewidgets/api/qwebenginecertificateerror.h b/src/webenginewidgets/api/qwebenginecertificateerror.h
index 82ac281be..f8805e8a7 100644
--- a/src/webenginewidgets/api/qwebenginecertificateerror.h
+++ b/src/webenginewidgets/api/qwebenginecertificateerror.h
@@ -42,11 +42,12 @@
#include <QtWebEngineWidgets/qtwebenginewidgetsglobal.h>
-#include <QtCore/qscopedpointer.h>
+#include <QtCore/qsharedpointer.h>
#include <QtCore/qurl.h>
QT_BEGIN_NAMESPACE
+class CertificateErrorController;
class QWebEngineCertificateErrorPrivate;
class QWEBENGINEWIDGETS_EXPORT QWebEngineCertificateError {
@@ -78,10 +79,20 @@ public:
bool isOverridable() const;
QString errorDescription() const;
+ QWebEngineCertificateError(const QWebEngineCertificateError &other);
+ QWebEngineCertificateError& operator=(const QWebEngineCertificateError &other);
+
+ void defer();
+ bool deferred() const;
+
+ void rejectCertificate();
+ void ignoreCertificateError();
+ bool answered() const;
+
private:
- Q_DISABLE_COPY(QWebEngineCertificateError)
- Q_DECLARE_PRIVATE(QWebEngineCertificateError)
- QScopedPointer<QWebEngineCertificateErrorPrivate> d_ptr;
+ friend class QWebEnginePagePrivate;
+ QWebEngineCertificateError(const QSharedPointer<CertificateErrorController> &controller);
+ QExplicitlySharedDataPointer<QWebEngineCertificateErrorPrivate> d;
};
QT_END_NAMESPACE
diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp
index c9e9177b7..b22d47916 100644
--- a/src/webenginewidgets/api/qwebenginepage.cpp
+++ b/src/webenginewidgets/api/qwebenginepage.cpp
@@ -294,6 +294,7 @@ void QWebEnginePagePrivate::loadStarted(const QUrl &provisionalUrl, bool isError
return;
isLoading = true;
+ m_certificateErrorControllers.clear();
QTimer::singleShot(0, q, &QWebEnginePage::loadStarted);
}
@@ -1715,10 +1716,11 @@ void QWebEnginePagePrivate::allowCertificateError(const QSharedPointer<Certifica
Q_Q(QWebEnginePage);
bool accepted = false;
- QWebEngineCertificateError error(controller->error(), controller->url(), controller->overridable() && !controller->strictEnforcement(), controller->errorString());
+ QWebEngineCertificateError error(controller);
accepted = q->certificateError(error);
-
- if (error.isOverridable())
+ if (error.deferred() && !error.answered())
+ m_certificateErrorControllers.append(controller);
+ else if (!error.answered() && error.isOverridable())
controller->accept(accepted);
}
diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h
index fae97b9fa..2843f69c4 100644
--- a/src/webenginewidgets/api/qwebenginepage_p.h
+++ b/src/webenginewidgets/api/qwebenginepage_p.h
@@ -210,6 +210,8 @@ public:
#if QT_CONFIG(webengine_printing_and_pdf)
QPrinter *currentPrinter;
#endif
+
+ QList<QSharedPointer<CertificateErrorController>> m_certificateErrorControllers;
};
class QContextMenuBuilder : public QtWebEngineCore::RenderViewContextMenuQt
diff --git a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc
index 64fe4c9cd..5536c0058 100644
--- a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc
+++ b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc
@@ -522,6 +522,8 @@
Return \c true to ignore the error and complete the request. Return \c false to stop loading
the request.
+ \note If the error was successfully deferred then the returned value will be ignored.
+
\sa QWebEngineCertificateError
*/
diff --git a/tests/auto/shared/https.pri b/tests/auto/shared/https.pri
new file mode 100644
index 000000000..ce4c147f7
--- /dev/null
+++ b/tests/auto/shared/https.pri
@@ -0,0 +1,4 @@
+include($$PWD/http.pri)
+
+HEADERS += $$PWD/httpsserver.h
+RESOURCES += $$PWD/httpsserver.qrc
diff --git a/tests/auto/shared/httpserver.cpp b/tests/auto/shared/httpserver.cpp
index b85af9901..e282fc8b8 100644
--- a/tests/auto/shared/httpserver.cpp
+++ b/tests/auto/shared/httpserver.cpp
@@ -31,9 +31,21 @@
Q_LOGGING_CATEGORY(gHttpServerLog, "HttpServer")
-HttpServer::HttpServer(QObject *parent) : QObject(parent)
+HttpServer::HttpServer(QObject *parent) : HttpServer(new QTcpServer, "http", parent)
{
- connect(&m_tcpServer, &QTcpServer::newConnection, this, &HttpServer::handleNewConnection);
+}
+
+HttpServer::HttpServer(QTcpServer *tcpServer, const QString &protocol, QObject *parent)
+ : QObject(parent), m_tcpServer(tcpServer)
+{
+ m_url.setHost(QStringLiteral("127.0.0.1"));
+ m_url.setScheme(protocol);
+ connect(tcpServer, &QTcpServer::newConnection, this, &HttpServer::handleNewConnection);
+}
+
+HttpServer::~HttpServer()
+{
+ delete m_tcpServer;
}
bool HttpServer::start()
@@ -41,21 +53,18 @@ bool HttpServer::start()
m_error = false;
m_expectingError = false;
- if (!m_tcpServer.listen()) {
- qCWarning(gHttpServerLog).noquote() << m_tcpServer.errorString();
+ if (!m_tcpServer->listen()) {
+ qCWarning(gHttpServerLog).noquote() << m_tcpServer->errorString();
return false;
}
- m_url.setScheme(QStringLiteral("http"));
- m_url.setHost(QStringLiteral("127.0.0.1"));
- m_url.setPort(m_tcpServer.serverPort());
-
+ m_url.setPort(m_tcpServer->serverPort());
return true;
}
bool HttpServer::stop()
{
- m_tcpServer.close();
+ m_tcpServer->close();
return m_error == m_expectingError;
}
@@ -73,12 +82,12 @@ QUrl HttpServer::url(const QString &path) const
void HttpServer::handleNewConnection()
{
- auto rr = new HttpReqRep(m_tcpServer.nextPendingConnection(), this);
+ auto rr = new HttpReqRep(m_tcpServer->nextPendingConnection(), this);
connect(rr, &HttpReqRep::requestReceived, [this, rr]() {
Q_EMIT newRequest(rr);
rr->close();
});
- connect(rr, &HttpReqRep::responseSent, [this, rr]() {
+ connect(rr, &HttpReqRep::responseSent, [rr]() {
qCInfo(gHttpServerLog).noquote() << rr->requestMethod() << rr->requestPath()
<< rr->responseStatus() << rr->responseBody().size();
});
diff --git a/tests/auto/shared/httpserver.h b/tests/auto/shared/httpserver.h
index b4649244e..57f824bb5 100644
--- a/tests/auto/shared/httpserver.h
+++ b/tests/auto/shared/httpserver.h
@@ -59,19 +59,22 @@ class HttpServer : public QObject
Q_OBJECT
public:
explicit HttpServer(QObject *parent = nullptr);
+ explicit HttpServer(QTcpServer *server, const QString &protocol, QObject *parent = nullptr);
+
+ ~HttpServer() override;
// Must be called to start listening.
//
// Returns true if a TCP port has been successfully bound.
- Q_REQUIRED_RESULT bool start();
+ Q_INVOKABLE Q_REQUIRED_RESULT bool start();
// Stops listening and performs final error checks.
- Q_REQUIRED_RESULT bool stop();
+ Q_INVOKABLE Q_REQUIRED_RESULT bool stop();
- void setExpectError(bool b);
+ Q_INVOKABLE void setExpectError(bool b);
// Full URL for given relative path
- QUrl url(const QString &path = QStringLiteral("/")) const;
+ Q_INVOKABLE QUrl url(const QString &path = QStringLiteral("/")) const;
Q_SIGNALS:
// Emitted after a HTTP request has been successfully parsed.
@@ -81,7 +84,7 @@ private Q_SLOTS:
void handleNewConnection();
private:
- QTcpServer m_tcpServer;
+ QTcpServer *m_tcpServer;
QUrl m_url;
bool m_error = false;
bool m_expectingError = false;
diff --git a/tests/auto/shared/httpsserver.h b/tests/auto/shared/httpsserver.h
new file mode 100644
index 000000000..76287a7e5
--- /dev/null
+++ b/tests/auto/shared/httpsserver.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+#ifndef HTTPSSERVER_H
+#define HTTPSSERVER_H
+
+#include "httpreqrep.h"
+#include "httpserver.h"
+
+#include <QDebug>
+#include <QFile>
+#include <QSslKey>
+#include <QSslSocket>
+#include <QSslConfiguration>
+#include <QTcpServer>
+
+struct SslTcpServer : QTcpServer
+{
+ SslTcpServer() {
+ sslconf.setLocalCertificate(QSslCertificate::fromPath(":/resources/cert.pem").first());
+ sslconf.setPrivateKey(readKey(":/resources/key.pem"));
+ }
+
+ void incomingConnection(qintptr d) override {
+ auto socket = new QSslSocket(this);
+ socket->setSslConfiguration(sslconf);
+
+ if (!socket->setSocketDescriptor(d)) {
+ qWarning() << "Failed to setup ssl socket!";
+ delete socket;
+ return;
+ }
+
+ connect(socket, QOverload<QSslSocket::SocketError>::of(&QSslSocket::error),
+ [] (QSslSocket::SocketError e) { qWarning() << "! Socket Error:" << e; });
+ connect(socket, QOverload<const QList<QSslError> &>::of(&QSslSocket::sslErrors),
+ [] (const QList<QSslError> &le) { qWarning() << "! SSL Errors:\n" << le; });
+
+ addPendingConnection(socket);
+ socket->startServerEncryption();
+ }
+
+ QSslKey readKey(const QString &path) const {
+ QFile file(path);
+ file.open(QIODevice::ReadOnly);
+ return QSslKey(file.readAll(), QSsl::Rsa, QSsl::Pem);
+ }
+
+ QSslConfiguration sslconf;
+};
+
+struct HttpsServer : HttpServer
+{
+ HttpsServer(QObject *parent = nullptr) : HttpServer(new SslTcpServer, "https", parent) { }
+};
+
+#endif
diff --git a/tests/auto/shared/httpsserver.qrc b/tests/auto/shared/httpsserver.qrc
new file mode 100644
index 000000000..ec57a1983
--- /dev/null
+++ b/tests/auto/shared/httpsserver.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>resources/cert.pem</file>
+ <file>resources/key.pem</file>
+</qresource>
+</RCC>
diff --git a/tests/auto/shared/resources/cert.pem b/tests/auto/shared/resources/cert.pem
new file mode 100644
index 000000000..518642d1d
--- /dev/null
+++ b/tests/auto/shared/resources/cert.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF3zCCA8egAwIBAgIULwmp8VArl0GVaR6HLEf/U1XNdJ8wDQYJKoZIhvcNAQEL
+BQAwfzELMAkGA1UEBhMCREUxDzANBgNVBAgMBkJlcmxpbjEPMA0GA1UEBwwGQmVy
+bGluMQ0wCwYDVQQKDARUUXRDMQswCQYDVQQLDAJXRTESMBAGA1UEAwwJbG9jYWxo
+b3N0MR4wHAYJKoZIhvcNAQkBFg9ibGFja2hvbGVAcXQuaW8wHhcNOTkxMjMxMjMw
+MDAxWhcNMDAxMjMwMjMwMDAxWjB/MQswCQYDVQQGEwJERTEPMA0GA1UECAwGQmVy
+bGluMQ8wDQYDVQQHDAZCZXJsaW4xDTALBgNVBAoMBFRRdEMxCzAJBgNVBAsMAldF
+MRIwEAYDVQQDDAlsb2NhbGhvc3QxHjAcBgkqhkiG9w0BCQEWD2JsYWNraG9sZUBx
+dC5pbzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL15eV6DVSOFW093
+p1+FlqmneX4riOzJXiNNF8DI00+rkTv4hT37D6keJlMxLLDgq3o9YwJnGJkpxMSd
+P9uvKGaIRb9hQd7WviXCMwX07Wz3BMIogKItJfY6nEk8dkCc/FPrhbk4CCKNoZkb
+fGRv4jFoCCXL8yaffN5ii+L/xF2azaXwr4MOOJbG5810HWGYbrppBMtSQk4c1jXI
+c0eVqOjnYtcFNCmoIyXwDdTynaRizNtUgeYRSaIBk/hXQGePDL35V0ARg2EbVGzL
+sJKftJf4WBoprjX8xmfk72zYB0SF8g7uUXGWb6D5Q661c7REGB7Ha7uLIz74Pow3
+MmJVbz93YiEZ4onxDNke5AIgNrllhd1hk8WGBBN7i/8RmR2KRS24OEa2jQd0u8Lx
+WvUsWpzWO5sSGN4vw1NA75fk8pKo80Jvhz2+1q2CeAEnkIhU2tsH301MWuHasrXJ
+6HY1zp0IoeYRwtCof/nuTbC9BYM3782tmJ/6O7O8BQyOM3G/7+8hgyUC+mfSigcm
+qVbpWbchSxBSHZ5DlMMHHHYJSxS0GAjSGx7fC4t7EBgZtnZyrLA12gYoGnh2kC5T
+RgWtfwVdJgHKGRWfeMdOhu73GlWyj9iEN+BaT5LkPxiytb+y1RmRcPtqBofMKkpV
+9D4X5iTQbAoXrdUztVcE5dBPm/VbAgMBAAGjUzBRMB0GA1UdDgQWBBSdQX4ziuSL
+BPNR1d0v5X2QaMTeNjAfBgNVHSMEGDAWgBSdQX4ziuSLBPNR1d0v5X2QaMTeNjAP
+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQAKqjEBoYk+t/qgTlGH
+Ab+aSM7kfLvHtktpGT7Shh9hUyczcqROOpj/jVFvd+y1tFXglE+II65jAnCZ7neX
+vJC+LbCMi7tggtInZR0QEYO9MiPaLXMA4UWf5UOgd0pDPu9pKTYd7suvPgTa/ApQ
+M3MRUQcm//6ABwHH3JHtZoaqAOp75NguuyNyzda29wGY8onFs9LeibR2NlRVbwgT
+u9SiqtPZj5mq20OAo0XynoR+D8y1l5wEDhzHadQRRk5gRq84rIt6iqYONdDynAYJ
+gTxUVvRLWE3vFe1EmQbI+4nJ2iGbZ78W0bHVTxRb7MHGt7VTDWrzL95UdopfmvLD
+KpYt2xzVLKc2prYGY1V464dZ2aPfMgSorJE8/U2z+2+ITd76xDFb2YaEAghzFZqb
+lIIz23+BGinEhq18brW1XfMpd8+NKNkxrOsyvHANMmnRJvUoLfNn0YATQ5b3c0QM
+7VUI7ddH40RBHSd6XuiaQVQtGyRtiKzC1G94syVdAWWq5aMPF90BZV0Am5kkM8B0
+yX6BsMWqMwCc8ZGgKq1oK3gOdnmzkmxqpgr+RhFpGwy9XYFTKv0QPW36DD9Pgpge
+sMSafPouMdYc8c3HuTxh2ZwHLxpqyaKMGVN+LdzDbddsZzOiUKd7Bq9XpNtG2o9y
+K+MCKRECBkh4ZvMxd3yEJAym0w==
+-----END CERTIFICATE-----
diff --git a/tests/auto/shared/resources/key.pem b/tests/auto/shared/resources/key.pem
new file mode 100644
index 000000000..bd350d7fb
--- /dev/null
+++ b/tests/auto/shared/resources/key.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+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
+zB9TRbOML1RSOJ+z+mbv7ONymoUI/Jf5
+-----END PRIVATE KEY-----
diff --git a/tests/auto/widgets/certificateerror/certificateerror.pro b/tests/auto/widgets/certificateerror/certificateerror.pro
new file mode 100644
index 000000000..73ba7515b
--- /dev/null
+++ b/tests/auto/widgets/certificateerror/certificateerror.pro
@@ -0,0 +1,3 @@
+include(../tests.pri)
+include(../../shared/https.pri)
+QT *= core-private
diff --git a/tests/auto/widgets/certificateerror/tst_certificateerror.cpp b/tests/auto/widgets/certificateerror/tst_certificateerror.cpp
new file mode 100644
index 000000000..b002dc363
--- /dev/null
+++ b/tests/auto/widgets/certificateerror/tst_certificateerror.cpp
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+#include <httpsserver.h>
+#include <util.h>
+
+#include <QWebEngineCertificateError>
+#include <QWebEnginePage>
+#include <QWebEngineSettings>
+
+#include <QtTest/QtTest>
+
+class tst_CertificateError : public QObject
+{
+ Q_OBJECT
+public:
+ tst_CertificateError() { }
+
+private Q_SLOTS:
+ void handleError_data();
+ void handleError();
+};
+
+struct PageWithCertificateErrorHandler : QWebEnginePage
+{
+ PageWithCertificateErrorHandler(bool defer, bool accept, QObject *p = nullptr)
+ : QWebEnginePage(p), deferError(defer), acceptCertificate(accept) {
+ connect(this, &QWebEnginePage::loadFinished, [&] (bool result) { spyLoad(result); });
+ }
+
+ bool deferError, acceptCertificate;
+
+ CallbackSpy<bool> spyLoad;
+ QScopedPointer<QWebEngineCertificateError> error;
+
+ bool certificateError(const QWebEngineCertificateError &e) override {
+ error.reset(new QWebEngineCertificateError(e));
+ if (deferError)
+ error->defer();
+ return acceptCertificate;
+ }
+};
+
+void tst_CertificateError::handleError_data()
+{
+ QTest::addColumn<bool>("deferError");
+ QTest::addColumn<bool>("acceptCertificate");
+ QTest::addColumn<QString>("expectedContent");
+ QTest::addRow("Reject") << false << false << QString();
+ QTest::addRow("DeferReject") << true << false << QString();
+ QTest::addRow("DeferAccept") << true << true << "TEST";
+}
+
+void tst_CertificateError::handleError()
+{
+ HttpsServer server;
+ server.setExpectError(true);
+ QVERIFY(server.start());
+
+ connect(&server, &HttpsServer::newRequest, [&] (HttpReqRep *rr) {
+ rr->setResponseBody(QByteArrayLiteral("<html><body>TEST</body></html>"));
+ rr->sendResponse();
+ });
+
+ QFETCH(bool, deferError);
+ QFETCH(bool, acceptCertificate);
+ QFETCH(QString, expectedContent);
+
+ PageWithCertificateErrorHandler page(deferError, acceptCertificate);
+ page.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false);
+
+ page.setUrl(server.url());
+ QTRY_VERIFY(page.error);
+ QVERIFY(page.error->isOverridable());
+
+ if (deferError) {
+ QVERIFY(page.error->deferred());
+ QVERIFY(!page.error->answered());
+ QVERIFY(!page.spyLoad.wasCalled());
+ QCOMPARE(toPlainTextSync(&page), QString());
+
+ if (acceptCertificate)
+ page.error->ignoreCertificateError();
+ else
+ page.error->rejectCertificate();
+
+ QVERIFY(page.error->answered());
+ page.error.reset();
+ }
+
+ bool loadResult = page.spyLoad.waitForResult();
+ QVERIFY(page.spyLoad.wasCalled());
+ QCOMPARE(loadResult, acceptCertificate);
+ QCOMPARE(toPlainTextSync(&page), expectedContent);
+}
+
+QTEST_MAIN(tst_CertificateError)
+#include <tst_certificateerror.moc>
diff --git a/tests/auto/widgets/widgets.pro b/tests/auto/widgets/widgets.pro
index 92159bf83..df553df55 100644
--- a/tests/auto/widgets/widgets.pro
+++ b/tests/auto/widgets/widgets.pro
@@ -4,6 +4,7 @@ QT_FOR_CONFIG += webenginecore webenginecore-private
TEMPLATE = subdirs
SUBDIRS += \
+ certificateerror \
defaultsurfaceformat \
devtools \
faviconmanager \