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