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