1 // Copyright 2016 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/http2/test_tools/http2_frame_builder.h"
6
7 #include <string>
8
9 #include "absl/strings/escaping.h"
10 #include "quiche/common/platform/api/quiche_test.h"
11
12 namespace http2 {
13 namespace test {
14 namespace {
15
16 const char kHighBitSetMsg[] = "High-bit of uint32_t should be clear";
17
TEST(Http2FrameBuilderTest,Constructors)18 TEST(Http2FrameBuilderTest, Constructors) {
19 {
20 Http2FrameBuilder fb;
21 EXPECT_EQ(0u, fb.size());
22 }
23 {
24 Http2FrameBuilder fb(Http2FrameType::DATA, 0, 123);
25 EXPECT_EQ(9u, fb.size());
26
27 std::string expected_data;
28 ASSERT_TRUE(
29 absl::HexStringToBytes("000000" // Payload length: 0 (unset)
30 "00" // Frame type: DATA
31 "00" // Flags: none
32 "0000007b", // Stream ID: 123
33 &expected_data));
34 EXPECT_EQ(expected_data, fb.buffer());
35 }
36 {
37 Http2FrameHeader header;
38 header.payload_length = (1 << 24) - 1;
39 header.type = Http2FrameType::HEADERS;
40 header.flags = Http2FrameFlag::END_HEADERS;
41 header.stream_id = StreamIdMask();
42 Http2FrameBuilder fb(header);
43 EXPECT_EQ(9u, fb.size());
44
45 std::string expected_data;
46 ASSERT_TRUE(absl::HexStringToBytes(
47 "ffffff" // Payload length: 2^24 - 1 (max uint24)
48 "01" // Frame type: HEADER
49 "04" // Flags: END_HEADERS
50 "7fffffff", // Stream ID: stream id mask
51 &expected_data));
52 EXPECT_EQ(expected_data, fb.buffer());
53 }
54 }
55
TEST(Http2FrameBuilderTest,SetPayloadLength)56 TEST(Http2FrameBuilderTest, SetPayloadLength) {
57 Http2FrameBuilder fb(Http2FrameType::DATA, PADDED, 20000);
58 EXPECT_EQ(9u, fb.size());
59
60 fb.AppendUInt8(50); // Trailing payload length
61 EXPECT_EQ(10u, fb.size());
62
63 fb.Append("ten bytes.");
64 EXPECT_EQ(20u, fb.size());
65
66 fb.AppendZeroes(50);
67 EXPECT_EQ(70u, fb.size());
68
69 fb.SetPayloadLength();
70 EXPECT_EQ(70u, fb.size());
71
72 std::string expected_data;
73 ASSERT_TRUE(
74 absl::HexStringToBytes("00003d" // Payload length: 61
75 "00" // Frame type: DATA
76 "08" // Flags: PADDED
77 "00004e20" // Stream ID: 20000
78 "32" // Padding Length: 50
79 "74656e2062797465732e" // "ten bytes."
80 "00000000000000000000" // Padding bytes
81 "00000000000000000000" // Padding bytes
82 "00000000000000000000" // Padding bytes
83 "00000000000000000000" // Padding bytes
84 "00000000000000000000", // Padding bytes
85 &expected_data));
86 EXPECT_EQ(expected_data, fb.buffer());
87 }
88
TEST(Http2FrameBuilderTest,Settings)89 TEST(Http2FrameBuilderTest, Settings) {
90 Http2FrameBuilder fb(Http2FrameType::SETTINGS, 0, 0);
91 Http2SettingFields sf;
92
93 sf.parameter = Http2SettingsParameter::HEADER_TABLE_SIZE;
94 sf.value = 1 << 12;
95 fb.Append(sf);
96
97 sf.parameter = Http2SettingsParameter::ENABLE_PUSH;
98 sf.value = 0;
99 fb.Append(sf);
100
101 sf.parameter = Http2SettingsParameter::MAX_CONCURRENT_STREAMS;
102 sf.value = ~0;
103 fb.Append(sf);
104
105 sf.parameter = Http2SettingsParameter::INITIAL_WINDOW_SIZE;
106 sf.value = 1 << 16;
107 fb.Append(sf);
108
109 sf.parameter = Http2SettingsParameter::MAX_FRAME_SIZE;
110 sf.value = 1 << 14;
111 fb.Append(sf);
112
113 sf.parameter = Http2SettingsParameter::MAX_HEADER_LIST_SIZE;
114 sf.value = 1 << 10;
115 fb.Append(sf);
116
117 size_t payload_size = 6 * Http2SettingFields::EncodedSize();
118 EXPECT_EQ(Http2FrameHeader::EncodedSize() + payload_size, fb.size());
119
120 fb.SetPayloadLength(payload_size);
121
122 std::string expected_data;
123 ASSERT_TRUE(
124 absl::HexStringToBytes("000024" // Payload length: 36
125 "04" // Frame type: SETTINGS
126 "00" // Flags: none
127 "00000000" // Stream ID: 0
128 "0001" // HEADER_TABLE_SIZE
129 "00001000" // 4096
130 "0002" // ENABLE_PUSH
131 "00000000" // 0
132 "0003" // MAX_CONCURRENT_STREAMS
133 "ffffffff" // 0xffffffff (max uint32)
134 "0004" // INITIAL_WINDOW_SIZE
135 "00010000" // 4096
136 "0005" // MAX_FRAME_SIZE
137 "00004000" // 4096
138 "0006" // MAX_HEADER_LIST_SIZE
139 "00000400", // 1024
140 &expected_data));
141 EXPECT_EQ(expected_data, fb.buffer());
142 }
143
TEST(Http2FrameBuilderTest,EnhanceYourCalm)144 TEST(Http2FrameBuilderTest, EnhanceYourCalm) {
145 std::string expected_data;
146 ASSERT_TRUE(absl::HexStringToBytes("0000000b", &expected_data));
147 {
148 Http2FrameBuilder fb;
149 fb.Append(Http2ErrorCode::ENHANCE_YOUR_CALM);
150 EXPECT_EQ(expected_data, fb.buffer());
151 }
152 {
153 Http2FrameBuilder fb;
154 Http2RstStreamFields rsp;
155 rsp.error_code = Http2ErrorCode::ENHANCE_YOUR_CALM;
156 fb.Append(rsp);
157 EXPECT_EQ(expected_data, fb.buffer());
158 }
159 }
160
TEST(Http2FrameBuilderTest,PushPromise)161 TEST(Http2FrameBuilderTest, PushPromise) {
162 std::string expected_data;
163 ASSERT_TRUE(absl::HexStringToBytes("7fffffff", &expected_data));
164 {
165 Http2FrameBuilder fb;
166 fb.Append(Http2PushPromiseFields{0x7fffffff});
167 EXPECT_EQ(expected_data, fb.buffer());
168 }
169 {
170 Http2FrameBuilder fb;
171 // Will generate an error if the high-bit of the stream id is set.
172 EXPECT_NONFATAL_FAILURE(fb.Append(Http2PushPromiseFields{0xffffffff}),
173 kHighBitSetMsg);
174 EXPECT_EQ(expected_data, fb.buffer());
175 }
176 }
177
TEST(Http2FrameBuilderTest,Ping)178 TEST(Http2FrameBuilderTest, Ping) {
179 Http2FrameBuilder fb;
180 Http2PingFields ping{"8 bytes"};
181 fb.Append(ping);
182
183 const absl::string_view kData{"8 bytes\0", 8};
184 EXPECT_EQ(kData.size(), Http2PingFields::EncodedSize());
185 EXPECT_EQ(kData, fb.buffer());
186 }
187
TEST(Http2FrameBuilderTest,GoAway)188 TEST(Http2FrameBuilderTest, GoAway) {
189 std::string expected_data;
190 ASSERT_TRUE(
191 absl::HexStringToBytes("12345678" // Last Stream Id
192 "00000001", // Error code
193 &expected_data));
194 EXPECT_EQ(expected_data.size(), Http2GoAwayFields::EncodedSize());
195 {
196 Http2FrameBuilder fb;
197 Http2GoAwayFields ga(0x12345678, Http2ErrorCode::PROTOCOL_ERROR);
198 fb.Append(ga);
199 EXPECT_EQ(expected_data, fb.buffer());
200 }
201 {
202 Http2FrameBuilder fb;
203 // Will generate a test failure if the high-bit of the stream id is set.
204 Http2GoAwayFields ga(0x92345678, Http2ErrorCode::PROTOCOL_ERROR);
205 EXPECT_NONFATAL_FAILURE(fb.Append(ga), kHighBitSetMsg);
206 EXPECT_EQ(expected_data, fb.buffer());
207 }
208 }
209
TEST(Http2FrameBuilderTest,WindowUpdate)210 TEST(Http2FrameBuilderTest, WindowUpdate) {
211 Http2FrameBuilder fb;
212 fb.Append(Http2WindowUpdateFields{123456});
213
214 // Will generate a test failure if the high-bit of the increment is set.
215 EXPECT_NONFATAL_FAILURE(fb.Append(Http2WindowUpdateFields{0x80000001}),
216 kHighBitSetMsg);
217
218 // Will generate a test failure if the increment is zero.
219 EXPECT_NONFATAL_FAILURE(fb.Append(Http2WindowUpdateFields{0}), "non-zero");
220
221 std::string expected_data;
222 ASSERT_TRUE(
223 absl::HexStringToBytes("0001e240" // Valid Window Size Increment
224 "00000001" // High-bit cleared
225 "00000000", // Invalid Window Size Increment
226 &expected_data));
227 EXPECT_EQ(expected_data.size(), 3 * Http2WindowUpdateFields::EncodedSize());
228 EXPECT_EQ(expected_data, fb.buffer());
229 }
230
TEST(Http2FrameBuilderTest,AltSvc)231 TEST(Http2FrameBuilderTest, AltSvc) {
232 Http2FrameBuilder fb;
233 fb.Append(Http2AltSvcFields{99});
234 fb.Append(Http2AltSvcFields{0}); // No optional origin
235 std::string expected_data;
236 ASSERT_TRUE(
237 absl::HexStringToBytes("0063" // Has origin.
238 "0000", // Doesn't have origin.
239 &expected_data));
240 EXPECT_EQ(expected_data.size(), 2 * Http2AltSvcFields::EncodedSize());
241 EXPECT_EQ(expected_data, fb.buffer());
242 }
243
244 } // namespace
245 } // namespace test
246 } // namespace http2
247