diff options
author | Timur Pocheptsov <timur.pocheptsov@qt.io> | 2018-05-23 09:31:34 +0200 |
---|---|---|
committer | Timur Pocheptsov <timur.pocheptsov@qt.io> | 2018-06-04 13:38:04 +0000 |
commit | a217188fe054ca0aaa34c8e12ce99f276fe7eb7c (patch) | |
tree | 6e1540bd886211e2af2ccac17675521ec775bf71 /tests/auto/network/access/http2 | |
parent | 04b180f7f25d73d002df31085cf1c352e075d4e5 (diff) |
tst_Http2 auto-test: stop sending DATA frames if test failed
Unlike QNAM, our toy http2 server sends payload as one big chunk as soon as
it fits in the receive window's size. Internally, 'frame writer' splits this
payload into many DATA frames of the appropriate size (imposed either by the
default value or the one from the client's SETTINGS frame). If some test fails,
we can end up with a server waiting for the writer to send all the DATA frames
though it is not needed anymore - there is nobody to receive them after a failure.
This patch moves such a loop into the test server instead and stops the loop early
if needed.
Change-Id: Iea2dcd718d8f83386fd16004807f6447bf999435
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'tests/auto/network/access/http2')
-rw-r--r-- | tests/auto/network/access/http2/http2srv.cpp | 32 | ||||
-rw-r--r-- | tests/auto/network/access/http2/http2srv.h | 4 | ||||
-rw-r--r-- | tests/auto/network/access/http2/tst_http2.cpp | 4 |
3 files changed, 34 insertions, 6 deletions
diff --git a/tests/auto/network/access/http2/http2srv.cpp b/tests/auto/network/access/http2/http2srv.cpp index b0bae13bad..1f9ffb8985 100644 --- a/tests/auto/network/access/http2/http2srv.cpp +++ b/tests/auto/network/access/http2/http2srv.cpp @@ -212,13 +212,30 @@ void Http2Server::sendDATA(quint32 streamID, quint32 windowSize) const quint32 offset = it->second; Q_ASSERT(offset < quint32(responseBody.size())); - const quint32 bytes = std::min<quint32>(windowSize, responseBody.size() - offset); + quint32 bytesToSend = std::min<quint32>(windowSize, responseBody.size() - offset); + quint32 bytesSent = 0; const quint32 frameSizeLimit(clientSetting(Settings::MAX_FRAME_SIZE_ID, Http2::maxFrameSize)); const uchar *src = reinterpret_cast<const uchar *>(responseBody.constData() + offset); - const bool last = offset + bytes == quint32(responseBody.size()); + const bool last = offset + bytesToSend == quint32(responseBody.size()); + + // The payload can significantly exceed frameSizeLimit. Internally, writer + // will do needed fragmentation, but if some test failed, there is no need + // to wait for writer to send all DATA frames, we check 'interrupted' and + // stop early instead. + const quint32 framesInChunk = 10; + while (bytesToSend) { + if (interrupted.loadAcquire()) + return; + const quint32 chunkSize = std::min<quint32>(framesInChunk * frameSizeLimit, bytesToSend); + writer.start(FrameType::DATA, FrameFlag::EMPTY, streamID); + writer.writeDATA(*socket, frameSizeLimit, src, chunkSize); + src += chunkSize; + bytesToSend -= chunkSize; + bytesSent += chunkSize; + } - writer.start(FrameType::DATA, FrameFlag::EMPTY, streamID); - writer.writeDATA(*socket, frameSizeLimit, src, bytes); + if (interrupted.loadAcquire()) + return; if (last) { writer.start(FrameType::DATA, FrameFlag::END_STREAM, streamID); @@ -230,7 +247,7 @@ void Http2Server::sendDATA(quint32 streamID, quint32 windowSize) Q_ASSERT(closedStreams.find(streamID) == closedStreams.end()); closedStreams.insert(streamID); } else { - it->second += bytes; + it->second += bytesSent; } } @@ -819,6 +836,11 @@ void Http2Server::sendResponse(quint32 streamID, bool emptyBody) } } +void Http2Server::stopSendingDATAFrames() +{ + interrupted.storeRelease(1); +} + void Http2Server::processRequest() { Q_ASSERT(continuedRequest.size()); diff --git a/tests/auto/network/access/http2/http2srv.h b/tests/auto/network/access/http2/http2srv.h index 14b41cc67d..87a17ced8b 100644 --- a/tests/auto/network/access/http2/http2srv.h +++ b/tests/auto/network/access/http2/http2srv.h @@ -40,6 +40,7 @@ #include <QtCore/qscopedpointer.h> #include <QtNetwork/qtcpserver.h> #include <QtCore/qbytearray.h> +#include <QtCore/qatomic.h> #include <QtCore/qglobal.h> #include <vector> @@ -96,6 +97,8 @@ public: Q_INVOKABLE void sendResponse(quint32 streamID, bool emptyBody); + void stopSendingDATAFrames(); + private: void processRequest(); @@ -191,6 +194,7 @@ private: // may still be sending DATA frames. See tst_Http2::earlyResponse(). bool redirectWhileReading = false; quint16 targetPort = 0; + QAtomicInt interrupted; protected slots: void ignoreErrorSlot(); }; diff --git a/tests/auto/network/access/http2/tst_http2.cpp b/tests/auto/network/access/http2/tst_http2.cpp index fa56a35c29..49daedf32c 100644 --- a/tests/auto/network/access/http2/tst_http2.cpp +++ b/tests/auto/network/access/http2/tst_http2.cpp @@ -132,8 +132,10 @@ struct ServerDeleter { static void cleanup(Http2Server *srv) { - if (srv) + if (srv) { + srv->stopSendingDATAFrames(); QMetaObject::invokeMethod(srv, "deleteLater", Qt::QueuedConnection); + } } }; |