blob: 3299d5e22616949e50274f81b932540401a16296 [file] [log] [blame]
QUICHE teamfd50a402018-12-07 22:54:05 -05001// 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 "net/third_party/quiche/src/http2/hpack/varint/hpack_varint_decoder.h"
6
7// Test HpackVarintDecoder against data encoded via HpackBlockBuilder,
8// which uses HpackVarintEncoder under the hood.
9
10#include <stddef.h>
11
12#include <iterator>
13#include <set>
14#include <vector>
15
16#include "base/logging.h"
17#include "testing/gtest/include/gtest/gtest.h"
18#include "net/third_party/quiche/src/http2/hpack/tools/hpack_block_builder.h"
19#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
20#include "net/third_party/quiche/src/http2/platform/api/http2_string_utils.h"
21#include "net/third_party/quiche/src/http2/tools/random_decoder_test.h"
22
23using ::testing::AssertionFailure;
24using ::testing::AssertionSuccess;
25using ::testing::Bool;
26using ::testing::WithParamInterface;
27
28namespace http2 {
29namespace test {
30namespace {
31
32// Save previous value of flag and restore on destruction.
33class FlagSaver {
34 public:
35 FlagSaver() = delete;
36 explicit FlagSaver(bool decode_64_bits)
37 : saved_value_(GetHttp2ReloadableFlag(http2_varint_decode_64_bits)) {
38 SetHttp2ReloadableFlag(http2_varint_decode_64_bits, decode_64_bits);
39 }
40 ~FlagSaver() {
41 SetHttp2ReloadableFlag(http2_varint_decode_64_bits, saved_value_);
42 }
43
44 private:
45 const bool saved_value_;
46};
47
48// Returns the highest value with the specified number of extension bytes
49// and the specified prefix length (bits).
50uint64_t HiValueOfExtensionBytes(uint32_t extension_bytes,
51 uint32_t prefix_length) {
52 return (1 << prefix_length) - 2 +
53 (extension_bytes == 0 ? 0 : (1LLU << (extension_bytes * 7)));
54}
55
56class HpackVarintRoundTripTest : public RandomDecoderTest,
57 public WithParamInterface<bool> {
58 protected:
59 HpackVarintRoundTripTest()
60 : decode_64_bits_(GetParam()),
61 flag_saver_(decode_64_bits_),
62 prefix_length_(0) {}
63
64 DecodeStatus StartDecoding(DecodeBuffer* b) override {
65 CHECK_LT(0u, b->Remaining());
66 uint8_t prefix = b->DecodeUInt8();
67 return decoder_.Start(prefix, prefix_length_, b);
68 }
69
70 DecodeStatus ResumeDecoding(DecodeBuffer* b) override {
71 return decoder_.Resume(b);
72 }
73
74 void DecodeSeveralWays(uint64_t expected_value, uint32_t expected_offset) {
75 // The validator is called after each of the several times that the input
76 // DecodeBuffer is decoded, each with a different segmentation of the input.
77 // Validate that decoder_.value() matches the expected value.
78 Validator validator = [expected_value, this](
79 const DecodeBuffer& db,
80 DecodeStatus status) -> AssertionResult {
81 if (decoder_.value() != expected_value) {
82 return AssertionFailure()
83 << "Value doesn't match expected: " << decoder_.value()
84 << " != " << expected_value;
85 }
86 return AssertionSuccess();
87 };
88
89 // First validate that decoding is done and that we've advanced the cursor
90 // the expected amount.
91 validator = ValidateDoneAndOffset(expected_offset, validator);
92
93 // StartDecoding, above, requires the DecodeBuffer be non-empty so that it
94 // can call Start with the prefix byte.
95 bool return_non_zero_on_first = true;
96
97 DecodeBuffer b(buffer_);
98 EXPECT_TRUE(
99 DecodeAndValidateSeveralWays(&b, return_non_zero_on_first, validator));
100
101 EXPECT_EQ(expected_value, decoder_.value());
102 EXPECT_EQ(expected_offset, b.Offset());
103 }
104
105 void EncodeNoRandom(uint64_t value, uint8_t prefix_length) {
106 DCHECK_LE(3, prefix_length);
QUICHE teamcc663702018-12-17 15:51:59 -0500107 DCHECK_LE(prefix_length, 8);
QUICHE teamfd50a402018-12-07 22:54:05 -0500108 prefix_length_ = prefix_length;
109
110 HpackBlockBuilder bb;
111 bb.AppendHighBitsAndVarint(0, prefix_length_, value);
112 buffer_ = bb.buffer();
113 ASSERT_LT(0u, buffer_.size());
114
115 const uint8_t prefix_mask = (1 << prefix_length_) - 1;
bnc23346472018-12-27 21:57:05 -0500116 ASSERT_EQ(static_cast<uint8_t>(buffer_[0]),
117 static_cast<uint8_t>(buffer_[0]) & prefix_mask);
QUICHE teamfd50a402018-12-07 22:54:05 -0500118 }
119
120 void Encode(uint64_t value, uint8_t prefix_length) {
121 EncodeNoRandom(value, prefix_length);
122 // Add some random bits to the prefix (the first byte) above the mask.
123 uint8_t prefix = buffer_[0];
124 buffer_[0] = prefix | (Random().Rand8() << prefix_length);
125 const uint8_t prefix_mask = (1 << prefix_length_) - 1;
126 ASSERT_EQ(prefix, buffer_[0] & prefix_mask);
127 }
128
129 // This is really a test of HpackBlockBuilder, making sure that the input to
130 // HpackVarintDecoder is as expected, which also acts as confirmation that
131 // my thinking about the encodings being used by the tests, i.e. cover the
132 // range desired.
133 void ValidateEncoding(uint64_t value,
134 uint64_t minimum,
135 uint64_t maximum,
136 size_t expected_bytes) {
137 ASSERT_EQ(expected_bytes, buffer_.size());
138 if (expected_bytes > 1) {
139 const uint8_t prefix_mask = (1 << prefix_length_) - 1;
140 EXPECT_EQ(prefix_mask, buffer_[0] & prefix_mask);
141 size_t last = expected_bytes - 1;
142 for (size_t ndx = 1; ndx < last; ++ndx) {
143 // Before the last extension byte, we expect the high-bit set.
144 uint8_t byte = buffer_[ndx];
145 if (value == minimum) {
146 EXPECT_EQ(0x80, byte) << "ndx=" << ndx;
147 } else if (value == maximum) {
148 if (expected_bytes < 11) {
149 EXPECT_EQ(0xff, byte) << "ndx=" << ndx;
150 }
151 } else {
152 EXPECT_EQ(0x80, byte & 0x80) << "ndx=" << ndx;
153 }
154 }
155 // The last extension byte should not have the high-bit set.
156 uint8_t byte = buffer_[last];
157 if (value == minimum) {
158 if (expected_bytes == 2) {
159 EXPECT_EQ(0x00, byte);
160 } else {
161 EXPECT_EQ(0x01, byte);
162 }
163 } else if (value == maximum) {
164 if (expected_bytes < 11) {
165 EXPECT_EQ(0x7f, byte);
166 }
167 } else {
168 EXPECT_EQ(0x00, byte & 0x80);
169 }
170 } else {
171 const uint8_t prefix_mask = (1 << prefix_length_) - 1;
172 EXPECT_EQ(value, static_cast<uint32_t>(buffer_[0] & prefix_mask));
173 EXPECT_LT(value, prefix_mask);
174 }
175 }
176
177 void EncodeAndDecodeValues(const std::set<uint64_t>& values,
178 uint8_t prefix_length,
179 size_t expected_bytes) {
180 CHECK(!values.empty());
181 const uint64_t minimum = *values.begin();
182 const uint64_t maximum = *values.rbegin();
183 for (const uint64_t value : values) {
184 Encode(value, prefix_length); // Sets buffer_.
185
186 Http2String msg = Http2StrCat("value=", value, " (0x", Http2Hex(value),
187 "), prefix_length=", prefix_length,
188 ", expected_bytes=", expected_bytes, "\n",
189 Http2HexDump(buffer_));
190
191 if (value == minimum) {
192 LOG(INFO) << "Checking minimum; " << msg;
193 } else if (value == maximum) {
194 LOG(INFO) << "Checking maximum; " << msg;
195 }
196
197 SCOPED_TRACE(msg);
198 ValidateEncoding(value, minimum, maximum, expected_bytes);
199 DecodeSeveralWays(value, expected_bytes);
200
201 // Append some random data to the end of buffer_ and repeat. That random
202 // data should be ignored.
203 buffer_.append(Random().RandString(1 + Random().Uniform(10)));
204 DecodeSeveralWays(value, expected_bytes);
205
206 // If possible, add extension bytes that don't change the value.
207 if (1 < expected_bytes) {
208 buffer_.resize(expected_bytes);
209 for (uint8_t total_bytes = expected_bytes + 1; total_bytes <= 6;
210 ++total_bytes) {
211 // Mark the current last byte as not being the last one.
212 EXPECT_EQ(0x00, 0x80 & buffer_.back());
213 buffer_.back() |= 0x80;
214 buffer_.push_back('\0');
215 DecodeSeveralWays(value, total_bytes);
216 }
217 }
218 }
219 }
220
221 // Encode values (all or some of it) in [start, start+range). Check
222 // that |start| is the smallest value and |start+range-1| is the largest value
223 // corresponding to |expected_bytes|, except if |expected_bytes| is maximal.
224 void EncodeAndDecodeValuesInRange(uint64_t start,
225 uint64_t range,
226 uint8_t prefix_length,
227 size_t expected_bytes) {
228 const uint8_t prefix_mask = (1 << prefix_length) - 1;
229 const uint64_t beyond = start + range;
230
231 LOG(INFO) << "############################################################";
232 LOG(INFO) << "prefix_length=" << static_cast<int>(prefix_length);
233 LOG(INFO) << "prefix_mask=" << std::hex << static_cast<int>(prefix_mask);
234 LOG(INFO) << "start=" << start << " (" << std::hex << start << ")";
235 LOG(INFO) << "range=" << range << " (" << std::hex << range << ")";
236 LOG(INFO) << "beyond=" << beyond << " (" << std::hex << beyond << ")";
237 LOG(INFO) << "expected_bytes=" << expected_bytes;
238
239 if (expected_bytes < 11) {
240 // Confirm the claim that beyond requires more bytes.
241 Encode(beyond, prefix_length);
242 EXPECT_EQ(expected_bytes + 1, buffer_.size()) << Http2HexDump(buffer_);
243 }
244
245 std::set<uint64_t> values;
246 if (range < 200) {
247 // Select all values in the range.
248 for (uint64_t offset = 0; offset < range; ++offset) {
249 values.insert(start + offset);
250 }
251 } else {
252 // Select some values in this range, including the minimum and maximum
253 // values that require exactly |expected_bytes| extension bytes.
254 values.insert({start, start + 1, beyond - 2, beyond - 1});
255 while (values.size() < 100) {
256 values.insert(Random().UniformInRange(start, beyond - 1));
257 }
258 }
259
260 EncodeAndDecodeValues(values, prefix_length, expected_bytes);
261 }
262
263 // |flag_saver_| must preceed |decoder_| so that the flag is already set when
264 // |decoder_| is constructed.
265 const bool decode_64_bits_;
266 FlagSaver flag_saver_;
267 HpackVarintDecoder decoder_;
268 Http2String buffer_;
269 uint8_t prefix_length_;
270};
271
272INSTANTIATE_TEST_CASE_P(HpackVarintRoundTripTest,
273 HpackVarintRoundTripTest,
274 Bool());
275
276// To help me and future debuggers of varint encodings, this LOGs out the
277// transition points where a new extension byte is added.
278TEST_P(HpackVarintRoundTripTest, Encode) {
QUICHE teamcc663702018-12-17 15:51:59 -0500279 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500280 const uint64_t a = HiValueOfExtensionBytes(0, prefix_length);
281 const uint64_t b = HiValueOfExtensionBytes(1, prefix_length);
282 const uint64_t c = HiValueOfExtensionBytes(2, prefix_length);
283 const uint64_t d = HiValueOfExtensionBytes(3, prefix_length);
284 const uint64_t e = HiValueOfExtensionBytes(4, prefix_length);
285 const uint64_t f = HiValueOfExtensionBytes(5, prefix_length);
286 const uint64_t g = HiValueOfExtensionBytes(6, prefix_length);
287 const uint64_t h = HiValueOfExtensionBytes(7, prefix_length);
288 const uint64_t i = HiValueOfExtensionBytes(8, prefix_length);
289 const uint64_t j = HiValueOfExtensionBytes(9, prefix_length);
290
291 LOG(INFO) << "############################################################";
292 LOG(INFO) << "prefix_length=" << prefix_length << " a=" << a
293 << " b=" << b << " c=" << c << " d=" << d << " e=" << e
294 << " f=" << f << " g=" << g << " h=" << h << " i=" << i
295 << " j=" << j;
296
297 std::vector<uint64_t> values = {
298 0, 1, // Force line break.
299 a - 1, a, a + 1, a + 2, a + 3, // Force line break.
300 b - 1, b, b + 1, b + 2, b + 3, // Force line break.
301 c - 1, c, c + 1, c + 2, c + 3, // Force line break.
302 d - 1, d, d + 1, d + 2, d + 3, // Force line break.
303 e - 1, e, e + 1, e + 2, e + 3 // Force line break.
304 };
305 if (decode_64_bits_) {
306 for (auto value : {
307 f - 1, f, f + 1, f + 2, f + 3, // Force line break.
308 g - 1, g, g + 1, g + 2, g + 3, // Force line break.
309 h - 1, h, h + 1, h + 2, h + 3, // Force line break.
310 i - 1, i, i + 1, i + 2, i + 3, // Force line break.
311 j - 1, j, j + 1, j + 2, j + 3, // Force line break.
312 }) {
313 values.push_back(value);
314 }
315 }
316
317 for (uint64_t value : values) {
318 EncodeNoRandom(value, prefix_length);
319 Http2String dump = Http2HexDump(buffer_);
320 LOG(INFO) << Http2StringPrintf("%10llu %0#18x ", value, value)
321 << Http2HexDump(buffer_).substr(7);
322 }
323 }
324}
325
326TEST_P(HpackVarintRoundTripTest, FromSpec1337) {
327 DecodeBuffer b(Http2StringPiece("\x1f\x9a\x0a"));
328 uint32_t prefix_length = 5;
329 uint8_t p = b.DecodeUInt8();
330 EXPECT_EQ(1u, b.Offset());
331 EXPECT_EQ(DecodeStatus::kDecodeDone, decoder_.Start(p, prefix_length, &b));
332 EXPECT_EQ(3u, b.Offset());
333 EXPECT_EQ(1337u, decoder_.value());
334
335 EncodeNoRandom(1337, prefix_length);
336 EXPECT_EQ(3u, buffer_.size());
337 EXPECT_EQ('\x1f', buffer_[0]);
338 EXPECT_EQ('\x9a', buffer_[1]);
339 EXPECT_EQ('\x0a', buffer_[2]);
340}
341
342// Test all the values that fit into the prefix (one less than the mask).
343TEST_P(HpackVarintRoundTripTest, ValidatePrefixOnly) {
QUICHE teamcc663702018-12-17 15:51:59 -0500344 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500345 const uint8_t prefix_mask = (1 << prefix_length) - 1;
346 EncodeAndDecodeValuesInRange(0, prefix_mask, prefix_length, 1);
347 }
348}
349
350// Test all values that require exactly 1 extension byte.
351TEST_P(HpackVarintRoundTripTest, ValidateOneExtensionByte) {
QUICHE teamcc663702018-12-17 15:51:59 -0500352 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500353 const uint64_t start = HiValueOfExtensionBytes(0, prefix_length) + 1;
354 EncodeAndDecodeValuesInRange(start, 128, prefix_length, 2);
355 }
356}
357
358// Test *some* values that require exactly 2 extension bytes.
359TEST_P(HpackVarintRoundTripTest, ValidateTwoExtensionBytes) {
QUICHE teamcc663702018-12-17 15:51:59 -0500360 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500361 const uint64_t start = HiValueOfExtensionBytes(1, prefix_length) + 1;
362 const uint64_t range = 127 << 7;
363
364 EncodeAndDecodeValuesInRange(start, range, prefix_length, 3);
365 }
366}
367
368// Test *some* values that require 3 extension bytes.
369TEST_P(HpackVarintRoundTripTest, ValidateThreeExtensionBytes) {
QUICHE teamcc663702018-12-17 15:51:59 -0500370 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500371 const uint64_t start = HiValueOfExtensionBytes(2, prefix_length) + 1;
372 const uint64_t range = 127 << 14;
373
374 EncodeAndDecodeValuesInRange(start, range, prefix_length, 4);
375 }
376}
377
378// Test *some* values that require 4 extension bytes.
379TEST_P(HpackVarintRoundTripTest, ValidateFourExtensionBytes) {
QUICHE teamcc663702018-12-17 15:51:59 -0500380 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500381 const uint64_t start = HiValueOfExtensionBytes(3, prefix_length) + 1;
382 const uint64_t range = 127 << 21;
383
384 EncodeAndDecodeValuesInRange(start, range, prefix_length, 5);
385 }
386}
387
388// Test *some* values that require 5 extension bytes.
389TEST_P(HpackVarintRoundTripTest, ValidateFiveExtensionBytes) {
390 if (!decode_64_bits_) {
391 return;
392 }
393
QUICHE teamcc663702018-12-17 15:51:59 -0500394 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500395 const uint64_t start = HiValueOfExtensionBytes(4, prefix_length) + 1;
396 const uint64_t range = 127llu << 28;
397
398 EncodeAndDecodeValuesInRange(start, range, prefix_length, 6);
399 }
400}
401
402// Test *some* values that require 6 extension bytes.
403TEST_P(HpackVarintRoundTripTest, ValidateSixExtensionBytes) {
404 if (!decode_64_bits_) {
405 return;
406 }
407
QUICHE teamcc663702018-12-17 15:51:59 -0500408 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500409 const uint64_t start = HiValueOfExtensionBytes(5, prefix_length) + 1;
410 const uint64_t range = 127llu << 35;
411
412 EncodeAndDecodeValuesInRange(start, range, prefix_length, 7);
413 }
414}
415
416// Test *some* values that require 7 extension bytes.
417TEST_P(HpackVarintRoundTripTest, ValidateSevenExtensionBytes) {
418 if (!decode_64_bits_) {
419 return;
420 }
421
QUICHE teamcc663702018-12-17 15:51:59 -0500422 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500423 const uint64_t start = HiValueOfExtensionBytes(6, prefix_length) + 1;
424 const uint64_t range = 127llu << 42;
425
426 EncodeAndDecodeValuesInRange(start, range, prefix_length, 8);
427 }
428}
429
430// Test *some* values that require 8 extension bytes.
431TEST_P(HpackVarintRoundTripTest, ValidateEightExtensionBytes) {
432 if (!decode_64_bits_) {
433 return;
434 }
435
QUICHE teamcc663702018-12-17 15:51:59 -0500436 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500437 const uint64_t start = HiValueOfExtensionBytes(7, prefix_length) + 1;
438 const uint64_t range = 127llu << 49;
439
440 EncodeAndDecodeValuesInRange(start, range, prefix_length, 9);
441 }
442}
443
444// Test *some* values that require 9 extension bytes.
445TEST_P(HpackVarintRoundTripTest, ValidateNineExtensionBytes) {
446 if (!decode_64_bits_) {
447 return;
448 }
449
QUICHE teamcc663702018-12-17 15:51:59 -0500450 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500451 const uint64_t start = HiValueOfExtensionBytes(8, prefix_length) + 1;
452 const uint64_t range = 127llu << 56;
453
454 EncodeAndDecodeValuesInRange(start, range, prefix_length, 10);
455 }
456}
457
458// Test *some* values that require 10 extension bytes.
459TEST_P(HpackVarintRoundTripTest, ValidateTenExtensionBytes) {
460 if (!decode_64_bits_) {
461 return;
462 }
463
QUICHE teamcc663702018-12-17 15:51:59 -0500464 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500465 const uint64_t start = HiValueOfExtensionBytes(9, prefix_length) + 1;
466 const uint64_t range = std::numeric_limits<uint64_t>::max() - start;
467
468 EncodeAndDecodeValuesInRange(start, range, prefix_length, 11);
469 }
470}
471
472// Test the value one larger than the largest that can be decoded.
473TEST_P(HpackVarintRoundTripTest, ValueTooLarge) {
474 // New implementation can decode any integer that HpackVarintEncoder can
475 // encode.
476 if (decode_64_bits_) {
477 return;
478 }
479
QUICHE teamcc663702018-12-17 15:51:59 -0500480 for (prefix_length_ = 3; prefix_length_ <= 8; ++prefix_length_) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500481 const uint64_t too_large = (1 << 28) + (1 << prefix_length_) - 1;
482 const uint32_t expected_offset = 6;
483 HpackBlockBuilder bb;
484 bb.AppendHighBitsAndVarint(0, prefix_length_, too_large);
485 buffer_ = bb.buffer();
486
487 // The validator is called after each of the several times that the input
488 // DecodeBuffer is decoded, each with a different segmentation of the input.
489 // Validate that decoder_.value() matches the expected value.
490 bool validated = false;
491 Validator validator = [&validated, expected_offset](
492 const DecodeBuffer& db,
493 DecodeStatus status) -> AssertionResult {
494 validated = true;
495 VERIFY_EQ(DecodeStatus::kDecodeError, status);
496 VERIFY_EQ(expected_offset, db.Offset());
497 return AssertionSuccess();
498 };
499
500 // StartDecoding, above, requires the DecodeBuffer be non-empty so that it
501 // can call Start with the prefix byte.
502 bool return_non_zero_on_first = true;
503 DecodeBuffer b(buffer_);
504 EXPECT_TRUE(
505 DecodeAndValidateSeveralWays(&b, return_non_zero_on_first, validator));
506 EXPECT_EQ(expected_offset, b.Offset());
507 EXPECT_TRUE(validated);
508 }
509}
510
511} // namespace
512} // namespace test
513} // namespace http2