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>bb10
parent
04b180f7f2
commit
a217188fe0
|
|
@ -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());
|
||||
|
||||
writer.start(FrameType::DATA, FrameFlag::EMPTY, streamID);
|
||||
writer.writeDATA(*socket, frameSizeLimit, src, bytes);
|
||||
// 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;
|
||||
}
|
||||
|
||||
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());
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -132,8 +132,10 @@ struct ServerDeleter
|
|||
{
|
||||
static void cleanup(Http2Server *srv)
|
||||
{
|
||||
if (srv)
|
||||
if (srv) {
|
||||
srv->stopSendingDATAFrames();
|
||||
QMetaObject::invokeMethod(srv, "deleteLater", Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue