QNetworkReply/http2: Add a contentEncoding test
Will be useful when DecompressHelper gets taken into use for both. Task-number: QTBUG-83269 Change-Id: Iaf253219bed193025c2b82d6609f4dcc4de33df8 Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
This commit is contained in:
parent
b35551a75e
commit
80e0d0e08e
@ -120,6 +120,11 @@ void Http2Server::setResponseBody(const QByteArray &body)
|
||||
responseBody = body;
|
||||
}
|
||||
|
||||
void Http2Server::setContentEncoding(const QByteArray &encoding)
|
||||
{
|
||||
contentEncoding = encoding;
|
||||
}
|
||||
|
||||
void Http2Server::emulateGOAWAY(int timeout)
|
||||
{
|
||||
Q_ASSERT(timeout >= 0);
|
||||
@ -841,6 +846,9 @@ void Http2Server::sendResponse(quint32 streamID, bool emptyBody)
|
||||
QString("%1").arg(responseBody.size()).toLatin1()));
|
||||
}
|
||||
|
||||
if (!contentEncoding.isEmpty())
|
||||
header.push_back(HPack::HeaderField("content-encoding", contentEncoding));
|
||||
|
||||
HPack::BitOStream ostream(writer.outboundFrame().buffer);
|
||||
const bool result = encoder.encodeResponse(ostream, header);
|
||||
Q_ASSERT(result);
|
||||
|
@ -86,6 +86,8 @@ public:
|
||||
// To be called before server started:
|
||||
void enablePushPromise(bool enabled, const QByteArray &path = QByteArray());
|
||||
void setResponseBody(const QByteArray &body);
|
||||
// No content encoding is actually performed, call setResponseBody with already encoded data
|
||||
void setContentEncoding(const QByteArray &contentEncoding);
|
||||
void emulateGOAWAY(int timeout);
|
||||
void redirectOpenStream(quint16 targetPort);
|
||||
|
||||
@ -211,6 +213,8 @@ private:
|
||||
bool redirectSent = false;
|
||||
quint16 targetPort = 0;
|
||||
QAtomicInt interrupted;
|
||||
|
||||
QByteArray contentEncoding;
|
||||
protected slots:
|
||||
void ignoreErrorSlot();
|
||||
};
|
||||
|
@ -111,6 +111,9 @@ private slots:
|
||||
void connectToHost();
|
||||
void maxFrameSize();
|
||||
|
||||
void contentEncoding_data();
|
||||
void contentEncoding();
|
||||
|
||||
protected slots:
|
||||
// Slots to listen to our in-process server:
|
||||
void serverStarted(quint16 port);
|
||||
@ -767,6 +770,109 @@ void tst_Http2::maxFrameSize()
|
||||
QVERIFY(serverGotSettingsACK);
|
||||
}
|
||||
|
||||
void tst_Http2::contentEncoding_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("encoding");
|
||||
QTest::addColumn<QByteArray>("body");
|
||||
QTest::addColumn<QByteArray>("expected");
|
||||
QTest::addColumn<QNetworkRequest::Attribute>("h2Attribute");
|
||||
QTest::addColumn<H2Type>("connectionType");
|
||||
|
||||
struct ContentEncodingData
|
||||
{
|
||||
ContentEncodingData(QByteArray &&ce, QByteArray &&body, QByteArray &&ex)
|
||||
: contentEncoding(ce), body(body), expected(ex)
|
||||
{
|
||||
}
|
||||
QByteArray contentEncoding;
|
||||
QByteArray body;
|
||||
QByteArray expected;
|
||||
};
|
||||
|
||||
QVector<ContentEncodingData> contentEncodingData;
|
||||
contentEncodingData.emplace_back(
|
||||
"gzip", QByteArray::fromBase64("H4sIAAAAAAAAA8tIzcnJVyjPL8pJAQCFEUoNCwAAAA=="),
|
||||
"hello world");
|
||||
contentEncodingData.emplace_back(
|
||||
"deflate", QByteArray::fromBase64("eJzLSM3JyVcozy/KSQEAGgsEXQ=="), "hello world");
|
||||
|
||||
// Loop through and add the data...
|
||||
for (const auto &data : contentEncodingData) {
|
||||
const char *name = data.contentEncoding.data();
|
||||
QTest::addRow("%s-h2c-upgrade", name)
|
||||
<< data.contentEncoding << data.body << data.expected
|
||||
<< QNetworkRequest::Http2AllowedAttribute << H2Type::h2c;
|
||||
QTest::addRow("%s-h2c-direct", name)
|
||||
<< data.contentEncoding << data.body << data.expected
|
||||
<< QNetworkRequest::Http2DirectAttribute << H2Type::h2cDirect;
|
||||
|
||||
if (!clearTextHTTP2)
|
||||
QTest::addRow("%s-h2-ALPN", name)
|
||||
<< data.contentEncoding << data.body << data.expected
|
||||
<< QNetworkRequest::Http2AllowedAttribute << H2Type::h2Alpn;
|
||||
|
||||
#if QT_CONFIG(ssl)
|
||||
QTest::addRow("%s-h2-direct", name)
|
||||
<< data.contentEncoding << data.body << data.expected
|
||||
<< QNetworkRequest::Http2DirectAttribute << H2Type::h2Direct;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void tst_Http2::contentEncoding()
|
||||
{
|
||||
clearHTTP2State();
|
||||
|
||||
#if QT_CONFIG(securetransport)
|
||||
// Normally on macOS we use plain text only for SecureTransport
|
||||
// does not support ALPN on the server side. With 'direct encrytped'
|
||||
// we have to use TLS sockets (== private key) and thus suppress a
|
||||
// keychain UI asking for permission to use a private key.
|
||||
// Our CI has this, but somebody testing locally - will have a problem.
|
||||
qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", QByteArray("1"));
|
||||
auto envRollback = qScopeGuard([]() { qunsetenv("QT_SSL_USE_TEMPORARY_KEYCHAIN"); });
|
||||
#endif
|
||||
|
||||
QFETCH(H2Type, connectionType);
|
||||
|
||||
ServerPtr targetServer(newServer(defaultServerSettings, connectionType));
|
||||
QFETCH(QByteArray, body);
|
||||
targetServer->setResponseBody(body);
|
||||
QFETCH(QByteArray, encoding);
|
||||
targetServer->setContentEncoding(encoding);
|
||||
|
||||
QMetaObject::invokeMethod(targetServer.data(), "startServer", Qt::QueuedConnection);
|
||||
runEventLoop();
|
||||
|
||||
QVERIFY(serverPort != 0);
|
||||
|
||||
nRequests = 1;
|
||||
|
||||
auto url = requestUrl(connectionType);
|
||||
url.setPath("/index.html");
|
||||
|
||||
QNetworkRequest request(url);
|
||||
QFETCH(const QNetworkRequest::Attribute, h2Attribute);
|
||||
request.setAttribute(h2Attribute, QVariant(true));
|
||||
|
||||
auto reply = manager->get(request);
|
||||
connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished);
|
||||
// Since we're using self-signed certificates,
|
||||
// ignore SSL errors:
|
||||
reply->ignoreSslErrors();
|
||||
|
||||
runEventLoop();
|
||||
STOP_ON_FAILURE
|
||||
|
||||
QVERIFY(nRequests == 0);
|
||||
QVERIFY(prefaceOK);
|
||||
QVERIFY(serverGotSettingsACK);
|
||||
|
||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||
QVERIFY(reply->isFinished());
|
||||
QTEST(reply->readAll(), "expected");
|
||||
}
|
||||
|
||||
void tst_Http2::serverStarted(quint16 port)
|
||||
{
|
||||
serverPort = port;
|
||||
|
@ -503,6 +503,10 @@ private Q_SLOTS:
|
||||
|
||||
void getWithTimeout();
|
||||
void postWithTimeout();
|
||||
|
||||
void contentEncoding_data();
|
||||
void contentEncoding();
|
||||
|
||||
// NOTE: This test must be last!
|
||||
void parentingRepliesToTheApp();
|
||||
private:
|
||||
@ -9175,6 +9179,57 @@ void tst_QNetworkReply::postWithTimeout()
|
||||
manager.setTransferTimeout(0);
|
||||
}
|
||||
|
||||
void tst_QNetworkReply::contentEncoding_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("encoding");
|
||||
QTest::addColumn<QByteArray>("body");
|
||||
QTest::addColumn<QByteArray>("expected");
|
||||
|
||||
QTest::newRow("gzip-hello-world")
|
||||
<< QByteArray("gzip")
|
||||
<< QByteArray::fromBase64("H4sIAAAAAAAAA8tIzcnJVyjPL8pJAQCFEUoNCwAAAA==")
|
||||
<< QByteArray("hello world");
|
||||
QTest::newRow("deflate-hello-world")
|
||||
<< QByteArray("deflate") << QByteArray::fromBase64("eJzLSM3JyVcozy/KSQEAGgsEXQ==")
|
||||
<< QByteArray("hello world");
|
||||
}
|
||||
|
||||
void tst_QNetworkReply::contentEncoding()
|
||||
{
|
||||
QFETCH(QByteArray, encoding);
|
||||
QFETCH(QByteArray, body);
|
||||
QString header("HTTP/1.0 200 OK\r\nContent-Encoding: %1\r\nContent-Length: %2\r\n\r\n");
|
||||
header = header.arg(encoding, QString::number(body.size()));
|
||||
|
||||
MiniHttpServer server(header.toLatin1() + body);
|
||||
|
||||
QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort())));
|
||||
QNetworkReplyPtr reply(manager.get(request));
|
||||
|
||||
QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply));
|
||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||
|
||||
{
|
||||
// Check that we included the content encoding method in our Accept-Encoding header
|
||||
const QByteArray &receivedData = server.receivedData;
|
||||
int start = receivedData.indexOf("Accept-Encoding");
|
||||
QVERIFY(start != -1);
|
||||
int end = receivedData.indexOf("\r\n", start);
|
||||
QVERIFY(end != -1);
|
||||
QByteArray acceptedEncoding = receivedData.mid(start, end - start);
|
||||
acceptedEncoding = acceptedEncoding.mid(acceptedEncoding.indexOf(':') + 1).trimmed();
|
||||
QByteArrayList list = acceptedEncoding.split(',');
|
||||
for (QByteArray &encoding : list)
|
||||
encoding = encoding.trimmed();
|
||||
QVERIFY2(list.contains(encoding), acceptedEncoding.data());
|
||||
}
|
||||
|
||||
QFETCH(QByteArray, expected);
|
||||
|
||||
QCOMPARE(reply->bytesAvailable(), expected.size());
|
||||
QCOMPARE(reply->readAll(), expected);
|
||||
}
|
||||
|
||||
// NOTE: This test must be last testcase in tst_qnetworkreply!
|
||||
void tst_QNetworkReply::parentingRepliesToTheApp()
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user