Convert date-time to UTC before claiming it's in GMT

QNetworkHeadersPrivate::toHttpDate() used a custom format to output a
date-time; the format supplied GMT as suffix, but neglected to convert
the date-time to UTC, so local-time was formatted as if it were UTC,
regardless of its actual offset from it. Fixing this (by the obvious
toUTC() call) broke formatting when the supplied header value was a
QDate, since it's packaged as a QVariant and QVariant's conversion of
QDate to QDateTime uses local time's (not UTC's) start of day. So fix
headerValue() to separate QDate and QDateTime cases and use
startOfDay(Qt::UTC) to get the right start of the day. Added tests for
non-UTC date-times appearing correctly in HTTP headers.

Fixes: QTBUG-80666
Pick-to: 6.3 6.2 6.2.3 5.15
Change-Id: I2792bce14a07be025cf551b0594630260c112269
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Edward Welbourne 2022-01-13 16:37:01 +01:00
parent 21735f24cf
commit aa8fd6bc39
2 changed files with 30 additions and 12 deletions

View File

@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of the QtNetwork module of the Qt Toolkit. ** This file is part of the QtNetwork module of the Qt Toolkit.
@ -1071,9 +1071,10 @@ static QByteArray headerValue(QNetworkRequest::KnownHeaders header, const QVaria
case QNetworkRequest::LastModifiedHeader: case QNetworkRequest::LastModifiedHeader:
case QNetworkRequest::IfModifiedSinceHeader: case QNetworkRequest::IfModifiedSinceHeader:
switch (value.userType()) { switch (value.userType()) {
// Generate RFC 1123/822 dates:
case QMetaType::QDate: case QMetaType::QDate:
return QNetworkHeadersPrivate::toHttpDate(value.toDate().startOfDay(Qt::UTC));
case QMetaType::QDateTime: case QMetaType::QDateTime:
// generate RFC 1123/822 dates:
return QNetworkHeadersPrivate::toHttpDate(value.toDateTime()); return QNetworkHeadersPrivate::toHttpDate(value.toDateTime());
default: default:
@ -1515,8 +1516,7 @@ QDateTime QNetworkHeadersPrivate::fromHttpDate(const QByteArray &value)
QByteArray QNetworkHeadersPrivate::toHttpDate(const QDateTime &dt) QByteArray QNetworkHeadersPrivate::toHttpDate(const QDateTime &dt)
{ {
return QLocale::c().toString(dt, u"ddd, dd MMM yyyy hh:mm:ss 'GMT'") return QLocale::c().toString(dt.toUTC(), u"ddd, dd MMM yyyy hh:mm:ss 'GMT'").toLatin1();
.toLatin1();
} }
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of the test suite of the Qt Toolkit. ** This file is part of the test suite of the Qt Toolkit.
@ -26,9 +26,11 @@
** **
****************************************************************************/ ****************************************************************************/
#include <QTest> #include <QTest>
#include <QtCore/QUrl> #include <QtCore/QUrl>
#if QT_CONFIG(timezone)
# include <QtCore/QTimeZone>
#endif
#include <QtNetwork/QNetworkRequest> #include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkCookie> #include <QtNetwork/QNetworkCookie>
@ -236,12 +238,28 @@ void tst_QNetworkRequest::setHeader_data()
<< QVariant(QDate(2007, 11, 01)) << QVariant(QDate(2007, 11, 01))
<< true << "Last-Modified" << true << "Last-Modified"
<< "Thu, 01 Nov 2007 00:00:00 GMT"; << "Thu, 01 Nov 2007 00:00:00 GMT";
QTest::newRow("Last-Modified-DateTime") << QNetworkRequest::LastModifiedHeader QTest::newRow("Last-Modified-DateTime-UTC")
<< QVariant(QDateTime(QDate(2007, 11, 01), << QNetworkRequest::LastModifiedHeader
QTime(18, 8, 30), << QVariant(QDateTime(QDate(2007, 11, 1), QTime(18, 8, 30), Qt::UTC))
Qt::UTC)) << true << "Last-Modified" << "Thu, 01 Nov 2007 18:08:30 GMT";
<< true << "Last-Modified" // QTBUG-80666: format dates correctly (as GMT) even if the date passed in isn't in UTC:
<< "Thu, 01 Nov 2007 18:08:30 GMT"; QTest::newRow("Last-Modified-DateTime-Local")
<< QNetworkRequest::LastModifiedHeader
<< QVariant(QDateTime(QDate(2007, 11, 1), QTime(18, 8, 30), Qt::UTC).toLocalTime())
<< true << "Last-Modified" << "Thu, 01 Nov 2007 18:08:30 GMT";
QTest::newRow("Last-Modified-DateTime-Offset")
<< QNetworkRequest::LastModifiedHeader
<< QVariant(QDateTime(QDate(2007, 11, 1), QTime(18, 8, 30), Qt::UTC).toOffsetFromUtc(3600))
<< true << "Last-Modified" << "Thu, 01 Nov 2007 18:08:30 GMT";
#if QT_CONFIG(timezone)
QTimeZone cet("Europe/Oslo");
if (cet.isValid()) {
QTest::newRow("Last-Modified-DateTime-CET")
<< QNetworkRequest::LastModifiedHeader
<< QVariant(QDateTime(QDate(2007, 11, 1), QTime(18, 8, 30), Qt::UTC).toTimeZone(cet))
<< true << "Last-Modified" << "Thu, 01 Nov 2007 18:08:30 GMT";
}
#endif
QTest::newRow("If-Modified-Since-Date") << QNetworkRequest::IfModifiedSinceHeader QTest::newRow("If-Modified-Since-Date") << QNetworkRequest::IfModifiedSinceHeader
<< QVariant(QDate(2017, 7, 01)) << QVariant(QDate(2017, 7, 01))