blob: 59473a7cd8b1a4f2820e5dd2c4ed69d3befb4f04 [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
QUICHE teamfd50a402018-12-07 22:54:05 -050016#include "testing/gtest/include/gtest/gtest.h"
17#include "net/third_party/quiche/src/http2/hpack/tools/hpack_block_builder.h"
QUICHE team61940b42019-03-07 23:32:27 -050018#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
QUICHE teamfd50a402018-12-07 22:54:05 -050019#include "net/third_party/quiche/src/http2/platform/api/http2_string_utils.h"
20#include "net/third_party/quiche/src/http2/tools/random_decoder_test.h"
bnc252403d2020-01-15 08:39:53 -080021#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
bnc74646d12019-12-13 09:21:19 -080022#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
QUICHE teamfd50a402018-12-07 22:54:05 -050023
24using ::testing::AssertionFailure;
25using ::testing::AssertionSuccess;
QUICHE teamfd50a402018-12-07 22:54:05 -050026
27namespace http2 {
28namespace test {
29namespace {
30
QUICHE teamfd50a402018-12-07 22:54:05 -050031// Returns the highest value with the specified number of extension bytes
32// and the specified prefix length (bits).
33uint64_t HiValueOfExtensionBytes(uint32_t extension_bytes,
34 uint32_t prefix_length) {
35 return (1 << prefix_length) - 2 +
36 (extension_bytes == 0 ? 0 : (1LLU << (extension_bytes * 7)));
37}
38
bnce72b8872019-01-22 19:59:50 -050039class HpackVarintRoundTripTest : public RandomDecoderTest {
QUICHE teamfd50a402018-12-07 22:54:05 -050040 protected:
bnce72b8872019-01-22 19:59:50 -050041 HpackVarintRoundTripTest() : prefix_length_(0) {}
QUICHE teamfd50a402018-12-07 22:54:05 -050042
43 DecodeStatus StartDecoding(DecodeBuffer* b) override {
44 CHECK_LT(0u, b->Remaining());
45 uint8_t prefix = b->DecodeUInt8();
46 return decoder_.Start(prefix, prefix_length_, b);
47 }
48
49 DecodeStatus ResumeDecoding(DecodeBuffer* b) override {
50 return decoder_.Resume(b);
51 }
52
53 void DecodeSeveralWays(uint64_t expected_value, uint32_t expected_offset) {
54 // The validator is called after each of the several times that the input
55 // DecodeBuffer is decoded, each with a different segmentation of the input.
56 // Validate that decoder_.value() matches the expected value.
57 Validator validator = [expected_value, this](
58 const DecodeBuffer& db,
59 DecodeStatus status) -> AssertionResult {
60 if (decoder_.value() != expected_value) {
61 return AssertionFailure()
62 << "Value doesn't match expected: " << decoder_.value()
63 << " != " << expected_value;
64 }
65 return AssertionSuccess();
66 };
67
68 // First validate that decoding is done and that we've advanced the cursor
69 // the expected amount.
70 validator = ValidateDoneAndOffset(expected_offset, validator);
71
72 // StartDecoding, above, requires the DecodeBuffer be non-empty so that it
73 // can call Start with the prefix byte.
74 bool return_non_zero_on_first = true;
75
76 DecodeBuffer b(buffer_);
77 EXPECT_TRUE(
78 DecodeAndValidateSeveralWays(&b, return_non_zero_on_first, validator));
79
80 EXPECT_EQ(expected_value, decoder_.value());
81 EXPECT_EQ(expected_offset, b.Offset());
82 }
83
84 void EncodeNoRandom(uint64_t value, uint8_t prefix_length) {
85 DCHECK_LE(3, prefix_length);
QUICHE teamcc663702018-12-17 15:51:59 -050086 DCHECK_LE(prefix_length, 8);
QUICHE teamfd50a402018-12-07 22:54:05 -050087 prefix_length_ = prefix_length;
88
89 HpackBlockBuilder bb;
90 bb.AppendHighBitsAndVarint(0, prefix_length_, value);
91 buffer_ = bb.buffer();
92 ASSERT_LT(0u, buffer_.size());
93
94 const uint8_t prefix_mask = (1 << prefix_length_) - 1;
bnc23346472018-12-27 21:57:05 -050095 ASSERT_EQ(static_cast<uint8_t>(buffer_[0]),
96 static_cast<uint8_t>(buffer_[0]) & prefix_mask);
QUICHE teamfd50a402018-12-07 22:54:05 -050097 }
98
99 void Encode(uint64_t value, uint8_t prefix_length) {
100 EncodeNoRandom(value, prefix_length);
101 // Add some random bits to the prefix (the first byte) above the mask.
102 uint8_t prefix = buffer_[0];
103 buffer_[0] = prefix | (Random().Rand8() << prefix_length);
104 const uint8_t prefix_mask = (1 << prefix_length_) - 1;
105 ASSERT_EQ(prefix, buffer_[0] & prefix_mask);
106 }
107
108 // This is really a test of HpackBlockBuilder, making sure that the input to
109 // HpackVarintDecoder is as expected, which also acts as confirmation that
110 // my thinking about the encodings being used by the tests, i.e. cover the
111 // range desired.
112 void ValidateEncoding(uint64_t value,
113 uint64_t minimum,
114 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
156 void EncodeAndDecodeValues(const std::set<uint64_t>& values,
157 uint8_t prefix_length,
158 size_t expected_bytes) {
159 CHECK(!values.empty());
160 const uint64_t minimum = *values.begin();
161 const uint64_t maximum = *values.rbegin();
162 for (const uint64_t value : values) {
163 Encode(value, prefix_length); // Sets buffer_.
164
bnc252403d2020-01-15 08:39:53 -0800165 std::string msg = quiche::QuicheStrCat(
166 "value=", value, " (0x", Http2Hex(value),
167 "), prefix_length=", prefix_length,
168 ", expected_bytes=", expected_bytes, "\n", Http2HexDump(buffer_));
QUICHE teamfd50a402018-12-07 22:54:05 -0500169
170 if (value == minimum) {
QUICHE team61940b42019-03-07 23:32:27 -0500171 HTTP2_LOG(INFO) << "Checking minimum; " << msg;
QUICHE teamfd50a402018-12-07 22:54:05 -0500172 } else if (value == maximum) {
QUICHE team61940b42019-03-07 23:32:27 -0500173 HTTP2_LOG(INFO) << "Checking maximum; " << msg;
QUICHE teamfd50a402018-12-07 22:54:05 -0500174 }
175
176 SCOPED_TRACE(msg);
177 ValidateEncoding(value, minimum, maximum, expected_bytes);
178 DecodeSeveralWays(value, expected_bytes);
179
180 // Append some random data to the end of buffer_ and repeat. That random
181 // data should be ignored.
182 buffer_.append(Random().RandString(1 + Random().Uniform(10)));
183 DecodeSeveralWays(value, expected_bytes);
184
185 // If possible, add extension bytes that don't change the value.
186 if (1 < expected_bytes) {
187 buffer_.resize(expected_bytes);
188 for (uint8_t total_bytes = expected_bytes + 1; total_bytes <= 6;
189 ++total_bytes) {
190 // Mark the current last byte as not being the last one.
191 EXPECT_EQ(0x00, 0x80 & buffer_.back());
192 buffer_.back() |= 0x80;
193 buffer_.push_back('\0');
194 DecodeSeveralWays(value, total_bytes);
195 }
196 }
197 }
198 }
199
200 // Encode values (all or some of it) in [start, start+range). Check
201 // that |start| is the smallest value and |start+range-1| is the largest value
202 // corresponding to |expected_bytes|, except if |expected_bytes| is maximal.
203 void EncodeAndDecodeValuesInRange(uint64_t start,
204 uint64_t range,
205 uint8_t prefix_length,
206 size_t expected_bytes) {
207 const uint8_t prefix_mask = (1 << prefix_length) - 1;
208 const uint64_t beyond = start + range;
209
QUICHE team61940b42019-03-07 23:32:27 -0500210 HTTP2_LOG(INFO)
211 << "############################################################";
212 HTTP2_LOG(INFO) << "prefix_length=" << static_cast<int>(prefix_length);
213 HTTP2_LOG(INFO) << "prefix_mask=" << std::hex
214 << static_cast<int>(prefix_mask);
215 HTTP2_LOG(INFO) << "start=" << start << " (" << std::hex << start << ")";
216 HTTP2_LOG(INFO) << "range=" << range << " (" << std::hex << range << ")";
217 HTTP2_LOG(INFO) << "beyond=" << beyond << " (" << std::hex << beyond << ")";
218 HTTP2_LOG(INFO) << "expected_bytes=" << expected_bytes;
QUICHE teamfd50a402018-12-07 22:54:05 -0500219
220 if (expected_bytes < 11) {
221 // Confirm the claim that beyond requires more bytes.
222 Encode(beyond, prefix_length);
223 EXPECT_EQ(expected_bytes + 1, buffer_.size()) << Http2HexDump(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
QUICHE teamfd50a402018-12-07 22:54:05 -0500244 HpackVarintDecoder decoder_;
bnc47904002019-08-16 11:49:48 -0700245 std::string buffer_;
QUICHE teamfd50a402018-12-07 22:54:05 -0500246 uint8_t prefix_length_;
247};
248
QUICHE team61940b42019-03-07 23:32:27 -0500249// To help me and future debuggers of varint encodings, this HTTP2_LOGs out the
QUICHE teamfd50a402018-12-07 22:54:05 -0500250// transition points where a new extension byte is added.
bnce72b8872019-01-22 19:59:50 -0500251TEST_F(HpackVarintRoundTripTest, Encode) {
QUICHE teamcc663702018-12-17 15:51:59 -0500252 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500253 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
QUICHE team61940b42019-03-07 23:32:27 -0500264 HTTP2_LOG(INFO)
265 << "############################################################";
266 HTTP2_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;
QUICHE teamfd50a402018-12-07 22:54:05 -0500270
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.
bnce72b8872019-01-22 19:59:50 -0500277 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.
QUICHE teamfd50a402018-12-07 22:54:05 -0500283 };
QUICHE teamfd50a402018-12-07 22:54:05 -0500284
285 for (uint64_t value : values) {
286 EncodeNoRandom(value, prefix_length);
bnc47904002019-08-16 11:49:48 -0700287 std::string dump = Http2HexDump(buffer_);
QUICHE team61940b42019-03-07 23:32:27 -0500288 HTTP2_LOG(INFO) << Http2StringPrintf("%10llu %0#18x ", value, value)
289 << Http2HexDump(buffer_).substr(7);
QUICHE teamfd50a402018-12-07 22:54:05 -0500290 }
291 }
292}
293
bnce72b8872019-01-22 19:59:50 -0500294TEST_F(HpackVarintRoundTripTest, FromSpec1337) {
bnc74646d12019-12-13 09:21:19 -0800295 DecodeBuffer b(quiche::QuicheStringPiece("\x1f\x9a\x0a"));
QUICHE teamfd50a402018-12-07 22:54:05 -0500296 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).
bnce72b8872019-01-22 19:59:50 -0500311TEST_F(HpackVarintRoundTripTest, ValidatePrefixOnly) {
QUICHE teamcc663702018-12-17 15:51:59 -0500312 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500313 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.
bnce72b8872019-01-22 19:59:50 -0500319TEST_F(HpackVarintRoundTripTest, ValidateOneExtensionByte) {
QUICHE teamcc663702018-12-17 15:51:59 -0500320 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500321 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.
bnce72b8872019-01-22 19:59:50 -0500327TEST_F(HpackVarintRoundTripTest, ValidateTwoExtensionBytes) {
QUICHE teamcc663702018-12-17 15:51:59 -0500328 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500329 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.
bnce72b8872019-01-22 19:59:50 -0500337TEST_F(HpackVarintRoundTripTest, ValidateThreeExtensionBytes) {
QUICHE teamcc663702018-12-17 15:51:59 -0500338 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500339 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.
bnce72b8872019-01-22 19:59:50 -0500347TEST_F(HpackVarintRoundTripTest, ValidateFourExtensionBytes) {
QUICHE teamcc663702018-12-17 15:51:59 -0500348 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500349 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.
bnce72b8872019-01-22 19:59:50 -0500357TEST_F(HpackVarintRoundTripTest, ValidateFiveExtensionBytes) {
QUICHE teamcc663702018-12-17 15:51:59 -0500358 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500359 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.
bnce72b8872019-01-22 19:59:50 -0500367TEST_F(HpackVarintRoundTripTest, ValidateSixExtensionBytes) {
QUICHE teamcc663702018-12-17 15:51:59 -0500368 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500369 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.
bnce72b8872019-01-22 19:59:50 -0500377TEST_F(HpackVarintRoundTripTest, ValidateSevenExtensionBytes) {
QUICHE teamcc663702018-12-17 15:51:59 -0500378 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500379 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.
bnce72b8872019-01-22 19:59:50 -0500387TEST_F(HpackVarintRoundTripTest, ValidateEightExtensionBytes) {
QUICHE teamcc663702018-12-17 15:51:59 -0500388 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500389 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.
bnce72b8872019-01-22 19:59:50 -0500397TEST_F(HpackVarintRoundTripTest, ValidateNineExtensionBytes) {
QUICHE teamcc663702018-12-17 15:51:59 -0500398 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500399 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.
bnce72b8872019-01-22 19:59:50 -0500407TEST_F(HpackVarintRoundTripTest, ValidateTenExtensionBytes) {
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(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
QUICHE teamfd50a402018-12-07 22:54:05 -0500416} // namespace
417} // namespace test
418} // namespace http2