summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYigit Akcay <yigit.akcay@qt.io>2023-01-27 13:07:58 +0100
committerYigit Akcay <yigit.akcay@qt.io>2023-02-13 09:12:10 +0100
commit95f70c9a0776ea0c51ec3f6c73ffb56cf9e956e6 (patch)
tree2f3e9cb19bb86cb0d443f8d43bbc38706be28177
parent5358dd0dca2f19e3b4d20fa98878c9d0038cf4ce (diff)
QWebEngineLoadingInfo: Add response headers
This change adds a member variable that contains the response headers to QWebEngineLoadingInfo. It is filled when a QWebEngineLoadingInfo instance is constructed inside WebContentsDelegateQt::emitLoadFinished(bool). The response headers are extracted from the navigation handle when WebContentsDelegateQt::DidFinishNavigation(content::NavigationHandle *) is called. The response headers are non-empty when QWebEngineLoadingInfo::status() is equal to QWebEngineLoadingInfo::LoadSucceededStatus or QWebEngineLoadingInfo::LoadFailedStatus. Fixes: QTBUG-106862 Change-Id: I4d196e3cc71725ddad9a5832af72d1b4e50924c8 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
-rw-r--r--src/core/api/qwebengineloadinginfo.cpp23
-rw-r--r--src/core/api/qwebengineloadinginfo.h6
-rw-r--r--src/core/web_contents_delegate_qt.cpp18
-rw-r--r--src/core/web_contents_delegate_qt.h1
-rw-r--r--tests/auto/core/CMakeLists.txt1
-rw-r--r--tests/auto/core/qwebengineloadinginfo/CMakeLists.txt10
-rw-r--r--tests/auto/core/qwebengineloadinginfo/tst_qwebengineloadinginfo.cpp91
-rw-r--r--tests/auto/quick/publicapi/tst_publicapi.cpp4
8 files changed, 148 insertions, 6 deletions
diff --git a/src/core/api/qwebengineloadinginfo.cpp b/src/core/api/qwebengineloadinginfo.cpp
index 14ec26be4..ed9618f49 100644
--- a/src/core/api/qwebengineloadinginfo.cpp
+++ b/src/core/api/qwebengineloadinginfo.cpp
@@ -22,13 +22,15 @@ Q_STATIC_ASSERT(static_cast<int>(WebEngineError::HttpStatusCodeDomain) == static
class QWebEngineLoadingInfo::QWebEngineLoadingInfoPrivate : public QSharedData {
public:
QWebEngineLoadingInfoPrivate(const QUrl& url, LoadStatus status, bool isErrorPage,
- const QString& errorString, int errorCode, ErrorDomain errorDomain)
+ const QString& errorString, int errorCode, ErrorDomain errorDomain,
+ const QHash<QByteArray,QByteArray>& responseHeaders)
: url(url)
, status(status)
, isErrorPage(isErrorPage)
, errorString(errorString)
, errorCode(errorCode)
, errorDomain(errorDomain)
+ , responseHeaders(responseHeaders)
{
}
@@ -38,6 +40,7 @@ public:
QString errorString;
int errorCode;
ErrorDomain errorDomain;
+ QHash<QByteArray,QByteArray> responseHeaders;
};
/*!
@@ -52,8 +55,10 @@ public:
\sa QWebEnginePage::loadStarted, QWebEnginePage::loadFinished, WebEngineView::loadingChanged
*/
QWebEngineLoadingInfo::QWebEngineLoadingInfo(const QUrl& url, LoadStatus status, bool isErrorPage,
- const QString& errorString, int errorCode, ErrorDomain errorDomain)
- : d_ptr(new QWebEngineLoadingInfoPrivate(url, status, isErrorPage, errorString, errorCode, errorDomain))
+ const QString& errorString, int errorCode, ErrorDomain errorDomain,
+ const QHash<QByteArray,QByteArray>& responseHeaders)
+ : d_ptr(new QWebEngineLoadingInfoPrivate(url, status, isErrorPage, errorString, errorCode, errorDomain,
+ responseHeaders))
{
}
@@ -157,6 +162,18 @@ int QWebEngineLoadingInfo::errorCode() const
return d->errorCode;
}
+/*!
+ \property QWebEngineLoadingInfo::responseHeaders
+ \brief Holds the response headers when \c QWebEngineLoadingInfo::status()
+ is equal to \c QWebEngineLoadingInfo::LoadSucceededStatus or
+ \c QWebEngineLoadingInfo::LoadFailedStatus.
+*/
+QHash<QByteArray,QByteArray> QWebEngineLoadingInfo::responseHeaders() const
+{
+ Q_D(const QWebEngineLoadingInfo);
+ return d->responseHeaders;
+}
+
QT_END_NAMESPACE
#include "moc_qwebengineloadinginfo.cpp"
diff --git a/src/core/api/qwebengineloadinginfo.h b/src/core/api/qwebengineloadinginfo.h
index a17588a57..11cce7365 100644
--- a/src/core/api/qwebengineloadinginfo.h
+++ b/src/core/api/qwebengineloadinginfo.h
@@ -9,6 +9,7 @@
#include <QtCore/qshareddata.h>
#include <QtCore/qobject.h>
#include <QtCore/qurl.h>
+#include <QHash>
namespace QtWebEngineCore {
class WebContentsAdapter;
@@ -26,6 +27,7 @@ class Q_WEBENGINECORE_EXPORT QWebEngineLoadingInfo
Q_PROPERTY(QString errorString READ errorString CONSTANT FINAL)
Q_PROPERTY(ErrorDomain errorDomain READ errorDomain CONSTANT FINAL)
Q_PROPERTY(int errorCode READ errorCode CONSTANT FINAL)
+ Q_PROPERTY(QHash<QByteArray,QByteArray> responseHeaders READ responseHeaders CONSTANT FINAL)
public:
enum LoadStatus {
@@ -60,11 +62,13 @@ public:
QString errorString() const;
ErrorDomain errorDomain() const;
int errorCode() const;
+ QHash<QByteArray,QByteArray> responseHeaders() const;
private:
QWebEngineLoadingInfo(const QUrl &url, LoadStatus status, bool isErrorPage = false,
const QString &errorString = QString(), int errorCode = 0,
- ErrorDomain errorDomain = NoErrorDomain);
+ ErrorDomain errorDomain = NoErrorDomain,
+ const QHash<QByteArray, QByteArray> &responseHeaders = {});
class QWebEngineLoadingInfoPrivate;
Q_DECLARE_PRIVATE(QWebEngineLoadingInfo)
QExplicitlySharedDataPointer<QWebEngineLoadingInfoPrivate> d_ptr;
diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp
index b58b56500..7470e5cc2 100644
--- a/src/core/web_contents_delegate_qt.cpp
+++ b/src/core/web_contents_delegate_qt.cpp
@@ -383,7 +383,8 @@ void WebContentsDelegateQt::emitLoadFinished(bool isErrorPage)
? QWebEngineLoadingInfo::LoadStoppedStatus : QWebEngineLoadingInfo::LoadFailedStatus);
QWebEngineLoadingInfo info(m_loadingInfo.url, loadStatus, m_loadingInfo.isErrorPage,
m_loadingInfo.errorDescription, m_loadingInfo.errorCode,
- QWebEngineLoadingInfo::ErrorDomain(m_loadingInfo.errorDomain));
+ QWebEngineLoadingInfo::ErrorDomain(m_loadingInfo.errorDomain),
+ m_loadingInfo.responseHeaders);
m_viewClient->loadFinished(std::move(info));
m_viewClient->updateNavigationActions();
}
@@ -411,6 +412,21 @@ void WebContentsDelegateQt::DidFinishNavigation(content::NavigationHandle *navig
emitLoadCommitted();
}
+ const net::HttpResponseHeaders * const responseHeaders = navigation_handle->GetResponseHeaders();
+ QHash<QByteArray, QByteArray> responseHeadersMap;
+ if (responseHeaders != nullptr) {
+ m_loadingInfo.responseHeaders.clear();
+ std::size_t iter = 0;
+ std::string headerName;
+ std::string headerValue;
+ while (responseHeaders->EnumerateHeaderLines(&iter, &headerName, &headerValue)) {
+ m_loadingInfo.responseHeaders.insert(
+ QByteArray::fromStdString(headerName),
+ QByteArray::fromStdString(headerValue)
+ );
+ }
+ }
+
// Success is reported by DidFinishLoad, but DidFailLoad is now dead code and needs to be handled below
if (navigation_handle->GetNetErrorCode() == net::OK)
return;
diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h
index eda4e1e57..37c2c7341 100644
--- a/src/core/web_contents_delegate_qt.h
+++ b/src/core/web_contents_delegate_qt.h
@@ -200,6 +200,7 @@ private:
int errorCode = 0, errorDomain = 0;
QString errorDescription;
bool triggersErrorPage = false;
+ QHash<QByteArray, QByteArray> responseHeaders;
void clear() { *this = LoadingInfo(); }
} m_loadingInfo;
diff --git a/tests/auto/core/CMakeLists.txt b/tests/auto/core/CMakeLists.txt
index 3f10e8303..6ba6ffd92 100644
--- a/tests/auto/core/CMakeLists.txt
+++ b/tests/auto/core/CMakeLists.txt
@@ -2,6 +2,7 @@
# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(qwebenginecookiestore)
+add_subdirectory(qwebengineloadinginfo)
add_subdirectory(qwebenginesettings)
add_subdirectory(qwebengineurlrequestinterceptor)
add_subdirectory(qwebengineurlrequestjob)
diff --git a/tests/auto/core/qwebengineloadinginfo/CMakeLists.txt b/tests/auto/core/qwebengineloadinginfo/CMakeLists.txt
new file mode 100644
index 000000000..09d9c30f5
--- /dev/null
+++ b/tests/auto/core/qwebengineloadinginfo/CMakeLists.txt
@@ -0,0 +1,10 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_test(tst_qwebengineloadinginfo
+ SOURCES
+ tst_qwebengineloadinginfo.cpp
+ LIBRARIES
+ Qt::WebEngineCore
+ Test::HttpServer
+)
diff --git a/tests/auto/core/qwebengineloadinginfo/tst_qwebengineloadinginfo.cpp b/tests/auto/core/qwebengineloadinginfo/tst_qwebengineloadinginfo.cpp
new file mode 100644
index 000000000..064abe816
--- /dev/null
+++ b/tests/auto/core/qwebengineloadinginfo/tst_qwebengineloadinginfo.cpp
@@ -0,0 +1,91 @@
+// 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/qwebengineprofile.h>
+#include <QtWebEngineCore/qwebenginepage.h>
+#include <QtWebEngineCore/qwebengineloadinginfo.h>
+#include <QtWebEngineCore/qwebenginehttprequest.h>
+
+#include <httpserver.h>
+#include <httpreqrep.h>
+
+typedef QHash<QByteArray, QByteArray> Map;
+
+class tst_QWebEngineLoadingInfo : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QWebEngineLoadingInfo() { }
+
+public slots:
+ void loadingInfoChanged(QWebEngineLoadingInfo loadingInfo)
+ {
+ const auto responseHeaders = loadingInfo.responseHeaders();
+ QFETCH(Map, expected);
+
+ if (loadingInfo.status() == QWebEngineLoadingInfo::LoadSucceededStatus
+ || loadingInfo.status() == QWebEngineLoadingInfo::LoadFailedStatus) {
+ if (!expected.empty())
+ QCOMPARE(responseHeaders, expected);
+ } else {
+ QVERIFY(responseHeaders.size() == 0);
+ }
+ }
+
+private Q_SLOTS:
+ void responseHeaders_data()
+ {
+ QTest::addColumn<int>("responseCode");
+ QTest::addColumn<Map>("input");
+ QTest::addColumn<Map>("expected");
+
+ const Map empty;
+ const Map input {
+ std::make_pair("header1", "value1"),
+ std::make_pair("header2", "value2")
+ };
+ const Map expected {
+ std::make_pair("header1", "value1"),
+ std::make_pair("header2", "value2"),
+ std::make_pair("Connection", "close")
+ };
+
+
+ QTest::newRow("with headers HTTP 200") << 200 << input << expected;
+ QTest::newRow("with headers HTTP 500") << 500 << input << expected;
+ QTest::newRow("without headers HTTP 200") << 200 << empty << empty;
+ QTest::newRow("without headers HTTP 500") << 500 << empty << empty;
+ }
+
+ void responseHeaders()
+ {
+ HttpServer httpServer;
+
+ QFETCH(Map, input);
+ QFETCH(int, responseCode);
+ QObject::connect(&httpServer, &HttpServer::newRequest, this, [&](HttpReqRep *rr) {
+ for (auto it = input.cbegin(); it != input.cend(); ++it)
+ rr->setResponseHeader(it.key(), it.value());
+
+ rr->sendResponse(responseCode);
+ });
+ QVERIFY(httpServer.start());
+
+ QWebEngineProfile profile;
+ QWebEnginePage page(&profile);
+ QSignalSpy spy(&page, SIGNAL(loadFinished(bool)));
+ QObject::connect(&page, &QWebEnginePage::loadingChanged, this, &tst_QWebEngineLoadingInfo::loadingInfoChanged);
+
+
+ QWebEngineHttpRequest request(httpServer.url("/somepage.html"));
+ page.load(request);
+
+ QVERIFY(spy.wait());
+ QVERIFY(httpServer.stop());
+ }
+};
+
+QTEST_MAIN(tst_QWebEngineLoadingInfo)
+#include "tst_qwebengineloadinginfo.moc"
diff --git a/tests/auto/quick/publicapi/tst_publicapi.cpp b/tests/auto/quick/publicapi/tst_publicapi.cpp
index 0cd031940..8b366f413 100644
--- a/tests/auto/quick/publicapi/tst_publicapi.cpp
+++ b/tests/auto/quick/publicapi/tst_publicapi.cpp
@@ -84,7 +84,8 @@ static const QStringList hardcodedTypes = QStringList()
<< "QWebEngineCookieStore*"
<< "Qt::LayoutDirection"
<< "QQuickWebEngineScriptCollection*"
- << "QQmlComponent*";
+ << "QQmlComponent*"
+ << "QHash<QByteArray,QByteArray>";
static const QStringList expectedAPI = QStringList()
<< "QQuickWebEngineAction.text --> QString"
@@ -293,6 +294,7 @@ static const QStringList expectedAPI = QStringList()
<< "QQuickWebEngineJavaScriptDialogRequest.title --> QString"
<< "QQuickWebEngineJavaScriptDialogRequest.type --> QQuickWebEngineJavaScriptDialogRequest::DialogType"
<< "QWebEngineLoadingInfo.errorCode --> int"
+ << "QWebEngineLoadingInfo.responseHeaders --> QHash<QByteArray,QByteArray>"
<< "QWebEngineLoadingInfo.errorDomain --> QWebEngineLoadingInfo::ErrorDomain"
<< "QWebEngineLoadingInfo.errorString --> QString"
<< "QWebEngineLoadingInfo.status --> QWebEngineLoadingInfo::LoadStatus"