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