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