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