xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/http2/hpack/decoder/hpack_block_decoder_test.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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/decoder/hpack_block_decoder.h"
6 
7 // Tests of HpackBlockDecoder.
8 
9 #include <cstdint>
10 #include <string>
11 
12 #include "absl/strings/string_view.h"
13 #include "quiche/http2/decoder/decode_buffer.h"
14 #include "quiche/http2/hpack/http2_hpack_constants.h"
15 #include "quiche/http2/test_tools/hpack_block_builder.h"
16 #include "quiche/http2/test_tools/hpack_block_collector.h"
17 #include "quiche/http2/test_tools/hpack_example.h"
18 #include "quiche/http2/test_tools/http2_random.h"
19 #include "quiche/http2/test_tools/random_decoder_test_base.h"
20 #include "quiche/common/platform/api/quiche_expect_bug.h"
21 #include "quiche/common/platform/api/quiche_test.h"
22 
23 namespace http2 {
24 namespace test {
25 namespace {
26 
27 class HpackBlockDecoderTest : public RandomDecoderTest {
28  protected:
HpackBlockDecoderTest()29   HpackBlockDecoderTest() : listener_(&collector_), decoder_(&listener_) {
30     stop_decode_on_done_ = false;
31     decoder_.Reset();
32     // Make sure logging doesn't crash. Not examining the result.
33     std::ostringstream strm;
34     strm << decoder_;
35   }
36 
StartDecoding(DecodeBuffer * db)37   DecodeStatus StartDecoding(DecodeBuffer* db) override {
38     collector_.Clear();
39     decoder_.Reset();
40     return ResumeDecoding(db);
41   }
42 
ResumeDecoding(DecodeBuffer * db)43   DecodeStatus ResumeDecoding(DecodeBuffer* db) override {
44     DecodeStatus status = decoder_.Decode(db);
45 
46     // Make sure logging doesn't crash. Not examining the result.
47     std::ostringstream strm;
48     strm << decoder_;
49 
50     return status;
51   }
52 
DecodeAndValidateSeveralWays(DecodeBuffer * db,const Validator & validator)53   AssertionResult DecodeAndValidateSeveralWays(DecodeBuffer* db,
54                                                const Validator& validator) {
55     bool return_non_zero_on_first = false;
56     return RandomDecoderTest::DecodeAndValidateSeveralWays(
57         db, return_non_zero_on_first, validator);
58   }
59 
DecodeAndValidateSeveralWays(const HpackBlockBuilder & hbb,const Validator & validator)60   AssertionResult DecodeAndValidateSeveralWays(const HpackBlockBuilder& hbb,
61                                                const Validator& validator) {
62     DecodeBuffer db(hbb.buffer());
63     return DecodeAndValidateSeveralWays(&db, validator);
64   }
65 
DecodeHpackExampleAndValidateSeveralWays(absl::string_view hpack_example,Validator validator)66   AssertionResult DecodeHpackExampleAndValidateSeveralWays(
67       absl::string_view hpack_example, Validator validator) {
68     std::string input = HpackExampleToStringOrDie(hpack_example);
69     DecodeBuffer db(input);
70     return DecodeAndValidateSeveralWays(&db, validator);
71   }
72 
Rand8()73   uint8_t Rand8() { return Random().Rand8(); }
74 
Rand8String()75   std::string Rand8String() { return Random().RandString(Rand8()); }
76 
77   HpackBlockCollector collector_;
78   HpackEntryDecoderVLoggingListener listener_;
79   HpackBlockDecoder decoder_;
80 };
81 
82 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.2.1
TEST_F(HpackBlockDecoderTest,SpecExample_C_2_1)83 TEST_F(HpackBlockDecoderTest, SpecExample_C_2_1) {
84   auto do_check = [this]() {
85     return collector_.ValidateSoleLiteralNameValueHeader(
86         HpackEntryType::kIndexedLiteralHeader, false, "custom-key", false,
87         "custom-header");
88   };
89   const char hpack_example[] = R"(
90       40                                      | == Literal indexed ==
91       0a                                      |   Literal name (len = 10)
92       6375 7374 6f6d 2d6b 6579                | custom-key
93       0d                                      |   Literal value (len = 13)
94       6375 7374 6f6d 2d68 6561 6465 72        | custom-header
95                                               | -> custom-key:
96                                               |   custom-header
97       )";
98   EXPECT_TRUE(DecodeHpackExampleAndValidateSeveralWays(
99       hpack_example, ValidateDoneAndEmpty(do_check)));
100   EXPECT_TRUE(do_check());
101 }
102 
103 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.2.2
TEST_F(HpackBlockDecoderTest,SpecExample_C_2_2)104 TEST_F(HpackBlockDecoderTest, SpecExample_C_2_2) {
105   auto do_check = [this]() {
106     return collector_.ValidateSoleLiteralValueHeader(
107         HpackEntryType::kUnindexedLiteralHeader, 4, false, "/sample/path");
108   };
109   const char hpack_example[] = R"(
110       04                                      | == Literal not indexed ==
111                                               |   Indexed name (idx = 4)
112                                               |     :path
113       0c                                      |   Literal value (len = 12)
114       2f73 616d 706c 652f 7061 7468           | /sample/path
115                                               | -> :path: /sample/path
116       )";
117   EXPECT_TRUE(DecodeHpackExampleAndValidateSeveralWays(
118       hpack_example, ValidateDoneAndEmpty(do_check)));
119   EXPECT_TRUE(do_check());
120 }
121 
122 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.2.3
TEST_F(HpackBlockDecoderTest,SpecExample_C_2_3)123 TEST_F(HpackBlockDecoderTest, SpecExample_C_2_3) {
124   auto do_check = [this]() {
125     return collector_.ValidateSoleLiteralNameValueHeader(
126         HpackEntryType::kNeverIndexedLiteralHeader, false, "password", false,
127         "secret");
128   };
129   const char hpack_example[] = R"(
130       10                                      | == Literal never indexed ==
131       08                                      |   Literal name (len = 8)
132       7061 7373 776f 7264                     | password
133       06                                      |   Literal value (len = 6)
134       7365 6372 6574                          | secret
135                                               | -> password: secret
136       )";
137   EXPECT_TRUE(DecodeHpackExampleAndValidateSeveralWays(
138       hpack_example, ValidateDoneAndEmpty(do_check)));
139   EXPECT_TRUE(do_check());
140 }
141 
142 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.2.4
TEST_F(HpackBlockDecoderTest,SpecExample_C_2_4)143 TEST_F(HpackBlockDecoderTest, SpecExample_C_2_4) {
144   auto do_check = [this]() { return collector_.ValidateSoleIndexedHeader(2); };
145   const char hpack_example[] = R"(
146       82                                      | == Indexed - Add ==
147                                               |   idx = 2
148                                               | -> :method: GET
149       )";
150   EXPECT_TRUE(DecodeHpackExampleAndValidateSeveralWays(
151       hpack_example, ValidateDoneAndEmpty(do_check)));
152   EXPECT_TRUE(do_check());
153 }
154 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.3.1
TEST_F(HpackBlockDecoderTest,SpecExample_C_3_1)155 TEST_F(HpackBlockDecoderTest, SpecExample_C_3_1) {
156   std::string example = R"(
157       82                                      | == Indexed - Add ==
158                                               |   idx = 2
159                                               | -> :method: GET
160       86                                      | == Indexed - Add ==
161                                               |   idx = 6
162                                               | -> :scheme: http
163       84                                      | == Indexed - Add ==
164                                               |   idx = 4
165                                               | -> :path: /
166       41                                      | == Literal indexed ==
167                                               |   Indexed name (idx = 1)
168                                               |     :authority
169       0f                                      |   Literal value (len = 15)
170       7777 772e 6578 616d 706c 652e 636f 6d   | www.example.com
171                                               | -> :authority:
172                                               |   www.example.com
173       )";
174   HpackBlockCollector expected;
175   expected.ExpectIndexedHeader(2);
176   expected.ExpectIndexedHeader(6);
177   expected.ExpectIndexedHeader(4);
178   expected.ExpectNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader,
179                                           1, false, "www.example.com");
180   EXPECT_TRUE(DecodeHpackExampleAndValidateSeveralWays(
181       example,
182       ValidateDoneAndEmpty([&] { return collector_.VerifyEq(expected); })));
183   EXPECT_TRUE(collector_.VerifyEq(expected));
184 }
185 
186 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.5.1
TEST_F(HpackBlockDecoderTest,SpecExample_C_5_1)187 TEST_F(HpackBlockDecoderTest, SpecExample_C_5_1) {
188   std::string example = R"(
189       48                                      | == Literal indexed ==
190                                               |   Indexed name (idx = 8)
191                                               |     :status
192       03                                      |   Literal value (len = 3)
193       3330 32                                 | 302
194                                               | -> :status: 302
195       58                                      | == Literal indexed ==
196                                               |   Indexed name (idx = 24)
197                                               |     cache-control
198       07                                      |   Literal value (len = 7)
199       7072 6976 6174 65                       | private
200                                               | -> cache-control: private
201       61                                      | == Literal indexed ==
202                                               |   Indexed name (idx = 33)
203                                               |     date
204       1d                                      |   Literal value (len = 29)
205       4d6f 6e2c 2032 3120 4f63 7420 3230 3133 | Mon, 21 Oct 2013
206       2032 303a 3133 3a32 3120 474d 54        |  20:13:21 GMT
207                                               | -> date: Mon, 21 Oct 2013
208                                               |   20:13:21 GMT
209       6e                                      | == Literal indexed ==
210                                               |   Indexed name (idx = 46)
211                                               |     location
212       17                                      |   Literal value (len = 23)
213       6874 7470 733a 2f2f 7777 772e 6578 616d | https://www.exam
214       706c 652e 636f 6d                       | ple.com
215                                               | -> location:
216                                               |   https://www.example.com
217       )";
218   HpackBlockCollector expected;
219   expected.ExpectNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader,
220                                           8, false, "302");
221   expected.ExpectNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader,
222                                           24, false, "private");
223   expected.ExpectNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader,
224                                           33, false,
225                                           "Mon, 21 Oct 2013 20:13:21 GMT");
226   expected.ExpectNameIndexAndLiteralValue(HpackEntryType::kIndexedLiteralHeader,
227                                           46, false, "https://www.example.com");
228   EXPECT_TRUE(DecodeHpackExampleAndValidateSeveralWays(
229       example,
230       ValidateDoneAndEmpty([&] { return collector_.VerifyEq(expected); })));
231   EXPECT_TRUE(collector_.VerifyEq(expected));
232 }
233 
234 // Generate a bunch of HPACK block entries to expect, use those expectations
235 // to generate an HPACK block, then decode it and confirm it matches those
236 // expectations. Some of these are invalid (such as Indexed, with index=0),
237 // but well-formed, and the decoder doesn't check for validity, just
238 // well-formedness. That includes the validity of the strings not being checked,
239 // such as lower-case ascii for the names, and valid Huffman encodings.
TEST_F(HpackBlockDecoderTest,Computed)240 TEST_F(HpackBlockDecoderTest, Computed) {
241   HpackBlockCollector expected;
242   expected.ExpectIndexedHeader(0);
243   expected.ExpectIndexedHeader(1);
244   expected.ExpectIndexedHeader(126);
245   expected.ExpectIndexedHeader(127);
246   expected.ExpectIndexedHeader(128);
247   expected.ExpectDynamicTableSizeUpdate(0);
248   expected.ExpectDynamicTableSizeUpdate(1);
249   expected.ExpectDynamicTableSizeUpdate(14);
250   expected.ExpectDynamicTableSizeUpdate(15);
251   expected.ExpectDynamicTableSizeUpdate(30);
252   expected.ExpectDynamicTableSizeUpdate(31);
253   expected.ExpectDynamicTableSizeUpdate(4095);
254   expected.ExpectDynamicTableSizeUpdate(4096);
255   expected.ExpectDynamicTableSizeUpdate(8192);
256   for (auto type : {HpackEntryType::kIndexedLiteralHeader,
257                     HpackEntryType::kUnindexedLiteralHeader,
258                     HpackEntryType::kNeverIndexedLiteralHeader}) {
259     for (bool value_huffman : {false, true}) {
260       // An entry with an index for the name. Ensure the name index
261       // is not zero by adding one to the Rand8() result.
262       expected.ExpectNameIndexAndLiteralValue(type, Rand8() + 1, value_huffman,
263                                               Rand8String());
264       // And two entries with literal names, one plain, one huffman encoded.
265       expected.ExpectLiteralNameAndValue(type, false, Rand8String(),
266                                          value_huffman, Rand8String());
267       expected.ExpectLiteralNameAndValue(type, true, Rand8String(),
268                                          value_huffman, Rand8String());
269     }
270   }
271   // Shuffle the entries and serialize them to produce an HPACK block.
272   expected.ShuffleEntries(RandomPtr());
273   HpackBlockBuilder hbb;
274   expected.AppendToHpackBlockBuilder(&hbb);
275 
276   EXPECT_TRUE(DecodeAndValidateSeveralWays(
277       hbb,
278       ValidateDoneAndEmpty([&] { return collector_.VerifyEq(expected); })));
279   EXPECT_TRUE(collector_.VerifyEq(expected));
280 }
281 
282 }  // namespace
283 }  // namespace test
284 }  // namespace http2
285