summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYigit Akcay <yigit.akcay@qt.io>2023-01-08 01:41:00 +0100
committerYigit Akcay <yigit.akcay@qt.io>2023-01-26 16:54:42 +0100
commitdc7a726e431bdeb11449093a002a2b6daea0f67b (patch)
tree3959b302af7b184cbb64ca482b267cc6990d3071
parent614d6639b875f53b21eaabd2d5928b84b59af707 (diff)
QWebEngineUrlRequestJob: Add function to set additional reponse headers
Add additional response headers field to URLRequestCustomJobDelegate. Those fields can be set via QWebEngineUrlRequestJob::setAdditionalResponseHeaders( const QMap<QByteArray, QByteArray> & ). They are added to URLRequestCustomJobProxy::m_client when URLRequestCustomJobProxy::reply(std::string, QIODevice) is called, and added to the response headers within CustomURLLoaderFactory::notifyHeadersComplete(). Fixes: QTBUG-106578 Change-Id: Ie0f0af07a5381c6f24ec0a1ee1b5bcb0e8c4fa5f Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
-rw-r--r--src/core/api/qwebengineurlrequestjob.cpp12
-rw-r--r--src/core/api/qwebengineurlrequestjob.h2
-rw-r--r--src/core/net/custom_url_loader_factory.cpp5
-rw-r--r--src/core/net/url_request_custom_job_delegate.cpp11
-rw-r--r--src/core/net/url_request_custom_job_delegate.h3
-rw-r--r--src/core/net/url_request_custom_job_proxy.cpp4
-rw-r--r--src/core/net/url_request_custom_job_proxy.h6
-rw-r--r--tests/auto/core/CMakeLists.txt1
-rw-r--r--tests/auto/core/qwebengineurlrequestjob/CMakeLists.txt21
-rw-r--r--tests/auto/core/qwebengineurlrequestjob/additionalResponseHeadersScript.html12
-rw-r--r--tests/auto/core/qwebengineurlrequestjob/tst_qwebengineurlrequestjob.cpp119
11 files changed, 192 insertions, 4 deletions
diff --git a/src/core/api/qwebengineurlrequestjob.cpp b/src/core/api/qwebengineurlrequestjob.cpp
index 6c0adfddf..099efef8e 100644
--- a/src/core/api/qwebengineurlrequestjob.cpp
+++ b/src/core/api/qwebengineurlrequestjob.cpp
@@ -112,6 +112,18 @@ QMap<QByteArray, QByteArray> QWebEngineUrlRequestJob::requestHeaders() const
}
/*!
+ \since 6.6
+ Set \a additionalResponseHeaders. These additional headers of the response
+ are only used when QWebEngineUrlRequestJob::reply(const QByteArray&, QIODevice*)
+ is called.
+*/
+void QWebEngineUrlRequestJob::setAdditionalResponseHeaders(
+ const QMap<QByteArray, QByteArray> &additionalResponseHeaders) const
+{
+ d_ptr->setAdditionalResponseHeaders(additionalResponseHeaders);
+}
+
+/*!
Replies to the request with \a device and the content type \a contentType.
Content type is similar to the HTTP Content-Type header, and can either be
a MIME type, or a MIME type and charset encoding combined like this:
diff --git a/src/core/api/qwebengineurlrequestjob.h b/src/core/api/qwebengineurlrequestjob.h
index 79947ccc4..75e065566 100644
--- a/src/core/api/qwebengineurlrequestjob.h
+++ b/src/core/api/qwebengineurlrequestjob.h
@@ -43,6 +43,8 @@ public:
void reply(const QByteArray &contentType, QIODevice *device);
void fail(Error error);
void redirect(const QUrl &url);
+ void setAdditionalResponseHeaders(
+ const QMap<QByteArray, QByteArray> &additionalResponseHeaders) const;
private:
QWebEngineUrlRequestJob(QtWebEngineCore::URLRequestCustomJobDelegate *);
diff --git a/src/core/net/custom_url_loader_factory.cpp b/src/core/net/custom_url_loader_factory.cpp
index 19a1a884f..bd19aa436 100644
--- a/src/core/net/custom_url_loader_factory.cpp
+++ b/src/core/net/custom_url_loader_factory.cpp
@@ -262,6 +262,11 @@ private:
headers += "Access-Control-Allow-Credentials: true\n";
}
}
+ for (auto it = m_additionalResponseHeaders.cbegin();
+ it != m_additionalResponseHeaders.cend(); ++it) {
+ headers += it.key().toLower().toStdString() + ": " + it.value().toLower().toStdString()
+ + "\n";
+ }
m_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(net::HttpUtil::AssembleRawHeaders(headers));
m_head->encoded_data_length = m_head->headers->raw_headers().length();
diff --git a/src/core/net/url_request_custom_job_delegate.cpp b/src/core/net/url_request_custom_job_delegate.cpp
index 22d26f735..07a1de1ec 100644
--- a/src/core/net/url_request_custom_job_delegate.cpp
+++ b/src/core/net/url_request_custom_job_delegate.cpp
@@ -51,13 +51,20 @@ QMap<QByteArray, QByteArray> URLRequestCustomJobDelegate::requestHeaders() const
return m_requestHeaders;
}
+void URLRequestCustomJobDelegate::setAdditionalResponseHeaders(
+ const QMap<QByteArray, QByteArray> &additionalResponseHeaders)
+{
+ m_additionalResponseHeaders = additionalResponseHeaders;
+}
+
void URLRequestCustomJobDelegate::reply(const QByteArray &contentType, QIODevice *device)
{
if (device)
QObject::connect(device, &QIODevice::readyRead, this, &URLRequestCustomJobDelegate::slotReadyRead);
m_proxy->m_ioTaskRunner->PostTask(FROM_HERE,
- base::BindOnce(&URLRequestCustomJobProxy::reply,
- m_proxy, contentType.toStdString(),device));
+ base::BindOnce(&URLRequestCustomJobProxy::reply, m_proxy,
+ contentType.toStdString(), device,
+ std::move(m_additionalResponseHeaders)));
}
void URLRequestCustomJobDelegate::slotReadyRead()
diff --git a/src/core/net/url_request_custom_job_delegate.h b/src/core/net/url_request_custom_job_delegate.h
index 7b0d6538c..6b6ee68cf 100644
--- a/src/core/net/url_request_custom_job_delegate.h
+++ b/src/core/net/url_request_custom_job_delegate.h
@@ -48,6 +48,8 @@ public:
QUrl initiator() const;
QMap<QByteArray, QByteArray> requestHeaders() const;
+ void
+ setAdditionalResponseHeaders(const QMap<QByteArray, QByteArray> &additionalResponseHeaders);
void reply(const QByteArray &contentType, QIODevice *device);
void redirect(const QUrl &url);
void abort();
@@ -69,6 +71,7 @@ private:
QByteArray m_method;
QUrl m_initiatorOrigin;
const QMap<QByteArray, QByteArray> m_requestHeaders;
+ QMap<QByteArray, QByteArray> m_additionalResponseHeaders;
};
} // namespace
diff --git a/src/core/net/url_request_custom_job_proxy.cpp b/src/core/net/url_request_custom_job_proxy.cpp
index 45372f020..d7adcc7e8 100644
--- a/src/core/net/url_request_custom_job_proxy.cpp
+++ b/src/core/net/url_request_custom_job_proxy.cpp
@@ -40,7 +40,8 @@ void URLRequestCustomJobProxy::release()
}
}
-void URLRequestCustomJobProxy::reply(std::string contentType, QIODevice *device)
+void URLRequestCustomJobProxy::reply(std::string contentType, QIODevice *device,
+ QMap<QByteArray, QByteArray> additionalResponseHeaders)
{
if (!m_client)
return;
@@ -58,6 +59,7 @@ void URLRequestCustomJobProxy::reply(std::string contentType, QIODevice *device)
}
m_client->m_mimeType = qcontentType.toStdString();
m_client->m_device = device;
+ m_client->m_additionalResponseHeaders = additionalResponseHeaders;
if (m_client->m_device && !m_client->m_device->isReadable())
m_client->m_device->open(QIODevice::ReadOnly);
diff --git a/src/core/net/url_request_custom_job_proxy.h b/src/core/net/url_request_custom_job_proxy.h
index 3795f7f14..1f8c77da2 100644
--- a/src/core/net/url_request_custom_job_proxy.h
+++ b/src/core/net/url_request_custom_job_proxy.h
@@ -10,6 +10,8 @@
#include "url/gurl.h"
#include "url/origin.h"
#include <QtCore/QPointer>
+#include <QMap>
+#include <QByteArray>
QT_FORWARD_DECLARE_CLASS(QIODevice)
@@ -29,6 +31,7 @@ public:
public:
std::string m_mimeType;
std::string m_charset;
+ QMap<QByteArray, QByteArray> m_additionalResponseHeaders;
GURL m_redirect;
QIODevice *m_device;
int64_t m_firstBytePosition;
@@ -49,7 +52,8 @@ public:
// Called from URLRequestCustomJobDelegate via post:
//void setReplyCharset(const std::string &);
- void reply(std::string mimeType, QIODevice *device);
+ void reply(std::string mimeType, QIODevice *device,
+ QMap<QByteArray, QByteArray> additionalResponseHeaders);
void redirect(GURL url);
void abort();
void fail(int error);
diff --git a/tests/auto/core/CMakeLists.txt b/tests/auto/core/CMakeLists.txt
index 5615d6b2d..3f10e8303 100644
--- a/tests/auto/core/CMakeLists.txt
+++ b/tests/auto/core/CMakeLists.txt
@@ -4,6 +4,7 @@
add_subdirectory(qwebenginecookiestore)
add_subdirectory(qwebenginesettings)
add_subdirectory(qwebengineurlrequestinterceptor)
+add_subdirectory(qwebengineurlrequestjob)
add_subdirectory(origins)
add_subdirectory(devtools)
diff --git a/tests/auto/core/qwebengineurlrequestjob/CMakeLists.txt b/tests/auto/core/qwebengineurlrequestjob/CMakeLists.txt
new file mode 100644
index 000000000..0a7699083
--- /dev/null
+++ b/tests/auto/core/qwebengineurlrequestjob/CMakeLists.txt
@@ -0,0 +1,21 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_test(tst_qwebengineurlrequestjob
+ SOURCES
+ tst_qwebengineurlrequestjob.cpp
+ LIBRARIES
+ Qt::WebEngineCore
+)
+
+# Resources:
+set(tst_qwebengineurlrequestjob_resource_files
+ "additionalResponseHeadersScript.html"
+)
+
+qt_add_resources(tst_qwebengineurlrequestjob "tst_qwebengineurlrequestjob"
+ PREFIX
+ "/"
+ FILES
+ ${tst_qwebengineurlrequestjob_resource_files}
+)
diff --git a/tests/auto/core/qwebengineurlrequestjob/additionalResponseHeadersScript.html b/tests/auto/core/qwebengineurlrequestjob/additionalResponseHeadersScript.html
new file mode 100644
index 000000000..a1b8a92d3
--- /dev/null
+++ b/tests/auto/core/qwebengineurlrequestjob/additionalResponseHeadersScript.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<html>
+<body>
+ <script type="text/javascript">
+ var request = new XMLHttpRequest();
+ request.open('GET', 'additionalresponseheadershandler:about', /* async = */ false);
+ request.send();
+ var headers = request.getAllResponseHeaders();
+ console.log("TST_ADDITIONALRESPONSEHEADERS;" + headers);
+ </script>
+</body>
+</html>
diff --git a/tests/auto/core/qwebengineurlrequestjob/tst_qwebengineurlrequestjob.cpp b/tests/auto/core/qwebengineurlrequestjob/tst_qwebengineurlrequestjob.cpp
new file mode 100644
index 000000000..5f679e912
--- /dev/null
+++ b/tests/auto/core/qwebengineurlrequestjob/tst_qwebengineurlrequestjob.cpp
@@ -0,0 +1,119 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include <QtTest/QtTest>
+#include <QtWebEngineCore/qwebengineurlschemehandler.h>
+#include <QtWebEngineCore/qwebengineurlscheme.h>
+#include <QtWebEngineCore/qwebengineurlrequestjob.h>
+#include <QtWebEngineCore/qwebengineprofile.h>
+#include <QtWebEngineCore/qwebenginepage.h>
+#include <QtWebEngineCore/qwebenginehttprequest.h>
+#include <QtWebEngineCore/qwebenginesettings.h>
+
+class AdditionalResponseHeadersHandler : public QWebEngineUrlSchemeHandler
+{
+ Q_OBJECT
+public:
+ AdditionalResponseHeadersHandler(bool addAdditionalResponseHeaders, QObject *parent = nullptr)
+ : QWebEngineUrlSchemeHandler(parent)
+ , m_addAdditionalResponseHeaders(addAdditionalResponseHeaders)
+ {
+ }
+
+ void requestStarted(QWebEngineUrlRequestJob *job) override
+ {
+ QCOMPARE(job->requestUrl(), QUrl(schemeName + ":about"));
+
+ QMap<QByteArray, QByteArray> additionalResponseHeaders;
+ if (m_addAdditionalResponseHeaders) {
+ additionalResponseHeaders.insert(QByteArray::fromStdString("test1"),
+ QByteArray::fromStdString("test1VALUE"));
+ additionalResponseHeaders.insert(QByteArray::fromStdString("test2"),
+ QByteArray::fromStdString("test2VALUE"));
+ }
+ job->setAdditionalResponseHeaders(additionalResponseHeaders);
+
+ QFile *file = new QFile(QStringLiteral(":additionalResponseHeadersScript.html"), job);
+ file->open(QIODevice::ReadOnly);
+
+ job->reply(QByteArrayLiteral("text/html"), file);
+ }
+
+ static void registerUrlScheme()
+ {
+ QWebEngineUrlScheme webUiScheme(schemeName);
+ webUiScheme.setFlags(QWebEngineUrlScheme::CorsEnabled);
+ QWebEngineUrlScheme::registerScheme(webUiScheme);
+ }
+
+ const static inline QByteArray schemeName =
+ QByteArrayLiteral("additionalresponseheadershandler");
+
+private:
+ bool m_addAdditionalResponseHeaders;
+};
+
+class AdditionalResponseHeadersPage : public QWebEnginePage
+{
+ Q_OBJECT
+
+public:
+ AdditionalResponseHeadersPage(QWebEngineProfile *profile, QString compareString,
+ QObject *parent = nullptr)
+ : QWebEnginePage(profile, parent), m_compareString(compareString)
+ {
+ }
+
+protected:
+ void javaScriptConsoleMessage(QWebEnginePage::JavaScriptConsoleMessageLevel level,
+ const QString &message, int lineNumber,
+ const QString &sourceID) override
+ {
+ auto splitMessage = message.split(";");
+ if (splitMessage[0] == QString("TST_ADDITIONALRESPONSEHEADERS"))
+ QCOMPARE(splitMessage[1], m_compareString);
+ }
+
+private:
+ QString m_compareString;
+};
+
+class tst_QWebEngineUrlRequestJob : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QWebEngineUrlRequestJob() { }
+
+private Q_SLOTS:
+ void initTestCase() { AdditionalResponseHeadersHandler::registerUrlScheme(); }
+
+ void withAdditionalResponseHeaders_data()
+ {
+ QTest::addColumn<bool>("withHeaders");
+ QTest::addColumn<QString>("expectedHeaders");
+ QTest::newRow("headers enabled")
+ << true << "content-type: text/html\r\ntest1: test1value\r\ntest2: test2value\r\n";
+ QTest::newRow("headers disabled") << false << "content-type: text/html\r\n";
+ }
+
+ void withAdditionalResponseHeaders()
+ {
+ QFETCH(bool, withHeaders);
+ QFETCH(QString, expectedHeaders);
+
+ QWebEngineProfile profile;
+
+ AdditionalResponseHeadersHandler handler(withHeaders);
+ profile.installUrlSchemeHandler(AdditionalResponseHeadersHandler::schemeName, &handler);
+
+ AdditionalResponseHeadersPage page(&profile, expectedHeaders);
+ QSignalSpy spy(&page, SIGNAL(loadFinished(bool)));
+
+ page.load(QUrl("qrc:///additionalResponseHeadersScript.html"));
+ QVERIFY(spy.wait());
+ }
+};
+
+QTEST_MAIN(tst_QWebEngineUrlRequestJob)
+#include "tst_qwebengineurlrequestjob.moc"