1 // Copyright 2018 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/quic/core/qpack/qpack_instruction_encoder.h"
6
7 #include "absl/strings/escaping.h"
8 #include "absl/strings/string_view.h"
9 #include "quiche/quic/platform/api/quic_logging.h"
10 #include "quiche/quic/platform/api/quic_test.h"
11
12 namespace quic {
13 namespace test {
14
15 class QpackInstructionWithValuesPeer {
16 public:
CreateQpackInstructionWithValues(const QpackInstruction * instruction)17 static QpackInstructionWithValues CreateQpackInstructionWithValues(
18 const QpackInstruction* instruction) {
19 QpackInstructionWithValues instruction_with_values;
20 instruction_with_values.instruction_ = instruction;
21 return instruction_with_values;
22 }
23
set_s_bit(QpackInstructionWithValues * instruction_with_values,bool s_bit)24 static void set_s_bit(QpackInstructionWithValues* instruction_with_values,
25 bool s_bit) {
26 instruction_with_values->s_bit_ = s_bit;
27 }
28
set_varint(QpackInstructionWithValues * instruction_with_values,uint64_t varint)29 static void set_varint(QpackInstructionWithValues* instruction_with_values,
30 uint64_t varint) {
31 instruction_with_values->varint_ = varint;
32 }
33
set_varint2(QpackInstructionWithValues * instruction_with_values,uint64_t varint2)34 static void set_varint2(QpackInstructionWithValues* instruction_with_values,
35 uint64_t varint2) {
36 instruction_with_values->varint2_ = varint2;
37 }
38
set_name(QpackInstructionWithValues * instruction_with_values,absl::string_view name)39 static void set_name(QpackInstructionWithValues* instruction_with_values,
40 absl::string_view name) {
41 instruction_with_values->name_ = name;
42 }
43
set_value(QpackInstructionWithValues * instruction_with_values,absl::string_view value)44 static void set_value(QpackInstructionWithValues* instruction_with_values,
45 absl::string_view value) {
46 instruction_with_values->value_ = value;
47 }
48 };
49
50 namespace {
51
52 class QpackInstructionEncoderTest : public QuicTest {
53 protected:
QpackInstructionEncoderTest()54 QpackInstructionEncoderTest() : verified_position_(0) {}
55 ~QpackInstructionEncoderTest() override = default;
56
57 // Append encoded |instruction| to |output_|.
EncodeInstruction(const QpackInstructionWithValues & instruction_with_values)58 void EncodeInstruction(
59 const QpackInstructionWithValues& instruction_with_values) {
60 encoder_.Encode(instruction_with_values, &output_);
61 }
62
63 // Compare substring appended to |output_| since last EncodedSegmentMatches()
64 // call against hex-encoded argument.
EncodedSegmentMatches(absl::string_view hex_encoded_expected_substring)65 bool EncodedSegmentMatches(absl::string_view hex_encoded_expected_substring) {
66 auto recently_encoded =
67 absl::string_view(output_).substr(verified_position_);
68 auto expected = absl::HexStringToBytes(hex_encoded_expected_substring);
69 verified_position_ = output_.size();
70 return recently_encoded == expected;
71 }
72
73 private:
74 QpackInstructionEncoder encoder_;
75 std::string output_;
76 std::string::size_type verified_position_;
77 };
78
TEST_F(QpackInstructionEncoderTest,Varint)79 TEST_F(QpackInstructionEncoderTest, Varint) {
80 const QpackInstruction instruction{QpackInstructionOpcode{0x00, 0x80},
81 {{QpackInstructionFieldType::kVarint, 7}}};
82
83 auto instruction_with_values =
84 QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues(
85 &instruction);
86 QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 5);
87 EncodeInstruction(instruction_with_values);
88 EXPECT_TRUE(EncodedSegmentMatches("05"));
89
90 QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 127);
91 EncodeInstruction(instruction_with_values);
92 EXPECT_TRUE(EncodedSegmentMatches("7f00"));
93 }
94
TEST_F(QpackInstructionEncoderTest,SBitAndTwoVarint2)95 TEST_F(QpackInstructionEncoderTest, SBitAndTwoVarint2) {
96 const QpackInstruction instruction{
97 QpackInstructionOpcode{0x80, 0xc0},
98 {{QpackInstructionFieldType::kSbit, 0x20},
99 {QpackInstructionFieldType::kVarint, 5},
100 {QpackInstructionFieldType::kVarint2, 8}}};
101
102 auto instruction_with_values =
103 QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues(
104 &instruction);
105 QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, true);
106 QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 5);
107 QpackInstructionWithValuesPeer::set_varint2(&instruction_with_values, 200);
108 EncodeInstruction(instruction_with_values);
109 EXPECT_TRUE(EncodedSegmentMatches("a5c8"));
110
111 QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, false);
112 QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 31);
113 QpackInstructionWithValuesPeer::set_varint2(&instruction_with_values, 356);
114 EncodeInstruction(instruction_with_values);
115 EXPECT_TRUE(EncodedSegmentMatches("9f00ff65"));
116 }
117
TEST_F(QpackInstructionEncoderTest,SBitAndVarintAndValue)118 TEST_F(QpackInstructionEncoderTest, SBitAndVarintAndValue) {
119 const QpackInstruction instruction{QpackInstructionOpcode{0xc0, 0xc0},
120 {{QpackInstructionFieldType::kSbit, 0x20},
121 {QpackInstructionFieldType::kVarint, 5},
122 {QpackInstructionFieldType::kValue, 7}}};
123
124 auto instruction_with_values =
125 QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues(
126 &instruction);
127 QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, true);
128 QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 100);
129 QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "foo");
130 EncodeInstruction(instruction_with_values);
131 EXPECT_TRUE(EncodedSegmentMatches("ff458294e7"));
132
133 QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, false);
134 QpackInstructionWithValuesPeer::set_varint(&instruction_with_values, 3);
135 QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "bar");
136 EncodeInstruction(instruction_with_values);
137 EXPECT_TRUE(EncodedSegmentMatches("c303626172"));
138 }
139
TEST_F(QpackInstructionEncoderTest,Name)140 TEST_F(QpackInstructionEncoderTest, Name) {
141 const QpackInstruction instruction{QpackInstructionOpcode{0xe0, 0xe0},
142 {{QpackInstructionFieldType::kName, 4}}};
143
144 auto instruction_with_values =
145 QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues(
146 &instruction);
147 QpackInstructionWithValuesPeer::set_name(&instruction_with_values, "");
148 EncodeInstruction(instruction_with_values);
149 EXPECT_TRUE(EncodedSegmentMatches("e0"));
150
151 QpackInstructionWithValuesPeer::set_name(&instruction_with_values, "foo");
152 EncodeInstruction(instruction_with_values);
153 EXPECT_TRUE(EncodedSegmentMatches("f294e7"));
154
155 QpackInstructionWithValuesPeer::set_name(&instruction_with_values, "bar");
156 EncodeInstruction(instruction_with_values);
157 EXPECT_TRUE(EncodedSegmentMatches("e3626172"));
158 }
159
TEST_F(QpackInstructionEncoderTest,Value)160 TEST_F(QpackInstructionEncoderTest, Value) {
161 const QpackInstruction instruction{QpackInstructionOpcode{0xf0, 0xf0},
162 {{QpackInstructionFieldType::kValue, 3}}};
163
164 auto instruction_with_values =
165 QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues(
166 &instruction);
167 QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "");
168 EncodeInstruction(instruction_with_values);
169 EXPECT_TRUE(EncodedSegmentMatches("f0"));
170
171 QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "foo");
172 EncodeInstruction(instruction_with_values);
173 EXPECT_TRUE(EncodedSegmentMatches("fa94e7"));
174
175 QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "bar");
176 EncodeInstruction(instruction_with_values);
177 EXPECT_TRUE(EncodedSegmentMatches("f3626172"));
178 }
179
TEST_F(QpackInstructionEncoderTest,SBitAndNameAndValue)180 TEST_F(QpackInstructionEncoderTest, SBitAndNameAndValue) {
181 const QpackInstruction instruction{QpackInstructionOpcode{0xf0, 0xf0},
182 {{QpackInstructionFieldType::kSbit, 0x08},
183 {QpackInstructionFieldType::kName, 2},
184 {QpackInstructionFieldType::kValue, 7}}};
185
186 auto instruction_with_values =
187 QpackInstructionWithValuesPeer::CreateQpackInstructionWithValues(
188 &instruction);
189 QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, false);
190 QpackInstructionWithValuesPeer::set_name(&instruction_with_values, "");
191 QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "");
192 EncodeInstruction(instruction_with_values);
193 EXPECT_TRUE(EncodedSegmentMatches("f000"));
194
195 QpackInstructionWithValuesPeer::set_s_bit(&instruction_with_values, true);
196 QpackInstructionWithValuesPeer::set_name(&instruction_with_values, "foo");
197 QpackInstructionWithValuesPeer::set_value(&instruction_with_values, "bar");
198 EncodeInstruction(instruction_with_values);
199 EXPECT_TRUE(EncodedSegmentMatches("fe94e703626172"));
200 }
201
202 } // namespace
203 } // namespace test
204 } // namespace quic
205