From 78b0d507ce8728c6287196f78b7c428d9bbdcda3 Mon Sep 17 00:00:00 2001 From: Lena Biliaieva Date: Mon, 22 Apr 2024 16:23:31 +0200 Subject: [PATCH] Add QHttpHeaders methods to QNetworkCacheMetaData MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ChangeLog][QtNetwork][QNetworkCacheMetaData] Added headers() and setHeaders() methods to QNetworkCacheMetaData to provide an interface to work with QHttpHeaders. Task-number: QTBUG-107751 Change-Id: I1dfed5c2e03f4912de0da96156425cd6b713c1d5 Reviewed-by: MÃ¥rten Nordheim Reviewed-by: Juha Vuolle --- src/network/access/qabstractnetworkcache.cpp | 43 +++++++++++--- src/network/access/qabstractnetworkcache.h | 3 + src/network/access/qnetworkdiskcache.cpp | 58 ++++++++----------- src/network/access/qnetworkrequest.cpp | 53 +++++++++++++++++ src/network/access/qnetworkrequest_p.h | 3 + .../tst_qnetworkcachemetadata.cpp | 51 +++++++++++++++- 6 files changed, 169 insertions(+), 42 deletions(-) diff --git a/src/network/access/qabstractnetworkcache.cpp b/src/network/access/qabstractnetworkcache.cpp index c8b940d801..3cd55d46fa 100644 --- a/src/network/access/qabstractnetworkcache.cpp +++ b/src/network/access/qabstractnetworkcache.cpp @@ -3,6 +3,8 @@ #include "qabstractnetworkcache.h" #include "qabstractnetworkcache_p.h" +#include "qnetworkrequest_p.h" +#include "qhttpheadershelper_p.h" #include #include @@ -28,14 +30,14 @@ public: url == other.url && lastModified == other.lastModified && expirationDate == other.expirationDate - && headers == other.headers - && saveToDisk == other.saveToDisk; + && saveToDisk == other.saveToDisk + && QHttpHeadersHelper::compareStrict(headers, other.headers); } QUrl url; QDateTime lastModified; QDateTime expirationDate; - QNetworkCacheMetaData::RawHeaderList headers; + QHttpHeaders headers; QNetworkCacheMetaData::AttributesMap attributes; bool saveToDisk; @@ -207,21 +209,45 @@ void QNetworkCacheMetaData::setUrl(const QUrl &url) Returns a list of all raw headers that are set in this meta data. The list is in the same order that the headers were set. - \sa setRawHeaders() + \sa setRawHeaders(), headers() */ QNetworkCacheMetaData::RawHeaderList QNetworkCacheMetaData::rawHeaders() const { - return d->headers; + return QNetworkHeadersPrivate::fromHttpToRaw(d->headers); } /*! Sets the raw headers to \a list. - \sa rawHeaders() + \sa rawHeaders(), setHeaders() */ void QNetworkCacheMetaData::setRawHeaders(const RawHeaderList &list) { - d->headers = list; + d->headers = QNetworkHeadersPrivate::fromRawToHttp(list); +} + +/*! + \since 6.8 + + Returns headers in form of QHttpHeaders that are set in this meta data. + + \sa setHeaders() +*/ +QHttpHeaders QNetworkCacheMetaData::headers() const +{ + return d->headers; +} + +/*! + \since 6.8 + + Sets the headers of this network cache meta data to \a headers. + + \sa headers() +*/ +void QNetworkCacheMetaData::setHeaders(const QHttpHeaders &headers) +{ + d->headers = headers; } /*! @@ -367,7 +393,8 @@ void QNetworkCacheMetaDataPrivate::load(QDataStream &in, QNetworkCacheMetaData & in >> p->lastModified; in >> p->saveToDisk; in >> p->attributes; - in >> p->headers; + QNetworkCacheMetaData::RawHeaderList list; in >> list; + metaData.setRawHeaders(list); } /*! diff --git a/src/network/access/qabstractnetworkcache.h b/src/network/access/qabstractnetworkcache.h index c70dcf737c..b12fd4f863 100644 --- a/src/network/access/qabstractnetworkcache.h +++ b/src/network/access/qabstractnetworkcache.h @@ -48,6 +48,9 @@ public: RawHeaderList rawHeaders() const; void setRawHeaders(const RawHeaderList &headers); + QHttpHeaders headers() const; + void setHeaders(const QHttpHeaders &headers); + QDateTime lastModified() const; void setLastModified(const QDateTime &dateTime); diff --git a/src/network/access/qnetworkdiskcache.cpp b/src/network/access/qnetworkdiskcache.cpp index c883a61886..b39924025e 100644 --- a/src/network/access/qnetworkdiskcache.cpp +++ b/src/network/access/qnetworkdiskcache.cpp @@ -154,15 +154,11 @@ QIODevice *QNetworkDiskCache::prepare(const QNetworkCacheMetaData &metaData) return nullptr; } - const auto headers = metaData.rawHeaders(); - for (const auto &header : headers) { - if (header.first.compare("content-length", Qt::CaseInsensitive) == 0) { - const qint64 size = header.second.toLongLong(); - if (size > (maximumCacheSize() * 3)/4) - return nullptr; - break; - } - } + const auto sizeValue = metaData.headers().value(QHttpHeaders::WellKnownHeader::ContentLength); + const qint64 size = sizeValue.toLongLong(); + if (size > (maximumCacheSize() * 3)/4) + return nullptr; + std::unique_ptr cacheItem = std::make_unique(); cacheItem->metaData = metaData; @@ -578,31 +574,27 @@ QString QNetworkDiskCachePrivate::cacheFileName(const QUrl &url) const */ bool QCacheItem::canCompress() const { - bool sizeOk = false; - bool typeOk = false; - const auto headers = metaData.rawHeaders(); - for (const auto &header : headers) { - if (header.first.compare("content-length", Qt::CaseInsensitive) == 0) { - qint64 size = header.second.toLongLong(); - if (size > MAX_COMPRESSION_SIZE) - return false; - else - sizeOk = true; - } + const auto h = metaData.headers(); - if (header.first.compare("content-type", Qt::CaseInsensitive) == 0) { - QByteArray type = header.second; - if (type.startsWith("text/") - || (type.startsWith("application/") - && (type.endsWith("javascript") || type.endsWith("ecmascript")))) - typeOk = true; - else - return false; - } - if (sizeOk && typeOk) - return true; + const auto sizeValue = h.value(QHttpHeaders::WellKnownHeader::ContentLength); + if (sizeValue.empty()) + return false; + + qint64 size = sizeValue.toLongLong(); + if (size > MAX_COMPRESSION_SIZE) + return false; + + const auto type = h.value(QHttpHeaders::WellKnownHeader::ContentType); + if (!type.empty()) + return false; + + if (!type.startsWith("text/") + && !(type.startsWith("application/") + && (type.endsWith("javascript") || type.endsWith("ecmascript")))) { + return false; } - return false; + + return true; } enum @@ -673,7 +665,7 @@ bool QCacheItem::read(QFileDevice *device, bool readData) if (!device->fileName().endsWith(expectedFilename)) return false; - return metaData.isValid() && !metaData.rawHeaders().isEmpty(); + return metaData.isValid() && !metaData.headers().isEmpty(); } QT_END_NAMESPACE diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index ad83dd38e3..a59de42a44 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -1602,6 +1602,59 @@ QByteArray QNetworkHeadersPrivate::toHttpDate(const QDateTime &dt) return QLocale::c().toString(dt.toUTC(), u"ddd, dd MMM yyyy hh:mm:ss 'GMT'").toLatin1(); } +QNetworkHeadersPrivate::RawHeadersList QNetworkHeadersPrivate::fromHttpToRaw(const QHttpHeaders &headers) +{ + if (headers.isEmpty()) + return {}; + + QNetworkHeadersPrivate::RawHeadersList list; + QHash nameToIndex; + list.reserve(headers.size()); + nameToIndex.reserve(headers.size()); + + for (qsizetype i = 0; i < headers.size(); ++i) { + const auto nameL1 = headers.nameAt(i); + const auto value = headers.valueAt(i); + + const bool isSetCookie = nameL1 == QHttpHeaders::wellKnownHeaderName( + QHttpHeaders::WellKnownHeader::SetCookie); + + const auto name = QByteArray(nameL1.data(), nameL1.size()); + if (auto it = nameToIndex.find(name); it != nameToIndex.end()) { + list[it.value()].second += isSetCookie ? "\n" : ", "; + list[it.value()].second += value; + } else { + nameToIndex[name] = list.size(); + list.emplaceBack(name, value.toByteArray()); + } + } + + return list; +} + +QHttpHeaders QNetworkHeadersPrivate::fromRawToHttp(const RawHeadersList &raw) +{ + if (raw.empty()) + return {}; + + QHttpHeaders headers; + headers.reserve(raw.size()); + + for (const auto &[key, value] : raw) { + const bool isSetCookie = key.compare(QHttpHeaders::wellKnownHeaderName( + QHttpHeaders::WellKnownHeader::SetCookie), + Qt::CaseInsensitive) == 0; + if (isSetCookie) { + for (auto header : QLatin1StringView(value).tokenize('\n'_L1)) + headers.append(key, header); + } else { + headers.append(key, value); + } + } + + return headers; +} + QT_END_NAMESPACE #include "moc_qnetworkrequest.cpp" diff --git a/src/network/access/qnetworkrequest_p.h b/src/network/access/qnetworkrequest_p.h index 88fb8cb246..a73d8f2162 100644 --- a/src/network/access/qnetworkrequest_p.h +++ b/src/network/access/qnetworkrequest_p.h @@ -59,6 +59,9 @@ public: static QDateTime fromHttpDate(const QByteArray &value); static QByteArray toHttpDate(const QDateTime &dt); + static RawHeadersList fromHttpToRaw(const QHttpHeaders &headers); + static QHttpHeaders fromRawToHttp(const RawHeadersList &raw); + private: void setRawHeaderInternal(const QByteArray &key, const QByteArray &value); void parseAndSetHeader(const QByteArray &key, const QByteArray &value); diff --git a/tests/auto/network/access/qnetworkcachemetadata/tst_qnetworkcachemetadata.cpp b/tests/auto/network/access/qnetworkcachemetadata/tst_qnetworkcachemetadata.cpp index f811943dea..d49195efc6 100644 --- a/tests/auto/network/access/qnetworkcachemetadata/tst_qnetworkcachemetadata.cpp +++ b/tests/auto/network/access/qnetworkcachemetadata/tst_qnetworkcachemetadata.cpp @@ -29,6 +29,8 @@ private slots: void operatorEqualEqual(); void rawHeaders_data(); void rawHeaders(); + void headers_data(); + void headers(); void saveToDisk_data(); void saveToDisk(); void url_data(); @@ -114,6 +116,12 @@ void tst_QNetworkCacheMetaData::isValid_data() QNetworkCacheMetaData data5; data5.setSaveToDisk(false); QTest::newRow("valid-5") << data5 << true; + + QNetworkCacheMetaData data6; + QHttpHeaders httpHeaders; + httpHeaders.append("name", "value"); + data6.setHeaders(httpHeaders); + QTest::newRow("valid-6") << data6 << true; } // public bool isValid() const @@ -153,6 +161,9 @@ void tst_QNetworkCacheMetaData::operatorEqual_data() QNetworkCacheMetaData::RawHeaderList headers; headers.append(QNetworkCacheMetaData::RawHeader("foo", "Bar")); data.setRawHeaders(headers); + QHttpHeaders httpHeaders; + httpHeaders.append("name", "value"); + data.setHeaders(httpHeaders); data.setLastModified(QDateTime::currentDateTime()); data.setExpirationDate(QDateTime::currentDateTime()); data.setSaveToDisk(false); @@ -212,6 +223,18 @@ void tst_QNetworkCacheMetaData::operatorEqualEqual_data() QTest::newRow("valid-5-4") << data5 << data2 << false; QTest::newRow("valid-5-5") << data5 << data3 << false; QTest::newRow("valid-5-6") << data5 << data4 << false; + + QNetworkCacheMetaData data6; + QHttpHeaders httpHeaders; + httpHeaders.append("name", "value"); + data6.setHeaders(httpHeaders); + QTest::newRow("valid-6-1") << data6 << QNetworkCacheMetaData() << false; + QTest::newRow("valid-6-2") << data6 << data6 << true; + QTest::newRow("valid-6-3") << data6 << data1 << false; + QTest::newRow("valid-6-4") << data6 << data2 << false; + QTest::newRow("valid-6-5") << data6 << data3 << false; + QTest::newRow("valid-6-6") << data6 << data4 << false; + QTest::newRow("valid-6-7") << data6 << data5 << false; } // public bool operator==(QNetworkCacheMetaData const& other) const @@ -231,7 +254,11 @@ void tst_QNetworkCacheMetaData::rawHeaders_data() QTest::newRow("null") << QNetworkCacheMetaData::RawHeaderList(); QNetworkCacheMetaData::RawHeaderList headers; headers.append(QNetworkCacheMetaData::RawHeader("foo", "Bar")); - QTest::newRow("valie") << headers; + QTest::newRow("valid") << headers; + headers.append(QNetworkCacheMetaData::RawHeader("n1", "V1, v2, v3")); + headers.append(QNetworkCacheMetaData::RawHeader("n2", "V2")); + headers.append(QNetworkCacheMetaData::RawHeader("set-cookie", "v1\nV2\nV3")); + QTest::newRow("valid-2") << headers; } // public QNetworkCacheMetaData::RawHeaderList rawHeaders() const @@ -245,6 +272,25 @@ void tst_QNetworkCacheMetaData::rawHeaders() QCOMPARE(data.rawHeaders(), rawHeaders); } +void tst_QNetworkCacheMetaData::headers_data() +{ + QTest::addColumn("httpHeaders"); + QTest::newRow("null") << QHttpHeaders(); + QHttpHeaders headers; + headers.append("foo", "Bar"); + QTest::newRow("valid") << headers; +} + +void tst_QNetworkCacheMetaData::headers() +{ + QFETCH(QHttpHeaders, httpHeaders); + + SubQNetworkCacheMetaData data; + + data.setHeaders(httpHeaders); + QCOMPARE(data.headers().toListOfPairs(), httpHeaders.toListOfPairs()); +} + void tst_QNetworkCacheMetaData::saveToDisk_data() { QTest::addColumn("saveToDisk"); @@ -289,6 +335,9 @@ void tst_QNetworkCacheMetaData::stream() QNetworkCacheMetaData::RawHeaderList headers; headers.append(QNetworkCacheMetaData::RawHeader("foo", "Bar")); data.setRawHeaders(headers); + QHttpHeaders httpHeaders; + httpHeaders.append("name", "value"); + data.setHeaders(httpHeaders); data.setLastModified(QDateTime::currentDateTime()); data.setExpirationDate(QDateTime::currentDateTime()); data.setSaveToDisk(false);