Http2: Ignore RST frames on already-closed streams

Some http servers like to send RST frames whenever they send their response.
The stream is already closed at that point so it's a little weird, but the
RFC doesn't disallow it, so we'll just ignore the frames.

Fixes: QTBUG-132124
Change-Id: Ic26e249437b739830935e2f3feec572687579b21
Reviewed-by: Øystein Heskestad <oystein.heskestad@qt.io>
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
(cherry picked from commit 2c71fdf043ca94d1c567f169d51245e2702bec19)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Mårten Nordheim 2024-12-16 11:09:19 +01:00 committed by Qt Cherry-pick Bot
parent aac98b795d
commit 0a4ff045f1
2 changed files with 44 additions and 0 deletions

View File

@ -708,6 +708,9 @@ void QHttp2Stream::handleHEADERS(Http2::FrameFlags frameFlags, const HPack::Http
void QHttp2Stream::handleRST_STREAM(const Frame &inboundFrame)
{
if (m_state == State::Closed) // The stream is already closed, we're not sending anything anyway
return;
transitionState(StateTransition::RST);
m_RST_STREAM_received = qFromBigEndian<quint32>(inboundFrame.dataBegin());
if (isUploadingDATA()) {

View File

@ -24,6 +24,7 @@ private slots:
void testRSTServerSide();
void testRSTClientSide();
void testRSTReplyOnDATAEND();
void resetAfterClose();
void testBadFrameSize_data();
void testBadFrameSize();
void testDataFrameAfterRSTIncoming();
@ -420,6 +421,46 @@ void tst_QHttp2Connection::testRSTReplyOnDATAEND()
QCOMPARE(errrorServerSpy.count(), 1);
}
void tst_QHttp2Connection::resetAfterClose()
{
auto [client, server] = makeFakeConnectedSockets();
auto connection = makeHttp2Connection(client.get(), {}, Client);
auto serverConnection = makeHttp2Connection(server.get(), {}, Server);
QHttp2Stream *clientStream = connection->createStream().unwrap();
QVERIFY(clientStream);
QVERIFY(waitForSettingsExchange(connection, serverConnection));
QSignalSpy newIncomingStreamSpy{ serverConnection, &QHttp2Connection::newIncomingStream };
QSignalSpy clientHeaderReceivedSpy{ clientStream, &QHttp2Stream::headersReceived };
HPack::HttpHeader headers = getRequiredHeaders();
clientStream->sendHEADERS(headers, true);
QVERIFY(newIncomingStreamSpy.wait());
auto *serverStream = newIncomingStreamSpy.front().front().value<QHttp2Stream *>();
QCOMPARE(clientStream->streamID(), serverStream->streamID());
QSignalSpy errorSpy(clientStream, &QHttp2Stream::errorOccurred);
const HPack::HttpHeader StatusOKHeaders{ { ":status", "200" } };
serverStream->sendHEADERS(StatusOKHeaders, true);
// Write the RST_STREAM frame manually because we guard against sending RST_STREAM on closed
// streams
auto &frameWriter = serverConnection->frameWriter;
frameWriter.start(Http2::FrameType::RST_STREAM, Http2::FrameFlag::EMPTY,
serverStream->streamID());
frameWriter.append(quint32(Http2::Http2Error::STREAM_CLOSED));
QVERIFY(frameWriter.write(*serverConnection->getSocket()));
QVERIFY(clientHeaderReceivedSpy.wait());
QCOMPARE(clientStream->state(), QHttp2Stream::State::Closed);
QTest::qWait(10); // Just needs to process events basically
QCOMPARE(errorSpy.count(), 0);
}
void tst_QHttp2Connection::testBadFrameSize_data()
{
QTest::addColumn<uchar>("frametype");