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 "quiche/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 <utility>
15 #include <vector>
16
17 #include "absl/strings/str_cat.h"
18 #include "absl/strings/str_format.h"
19 #include "absl/strings/string_view.h"
20 #include "quiche/http2/test_tools/hpack_block_builder.h"
21 #include "quiche/http2/test_tools/random_decoder_test_base.h"
22 #include "quiche/common/platform/api/quiche_logging.h"
23 #include "quiche/common/platform/api/quiche_test.h"
24 #include "quiche/common/quiche_text_utils.h"
25
26 using ::testing::AssertionFailure;
27 using ::testing::AssertionSuccess;
28
29 namespace http2 {
30 namespace test {
31 namespace {
32
33 // Returns the highest value with the specified number of extension bytes
34 // and the specified prefix length (bits).
HiValueOfExtensionBytes(uint32_t extension_bytes,uint32_t prefix_length)35 uint64_t HiValueOfExtensionBytes(uint32_t extension_bytes,
36 uint32_t prefix_length) {
37 return (1 << prefix_length) - 2 +
38 (extension_bytes == 0 ? 0 : (1LLU << (extension_bytes * 7)));
39 }
40
41 class HpackVarintRoundTripTest : public RandomDecoderTest {
42 protected:
HpackVarintRoundTripTest()43 HpackVarintRoundTripTest() : prefix_length_(0) {}
44
StartDecoding(DecodeBuffer * b)45 DecodeStatus StartDecoding(DecodeBuffer* b) override {
46 QUICHE_CHECK_LT(0u, b->Remaining());
47 uint8_t prefix = b->DecodeUInt8();
48 return decoder_.Start(prefix, prefix_length_, b);
49 }
50
ResumeDecoding(DecodeBuffer * b)51 DecodeStatus ResumeDecoding(DecodeBuffer* b) override {
52 return decoder_.Resume(b);
53 }
54
DecodeSeveralWays(uint64_t expected_value,uint32_t expected_offset)55 void DecodeSeveralWays(uint64_t expected_value, uint32_t expected_offset) {
56 // The validator is called after each of the several times that the input
57 // DecodeBuffer is decoded, each with a different segmentation of the input.
58 // Validate that decoder_.value() matches the expected value.
59 Validator validator = [expected_value, this](
60 const DecodeBuffer& /*db*/,
61 DecodeStatus /*status*/) -> AssertionResult {
62 if (decoder_.value() != expected_value) {
63 return AssertionFailure()
64 << "Value doesn't match expected: " << decoder_.value()
65 << " != " << expected_value;
66 }
67 return AssertionSuccess();
68 };
69
70 // First validate that decoding is done and that we've advanced the cursor
71 // the expected amount.
72 validator = ValidateDoneAndOffset(expected_offset, std::move(validator));
73
74 // StartDecoding, above, requires the DecodeBuffer be non-empty so that it
75 // can call Start with the prefix byte.
76 bool return_non_zero_on_first = true;
77
78 DecodeBuffer b(buffer_);
79 EXPECT_TRUE(
80 DecodeAndValidateSeveralWays(&b, return_non_zero_on_first, validator));
81
82 EXPECT_EQ(expected_value, decoder_.value());
83 EXPECT_EQ(expected_offset, b.Offset());
84 }
85
EncodeNoRandom(uint64_t value,uint8_t prefix_length)86 void EncodeNoRandom(uint64_t value, uint8_t prefix_length) {
87 QUICHE_DCHECK_LE(3, prefix_length);
88 QUICHE_DCHECK_LE(prefix_length, 8);
89 prefix_length_ = prefix_length;
90
91 HpackBlockBuilder bb;
92 bb.AppendHighBitsAndVarint(0, prefix_length_, value);
93 buffer_ = bb.buffer();
94 ASSERT_LT(0u, buffer_.size());
95
96 const uint8_t prefix_mask = (1 << prefix_length_) - 1;
97 ASSERT_EQ(static_cast<uint8_t>(buffer_[0]),
98 static_cast<uint8_t>(buffer_[0]) & prefix_mask);
99 }
100
Encode(uint64_t value,uint8_t prefix_length)101 void Encode(uint64_t value, uint8_t prefix_length) {
102 EncodeNoRandom(value, prefix_length);
103 // Add some random bits to the prefix (the first byte) above the mask.
104 uint8_t prefix = buffer_[0];
105 buffer_[0] = prefix | (Random().Rand8() << prefix_length);
106 const uint8_t prefix_mask = (1 << prefix_length_) - 1;
107 ASSERT_EQ(prefix, buffer_[0] & prefix_mask);
108 }
109
110 // This is really a test of HpackBlockBuilder, making sure that the input to
111 // HpackVarintDecoder is as expected, which also acts as confirmation that
112 // my thinking about the encodings being used by the tests, i.e. cover the
113 // range desired.
ValidateEncoding(uint64_t value,uint64_t minimum,uint64_t maximum,size_t expected_bytes)114 void ValidateEncoding(uint64_t value, uint64_t minimum, uint64_t maximum,
115 size_t expected_bytes) {
116 ASSERT_EQ(expected_bytes, buffer_.size());
117 if (expected_bytes > 1) {
118 const uint8_t prefix_mask = (1 << prefix_length_) - 1;
119 EXPECT_EQ(prefix_mask, buffer_[0] & prefix_mask);
120 size_t last = expected_bytes - 1;
121 for (size_t ndx = 1; ndx < last; ++ndx) {
122 // Before the last extension byte, we expect the high-bit set.
123 uint8_t byte = buffer_[ndx];
124 if (value == minimum) {
125 EXPECT_EQ(0x80, byte) << "ndx=" << ndx;
126 } else if (value == maximum) {
127 if (expected_bytes < 11) {
128 EXPECT_EQ(0xff, byte) << "ndx=" << ndx;
129 }
130 } else {
131 EXPECT_EQ(0x80, byte & 0x80) << "ndx=" << ndx;
132 }
133 }
134 // The last extension byte should not have the high-bit set.
135 uint8_t byte = buffer_[last];
136 if (value == minimum) {
137 if (expected_bytes == 2) {
138 EXPECT_EQ(0x00, byte);
139 } else {
140 EXPECT_EQ(0x01, byte);
141 }
142 } else if (value == maximum) {
143 if (expected_bytes < 11) {
144 EXPECT_EQ(0x7f, byte);
145 }
146 } else {
147 EXPECT_EQ(0x00, byte & 0x80);
148 }
149 } else {
150 const uint8_t prefix_mask = (1 << prefix_length_) - 1;
151 EXPECT_EQ(value, static_cast<uint32_t>(buffer_[0] & prefix_mask));
152 EXPECT_LT(value, prefix_mask);
153 }
154 }
155
EncodeAndDecodeValues(const std::set<uint64_t> & values,uint8_t prefix_length,size_t expected_bytes)156 void EncodeAndDecodeValues(const std::set<uint64_t>& values,
157 uint8_t prefix_length, size_t expected_bytes) {
158 QUICHE_CHECK(!values.empty());
159 const uint64_t minimum = *values.begin();
160 const uint64_t maximum = *values.rbegin();
161 for (const uint64_t value : values) {
162 Encode(value, prefix_length); // Sets buffer_.
163
164 std::string msg = absl::StrCat("value=", value, " (0x", absl::Hex(value),
165 "), prefix_length=", prefix_length,
166 ", expected_bytes=", expected_bytes, "\n",
167 quiche::QuicheTextUtils::HexDump(buffer_));
168
169 if (value == minimum) {
170 QUICHE_LOG(INFO) << "Checking minimum; " << msg;
171 } else if (value == maximum) {
172 QUICHE_LOG(INFO) << "Checking maximum; " << msg;
173 }
174
175 SCOPED_TRACE(msg);
176 ValidateEncoding(value, minimum, maximum, expected_bytes);
177 DecodeSeveralWays(value, expected_bytes);
178
179 // Append some random data to the end of buffer_ and repeat. That random
180 // data should be ignored.
181 buffer_.append(Random().RandString(1 + Random().Uniform(10)));
182 DecodeSeveralWays(value, expected_bytes);
183
184 // If possible, add extension bytes that don't change the value.
185 if (1 < expected_bytes) {
186 buffer_.resize(expected_bytes);
187 for (uint8_t total_bytes = expected_bytes + 1; total_bytes <= 6;
188 ++total_bytes) {
189 // Mark the current last byte as not being the last one.
190 EXPECT_EQ(0x00, 0x80 & buffer_.back());
191 buffer_.back() |= 0x80;
192 buffer_.push_back('\0');
193 DecodeSeveralWays(value, total_bytes);
194 }
195 }
196 }
197 }
198
199 // Encode values (all or some of it) in [start, start+range). Check
200 // that |start| is the smallest value and |start+range-1| is the largest value
201 // corresponding to |expected_bytes|, except if |expected_bytes| is maximal.
EncodeAndDecodeValuesInRange(uint64_t start,uint64_t range,uint8_t prefix_length,size_t expected_bytes)202 void EncodeAndDecodeValuesInRange(uint64_t start, uint64_t range,
203 uint8_t prefix_length,
204 size_t expected_bytes) {
205 const uint8_t prefix_mask = (1 << prefix_length) - 1;
206 const uint64_t beyond = start + range;
207
208 QUICHE_LOG(INFO)
209 << "############################################################";
210 QUICHE_LOG(INFO) << "prefix_length=" << static_cast<int>(prefix_length);
211 QUICHE_LOG(INFO) << "prefix_mask=" << std::hex
212 << static_cast<int>(prefix_mask);
213 QUICHE_LOG(INFO) << "start=" << start << " (" << std::hex << start << ")";
214 QUICHE_LOG(INFO) << "range=" << range << " (" << std::hex << range << ")";
215 QUICHE_LOG(INFO) << "beyond=" << beyond << " (" << std::hex << beyond
216 << ")";
217 QUICHE_LOG(INFO) << "expected_bytes=" << expected_bytes;
218
219 if (expected_bytes < 11) {
220 // Confirm the claim that beyond requires more bytes.
221 Encode(beyond, prefix_length);
222 EXPECT_EQ(expected_bytes + 1, buffer_.size())
223 << quiche::QuicheTextUtils::HexDump(buffer_);
224 }
225
226 std::set<uint64_t> values;
227 if (range < 200) {
228 // Select all values in the range.
229 for (uint64_t offset = 0; offset < range; ++offset) {
230 values.insert(start + offset);
231 }
232 } else {
233 // Select some values in this range, including the minimum and maximum
234 // values that require exactly |expected_bytes| extension bytes.
235 values.insert({start, start + 1, beyond - 2, beyond - 1});
236 while (values.size() < 100) {
237 values.insert(Random().UniformInRange(start, beyond - 1));
238 }
239 }
240
241 EncodeAndDecodeValues(values, prefix_length, expected_bytes);
242 }
243
244 HpackVarintDecoder decoder_;
245 std::string buffer_;
246 uint8_t prefix_length_;
247 };
248
249 // To help me and future debuggers of varint encodings, this HTTP2_LOGs out the
250 // transition points where a new extension byte is added.
TEST_F(HpackVarintRoundTripTest,Encode)251 TEST_F(HpackVarintRoundTripTest, Encode) {
252 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
253 const uint64_t a = HiValueOfExtensionBytes(0, prefix_length);
254 const uint64_t b = HiValueOfExtensionBytes(1, prefix_length);
255 const uint64_t c = HiValueOfExtensionBytes(2, prefix_length);
256 const uint64_t d = HiValueOfExtensionBytes(3, prefix_length);
257 const uint64_t e = HiValueOfExtensionBytes(4, prefix_length);
258 const uint64_t f = HiValueOfExtensionBytes(5, prefix_length);
259 const uint64_t g = HiValueOfExtensionBytes(6, prefix_length);
260 const uint64_t h = HiValueOfExtensionBytes(7, prefix_length);
261 const uint64_t i = HiValueOfExtensionBytes(8, prefix_length);
262 const uint64_t j = HiValueOfExtensionBytes(9, prefix_length);
263
264 QUICHE_LOG(INFO)
265 << "############################################################";
266 QUICHE_LOG(INFO) << "prefix_length=" << prefix_length << " a=" << a
267 << " b=" << b << " c=" << c << " d=" << d
268 << " e=" << e << " f=" << f << " g=" << g
269 << " h=" << h << " i=" << i << " j=" << j;
270
271 std::vector<uint64_t> values = {
272 0, 1, // Force line break.
273 a - 1, a, a + 1, a + 2, a + 3, // Force line break.
274 b - 1, b, b + 1, b + 2, b + 3, // Force line break.
275 c - 1, c, c + 1, c + 2, c + 3, // Force line break.
276 d - 1, d, d + 1, d + 2, d + 3, // Force line break.
277 e - 1, e, e + 1, e + 2, e + 3, // Force line break.
278 f - 1, f, f + 1, f + 2, f + 3, // Force line break.
279 g - 1, g, g + 1, g + 2, g + 3, // Force line break.
280 h - 1, h, h + 1, h + 2, h + 3, // Force line break.
281 i - 1, i, i + 1, i + 2, i + 3, // Force line break.
282 j - 1, j, j + 1, j + 2, j + 3, // Force line break.
283 };
284
285 for (uint64_t value : values) {
286 EncodeNoRandom(value, prefix_length);
287 std::string dump = quiche::QuicheTextUtils::HexDump(buffer_);
288 QUICHE_LOG(INFO) << absl::StrFormat("%10llu %0#18x ", value, value)
289 << quiche::QuicheTextUtils::HexDump(buffer_).substr(7);
290 }
291 }
292 }
293
TEST_F(HpackVarintRoundTripTest,FromSpec1337)294 TEST_F(HpackVarintRoundTripTest, FromSpec1337) {
295 DecodeBuffer b(absl::string_view("\x1f\x9a\x0a"));
296 uint32_t prefix_length = 5;
297 uint8_t p = b.DecodeUInt8();
298 EXPECT_EQ(1u, b.Offset());
299 EXPECT_EQ(DecodeStatus::kDecodeDone, decoder_.Start(p, prefix_length, &b));
300 EXPECT_EQ(3u, b.Offset());
301 EXPECT_EQ(1337u, decoder_.value());
302
303 EncodeNoRandom(1337, prefix_length);
304 EXPECT_EQ(3u, buffer_.size());
305 EXPECT_EQ('\x1f', buffer_[0]);
306 EXPECT_EQ('\x9a', buffer_[1]);
307 EXPECT_EQ('\x0a', buffer_[2]);
308 }
309
310 // Test all the values that fit into the prefix (one less than the mask).
TEST_F(HpackVarintRoundTripTest,ValidatePrefixOnly)311 TEST_F(HpackVarintRoundTripTest, ValidatePrefixOnly) {
312 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
313 const uint8_t prefix_mask = (1 << prefix_length) - 1;
314 EncodeAndDecodeValuesInRange(0, prefix_mask, prefix_length, 1);
315 }
316 }
317
318 // Test all values that require exactly 1 extension byte.
TEST_F(HpackVarintRoundTripTest,ValidateOneExtensionByte)319 TEST_F(HpackVarintRoundTripTest, ValidateOneExtensionByte) {
320 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
321 const uint64_t start = HiValueOfExtensionBytes(0, prefix_length) + 1;
322 EncodeAndDecodeValuesInRange(start, 128, prefix_length, 2);
323 }
324 }
325
326 // Test *some* values that require exactly 2 extension bytes.
TEST_F(HpackVarintRoundTripTest,ValidateTwoExtensionBytes)327 TEST_F(HpackVarintRoundTripTest, ValidateTwoExtensionBytes) {
328 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
329 const uint64_t start = HiValueOfExtensionBytes(1, prefix_length) + 1;
330 const uint64_t range = 127 << 7;
331
332 EncodeAndDecodeValuesInRange(start, range, prefix_length, 3);
333 }
334 }
335
336 // Test *some* values that require 3 extension bytes.
TEST_F(HpackVarintRoundTripTest,ValidateThreeExtensionBytes)337 TEST_F(HpackVarintRoundTripTest, ValidateThreeExtensionBytes) {
338 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
339 const uint64_t start = HiValueOfExtensionBytes(2, prefix_length) + 1;
340 const uint64_t range = 127 << 14;
341
342 EncodeAndDecodeValuesInRange(start, range, prefix_length, 4);
343 }
344 }
345
346 // Test *some* values that require 4 extension bytes.
TEST_F(HpackVarintRoundTripTest,ValidateFourExtensionBytes)347 TEST_F(HpackVarintRoundTripTest, ValidateFourExtensionBytes) {
348 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
349 const uint64_t start = HiValueOfExtensionBytes(3, prefix_length) + 1;
350 const uint64_t range = 127 << 21;
351
352 EncodeAndDecodeValuesInRange(start, range, prefix_length, 5);
353 }
354 }
355
356 // Test *some* values that require 5 extension bytes.
TEST_F(HpackVarintRoundTripTest,ValidateFiveExtensionBytes)357 TEST_F(HpackVarintRoundTripTest, ValidateFiveExtensionBytes) {
358 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
359 const uint64_t start = HiValueOfExtensionBytes(4, prefix_length) + 1;
360 const uint64_t range = 127llu << 28;
361
362 EncodeAndDecodeValuesInRange(start, range, prefix_length, 6);
363 }
364 }
365
366 // Test *some* values that require 6 extension bytes.
TEST_F(HpackVarintRoundTripTest,ValidateSixExtensionBytes)367 TEST_F(HpackVarintRoundTripTest, ValidateSixExtensionBytes) {
368 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
369 const uint64_t start = HiValueOfExtensionBytes(5, prefix_length) + 1;
370 const uint64_t range = 127llu << 35;
371
372 EncodeAndDecodeValuesInRange(start, range, prefix_length, 7);
373 }
374 }
375
376 // Test *some* values that require 7 extension bytes.
TEST_F(HpackVarintRoundTripTest,ValidateSevenExtensionBytes)377 TEST_F(HpackVarintRoundTripTest, ValidateSevenExtensionBytes) {
378 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
379 const uint64_t start = HiValueOfExtensionBytes(6, prefix_length) + 1;
380 const uint64_t range = 127llu << 42;
381
382 EncodeAndDecodeValuesInRange(start, range, prefix_length, 8);
383 }
384 }
385
386 // Test *some* values that require 8 extension bytes.
TEST_F(HpackVarintRoundTripTest,ValidateEightExtensionBytes)387 TEST_F(HpackVarintRoundTripTest, ValidateEightExtensionBytes) {
388 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
389 const uint64_t start = HiValueOfExtensionBytes(7, prefix_length) + 1;
390 const uint64_t range = 127llu << 49;
391
392 EncodeAndDecodeValuesInRange(start, range, prefix_length, 9);
393 }
394 }
395
396 // Test *some* values that require 9 extension bytes.
TEST_F(HpackVarintRoundTripTest,ValidateNineExtensionBytes)397 TEST_F(HpackVarintRoundTripTest, ValidateNineExtensionBytes) {
398 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
399 const uint64_t start = HiValueOfExtensionBytes(8, prefix_length) + 1;
400 const uint64_t range = 127llu << 56;
401
402 EncodeAndDecodeValuesInRange(start, range, prefix_length, 10);
403 }
404 }
405
406 // Test *some* values that require 10 extension bytes.
TEST_F(HpackVarintRoundTripTest,ValidateTenExtensionBytes)407 TEST_F(HpackVarintRoundTripTest, ValidateTenExtensionBytes) {
408 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
409 const uint64_t start = HiValueOfExtensionBytes(9, prefix_length) + 1;
410 const uint64_t range = std::numeric_limits<uint64_t>::max() - start;
411
412 EncodeAndDecodeValuesInRange(start, range, prefix_length, 11);
413 }
414 }
415
416 } // namespace
417 } // namespace test
418 } // namespace http2
419