• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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