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