xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/qpack/fuzzer/qpack_round_trip_fuzzer.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <fuzzer/FuzzedDataProvider.h>
6 
7 #include <algorithm>
8 #include <cstddef>
9 #include <cstdint>
10 #include <string>
11 #include <utility>
12 
13 #include "absl/strings/string_view.h"
14 #include "quiche/quic/core/http/quic_header_list.h"
15 #include "quiche/quic/core/qpack/qpack_decoded_headers_accumulator.h"
16 #include "quiche/quic/core/qpack/qpack_decoder.h"
17 #include "quiche/quic/core/qpack/qpack_encoder.h"
18 #include "quiche/quic/core/qpack/qpack_stream_sender_delegate.h"
19 #include "quiche/quic/core/qpack/value_splitting_header_list.h"
20 #include "quiche/quic/core/quic_error_codes.h"
21 #include "quiche/quic/test_tools/qpack/qpack_decoder_test_utils.h"
22 #include "quiche/quic/test_tools/qpack/qpack_encoder_peer.h"
23 #include "quiche/common/quiche_circular_deque.h"
24 #include "quiche/spdy/core/http2_header_block.h"
25 
26 namespace quic {
27 namespace test {
28 namespace {
29 
30 // Find the first occurrence of invalid characters NUL, LF, CR in |*value| and
31 // remove that and the remaining of the string.
TruncateValueOnInvalidChars(std::string * value)32 void TruncateValueOnInvalidChars(std::string* value) {
33   for (auto it = value->begin(); it != value->end(); ++it) {
34     if (*it == '\0' || *it == '\n' || *it == '\r') {
35       value->erase(it, value->end());
36       return;
37     }
38   }
39 }
40 
41 }  // anonymous namespace
42 
43 // Class to hold QpackEncoder and its DecoderStreamErrorDelegate.
44 class EncodingEndpoint {
45  public:
EncodingEndpoint(uint64_t maximum_dynamic_table_capacity,uint64_t maximum_blocked_streams,HuffmanEncoding huffman_encoding)46   EncodingEndpoint(uint64_t maximum_dynamic_table_capacity,
47                    uint64_t maximum_blocked_streams,
48                    HuffmanEncoding huffman_encoding)
49       : encoder_(&decoder_stream_error_delegate, huffman_encoding) {
50     encoder_.SetMaximumDynamicTableCapacity(maximum_dynamic_table_capacity);
51     encoder_.SetMaximumBlockedStreams(maximum_blocked_streams);
52   }
53 
~EncodingEndpoint()54   ~EncodingEndpoint() {
55     // Every reference should be acknowledged.
56     QUICHE_CHECK_EQ(std::numeric_limits<uint64_t>::max(),
57                     QpackEncoderPeer::smallest_blocking_index(&encoder_));
58   }
59 
set_qpack_stream_sender_delegate(QpackStreamSenderDelegate * delegate)60   void set_qpack_stream_sender_delegate(QpackStreamSenderDelegate* delegate) {
61     encoder_.set_qpack_stream_sender_delegate(delegate);
62   }
63 
SetDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity)64   void SetDynamicTableCapacity(uint64_t maximum_dynamic_table_capacity) {
65     encoder_.SetDynamicTableCapacity(maximum_dynamic_table_capacity);
66   }
67 
decoder_stream_receiver()68   QpackStreamReceiver* decoder_stream_receiver() {
69     return encoder_.decoder_stream_receiver();
70   }
71 
EncodeHeaderList(QuicStreamId stream_id,const spdy::Http2HeaderBlock & header_list)72   std::string EncodeHeaderList(QuicStreamId stream_id,
73                                const spdy::Http2HeaderBlock& header_list) {
74     return encoder_.EncodeHeaderList(stream_id, header_list, nullptr);
75   }
76 
77  private:
78   // DecoderStreamErrorDelegate implementation that crashes on error.
79   class CrashingDecoderStreamErrorDelegate
80       : public QpackEncoder::DecoderStreamErrorDelegate {
81    public:
82     ~CrashingDecoderStreamErrorDelegate() override = default;
83 
OnDecoderStreamError(QuicErrorCode error_code,absl::string_view error_message)84     void OnDecoderStreamError(QuicErrorCode error_code,
85                               absl::string_view error_message) override {
86       QUICHE_CHECK(false) << QuicErrorCodeToString(error_code) << " "
87                           << error_message;
88     }
89   };
90 
91   CrashingDecoderStreamErrorDelegate decoder_stream_error_delegate;
92   QpackEncoder encoder_;
93 };
94 
95 // Class that receives all header blocks from the encoding endpoint and passes
96 // them to the decoding endpoint, with delay determined by fuzzer data,
97 // preserving order within each stream but not among streams.
98 class DelayedHeaderBlockTransmitter {
99  public:
100   class Visitor {
101    public:
102     virtual ~Visitor() = default;
103 
104     // If decoding of the previous header block is still in progress, then
105     // DelayedHeaderBlockTransmitter will not start transmitting the next header
106     // block.
107     virtual bool IsDecodingInProgressOnStream(QuicStreamId stream_id) = 0;
108 
109     // Called when a header block starts.
110     virtual void OnHeaderBlockStart(QuicStreamId stream_id) = 0;
111     // Called when part or all of a header block is transmitted.
112     virtual void OnHeaderBlockFragment(QuicStreamId stream_id,
113                                        absl::string_view data) = 0;
114     // Called when transmission of a header block is complete.
115     virtual void OnHeaderBlockEnd(QuicStreamId stream_id) = 0;
116   };
117 
DelayedHeaderBlockTransmitter(Visitor * visitor,FuzzedDataProvider * provider)118   DelayedHeaderBlockTransmitter(Visitor* visitor, FuzzedDataProvider* provider)
119       : visitor_(visitor), provider_(provider) {}
120 
~DelayedHeaderBlockTransmitter()121   ~DelayedHeaderBlockTransmitter() { QUICHE_CHECK(header_blocks_.empty()); }
122 
123   // Enqueues |encoded_header_block| for delayed transmission.
SendEncodedHeaderBlock(QuicStreamId stream_id,std::string encoded_header_block)124   void SendEncodedHeaderBlock(QuicStreamId stream_id,
125                               std::string encoded_header_block) {
126     auto it = header_blocks_.lower_bound(stream_id);
127     if (it == header_blocks_.end() || it->first != stream_id) {
128       it = header_blocks_.insert(it, {stream_id, {}});
129     }
130     QUICHE_CHECK_EQ(stream_id, it->first);
131     it->second.push(HeaderBlock(std::move(encoded_header_block)));
132   }
133 
134   // Release some (possibly none) header block data.
MaybeTransmitSomeData()135   void MaybeTransmitSomeData() {
136     if (header_blocks_.empty()) {
137       return;
138     }
139 
140     auto index =
141         provider_->ConsumeIntegralInRange<size_t>(0, header_blocks_.size() - 1);
142     auto it = header_blocks_.begin();
143     std::advance(it, index);
144     const QuicStreamId stream_id = it->first;
145 
146     // Do not start new header block if processing of previous header block is
147     // blocked.
148     if (visitor_->IsDecodingInProgressOnStream(stream_id)) {
149       return;
150     }
151 
152     auto& header_block_queue = it->second;
153     HeaderBlock& header_block = header_block_queue.front();
154 
155     if (header_block.ConsumedLength() == 0) {
156       visitor_->OnHeaderBlockStart(stream_id);
157     }
158 
159     QUICHE_DCHECK_NE(0u, header_block.RemainingLength());
160 
161     size_t length = provider_->ConsumeIntegralInRange<size_t>(
162         1, header_block.RemainingLength());
163     visitor_->OnHeaderBlockFragment(stream_id, header_block.Consume(length));
164 
165     QUICHE_DCHECK_NE(0u, header_block.ConsumedLength());
166 
167     if (header_block.RemainingLength() == 0) {
168       visitor_->OnHeaderBlockEnd(stream_id);
169 
170       header_block_queue.pop();
171       if (header_block_queue.empty()) {
172         header_blocks_.erase(it);
173       }
174     }
175   }
176 
177   // Release all header block data.  Must be called before destruction.  All
178   // encoder stream data must have been released before calling Flush() so that
179   // all header blocks can be decoded synchronously.
Flush()180   void Flush() {
181     while (!header_blocks_.empty()) {
182       auto it = header_blocks_.begin();
183       const QuicStreamId stream_id = it->first;
184 
185       auto& header_block_queue = it->second;
186       HeaderBlock& header_block = header_block_queue.front();
187 
188       if (header_block.ConsumedLength() == 0) {
189         QUICHE_CHECK(!visitor_->IsDecodingInProgressOnStream(stream_id));
190         visitor_->OnHeaderBlockStart(stream_id);
191       }
192 
193       QUICHE_DCHECK_NE(0u, header_block.RemainingLength());
194 
195       visitor_->OnHeaderBlockFragment(stream_id,
196                                       header_block.ConsumeRemaining());
197 
198       QUICHE_DCHECK_NE(0u, header_block.ConsumedLength());
199       QUICHE_DCHECK_EQ(0u, header_block.RemainingLength());
200 
201       visitor_->OnHeaderBlockEnd(stream_id);
202       QUICHE_CHECK(!visitor_->IsDecodingInProgressOnStream(stream_id));
203 
204       header_block_queue.pop();
205       if (header_block_queue.empty()) {
206         header_blocks_.erase(it);
207       }
208     }
209   }
210 
211  private:
212   // Helper class that allows the header block to be consumed in parts.
213   class HeaderBlock {
214    public:
HeaderBlock(std::string data)215     explicit HeaderBlock(std::string data)
216         : data_(std::move(data)), offset_(0) {
217       // Valid QPACK header block cannot be empty.
218       QUICHE_DCHECK(!data_.empty());
219     }
220 
ConsumedLength() const221     size_t ConsumedLength() const { return offset_; }
222 
RemainingLength() const223     size_t RemainingLength() const { return data_.length() - offset_; }
224 
Consume(size_t length)225     absl::string_view Consume(size_t length) {
226       QUICHE_DCHECK_NE(0u, length);
227       QUICHE_DCHECK_LE(length, RemainingLength());
228 
229       absl::string_view consumed = absl::string_view(&data_[offset_], length);
230       offset_ += length;
231       return consumed;
232     }
233 
ConsumeRemaining()234     absl::string_view ConsumeRemaining() { return Consume(RemainingLength()); }
235 
236    private:
237     // Complete header block.
238     const std::string data_;
239 
240     // Offset of the part not consumed yet.  Same as number of consumed bytes.
241     size_t offset_;
242   };
243 
244   Visitor* const visitor_;
245   FuzzedDataProvider* const provider_;
246 
247   std::map<QuicStreamId, std::queue<HeaderBlock>> header_blocks_;
248 };
249 
250 // Class to decode and verify a header block, and in case of blocked decoding,
251 // keep necessary decoding context while waiting for decoding to complete.
252 class VerifyingDecoder : public QpackDecodedHeadersAccumulator::Visitor {
253  public:
254   class Visitor {
255    public:
256     virtual ~Visitor() = default;
257 
258     // Called when header block is decoded, either synchronously or
259     // asynchronously.  Might destroy VerifyingDecoder.
260     virtual void OnHeaderBlockDecoded(QuicStreamId stream_id) = 0;
261   };
262 
VerifyingDecoder(QuicStreamId stream_id,Visitor * visitor,QpackDecoder * qpack_decoder,QuicHeaderList expected_header_list)263   VerifyingDecoder(QuicStreamId stream_id, Visitor* visitor,
264                    QpackDecoder* qpack_decoder,
265                    QuicHeaderList expected_header_list)
266       : stream_id_(stream_id),
267         visitor_(visitor),
268         accumulator_(
269             stream_id, qpack_decoder, this,
270             /* max_header_list_size = */ std::numeric_limits<size_t>::max()),
271         expected_header_list_(std::move(expected_header_list)) {}
272 
273   VerifyingDecoder(const VerifyingDecoder&) = delete;
274   VerifyingDecoder& operator=(const VerifyingDecoder&) = delete;
275   // VerifyingDecoder must not be moved because it passes |this| to
276   // |accumulator_| upon construction.
277   VerifyingDecoder(VerifyingDecoder&&) = delete;
278   VerifyingDecoder& operator=(VerifyingDecoder&&) = delete;
279 
280   virtual ~VerifyingDecoder() = default;
281 
282   // QpackDecodedHeadersAccumulator::Visitor implementation.
OnHeadersDecoded(QuicHeaderList headers,bool header_list_size_limit_exceeded)283   void OnHeadersDecoded(QuicHeaderList headers,
284                         bool header_list_size_limit_exceeded) override {
285     // Verify headers.
286     QUICHE_CHECK(!header_list_size_limit_exceeded);
287     QUICHE_CHECK(expected_header_list_ == headers);
288 
289     // Might destroy |this|.
290     visitor_->OnHeaderBlockDecoded(stream_id_);
291   }
292 
OnHeaderDecodingError(QuicErrorCode error_code,absl::string_view error_message)293   void OnHeaderDecodingError(QuicErrorCode error_code,
294                              absl::string_view error_message) override {
295     QUICHE_CHECK(false) << QuicErrorCodeToString(error_code) << " "
296                         << error_message;
297   }
298 
Decode(absl::string_view data)299   void Decode(absl::string_view data) { accumulator_.Decode(data); }
300 
EndHeaderBlock()301   void EndHeaderBlock() { accumulator_.EndHeaderBlock(); }
302 
303  private:
304   QuicStreamId stream_id_;
305   Visitor* const visitor_;
306   QpackDecodedHeadersAccumulator accumulator_;
307   QuicHeaderList expected_header_list_;
308 };
309 
310 // Class that holds QpackDecoder and its EncoderStreamErrorDelegate, and creates
311 // and keeps VerifyingDecoders for each received header block until decoding is
312 // complete.
313 class DecodingEndpoint : public DelayedHeaderBlockTransmitter::Visitor,
314                          public VerifyingDecoder::Visitor {
315  public:
DecodingEndpoint(uint64_t maximum_dynamic_table_capacity,uint64_t maximum_blocked_streams,FuzzedDataProvider * provider)316   DecodingEndpoint(uint64_t maximum_dynamic_table_capacity,
317                    uint64_t maximum_blocked_streams,
318                    FuzzedDataProvider* provider)
319       : decoder_(maximum_dynamic_table_capacity, maximum_blocked_streams,
320                  &encoder_stream_error_delegate_),
321         provider_(provider) {}
322 
~DecodingEndpoint()323   ~DecodingEndpoint() override {
324     // All decoding must have been completed.
325     QUICHE_CHECK(expected_header_lists_.empty());
326     QUICHE_CHECK(verifying_decoders_.empty());
327   }
328 
set_qpack_stream_sender_delegate(QpackStreamSenderDelegate * delegate)329   void set_qpack_stream_sender_delegate(QpackStreamSenderDelegate* delegate) {
330     decoder_.set_qpack_stream_sender_delegate(delegate);
331   }
332 
encoder_stream_receiver()333   QpackStreamReceiver* encoder_stream_receiver() {
334     return decoder_.encoder_stream_receiver();
335   }
336 
AddExpectedHeaderList(QuicStreamId stream_id,QuicHeaderList expected_header_list)337   void AddExpectedHeaderList(QuicStreamId stream_id,
338                              QuicHeaderList expected_header_list) {
339     auto it = expected_header_lists_.lower_bound(stream_id);
340     if (it == expected_header_lists_.end() || it->first != stream_id) {
341       it = expected_header_lists_.insert(it, {stream_id, {}});
342     }
343     QUICHE_CHECK_EQ(stream_id, it->first);
344     it->second.push(std::move(expected_header_list));
345   }
346 
347   // VerifyingDecoder::Visitor implementation.
OnHeaderBlockDecoded(QuicStreamId stream_id)348   void OnHeaderBlockDecoded(QuicStreamId stream_id) override {
349     auto result = verifying_decoders_.erase(stream_id);
350     QUICHE_CHECK_EQ(1u, result);
351   }
352 
353   // DelayedHeaderBlockTransmitter::Visitor implementation.
IsDecodingInProgressOnStream(QuicStreamId stream_id)354   bool IsDecodingInProgressOnStream(QuicStreamId stream_id) override {
355     return verifying_decoders_.find(stream_id) != verifying_decoders_.end();
356   }
357 
OnHeaderBlockStart(QuicStreamId stream_id)358   void OnHeaderBlockStart(QuicStreamId stream_id) override {
359     QUICHE_CHECK(!IsDecodingInProgressOnStream(stream_id));
360     auto it = expected_header_lists_.find(stream_id);
361     QUICHE_CHECK(it != expected_header_lists_.end());
362 
363     auto& header_list_queue = it->second;
364     QuicHeaderList expected_header_list = std::move(header_list_queue.front());
365 
366     header_list_queue.pop();
367     if (header_list_queue.empty()) {
368       expected_header_lists_.erase(it);
369     }
370 
371     auto verifying_decoder = std::make_unique<VerifyingDecoder>(
372         stream_id, this, &decoder_, std::move(expected_header_list));
373     auto result =
374         verifying_decoders_.insert({stream_id, std::move(verifying_decoder)});
375     QUICHE_CHECK(result.second);
376   }
377 
OnHeaderBlockFragment(QuicStreamId stream_id,absl::string_view data)378   void OnHeaderBlockFragment(QuicStreamId stream_id,
379                              absl::string_view data) override {
380     auto it = verifying_decoders_.find(stream_id);
381     QUICHE_CHECK(it != verifying_decoders_.end());
382     it->second->Decode(data);
383   }
384 
OnHeaderBlockEnd(QuicStreamId stream_id)385   void OnHeaderBlockEnd(QuicStreamId stream_id) override {
386     auto it = verifying_decoders_.find(stream_id);
387     QUICHE_CHECK(it != verifying_decoders_.end());
388     it->second->EndHeaderBlock();
389   }
390 
391   // Flush decoder stream data buffered within the decoder.
FlushDecoderStream()392   void FlushDecoderStream() { decoder_.FlushDecoderStream(); }
MaybeFlushDecoderStream()393   void MaybeFlushDecoderStream() {
394     if (provider_->ConsumeBool()) {
395       FlushDecoderStream();
396     }
397   }
398 
399  private:
400   // EncoderStreamErrorDelegate implementation that crashes on error.
401   class CrashingEncoderStreamErrorDelegate
402       : public QpackDecoder::EncoderStreamErrorDelegate {
403    public:
404     ~CrashingEncoderStreamErrorDelegate() override = default;
405 
OnEncoderStreamError(QuicErrorCode error_code,absl::string_view error_message)406     void OnEncoderStreamError(QuicErrorCode error_code,
407                               absl::string_view error_message) override {
408       QUICHE_CHECK(false) << QuicErrorCodeToString(error_code) << " "
409                           << error_message;
410     }
411   };
412 
413   CrashingEncoderStreamErrorDelegate encoder_stream_error_delegate_;
414   QpackDecoder decoder_;
415   FuzzedDataProvider* const provider_;
416 
417   // Expected header lists in order for each stream.
418   std::map<QuicStreamId, std::queue<QuicHeaderList>> expected_header_lists_;
419 
420   // A VerifyingDecoder object keeps context necessary for asynchronously
421   // decoding blocked header blocks.  It is destroyed as soon as it signals that
422   // decoding is completed, which might happen synchronously within an
423   // EndHeaderBlock() call.
424   std::map<QuicStreamId, std::unique_ptr<VerifyingDecoder>> verifying_decoders_;
425 };
426 
427 // Class that receives encoder stream data from the encoder and passes it to the
428 // decoder, or receives decoder stream data from the decoder and passes it to
429 // the encoder, with delay determined by fuzzer data.
430 class DelayedStreamDataTransmitter : public QpackStreamSenderDelegate {
431  public:
DelayedStreamDataTransmitter(QpackStreamReceiver * receiver,FuzzedDataProvider * provider)432   DelayedStreamDataTransmitter(QpackStreamReceiver* receiver,
433                                FuzzedDataProvider* provider)
434       : receiver_(receiver), provider_(provider) {}
435 
~DelayedStreamDataTransmitter()436   ~DelayedStreamDataTransmitter() { QUICHE_CHECK(stream_data.empty()); }
437 
438   // QpackStreamSenderDelegate implementation.
WriteStreamData(absl::string_view data)439   void WriteStreamData(absl::string_view data) override {
440     stream_data.push_back(std::string(data.data(), data.size()));
441   }
NumBytesBuffered() const442   uint64_t NumBytesBuffered() const override { return 0; }
443 
444   // Release some (possibly none) delayed stream data.
MaybeTransmitSomeData()445   void MaybeTransmitSomeData() {
446     auto count = provider_->ConsumeIntegral<uint8_t>();
447     while (!stream_data.empty() && count > 0) {
448       receiver_->Decode(stream_data.front());
449       stream_data.pop_front();
450       --count;
451     }
452   }
453 
454   // Release all delayed stream data.  Must be called before destruction.
Flush()455   void Flush() {
456     while (!stream_data.empty()) {
457       receiver_->Decode(stream_data.front());
458       stream_data.pop_front();
459     }
460   }
461 
462  private:
463   QpackStreamReceiver* const receiver_;
464   FuzzedDataProvider* const provider_;
465   quiche::QuicheCircularDeque<std::string> stream_data;
466 };
467 
468 // Generate header list using fuzzer data.
GenerateHeaderList(FuzzedDataProvider * provider)469 spdy::Http2HeaderBlock GenerateHeaderList(FuzzedDataProvider* provider) {
470   spdy::Http2HeaderBlock header_list;
471   uint8_t header_count = provider->ConsumeIntegral<uint8_t>();
472   for (uint8_t header_index = 0; header_index < header_count; ++header_index) {
473     if (provider->remaining_bytes() == 0) {
474       // Do not add more headers if there is no more fuzzer data.
475       break;
476     }
477 
478     std::string name;
479     std::string value;
480     switch (provider->ConsumeIntegral<uint8_t>()) {
481       case 0:
482         // Static table entry with no header value.
483         name = ":authority";
484         break;
485       case 1:
486         // Static table entry with no header value, using non-empty header
487         // value.
488         name = ":authority";
489         value = "www.example.org";
490         break;
491       case 2:
492         // Static table entry with header value, using that header value.
493         name = ":accept-encoding";
494         value = "gzip, deflate";
495         break;
496       case 3:
497         // Static table entry with header value, using empty header value.
498         name = ":accept-encoding";
499         break;
500       case 4:
501         // Static table entry with header value, using different, non-empty
502         // header value.
503         name = ":accept-encoding";
504         value = "brotli";
505         break;
506       case 5:
507         // Header name that has multiple entries in the static table,
508         // using header value from one of them.
509         name = ":method";
510         value = "GET";
511         break;
512       case 6:
513         // Header name that has multiple entries in the static table,
514         // using empty header value.
515         name = ":method";
516         break;
517       case 7:
518         // Header name that has multiple entries in the static table,
519         // using different, non-empty header value.
520         name = ":method";
521         value = "CONNECT";
522         break;
523       case 8:
524         // Header name not in the static table, empty header value.
525         name = "foo";
526         value = "";
527         break;
528       case 9:
529         // Header name not in the static table, non-empty fixed header value.
530         name = "foo";
531         value = "bar";
532         break;
533       case 10:
534         // Header name not in the static table, fuzzed header value.
535         name = "foo";
536         value = provider->ConsumeRandomLengthString(128);
537         TruncateValueOnInvalidChars(&value);
538         break;
539       case 11:
540         // Another header name not in the static table, empty header value.
541         name = "bar";
542         value = "";
543         break;
544       case 12:
545         // Another header name not in the static table, non-empty fixed header
546         // value.
547         name = "bar";
548         value = "baz";
549         break;
550       case 13:
551         // Another header name not in the static table, fuzzed header value.
552         name = "bar";
553         value = provider->ConsumeRandomLengthString(128);
554         TruncateValueOnInvalidChars(&value);
555         break;
556       default:
557         // Fuzzed header name and header value.
558         name = provider->ConsumeRandomLengthString(128);
559         value = provider->ConsumeRandomLengthString(128);
560         TruncateValueOnInvalidChars(&value);
561     }
562 
563     header_list.AppendValueOrAddHeader(name, value);
564   }
565 
566   return header_list;
567 }
568 
569 // Splits |*header_list| header values along '\0' or ';' separators.
SplitHeaderList(const spdy::Http2HeaderBlock & header_list)570 QuicHeaderList SplitHeaderList(const spdy::Http2HeaderBlock& header_list) {
571   QuicHeaderList split_header_list;
572   split_header_list.OnHeaderBlockStart();
573 
574   size_t total_size = 0;
575   ValueSplittingHeaderList splitting_header_list(&header_list);
576   for (const auto& header : splitting_header_list) {
577     split_header_list.OnHeader(header.first, header.second);
578     total_size += header.first.size() + header.second.size();
579   }
580 
581   split_header_list.OnHeaderBlockEnd(total_size, total_size);
582 
583   return split_header_list;
584 }
585 
586 // This fuzzer exercises QpackEncoder and QpackDecoder.  It should be able to
587 // cover all possible code paths of QpackEncoder.  However, since the resulting
588 // header block is always valid and is encoded in a particular way, this fuzzer
589 // is not expected to cover all code paths of QpackDecoder.  On the other hand,
590 // encoding then decoding is expected to result in the original header list, and
591 // this fuzzer checks for that.
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)592 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
593   FuzzedDataProvider provider(data, size);
594 
595   // Maximum 256 byte dynamic table.  Such a small size helps test draining
596   // entries and eviction.
597   const uint64_t maximum_dynamic_table_capacity =
598       provider.ConsumeIntegral<uint8_t>();
599   // Maximum 256 blocked streams.
600   const uint64_t maximum_blocked_streams = provider.ConsumeIntegral<uint8_t>();
601 
602   // Set up encoder.
603   EncodingEndpoint encoder(maximum_dynamic_table_capacity,
604                            maximum_blocked_streams,
605                            provider.ConsumeBool() ? HuffmanEncoding::kEnabled
606                                                   : HuffmanEncoding::kDisabled);
607 
608   // Set up decoder.
609   DecodingEndpoint decoder(maximum_dynamic_table_capacity,
610                            maximum_blocked_streams, &provider);
611 
612   // Transmit encoder stream data from encoder to decoder.
613   DelayedStreamDataTransmitter encoder_stream_transmitter(
614       decoder.encoder_stream_receiver(), &provider);
615   encoder.set_qpack_stream_sender_delegate(&encoder_stream_transmitter);
616 
617   // Use a dynamic table as large as the peer allows.  This sends data on the
618   // encoder stream, so it can only be done after delegate is set.
619   encoder.SetDynamicTableCapacity(maximum_dynamic_table_capacity);
620 
621   // Transmit decoder stream data from encoder to decoder.
622   DelayedStreamDataTransmitter decoder_stream_transmitter(
623       encoder.decoder_stream_receiver(), &provider);
624   decoder.set_qpack_stream_sender_delegate(&decoder_stream_transmitter);
625 
626   // Transmit header blocks from encoder to decoder.
627   DelayedHeaderBlockTransmitter header_block_transmitter(&decoder, &provider);
628 
629   // Maximum 256 header lists to limit runtime and memory usage.
630   auto header_list_count = provider.ConsumeIntegral<uint8_t>();
631   while (header_list_count > 0 && provider.remaining_bytes() > 0) {
632     const QuicStreamId stream_id = provider.ConsumeIntegral<uint8_t>();
633 
634     // Generate header list.
635     spdy::Http2HeaderBlock header_list = GenerateHeaderList(&provider);
636 
637     // Encode header list.
638     std::string encoded_header_block =
639         encoder.EncodeHeaderList(stream_id, header_list);
640 
641     // TODO(bnc): Randomly cancel the stream.
642 
643     // Encoder splits |header_list| header values along '\0' or ';' separators.
644     // Do the same here so that we get matching results.
645     QuicHeaderList expected_header_list = SplitHeaderList(header_list);
646     decoder.AddExpectedHeaderList(stream_id, std::move(expected_header_list));
647 
648     header_block_transmitter.SendEncodedHeaderBlock(
649         stream_id, std::move(encoded_header_block));
650 
651     // Transmit some encoder stream data, decoder stream data, or header blocks
652     // on the request stream, repeating a few times.
653     for (auto transmit_data_count = provider.ConsumeIntegralInRange(1, 5);
654          transmit_data_count > 0; --transmit_data_count) {
655       encoder_stream_transmitter.MaybeTransmitSomeData();
656       decoder.MaybeFlushDecoderStream();
657       decoder_stream_transmitter.MaybeTransmitSomeData();
658       header_block_transmitter.MaybeTransmitSomeData();
659     }
660 
661     --header_list_count;
662   }
663 
664   // Release all delayed encoder stream data so that remaining header blocks can
665   // be decoded synchronously.
666   encoder_stream_transmitter.Flush();
667   // Release all delayed header blocks.
668   header_block_transmitter.Flush();
669   // Flush decoder stream data buffered within the decoder. This will then be
670   // buffered in and delayed by `decoder_stream_transmitter`.
671   decoder.FlushDecoderStream();
672   // Release all delayed decoder stream data.
673   decoder_stream_transmitter.Flush();
674 
675   return 0;
676 }
677 
678 }  // namespace test
679 }  // namespace quic
680