Support blocked decoding in qpack_round_trip_fuzzer.cc. gfe-relnote: n/a, test-only change. PiperOrigin-RevId: 263656501 Change-Id: I608df789a1c2e9df680051982bb11c47e4d8a51b
diff --git a/quic/core/qpack/fuzzer/qpack_round_trip_fuzzer.cc b/quic/core/qpack/fuzzer/qpack_round_trip_fuzzer.cc index 84c6948..164b05d 100644 --- a/quic/core/qpack/fuzzer/qpack_round_trip_fuzzer.cc +++ b/quic/core/qpack/fuzzer/qpack_round_trip_fuzzer.cc
@@ -79,6 +79,11 @@ public: virtual ~Visitor() = default; + // If decoding of the previous header block is still in progress, then + // DelayedHeaderBlockTransmitter will not start transmitting the next header + // block. + virtual bool IsDecodingInProgressOnStream(QuicStreamId stream_id) = 0; + // Called when a header block starts. virtual void OnHeaderBlockStart(QuicStreamId stream_id) = 0; // Called when part or all of a header block is transmitted. @@ -117,6 +122,12 @@ std::advance(it, index); const QuicStreamId stream_id = it->first; + // Do not start new header block if processing of previous header block is + // blocked. + if (visitor_->IsDecodingInProgressOnStream(stream_id)) { + return; + } + auto& header_block_queue = it->second; visitor_->OnHeaderBlockStart(stream_id); visitor_->OnHeaderBlockFragment(stream_id, header_block_queue.front()); @@ -130,11 +141,12 @@ // Release all header block data. Must be called before destruction. All // encoder stream data must have been released before calling Flush() so that - // all remaining header blocks can be decoded synchronously. + // all header blocks can be decoded synchronously. void Flush() { while (!header_blocks_.empty()) { auto it = header_blocks_.begin(); const QuicStreamId stream_id = it->first; + CHECK(!visitor_->IsDecodingInProgressOnStream(stream_id)); auto& header_block_queue = it->second; visitor_->OnHeaderBlockStart(stream_id); @@ -160,10 +172,22 @@ // keep necessary decoding context while waiting for decoding to complete. class VerifyingDecoder : public QpackDecodedHeadersAccumulator::Visitor { public: + class Visitor { + public: + virtual ~Visitor() = default; + + // Called when header block is decoded, either synchronously or + // asynchronously. Might destroy VerifyingDecoder. + virtual void OnHeaderBlockDecoded(QuicStreamId stream_id) = 0; + }; + VerifyingDecoder(QuicStreamId stream_id, + Visitor* visitor, QpackDecoder* qpack_decoder, QuicHeaderList expected_header_list) - : accumulator_( + : stream_id_(stream_id), + visitor_(visitor), + accumulator_( stream_id, qpack_decoder, this, @@ -180,7 +204,13 @@ virtual ~VerifyingDecoder() = default; // QpackDecodedHeadersAccumulator::Visitor implementation. - void OnHeadersDecoded(QuicHeaderList /*headers*/) override {} + void OnHeadersDecoded(QuicHeaderList headers) override { + // Verify headers. + CHECK(expected_header_list_ == headers); + + // Might destroy |this|. + visitor_->OnHeaderBlockDecoded(stream_id_); + } void OnHeaderDecodingError() override { CHECK(false) << accumulator_.error_message(); @@ -198,13 +228,21 @@ CHECK(status != QpackDecodedHeadersAccumulator::Status::kError) << accumulator_.error_message(); + if (status == QpackDecodedHeadersAccumulator::Status::kBlocked) { + return; + } + CHECK(status == QpackDecodedHeadersAccumulator::Status::kSuccess); // Compare resulting header list to original. CHECK(expected_header_list_ == accumulator_.quic_header_list()); + // Might destroy |this|. + visitor_->OnHeaderBlockDecoded(stream_id_); } private: + QuicStreamId stream_id_; + Visitor* const visitor_; QpackDecodedHeadersAccumulator accumulator_; QuicHeaderList expected_header_list_; }; @@ -212,7 +250,8 @@ // Class that holds QpackDecoder and its EncoderStreamErrorDelegate, and creates // and keeps VerifyingDecoders for each received header block until decoding is // complete. -class DecodingEndpoint : public DelayedHeaderBlockTransmitter::Visitor { +class DecodingEndpoint : public DelayedHeaderBlockTransmitter::Visitor, + public VerifyingDecoder::Visitor { public: DecodingEndpoint(uint64_t maximum_dynamic_table_capacity, uint64_t maximum_blocked_streams) @@ -244,8 +283,19 @@ it->second.push(std::move(expected_header_list)); } + // VerifyingDecoder::Visitor implementation. + void OnHeaderBlockDecoded(QuicStreamId stream_id) override { + auto result = verifying_decoders_.erase(stream_id); + CHECK_EQ(1u, result); + } + // DelayedHeaderBlockTransmitter::Visitor implementation. + bool IsDecodingInProgressOnStream(QuicStreamId stream_id) override { + return verifying_decoders_.find(stream_id) != verifying_decoders_.end(); + } + void OnHeaderBlockStart(QuicStreamId stream_id) override { + CHECK(!IsDecodingInProgressOnStream(stream_id)); auto it = expected_header_lists_.find(stream_id); CHECK(it != expected_header_lists_.end()); @@ -258,7 +308,7 @@ } auto verifying_decoder = QuicMakeUnique<VerifyingDecoder>( - stream_id, &decoder_, std::move(expected_header_list)); + stream_id, this, &decoder_, std::move(expected_header_list)); auto result = verifying_decoders_.insert({stream_id, std::move(verifying_decoder)}); CHECK(result.second); @@ -275,8 +325,6 @@ auto it = verifying_decoders_.find(stream_id); CHECK(it != verifying_decoders_.end()); it->second->EndHeaderBlock(); - auto result = verifying_decoders_.erase(stream_id); - CHECK_EQ(1u, result); } private: