xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/http2/hpack/decoder/hpack_entry_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_entry_decoder.h"
6 
7 // Tests of HpackEntryDecoder.
8 
9 #include <cstdint>
10 
11 #include "quiche/http2/test_tools/hpack_block_builder.h"
12 #include "quiche/http2/test_tools/hpack_entry_collector.h"
13 #include "quiche/http2/test_tools/http2_random.h"
14 #include "quiche/http2/test_tools/random_decoder_test_base.h"
15 #include "quiche/common/platform/api/quiche_expect_bug.h"
16 #include "quiche/common/platform/api/quiche_test.h"
17 
18 namespace http2 {
19 namespace test {
20 namespace {
21 
22 class HpackEntryDecoderTest : public RandomDecoderTest {
23  protected:
HpackEntryDecoderTest()24   HpackEntryDecoderTest() : listener_(&collector_) {}
25 
StartDecoding(DecodeBuffer * b)26   DecodeStatus StartDecoding(DecodeBuffer* b) override {
27     collector_.Clear();
28     return decoder_.Start(b, &listener_);
29   }
30 
ResumeDecoding(DecodeBuffer * b)31   DecodeStatus ResumeDecoding(DecodeBuffer* b) override {
32     return decoder_.Resume(b, &listener_);
33   }
34 
DecodeAndValidateSeveralWays(DecodeBuffer * db,const Validator & validator)35   AssertionResult DecodeAndValidateSeveralWays(DecodeBuffer* db,
36                                                const Validator& validator) {
37     // StartDecoding, above, requires the DecodeBuffer be non-empty so that it
38     // can call Start with the prefix byte.
39     bool return_non_zero_on_first = true;
40     return RandomDecoderTest::DecodeAndValidateSeveralWays(
41         db, return_non_zero_on_first, validator);
42   }
43 
DecodeAndValidateSeveralWays(const HpackBlockBuilder & hbb,const Validator & validator)44   AssertionResult DecodeAndValidateSeveralWays(const HpackBlockBuilder& hbb,
45                                                const Validator& validator) {
46     DecodeBuffer db(hbb.buffer());
47     return DecodeAndValidateSeveralWays(&db, validator);
48   }
49 
50   HpackEntryDecoder decoder_;
51   HpackEntryCollector collector_;
52   HpackEntryDecoderVLoggingListener listener_;
53 };
54 
TEST_F(HpackEntryDecoderTest,IndexedHeader_Literals)55 TEST_F(HpackEntryDecoderTest, IndexedHeader_Literals) {
56   {
57     const char input[] = {'\x82'};  // == Index 2 ==
58     DecodeBuffer b(input);
59     auto do_check = [this]() { return collector_.ValidateIndexedHeader(2); };
60     EXPECT_TRUE(
61         DecodeAndValidateSeveralWays(&b, ValidateDoneAndEmpty(do_check)));
62     EXPECT_TRUE(do_check());
63   }
64   collector_.Clear();
65   {
66     const char input[] = {'\xfe'};  // == Index 126 ==
67     DecodeBuffer b(input);
68     auto do_check = [this]() { return collector_.ValidateIndexedHeader(126); };
69     EXPECT_TRUE(
70         DecodeAndValidateSeveralWays(&b, ValidateDoneAndEmpty(do_check)));
71     EXPECT_TRUE(do_check());
72   }
73   collector_.Clear();
74   {
75     const char input[] = {'\xff', '\x00'};  // == Index 127 ==
76     DecodeBuffer b(input);
77     auto do_check = [this]() { return collector_.ValidateIndexedHeader(127); };
78     EXPECT_TRUE(
79         DecodeAndValidateSeveralWays(&b, ValidateDoneAndEmpty(do_check)));
80     EXPECT_TRUE(do_check());
81   }
82 }
83 
TEST_F(HpackEntryDecoderTest,IndexedHeader_Various)84 TEST_F(HpackEntryDecoderTest, IndexedHeader_Various) {
85   // Indices chosen to hit encoding and table boundaries.
86   for (const uint32_t ndx : {1, 2, 61, 62, 63, 126, 127, 254, 255, 256}) {
87     HpackBlockBuilder hbb;
88     hbb.AppendIndexedHeader(ndx);
89 
90     auto do_check = [this, ndx]() {
91       return collector_.ValidateIndexedHeader(ndx);
92     };
93     EXPECT_TRUE(
94         DecodeAndValidateSeveralWays(hbb, ValidateDoneAndEmpty(do_check)));
95     EXPECT_TRUE(do_check());
96   }
97 }
98 
TEST_F(HpackEntryDecoderTest,IndexedLiteralValue_Literal)99 TEST_F(HpackEntryDecoderTest, IndexedLiteralValue_Literal) {
100   const char input[] =
101       "\x7f"            // == Literal indexed, name index 0x40 ==
102       "\x01"            // 2nd byte of name index (0x01 + 0x3f == 0x40)
103       "\x0d"            // Value length (13)
104       "custom-header";  // Value
105   DecodeBuffer b(input, sizeof input - 1);
106   auto do_check = [this]() {
107     return collector_.ValidateLiteralValueHeader(
108         HpackEntryType::kIndexedLiteralHeader, 0x40, false, "custom-header");
109   };
110   EXPECT_TRUE(DecodeAndValidateSeveralWays(&b, ValidateDoneAndEmpty(do_check)));
111   EXPECT_TRUE(do_check());
112 }
113 
TEST_F(HpackEntryDecoderTest,IndexedLiteralNameValue_Literal)114 TEST_F(HpackEntryDecoderTest, IndexedLiteralNameValue_Literal) {
115   const char input[] =
116       "\x40"            // == Literal indexed ==
117       "\x0a"            // Name length (10)
118       "custom-key"      // Name
119       "\x0d"            // Value length (13)
120       "custom-header";  // Value
121 
122   DecodeBuffer b(input, sizeof input - 1);
123   auto do_check = [this]() {
124     return collector_.ValidateLiteralNameValueHeader(
125         HpackEntryType::kIndexedLiteralHeader, false, "custom-key", false,
126         "custom-header");
127   };
128   EXPECT_TRUE(DecodeAndValidateSeveralWays(&b, ValidateDoneAndEmpty(do_check)));
129   EXPECT_TRUE(do_check());
130 }
131 
TEST_F(HpackEntryDecoderTest,DynamicTableSizeUpdate_Literal)132 TEST_F(HpackEntryDecoderTest, DynamicTableSizeUpdate_Literal) {
133   // Size update, length 31.
134   const char input[] = "\x3f\x00";
135   DecodeBuffer b(input, 2);
136   auto do_check = [this]() {
137     return collector_.ValidateDynamicTableSizeUpdate(31);
138   };
139   EXPECT_TRUE(DecodeAndValidateSeveralWays(&b, ValidateDoneAndEmpty(do_check)));
140   EXPECT_TRUE(do_check());
141 }
142 
143 class HpackLiteralEntryDecoderTest
144     : public HpackEntryDecoderTest,
145       public ::testing::WithParamInterface<HpackEntryType> {
146  protected:
HpackLiteralEntryDecoderTest()147   HpackLiteralEntryDecoderTest() : entry_type_(GetParam()) {}
148 
149   const HpackEntryType entry_type_;
150 };
151 
152 INSTANTIATE_TEST_SUITE_P(
153     AllLiteralTypes, HpackLiteralEntryDecoderTest,
154     testing::Values(HpackEntryType::kIndexedLiteralHeader,
155                     HpackEntryType::kUnindexedLiteralHeader,
156                     HpackEntryType::kNeverIndexedLiteralHeader));
157 
TEST_P(HpackLiteralEntryDecoderTest,RandNameIndexAndLiteralValue)158 TEST_P(HpackLiteralEntryDecoderTest, RandNameIndexAndLiteralValue) {
159   for (int n = 0; n < 10; n++) {
160     const uint32_t ndx = 1 + Random().Rand8();
161     const bool value_is_huffman_encoded = (n % 2) == 0;
162     const std::string value = Random().RandString(Random().Rand8());
163     HpackBlockBuilder hbb;
164     hbb.AppendNameIndexAndLiteralValue(entry_type_, ndx,
165                                        value_is_huffman_encoded, value);
166     auto do_check = [this, ndx, value_is_huffman_encoded,
167                      value]() -> AssertionResult {
168       return collector_.ValidateLiteralValueHeader(
169           entry_type_, ndx, value_is_huffman_encoded, value);
170     };
171     EXPECT_TRUE(
172         DecodeAndValidateSeveralWays(hbb, ValidateDoneAndEmpty(do_check)));
173     EXPECT_TRUE(do_check());
174   }
175 }
176 
TEST_P(HpackLiteralEntryDecoderTest,RandLiteralNameAndValue)177 TEST_P(HpackLiteralEntryDecoderTest, RandLiteralNameAndValue) {
178   for (int n = 0; n < 10; n++) {
179     const bool name_is_huffman_encoded = (n & 1) == 0;
180     const int name_len = 1 + Random().Rand8();
181     const std::string name = Random().RandString(name_len);
182     const bool value_is_huffman_encoded = (n & 2) == 0;
183     const int value_len = Random().Skewed(10);
184     const std::string value = Random().RandString(value_len);
185     HpackBlockBuilder hbb;
186     hbb.AppendLiteralNameAndValue(entry_type_, name_is_huffman_encoded, name,
187                                   value_is_huffman_encoded, value);
188     auto do_check = [this, name_is_huffman_encoded, name,
189                      value_is_huffman_encoded, value]() -> AssertionResult {
190       return collector_.ValidateLiteralNameValueHeader(
191           entry_type_, name_is_huffman_encoded, name, value_is_huffman_encoded,
192           value);
193     };
194     EXPECT_TRUE(
195         DecodeAndValidateSeveralWays(hbb, ValidateDoneAndEmpty(do_check)));
196     EXPECT_TRUE(do_check());
197   }
198 }
199 
200 }  // namespace
201 }  // namespace test
202 }  // namespace http2
203