Add QHttpHeaders to QNetworkRequest

Added headers() and setHeaders() methods to QNetworkRequest.

[ChangeLog][QtNetwork][QNetworkRequest] Added headers() and setHeaders()
methods to QNetworkRequest, which provide an interface to work with
QHttpHeaders.

Task-number: QTBUG-107751
Change-Id: I2e1dc7cb2efab5903eb7ff23b75d01aefe13273d
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
bb10
Lena Biliaieva 2024-03-08 18:10:02 +01:00
parent 979836382e
commit fa456ad550
11 changed files with 259 additions and 1 deletions

View File

@ -22,6 +22,7 @@ qt_internal_add_module(Network
access/qnetworkfile.cpp access/qnetworkfile_p.h
access/qhttpheaders.cpp access/qhttpheaders.h
access/qhttpheaderparser.cpp access/qhttpheaderparser_p.h
access/qhttpheadershelper.cpp access/qhttpheadershelper_p.h
access/qnetworkreply.cpp access/qnetworkreply.h access/qnetworkreply_p.h
access/qnetworkreplydataimpl.cpp access/qnetworkreplydataimpl_p.h
access/qnetworkreplyfileimpl.cpp access/qnetworkreplyfileimpl_p.h

View File

@ -4,7 +4,8 @@
#ifndef QHTTPHEADERS_H
#define QHTTPHEADERS_H
#include <QtNetwork/qnetworkrequest.h>
#include <QtNetwork/qtnetworkglobal.h>
#include <QtCore/qmetaobject.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qcontainerfwd.h>

View File

@ -0,0 +1,25 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qhttpheadershelper_p.h"
#include <QtNetwork/qhttpheaders.h>
QT_BEGIN_NAMESPACE
bool QHttpHeadersHelper::compareStrict(const QHttpHeaders &left, const QHttpHeaders &right)
{
if (left.size() != right.size())
return false;
for (qsizetype i = 0; i < left.size(); ++i) {
if (left.nameAt(i) != right.nameAt(i))
return false;
if (left.valueAt(i) != right.valueAt(i))
return false;
}
return true;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,30 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHTTPHEADERSHELPER_H
#define QHTTPHEADERSHELPER_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of the Network Access API. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
#include <QtNetwork/private/qtnetworkglobal_p.h>
QT_BEGIN_NAMESPACE
class QHttpHeaders;
namespace QHttpHeadersHelper {
Q_NETWORK_EXPORT bool compareStrict(const QHttpHeaders &left, const QHttpHeaders &right);
};
QT_END_NAMESPACE
#endif // QHTTPHEADERSHELPER_H

View File

@ -6,6 +6,7 @@
#include "qplatformdefs.h"
#include "qnetworkcookie.h"
#include "qsslconfiguration.h"
#include "qhttpheadershelper_p.h"
#if QT_CONFIG(http)
#include "qhttp1configuration.h"
#include "qhttp2configuration.h"
@ -475,6 +476,7 @@ public:
&& decompressedSafetyCheckThreshold == other.decompressedSafetyCheckThreshold
#endif
&& transferTimeout == other.transferTimeout
&& QHttpHeadersHelper::compareStrict(httpHeaders, other.httpHeaders)
;
// don't compare cookedHeaders
}
@ -600,6 +602,43 @@ void QNetworkRequest::setUrl(const QUrl &url)
d->url = url;
}
/*!
\since 6.8
Returns headers that are set in this network request.
\sa setHeaders()
*/
QHttpHeaders QNetworkRequest::headers() const
{
return d->headers();
}
/*!
\since 6.8
Sets \a newHeaders as headers in this network request, overriding
any previously set headers.
If some headers correspond to the known headers, the values will
be parsed and the corresponding parsed form will also be set.
\sa headers(), KnownHeaders
*/
void QNetworkRequest::setHeaders(QHttpHeaders &&newHeaders)
{
d->setHeaders(std::move(newHeaders));
}
/*!
\overload
\since 6.8
*/
void QNetworkRequest::setHeaders(const QHttpHeaders &newHeaders)
{
d->setHeaders(newHeaders);
}
/*!
Returns the value of the known network header \a header if it is
present in this request. If it is not present, returns QVariant()
@ -1401,6 +1440,33 @@ void QNetworkHeadersPrivate::setCookedHeader(QNetworkRequest::KnownHeaders heade
}
}
QHttpHeaders QNetworkHeadersPrivate::headers() const
{
return httpHeaders;
}
void QNetworkHeadersPrivate::setHeaders(const QHttpHeaders &newHeaders)
{
httpHeaders = newHeaders;
}
void QNetworkHeadersPrivate::setHeaders(QHttpHeaders &&newHeaders)
{
httpHeaders = std::move(newHeaders);
}
void QNetworkHeadersPrivate::setHeader(QHttpHeaders::WellKnownHeader name, QByteArrayView value)
{
httpHeaders.replaceOrAppend(name, value);
}
void QNetworkHeadersPrivate::clearHeaders()
{
httpHeaders.clear();
rawHeaders.clear();
cookedHeaders.clear();
}
void QNetworkHeadersPrivate::setRawHeaderInternal(const QByteArray &key, const QByteArray &value)
{
auto firstEqualsKey = [&key](const RawHeaderPair &header) {

View File

@ -5,6 +5,7 @@
#define QNETWORKREQUEST_H
#include <QtNetwork/qtnetworkglobal.h>
#include <QtNetwork/qhttpheaders.h>
#include <QtCore/QSharedDataPointer>
#include <QtCore/QString>
#include <QtCore/QUrl>
@ -119,6 +120,10 @@ public:
QUrl url() const;
void setUrl(const QUrl &url);
QHttpHeaders headers() const;
void setHeaders(const QHttpHeaders &newHeaders);
void setHeaders(QHttpHeaders &&newHeaders);
// "cooked" headers
QVariant header(KnownHeaders header) const;
void setHeader(KnownHeaders header, const QVariant &value);

View File

@ -16,6 +16,7 @@
//
#include <QtNetwork/private/qtnetworkglobal_p.h>
#include <QtNetwork/qhttpheaders.h>
#include "qnetworkrequest.h"
#include "QtCore/qbytearray.h"
#include "QtCore/qlist.h"
@ -36,6 +37,7 @@ public:
typedef QHash<QNetworkRequest::Attribute, QVariant> AttributesMap;
RawHeadersList rawHeaders;
QHttpHeaders httpHeaders;
CookedHeadersMap cookedHeaders;
AttributesMap attributes;
QPointer<QObject> originatingObject;
@ -47,6 +49,13 @@ public:
void setAllRawHeaders(const RawHeadersList &list);
void setCookedHeader(QNetworkRequest::KnownHeaders header, const QVariant &value);
QHttpHeaders headers() const;
void setHeaders(const QHttpHeaders &newHeaders);
void setHeaders(QHttpHeaders &&newHeaders);
void setHeader(QHttpHeaders::WellKnownHeader name, QByteArrayView value);
void clearHeaders();
static QDateTime fromHttpDate(const QByteArray &value);
static QByteArray toHttpDate(const QDateTime &dt);

View File

@ -15,6 +15,7 @@ add_subdirectory(qrestaccessmanager)
if(QT_FEATURE_private_tests)
add_subdirectory(qhttp2connection)
add_subdirectory(qhttpheaderparser)
add_subdirectory(qhttpheadershelper)
add_subdirectory(qhttpnetworkconnection)
add_subdirectory(qhttpnetworkreply)
add_subdirectory(hpack)

View File

@ -0,0 +1,15 @@
# Copyright (C) 2024 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
cmake_minimum_required(VERSION 3.16)
project(tst_qhttpheadershelper LANGUAGES CXX)
find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
endif()
qt_internal_add_test(tst_qhttpheadershelper
SOURCES
tst_qhttpheadershelper.cpp
LIBRARIES
Qt::NetworkPrivate
)

View File

@ -0,0 +1,76 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtNetwork/qhttpheaders.h>
#include <QtNetwork/private/qhttpheadershelper_p.h>
#include <QtTest/qtest.h>
using namespace Qt::StringLiterals;
class tst_QHttpHeadersHelper : public QObject
{
Q_OBJECT
private slots:
void testCompareStrict();
private:
static constexpr QAnyStringView n1{"name1"};
static constexpr QAnyStringView n2{"name2"};
static constexpr QAnyStringView v1{"value1"};
static constexpr QAnyStringView v2{"value2"};
static constexpr QAnyStringView N1{"NAME1"};
static constexpr QAnyStringView N2{"NAME2"};
static constexpr QAnyStringView V1{"VALUE1"};
static constexpr QAnyStringView V2{"VALUE2"};
};
void tst_QHttpHeadersHelper::testCompareStrict()
{
using namespace QHttpHeadersHelper;
// Basic comparisons
QHttpHeaders h1;
QHttpHeaders h2;
QVERIFY(compareStrict(h1, h2)); // empties
h1.append(n1, v1);
QVERIFY(compareStrict(h1, h1)); // self
h2.append(n1, v1);
QVERIFY(compareStrict(h1, h2));
h1.append(n2, v2);
QVERIFY(!compareStrict(h1, h2));
h1.removeAll(n2);
QVERIFY(compareStrict(h1, h2));
// Order-sensitivity
h1.clear();
h2.clear();
// Same headers but in different order
h1.append(n1, v1);
h1.append(n2, v2);
h2.append(n2, v2);
h2.append(n1, v1);
QVERIFY(!compareStrict(h1, h2));
// Different number of headers
h1.clear();
h2.clear();
h1.append(n1, v1);
h2.append(n1, v1);
h2.append(n2, v2);
QVERIFY(!compareStrict(h1, h2));
// Same header name, multiple values
h1.clear();
h2.clear();
h1.append(n1, v1);
h1.append(n1, v2);
h2.append(n1, v1);
QVERIFY(!compareStrict(h1, h2));
h2.append(n1, v2);
QVERIFY(compareStrict(h1, h2));
}
QTEST_MAIN(tst_QHttpHeadersHelper)
#include "tst_qhttpheadershelper.moc"

View File

@ -31,6 +31,8 @@ private slots:
void rawHeaderParsing_data();
void rawHeaderParsing();
void originatingObject();
void setHeaders_data();
void setHeaders();
void removeHeader();
};
@ -552,5 +554,32 @@ void tst_QNetworkRequest::originatingObject()
QVERIFY(!request.originatingObject());
}
void tst_QNetworkRequest::setHeaders_data()
{
QTest::addColumn<QHttpHeaders>("h");
QTest::newRow("null") << QHttpHeaders();
QHttpHeaders headers;
headers.append("name1", "value1");
QTest::newRow("valid") << headers;
}
void tst_QNetworkRequest::setHeaders()
{
QFETCH(QHttpHeaders, h);
QNetworkRequest r1;
auto result = r1.headers();
QVERIFY(result.isEmpty());
r1.setHeaders(h);
QCOMPARE(r1.headers().toListOfPairs(), h.toListOfPairs());
QNetworkRequest r2;
auto tmp = h;
r2.setHeaders(std::move(tmp));
QCOMPARE(r2.headers().toListOfPairs(), h.toListOfPairs());
}
QTEST_MAIN(tst_QNetworkRequest)
#include "tst_qnetworkrequest.moc"