blob: a5318fb99493aa67f7b84c969da0656a26787060 [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_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;
QUICHE teamfd50a402018-12-07 22:54:05 -050025
26namespace http2 {
27namespace test {
28namespace {
29
QUICHE teamfd50a402018-12-07 22:54:05 -050030// Returns the highest value with the specified number of extension bytes
31// and the specified prefix length (bits).
32uint64_t HiValueOfExtensionBytes(uint32_t extension_bytes,
33 uint32_t prefix_length) {
34 return (1 << prefix_length) - 2 +
35 (extension_bytes == 0 ? 0 : (1LLU << (extension_bytes * 7)));
36}
37
bnce72b8872019-01-22 19:59:50 -050038class HpackVarintRoundTripTest : public RandomDecoderTest {
QUICHE teamfd50a402018-12-07 22:54:05 -050039 protected:
bnce72b8872019-01-22 19:59:50 -050040 HpackVarintRoundTripTest() : prefix_length_(0) {}
QUICHE teamfd50a402018-12-07 22:54:05 -050041
42 DecodeStatus StartDecoding(DecodeBuffer* b) override {
43 CHECK_LT(0u, b->Remaining());
44 uint8_t prefix = b->DecodeUInt8();
45 return decoder_.Start(prefix, prefix_length_, b);
46 }
47
48 DecodeStatus ResumeDecoding(DecodeBuffer* b) override {
49 return decoder_.Resume(b);
50 }
51
52 void DecodeSeveralWays(uint64_t expected_value, uint32_t expected_offset) {
53 // The validator is called after each of the several times that the input
54 // DecodeBuffer is decoded, each with a different segmentation of the input.
55 // Validate that decoder_.value() matches the expected value.
56 Validator validator = [expected_value, this](
57 const DecodeBuffer& db,
58 DecodeStatus status) -> AssertionResult {
59 if (decoder_.value() != expected_value) {
60 return AssertionFailure()
61 << "Value doesn't match expected: " << decoder_.value()
62 << " != " << expected_value;
63 }
64 return AssertionSuccess();
65 };
66
67 // First validate that decoding is done and that we've advanced the cursor
68 // the expected amount.
69 validator = ValidateDoneAndOffset(expected_offset, validator);
70
71 // StartDecoding, above, requires the DecodeBuffer be non-empty so that it
72 // can call Start with the prefix byte.
73 bool return_non_zero_on_first = true;
74
75 DecodeBuffer b(buffer_);
76 EXPECT_TRUE(
77 DecodeAndValidateSeveralWays(&b, return_non_zero_on_first, validator));
78
79 EXPECT_EQ(expected_value, decoder_.value());
80 EXPECT_EQ(expected_offset, b.Offset());
81 }
82
83 void EncodeNoRandom(uint64_t value, uint8_t prefix_length) {
84 DCHECK_LE(3, prefix_length);
QUICHE teamcc663702018-12-17 15:51:59 -050085 DCHECK_LE(prefix_length, 8);
QUICHE teamfd50a402018-12-07 22:54:05 -050086 prefix_length_ = prefix_length;
87
88 HpackBlockBuilder bb;
89 bb.AppendHighBitsAndVarint(0, prefix_length_, value);
90 buffer_ = bb.buffer();
91 ASSERT_LT(0u, buffer_.size());
92
93 const uint8_t prefix_mask = (1 << prefix_length_) - 1;
bnc23346472018-12-27 21:57:05 -050094 ASSERT_EQ(static_cast<uint8_t>(buffer_[0]),
95 static_cast<uint8_t>(buffer_[0]) & prefix_mask);
QUICHE teamfd50a402018-12-07 22:54:05 -050096 }
97
98 void Encode(uint64_t value, uint8_t prefix_length) {
99 EncodeNoRandom(value, prefix_length);
100 // Add some random bits to the prefix (the first byte) above the mask.
101 uint8_t prefix = buffer_[0];
102 buffer_[0] = prefix | (Random().Rand8() << prefix_length);
103 const uint8_t prefix_mask = (1 << prefix_length_) - 1;
104 ASSERT_EQ(prefix, buffer_[0] & prefix_mask);
105 }
106
107 // This is really a test of HpackBlockBuilder, making sure that the input to
108 // HpackVarintDecoder is as expected, which also acts as confirmation that
109 // my thinking about the encodings being used by the tests, i.e. cover the
110 // range desired.
111 void ValidateEncoding(uint64_t value,
112 uint64_t minimum,
113 uint64_t maximum,
114 size_t expected_bytes) {
115 ASSERT_EQ(expected_bytes, buffer_.size());
116 if (expected_bytes > 1) {
117 const uint8_t prefix_mask = (1 << prefix_length_) - 1;
118 EXPECT_EQ(prefix_mask, buffer_[0] & prefix_mask);
119 size_t last = expected_bytes - 1;
120 for (size_t ndx = 1; ndx < last; ++ndx) {
121 // Before the last extension byte, we expect the high-bit set.
122 uint8_t byte = buffer_[ndx];
123 if (value == minimum) {
124 EXPECT_EQ(0x80, byte) << "ndx=" << ndx;
125 } else if (value == maximum) {
126 if (expected_bytes < 11) {
127 EXPECT_EQ(0xff, byte) << "ndx=" << ndx;
128 }
129 } else {
130 EXPECT_EQ(0x80, byte & 0x80) << "ndx=" << ndx;
131 }
132 }
133 // The last extension byte should not have the high-bit set.
134 uint8_t byte = buffer_[last];
135 if (value == minimum) {
136 if (expected_bytes == 2) {
137 EXPECT_EQ(0x00, byte);
138 } else {
139 EXPECT_EQ(0x01, byte);
140 }
141 } else if (value == maximum) {
142 if (expected_bytes < 11) {
143 EXPECT_EQ(0x7f, byte);
144 }
145 } else {
146 EXPECT_EQ(0x00, byte & 0x80);
147 }
148 } else {
149 const uint8_t prefix_mask = (1 << prefix_length_) - 1;
150 EXPECT_EQ(value, static_cast<uint32_t>(buffer_[0] & prefix_mask));
151 EXPECT_LT(value, prefix_mask);
152 }
153 }
154
155 void EncodeAndDecodeValues(const std::set<uint64_t>& values,
156 uint8_t prefix_length,
157 size_t expected_bytes) {
158 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
bnc47904002019-08-16 11:49:48 -0700164 std::string msg = Http2StrCat("value=", value, " (0x", Http2Hex(value),
QUICHE teamfd50a402018-12-07 22:54:05 -0500165 "), prefix_length=", prefix_length,
166 ", expected_bytes=", expected_bytes, "\n",
167 Http2HexDump(buffer_));
168
169 if (value == minimum) {
QUICHE team61940b42019-03-07 23:32:27 -0500170 HTTP2_LOG(INFO) << "Checking minimum; " << msg;
QUICHE teamfd50a402018-12-07 22:54:05 -0500171 } else if (value == maximum) {
QUICHE team61940b42019-03-07 23:32:27 -0500172 HTTP2_LOG(INFO) << "Checking maximum; " << msg;
QUICHE teamfd50a402018-12-07 22:54:05 -0500173 }
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.
202 void EncodeAndDecodeValuesInRange(uint64_t start,
203 uint64_t range,
204 uint8_t prefix_length,
205 size_t expected_bytes) {
206 const uint8_t prefix_mask = (1 << prefix_length) - 1;
207 const uint64_t beyond = start + range;
208
QUICHE team61940b42019-03-07 23:32:27 -0500209 HTTP2_LOG(INFO)
210 << "############################################################";
211 HTTP2_LOG(INFO) << "prefix_length=" << static_cast<int>(prefix_length);
212 HTTP2_LOG(INFO) << "prefix_mask=" << std::hex
213 << static_cast<int>(prefix_mask);
214 HTTP2_LOG(INFO) << "start=" << start << " (" << std::hex << start << ")";
215 HTTP2_LOG(INFO) << "range=" << range << " (" << std::hex << range << ")";
216 HTTP2_LOG(INFO) << "beyond=" << beyond << " (" << std::hex << beyond << ")";
217 HTTP2_LOG(INFO) << "expected_bytes=" << expected_bytes;
QUICHE teamfd50a402018-12-07 22:54:05 -0500218
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()) << Http2HexDump(buffer_);
223 }
224
225 std::set<uint64_t> values;
226 if (range < 200) {
227 // Select all values in the range.
228 for (uint64_t offset = 0; offset < range; ++offset) {
229 values.insert(start + offset);
230 }
231 } else {
232 // Select some values in this range, including the minimum and maximum
233 // values that require exactly |expected_bytes| extension bytes.
234 values.insert({start, start + 1, beyond - 2, beyond - 1});
235 while (values.size() < 100) {
236 values.insert(Random().UniformInRange(start, beyond - 1));
237 }
238 }
239
240 EncodeAndDecodeValues(values, prefix_length, expected_bytes);
241 }
242
QUICHE teamfd50a402018-12-07 22:54:05 -0500243 HpackVarintDecoder decoder_;
bnc47904002019-08-16 11:49:48 -0700244 std::string buffer_;
QUICHE teamfd50a402018-12-07 22:54:05 -0500245 uint8_t prefix_length_;
246};
247
QUICHE team61940b42019-03-07 23:32:27 -0500248// To help me and future debuggers of varint encodings, this HTTP2_LOGs out the
QUICHE teamfd50a402018-12-07 22:54:05 -0500249// transition points where a new extension byte is added.
bnce72b8872019-01-22 19:59:50 -0500250TEST_F(HpackVarintRoundTripTest, Encode) {
QUICHE teamcc663702018-12-17 15:51:59 -0500251 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500252 const uint64_t a = HiValueOfExtensionBytes(0, prefix_length);
253 const uint64_t b = HiValueOfExtensionBytes(1, prefix_length);
254 const uint64_t c = HiValueOfExtensionBytes(2, prefix_length);
255 const uint64_t d = HiValueOfExtensionBytes(3, prefix_length);
256 const uint64_t e = HiValueOfExtensionBytes(4, prefix_length);
257 const uint64_t f = HiValueOfExtensionBytes(5, prefix_length);
258 const uint64_t g = HiValueOfExtensionBytes(6, prefix_length);
259 const uint64_t h = HiValueOfExtensionBytes(7, prefix_length);
260 const uint64_t i = HiValueOfExtensionBytes(8, prefix_length);
261 const uint64_t j = HiValueOfExtensionBytes(9, prefix_length);
262
QUICHE team61940b42019-03-07 23:32:27 -0500263 HTTP2_LOG(INFO)
264 << "############################################################";
265 HTTP2_LOG(INFO) << "prefix_length=" << prefix_length << " a=" << a
266 << " b=" << b << " c=" << c << " d=" << d
267 << " e=" << e << " f=" << f << " g=" << g
268 << " h=" << h << " i=" << i << " j=" << j;
QUICHE teamfd50a402018-12-07 22:54:05 -0500269
270 std::vector<uint64_t> values = {
271 0, 1, // Force line break.
272 a - 1, a, a + 1, a + 2, a + 3, // Force line break.
273 b - 1, b, b + 1, b + 2, b + 3, // Force line break.
274 c - 1, c, c + 1, c + 2, c + 3, // Force line break.
275 d - 1, d, d + 1, d + 2, d + 3, // Force line break.
bnce72b8872019-01-22 19:59:50 -0500276 e - 1, e, e + 1, e + 2, e + 3, // Force line break.
277 f - 1, f, f + 1, f + 2, f + 3, // Force line break.
278 g - 1, g, g + 1, g + 2, g + 3, // Force line break.
279 h - 1, h, h + 1, h + 2, h + 3, // Force line break.
280 i - 1, i, i + 1, i + 2, i + 3, // Force line break.
281 j - 1, j, j + 1, j + 2, j + 3, // Force line break.
QUICHE teamfd50a402018-12-07 22:54:05 -0500282 };
QUICHE teamfd50a402018-12-07 22:54:05 -0500283
284 for (uint64_t value : values) {
285 EncodeNoRandom(value, prefix_length);
bnc47904002019-08-16 11:49:48 -0700286 std::string dump = Http2HexDump(buffer_);
QUICHE team61940b42019-03-07 23:32:27 -0500287 HTTP2_LOG(INFO) << Http2StringPrintf("%10llu %0#18x ", value, value)
288 << Http2HexDump(buffer_).substr(7);
QUICHE teamfd50a402018-12-07 22:54:05 -0500289 }
290 }
291}
292
bnce72b8872019-01-22 19:59:50 -0500293TEST_F(HpackVarintRoundTripTest, FromSpec1337) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500294 DecodeBuffer b(Http2StringPiece("\x1f\x9a\x0a"));
295 uint32_t prefix_length = 5;
296 uint8_t p = b.DecodeUInt8();
297 EXPECT_EQ(1u, b.Offset());
298 EXPECT_EQ(DecodeStatus::kDecodeDone, decoder_.Start(p, prefix_length, &b));
299 EXPECT_EQ(3u, b.Offset());
300 EXPECT_EQ(1337u, decoder_.value());
301
302 EncodeNoRandom(1337, prefix_length);
303 EXPECT_EQ(3u, buffer_.size());
304 EXPECT_EQ('\x1f', buffer_[0]);
305 EXPECT_EQ('\x9a', buffer_[1]);
306 EXPECT_EQ('\x0a', buffer_[2]);
307}
308
309// Test all the values that fit into the prefix (one less than the mask).
bnce72b8872019-01-22 19:59:50 -0500310TEST_F(HpackVarintRoundTripTest, ValidatePrefixOnly) {
QUICHE teamcc663702018-12-17 15:51:59 -0500311 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500312 const uint8_t prefix_mask = (1 << prefix_length) - 1;
313 EncodeAndDecodeValuesInRange(0, prefix_mask, prefix_length, 1);
314 }
315}
316
317// Test all values that require exactly 1 extension byte.
bnce72b8872019-01-22 19:59:50 -0500318TEST_F(HpackVarintRoundTripTest, ValidateOneExtensionByte) {
QUICHE teamcc663702018-12-17 15:51:59 -0500319 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500320 const uint64_t start = HiValueOfExtensionBytes(0, prefix_length) + 1;
321 EncodeAndDecodeValuesInRange(start, 128, prefix_length, 2);
322 }
323}
324
325// Test *some* values that require exactly 2 extension bytes.
bnce72b8872019-01-22 19:59:50 -0500326TEST_F(HpackVarintRoundTripTest, ValidateTwoExtensionBytes) {
QUICHE teamcc663702018-12-17 15:51:59 -0500327 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500328 const uint64_t start = HiValueOfExtensionBytes(1, prefix_length) + 1;
329 const uint64_t range = 127 << 7;
330
331 EncodeAndDecodeValuesInRange(start, range, prefix_length, 3);
332 }
333}
334
335// Test *some* values that require 3 extension bytes.
bnce72b8872019-01-22 19:59:50 -0500336TEST_F(HpackVarintRoundTripTest, ValidateThreeExtensionBytes) {
QUICHE teamcc663702018-12-17 15:51:59 -0500337 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500338 const uint64_t start = HiValueOfExtensionBytes(2, prefix_length) + 1;
339 const uint64_t range = 127 << 14;
340
341 EncodeAndDecodeValuesInRange(start, range, prefix_length, 4);
342 }
343}
344
345// Test *some* values that require 4 extension bytes.
bnce72b8872019-01-22 19:59:50 -0500346TEST_F(HpackVarintRoundTripTest, ValidateFourExtensionBytes) {
QUICHE teamcc663702018-12-17 15:51:59 -0500347 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500348 const uint64_t start = HiValueOfExtensionBytes(3, prefix_length) + 1;
349 const uint64_t range = 127 << 21;
350
351 EncodeAndDecodeValuesInRange(start, range, prefix_length, 5);
352 }
353}
354
355// Test *some* values that require 5 extension bytes.
bnce72b8872019-01-22 19:59:50 -0500356TEST_F(HpackVarintRoundTripTest, ValidateFiveExtensionBytes) {
QUICHE teamcc663702018-12-17 15:51:59 -0500357 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500358 const uint64_t start = HiValueOfExtensionBytes(4, prefix_length) + 1;
359 const uint64_t range = 127llu << 28;
360
361 EncodeAndDecodeValuesInRange(start, range, prefix_length, 6);
362 }
363}
364
365// Test *some* values that require 6 extension bytes.
bnce72b8872019-01-22 19:59:50 -0500366TEST_F(HpackVarintRoundTripTest, ValidateSixExtensionBytes) {
QUICHE teamcc663702018-12-17 15:51:59 -0500367 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500368 const uint64_t start = HiValueOfExtensionBytes(5, prefix_length) + 1;
369 const uint64_t range = 127llu << 35;
370
371 EncodeAndDecodeValuesInRange(start, range, prefix_length, 7);
372 }
373}
374
375// Test *some* values that require 7 extension bytes.
bnce72b8872019-01-22 19:59:50 -0500376TEST_F(HpackVarintRoundTripTest, ValidateSevenExtensionBytes) {
QUICHE teamcc663702018-12-17 15:51:59 -0500377 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500378 const uint64_t start = HiValueOfExtensionBytes(6, prefix_length) + 1;
379 const uint64_t range = 127llu << 42;
380
381 EncodeAndDecodeValuesInRange(start, range, prefix_length, 8);
382 }
383}
384
385// Test *some* values that require 8 extension bytes.
bnce72b8872019-01-22 19:59:50 -0500386TEST_F(HpackVarintRoundTripTest, ValidateEightExtensionBytes) {
QUICHE teamcc663702018-12-17 15:51:59 -0500387 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500388 const uint64_t start = HiValueOfExtensionBytes(7, prefix_length) + 1;
389 const uint64_t range = 127llu << 49;
390
391 EncodeAndDecodeValuesInRange(start, range, prefix_length, 9);
392 }
393}
394
395// Test *some* values that require 9 extension bytes.
bnce72b8872019-01-22 19:59:50 -0500396TEST_F(HpackVarintRoundTripTest, ValidateNineExtensionBytes) {
QUICHE teamcc663702018-12-17 15:51:59 -0500397 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500398 const uint64_t start = HiValueOfExtensionBytes(8, prefix_length) + 1;
399 const uint64_t range = 127llu << 56;
400
401 EncodeAndDecodeValuesInRange(start, range, prefix_length, 10);
402 }
403}
404
405// Test *some* values that require 10 extension bytes.
bnce72b8872019-01-22 19:59:50 -0500406TEST_F(HpackVarintRoundTripTest, ValidateTenExtensionBytes) {
QUICHE teamcc663702018-12-17 15:51:59 -0500407 for (int prefix_length = 3; prefix_length <= 8; ++prefix_length) {
QUICHE teamfd50a402018-12-07 22:54:05 -0500408 const uint64_t start = HiValueOfExtensionBytes(9, prefix_length) + 1;
409 const uint64_t range = std::numeric_limits<uint64_t>::max() - start;
410
411 EncodeAndDecodeValuesInRange(start, range, prefix_length, 11);
412 }
413}
414
QUICHE teamfd50a402018-12-07 22:54:05 -0500415} // namespace
416} // namespace test
417} // namespace http2