diff options
author | Lena Biliaieva <[email protected]> | 2024-07-02 15:52:50 +0200 |
---|---|---|
committer | Lena Biliaieva <[email protected]> | 2024-07-16 16:07:33 +0200 |
commit | 6aa1cb05e357cf4221aaedd4cf742c45983af446 (patch) | |
tree | 8515cf89e587f784c99eb1a74e3f4052ba28f65d | |
parent | 37e6159ab0c1456e8dc38f38f3b21643585c1273 (diff) |
QHttp2Connection: Add test for CONTINUATION frames
Pick-to: 6.8
Task-number: QTBUG-122458
Change-Id: I6c87a7361852bb04173f0216e69cd7c5309a242b
Reviewed-by: Edward Welbourne <[email protected]>
-rw-r--r-- | tests/auto/network/access/qhttp2connection/tst_qhttp2connection.cpp | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/tests/auto/network/access/qhttp2connection/tst_qhttp2connection.cpp b/tests/auto/network/access/qhttp2connection/tst_qhttp2connection.cpp index c4095d0a404..40887172df1 100644 --- a/tests/auto/network/access/qhttp2connection/tst_qhttp2connection.cpp +++ b/tests/auto/network/access/qhttp2connection/tst_qhttp2connection.cpp @@ -23,6 +23,7 @@ private slots: void testPING(); void connectToServer(); void WINDOW_UPDATE(); + void testCONTINUATIONFrame(); private: enum PeerType { Client, Server }; @@ -386,6 +387,168 @@ void tst_QHttp2Connection::WINDOW_UPDATE() QCOMPARE(serverStream->state(), QHttp2Stream::State::Closed); } +namespace { + +void sendHEADERSFrame(HPack::Encoder &encoder, + Http2::FrameWriter &frameWriter, + quint32 streamId, + const HPack::HttpHeader &headers, + Http2::FrameFlags flags, + QIODevice &socket) +{ + frameWriter.start(Http2::FrameType::HEADERS, + flags, + streamId); + frameWriter.append(quint32()); + frameWriter.append(QHttp2Stream::DefaultPriority); + + HPack::BitOStream outputStream(frameWriter.outboundFrame().buffer); + QVERIFY(encoder.encodeRequest(outputStream, headers)); + frameWriter.setPayloadSize(frameWriter.outboundFrame().buffer.size() + - Http2::Http2PredefinedParameters::frameHeaderSize); + frameWriter.write(socket); +} + +void sendDATAFrame(Http2::FrameWriter &frameWriter, + quint32 streamId, + Http2::FrameFlags flags, + QIODevice &socket) +{ + frameWriter.start(Http2::FrameType::DATA, + flags, + streamId); + frameWriter.write(socket); +} + +void sendCONTINUATIONFrame(HPack::Encoder &encoder, + Http2::FrameWriter &frameWriter, + quint32 streamId, + const HPack::HttpHeader &headers, + Http2::FrameFlags flags, + QIODevice &socket) +{ + frameWriter.start(Http2::FrameType::CONTINUATION, + flags, + streamId); + + HPack::BitOStream outputStream(frameWriter.outboundFrame().buffer); + QVERIFY(encoder.encodeRequest(outputStream, headers)); + frameWriter.setPayloadSize(frameWriter.outboundFrame().buffer.size() + - Http2::Http2PredefinedParameters::frameHeaderSize); + frameWriter.write(socket); +} + +} + +void tst_QHttp2Connection::testCONTINUATIONFrame() +{ + static const HPack::HttpHeader headers = HPack::HttpHeader { + { ":authority", "example.com" }, + { ":method", "GET" }, + { ":path", "/" }, + { ":scheme", "https" }, + { "n1", "v1" }, + { "n2", "v2" }, + { "n3", "v3" } + }; + + #define CREATE_CONNECTION() \ + auto [client, server] = makeFakeConnectedSockets(); \ + auto clientConnection = makeHttp2Connection(client.get(), {}, Client); \ + auto serverConnection = makeHttp2Connection(server.get(), {}, Server); \ + QVERIFY(waitForSettingsExchange(clientConnection, serverConnection)); \ + \ + HPack::Encoder encoder = HPack::Encoder(HPack::FieldLookupTable::DefaultSize, true); \ + Http2::FrameWriter frameWriter; \ + \ + QSignalSpy serverIncomingStreamSpy{ serverConnection, &QHttp2Connection::newIncomingStream }; \ + QSignalSpy receivedGOAWAYSpy{ clientConnection, &QHttp2Connection::receivedGOAWAY }; \ + \ + QHttp2Stream *clientStream = clientConnection->createStream().unwrap(); \ + QVERIFY(clientStream); + + // Send multiple CONTINUATION frames + { + CREATE_CONNECTION(); + + frameWriter.start(Http2::FrameType::HEADERS, + Http2::FrameFlag::PRIORITY, + clientStream->streamID()); + frameWriter.append(quint32()); + frameWriter.append(QHttp2Stream::DefaultPriority); + HPack::BitOStream outputStream(frameWriter.outboundFrame().buffer); + QVERIFY(encoder.encodeRequest(outputStream, headers)); + + // split headers into multiple CONTINUATION frames + const size_t sizeLimit = frameWriter.outboundFrame().buffer.size() / 5; + frameWriter.writeHEADERS(*client, sizeLimit); + + QVERIFY(serverIncomingStreamSpy.wait()); + auto *serverStream = serverIncomingStreamSpy.front().front().value<QHttp2Stream *>(); + QVERIFY(serverStream); + // correct behavior accepted and handled sensibly + QCOMPARE(serverStream->receivedHeaders(), headers); + } + + // A DATA frame between a HEADERS frame and a CONTINUATION frame. + { + CREATE_CONNECTION(); + + sendHEADERSFrame(encoder, frameWriter, clientStream->streamID(), + headers, Http2::FrameFlag::PRIORITY, *client); + QVERIFY(serverIncomingStreamSpy.wait()); + + sendDATAFrame(frameWriter, clientStream->streamID(), Http2::FrameFlag::EMPTY, *client); + // the client correctly rejected our malformed stream contents by telling us to GO AWAY + QVERIFY(receivedGOAWAYSpy.wait()); + } + + // A CONTINUATION frame after a frame with the END_HEADERS set. + { + CREATE_CONNECTION(); + + sendHEADERSFrame(encoder, frameWriter, clientStream->streamID(), headers, + Http2::FrameFlag::PRIORITY | Http2::FrameFlag::END_HEADERS, *client); + QVERIFY(serverIncomingStreamSpy.wait()); + + sendCONTINUATIONFrame(encoder, frameWriter, clientStream->streamID(), + headers, Http2::FrameFlag::EMPTY, *client); + // the client correctly rejected our malformed stream contents by telling us to GO AWAY + QVERIFY(receivedGOAWAYSpy.wait()); + } + + // A CONTINUATION frame with the stream id 0x00. + { + CREATE_CONNECTION(); + + sendHEADERSFrame(encoder, frameWriter, clientStream->streamID(), + headers, Http2::FrameFlag::PRIORITY, *client); + QVERIFY(serverIncomingStreamSpy.wait()); + + sendCONTINUATIONFrame(encoder, frameWriter, 0, + headers, Http2::FrameFlag::EMPTY, *client); + // the client correctly rejected our malformed stream contents by telling us to GO AWAY + QVERIFY(receivedGOAWAYSpy.wait()); + } + + // A CONTINUATION frame with a different stream id then the previous frame. + { + CREATE_CONNECTION(); + + sendHEADERSFrame(encoder, frameWriter, clientStream->streamID(), + headers, Http2::FrameFlag::PRIORITY, *client); + QVERIFY(serverIncomingStreamSpy.wait()); + + QHttp2Stream *newClientStream = clientConnection->createStream().unwrap(); + QVERIFY(newClientStream); + + sendCONTINUATIONFrame(encoder, frameWriter, newClientStream->streamID(), + headers, Http2::FrameFlag::EMPTY, *client); + // the client correctly rejected our malformed stream contents by telling us to GO AWAY + QVERIFY(receivedGOAWAYSpy.wait()); + } +} + QTEST_MAIN(tst_QHttp2Connection) #include "tst_qhttp2connection.moc" |