1 // Copyright (c) 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_encoder_stream_sender.h"
6 
7 #include <string>
8 
9 #include "absl/strings/escaping.h"
10 #include "quiche/quic/platform/api/quic_test.h"
11 #include "quiche/quic/test_tools/qpack/qpack_test_utils.h"
12 
13 using ::testing::Eq;
14 using ::testing::StrictMock;
15 
16 namespace quic {
17 namespace test {
18 namespace {
19 
20 class QpackEncoderStreamSenderTest : public QuicTestWithParam<bool> {
21  protected:
QpackEncoderStreamSenderTest()22   QpackEncoderStreamSenderTest() : stream_(HuffmanEncoding()) {
23     stream_.set_qpack_stream_sender_delegate(&delegate_);
24   }
25   ~QpackEncoderStreamSenderTest() override = default;
26 
DisableHuffmanEncoding()27   bool DisableHuffmanEncoding() { return GetParam(); }
HuffmanEncoding()28   HuffmanEncoding HuffmanEncoding() {
29     return DisableHuffmanEncoding() ? HuffmanEncoding::kDisabled
30                                     : HuffmanEncoding::kEnabled;
31   }
32 
33   StrictMock<MockQpackStreamSenderDelegate> delegate_;
34   QpackEncoderStreamSender stream_;
35 };
36 
37 INSTANTIATE_TEST_SUITE_P(DisableHuffmanEncoding, QpackEncoderStreamSenderTest,
38                          testing::Values(false, true));
39 
TEST_P(QpackEncoderStreamSenderTest,InsertWithNameReference)40 TEST_P(QpackEncoderStreamSenderTest, InsertWithNameReference) {
41   EXPECT_EQ(0u, stream_.BufferedByteCount());
42 
43   // Static, index fits in prefix, empty value.
44   std::string expected_encoded_data;
45   ASSERT_TRUE(absl::HexStringToBytes("c500", &expected_encoded_data));
46   EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
47   stream_.SendInsertWithNameReference(true, 5, "");
48   EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
49   stream_.Flush();
50 
51   if (DisableHuffmanEncoding()) {
52     // Static, index fits in prefix, not Huffman encoded value.
53     ASSERT_TRUE(absl::HexStringToBytes("c203666f6f", &expected_encoded_data));
54   } else {
55     // Static, index fits in prefix, Huffman encoded value.
56     ASSERT_TRUE(absl::HexStringToBytes("c28294e7", &expected_encoded_data));
57   }
58   EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
59   stream_.SendInsertWithNameReference(true, 2, "foo");
60   EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
61   stream_.Flush();
62 
63   // Not static, index does not fit in prefix, not Huffman encoded value.
64   ASSERT_TRUE(absl::HexStringToBytes("bf4a03626172", &expected_encoded_data));
65   EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
66   stream_.SendInsertWithNameReference(false, 137, "bar");
67   EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
68   stream_.Flush();
69 
70   // Value length does not fit in prefix.
71   // 'Z' would be Huffman encoded to 8 bits, so no Huffman encoding is used.
72   ASSERT_TRUE(absl::HexStringToBytes(
73       "aa7f005a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
74       "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
75       "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
76       "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a",
77       &expected_encoded_data));
78   EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
79   stream_.SendInsertWithNameReference(false, 42, std::string(127, 'Z'));
80   EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
81   stream_.Flush();
82 }
83 
TEST_P(QpackEncoderStreamSenderTest,InsertWithoutNameReference)84 TEST_P(QpackEncoderStreamSenderTest, InsertWithoutNameReference) {
85   EXPECT_EQ(0u, stream_.BufferedByteCount());
86 
87   // Empty name and value.
88   std::string expected_encoded_data;
89   ASSERT_TRUE(absl::HexStringToBytes("4000", &expected_encoded_data));
90   EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
91   stream_.SendInsertWithoutNameReference("", "");
92   EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
93   stream_.Flush();
94 
95   if (DisableHuffmanEncoding()) {
96     // Not Huffman encoded short strings.
97     ASSERT_TRUE(
98         absl::HexStringToBytes("43666f6f03666f6f", &expected_encoded_data));
99   } else {
100     // Huffman encoded short strings.
101     ASSERT_TRUE(absl::HexStringToBytes("6294e78294e7", &expected_encoded_data));
102   }
103 
104   EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
105   stream_.SendInsertWithoutNameReference("foo", "foo");
106   EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
107   stream_.Flush();
108 
109   // Not Huffman encoded short strings.
110   ASSERT_TRUE(
111       absl::HexStringToBytes("4362617203626172", &expected_encoded_data));
112   EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
113   stream_.SendInsertWithoutNameReference("bar", "bar");
114   EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
115   stream_.Flush();
116 
117   // Not Huffman encoded long strings; length does not fit on prefix.
118   // 'Z' would be Huffman encoded to 8 bits, so no Huffman encoding is used.
119   ASSERT_TRUE(absl::HexStringToBytes(
120       "5f005a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a7f"
121       "005a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
122       "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
123       "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a"
124       "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a",
125       &expected_encoded_data));
126   EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
127   stream_.SendInsertWithoutNameReference(std::string(31, 'Z'),
128                                          std::string(127, 'Z'));
129   EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
130   stream_.Flush();
131 }
132 
TEST_P(QpackEncoderStreamSenderTest,Duplicate)133 TEST_P(QpackEncoderStreamSenderTest, Duplicate) {
134   EXPECT_EQ(0u, stream_.BufferedByteCount());
135 
136   // Small index fits in prefix.
137   std::string expected_encoded_data;
138   ASSERT_TRUE(absl::HexStringToBytes("11", &expected_encoded_data));
139   EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
140   stream_.SendDuplicate(17);
141   EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
142   stream_.Flush();
143 
144   // Large index requires two extension bytes.
145   ASSERT_TRUE(absl::HexStringToBytes("1fd503", &expected_encoded_data));
146   EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
147   stream_.SendDuplicate(500);
148   EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
149   stream_.Flush();
150 }
151 
TEST_P(QpackEncoderStreamSenderTest,SetDynamicTableCapacity)152 TEST_P(QpackEncoderStreamSenderTest, SetDynamicTableCapacity) {
153   EXPECT_EQ(0u, stream_.BufferedByteCount());
154 
155   // Small capacity fits in prefix.
156   std::string expected_encoded_data;
157   ASSERT_TRUE(absl::HexStringToBytes("31", &expected_encoded_data));
158   EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
159   stream_.SendSetDynamicTableCapacity(17);
160   EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
161   stream_.Flush();
162   EXPECT_EQ(0u, stream_.BufferedByteCount());
163 
164   // Large capacity requires two extension bytes.
165   ASSERT_TRUE(absl::HexStringToBytes("3fd503", &expected_encoded_data));
166   EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
167   stream_.SendSetDynamicTableCapacity(500);
168   EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
169   stream_.Flush();
170   EXPECT_EQ(0u, stream_.BufferedByteCount());
171 }
172 
173 // No writes should happen until Flush is called.
TEST_P(QpackEncoderStreamSenderTest,Coalesce)174 TEST_P(QpackEncoderStreamSenderTest, Coalesce) {
175   // Insert entry with static name reference, empty value.
176   stream_.SendInsertWithNameReference(true, 5, "");
177 
178   // Insert entry with static name reference, Huffman encoded value.
179   stream_.SendInsertWithNameReference(true, 2, "foo");
180 
181   // Insert literal entry, Huffman encoded short strings.
182   stream_.SendInsertWithoutNameReference("foo", "foo");
183 
184   // Duplicate entry.
185   stream_.SendDuplicate(17);
186 
187   std::string expected_encoded_data;
188   if (DisableHuffmanEncoding()) {
189     ASSERT_TRUE(absl::HexStringToBytes(
190         "c500"              // Insert entry with static name reference.
191         "c203666f6f"        // Insert entry with static name reference.
192         "43666f6f03666f6f"  // Insert literal entry.
193         "11",               // Duplicate entry.
194         &expected_encoded_data));
195   } else {
196     ASSERT_TRUE(absl::HexStringToBytes(
197         "c500"          // Insert entry with static name reference.
198         "c28294e7"      // Insert entry with static name reference.
199         "6294e78294e7"  // Insert literal entry.
200         "11",           // Duplicate entry.
201         &expected_encoded_data));
202   }
203   EXPECT_CALL(delegate_, WriteStreamData(Eq(expected_encoded_data)));
204   EXPECT_EQ(expected_encoded_data.size(), stream_.BufferedByteCount());
205   stream_.Flush();
206   EXPECT_EQ(0u, stream_.BufferedByteCount());
207 }
208 
209 // No writes should happen if QpackEncoderStreamSender::Flush() is called
210 // when the buffer is empty.
TEST_P(QpackEncoderStreamSenderTest,FlushEmpty)211 TEST_P(QpackEncoderStreamSenderTest, FlushEmpty) {
212   EXPECT_EQ(0u, stream_.BufferedByteCount());
213   stream_.Flush();
214   EXPECT_EQ(0u, stream_.BufferedByteCount());
215 }
216 
217 }  // namespace
218 }  // namespace test
219 }  // namespace quic
220