blob: 9e38248b036b294239ad2d74b246d0423421553f [file] [log] [blame]
QUICHE teamfd50a402018-12-07 22:54:05 -05001// 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 "net/third_party/quiche/src/http2/http2_structures.h"
6
7// Tests are focused on Http2FrameHeader because it has by far the most
8// methods of any of the structures.
9// Note that EXPECT.*DEATH tests are slow (a fork is probably involved).
10
11// And in case you're wondering, yes, these are ridiculously thorough tests,
12// but believe it or not, I've found stupid bugs this way.
13
14#include <memory>
15#include <ostream>
16#include <sstream>
17#include <tuple>
18#include <type_traits>
19#include <vector>
20
21#include "testing/gmock/include/gmock/gmock.h"
22#include "testing/gtest/include/gtest/gtest.h"
23#include "net/third_party/quiche/src/http2/http2_structures_test_util.h"
24#include "net/third_party/quiche/src/http2/platform/api/http2_string_utils.h"
25#include "net/third_party/quiche/src/http2/platform/api/http2_test_helpers.h"
26#include "net/third_party/quiche/src/http2/test_tools/http2_random.h"
27
28using ::testing::AssertionResult;
29using ::testing::AssertionSuccess;
30using ::testing::Combine;
31using ::testing::HasSubstr;
32using ::testing::MatchesRegex;
33using ::testing::Not;
34using ::testing::Values;
35using ::testing::ValuesIn;
36
37namespace http2 {
38namespace test {
39namespace {
40
41template <typename E>
42E IncrementEnum(E e) {
43 using I = typename std::underlying_type<E>::type;
44 return static_cast<E>(1 + static_cast<I>(e));
45}
46
47template <class T>
48AssertionResult VerifyRandomCalls() {
49 T t1;
50 Http2Random seq1;
51 Randomize(&t1, &seq1);
52
53 T t2;
54 Http2Random seq2(seq1.Key());
55 Randomize(&t2, &seq2);
56
57 // The two Randomize calls should have made the same number of calls into
58 // the Http2Random implementations.
59 VERIFY_EQ(seq1.Rand64(), seq2.Rand64());
60
61 // And because Http2Random implementation is returning the same sequence, and
62 // Randomize should have been consistent in applying those results, the two
63 // Ts should have the same value.
64 VERIFY_EQ(t1, t2);
65
66 Randomize(&t2, &seq2);
67 VERIFY_NE(t1, t2);
68
69 Randomize(&t1, &seq1);
70 VERIFY_EQ(t1, t2);
71
72 VERIFY_EQ(seq1.Rand64(), seq2.Rand64());
73
74 return AssertionSuccess();
75}
76
77#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
78std::vector<Http2FrameType> ValidFrameTypes() {
79 std::vector<Http2FrameType> valid_types{Http2FrameType::DATA};
80 while (valid_types.back() != Http2FrameType::ALTSVC) {
81 valid_types.push_back(IncrementEnum(valid_types.back()));
82 }
83 return valid_types;
84}
85#endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
86
87TEST(Http2FrameHeaderTest, Constructor) {
88 Http2Random random;
89 uint8_t frame_type = 0;
90 do {
91 // Only the payload length is DCHECK'd in the constructor, so we need to
92 // make sure it is a "uint24".
93 uint32_t payload_length = random.Rand32() & 0xffffff;
94 Http2FrameType type = static_cast<Http2FrameType>(frame_type);
95 uint8_t flags = random.Rand8();
96 uint32_t stream_id = random.Rand32();
97
98 Http2FrameHeader v(payload_length, type, flags, stream_id);
99
100 EXPECT_EQ(payload_length, v.payload_length);
101 EXPECT_EQ(type, v.type);
102 EXPECT_EQ(flags, v.flags);
103 EXPECT_EQ(stream_id, v.stream_id);
104 } while (frame_type++ == 255);
105
106#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
107 EXPECT_DEBUG_DEATH(Http2FrameHeader(0x01000000, Http2FrameType::DATA, 0, 1),
108 "payload_length");
109#endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
110}
111
112TEST(Http2FrameHeaderTest, Eq) {
113 Http2Random random;
114 uint32_t payload_length = random.Rand32() & 0xffffff;
115 Http2FrameType type = static_cast<Http2FrameType>(random.Rand8());
116
117 uint8_t flags = random.Rand8();
118 uint32_t stream_id = random.Rand32();
119
120 Http2FrameHeader v(payload_length, type, flags, stream_id);
121
122 EXPECT_EQ(payload_length, v.payload_length);
123 EXPECT_EQ(type, v.type);
124 EXPECT_EQ(flags, v.flags);
125 EXPECT_EQ(stream_id, v.stream_id);
126
127 Http2FrameHeader u(0, type, ~flags, stream_id);
128
129 EXPECT_NE(u, v);
130 EXPECT_NE(v, u);
131 EXPECT_FALSE(u == v);
132 EXPECT_FALSE(v == u);
133 EXPECT_TRUE(u != v);
134 EXPECT_TRUE(v != u);
135
136 u = v;
137
138 EXPECT_EQ(u, v);
139 EXPECT_EQ(v, u);
140 EXPECT_TRUE(u == v);
141 EXPECT_TRUE(v == u);
142 EXPECT_FALSE(u != v);
143 EXPECT_FALSE(v != u);
144
145 EXPECT_TRUE(VerifyRandomCalls<Http2FrameHeader>());
146}
147
148#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
149// The tests of the valid frame types include EXPECT_DEBUG_DEATH, which is
150// quite slow, so using value parameterized tests in order to allow sharding.
151class Http2FrameHeaderTypeAndFlagTest
152 : public ::testing::TestWithParam<
153 std::tuple<Http2FrameType, Http2FrameFlag>> {
154 protected:
155 Http2FrameHeaderTypeAndFlagTest()
156 : type_(std::get<0>(GetParam())), flags_(std::get<1>(GetParam())) {
QUICHE team61940b42019-03-07 23:32:27 -0500157 HTTP2_LOG(INFO) << "Frame type: " << type_;
158 HTTP2_LOG(INFO) << "Frame flags: "
159 << Http2FrameFlagsToString(type_, flags_);
QUICHE teamfd50a402018-12-07 22:54:05 -0500160 }
161
162 const Http2FrameType type_;
163 const Http2FrameFlag flags_;
164};
165
166class IsEndStreamTest : public Http2FrameHeaderTypeAndFlagTest {};
QUICHE team61940b42019-03-07 23:32:27 -0500167INSTANTIATE_TEST_SUITE_P(IsEndStream,
168 IsEndStreamTest,
QUICHE team3cab5a92019-01-30 21:10:16 -0500169 Combine(ValuesIn(ValidFrameTypes()),
170 Values(~Http2FrameFlag::END_STREAM, 0xff)));
QUICHE teamfd50a402018-12-07 22:54:05 -0500171TEST_P(IsEndStreamTest, IsEndStream) {
172 const bool is_set =
173 (flags_ & Http2FrameFlag::END_STREAM) == Http2FrameFlag::END_STREAM;
174 Http2String flags_string;
175 Http2FrameHeader v(0, type_, flags_, 0);
176 switch (type_) {
177 case Http2FrameType::DATA:
178 case Http2FrameType::HEADERS:
179 EXPECT_EQ(is_set, v.IsEndStream()) << v;
180 flags_string = v.FlagsToString();
181 if (is_set) {
182 EXPECT_THAT(flags_string, MatchesRegex(".*\\|?END_STREAM\\|.*"));
183 } else {
184 EXPECT_THAT(flags_string, Not(HasSubstr("END_STREAM")));
185 }
186 v.RetainFlags(Http2FrameFlag::END_STREAM);
187 EXPECT_EQ(is_set, v.IsEndStream()) << v;
188 {
189 std::stringstream s;
190 s << v;
191 EXPECT_EQ(v.ToString(), s.str());
192 if (is_set) {
193 EXPECT_THAT(s.str(), HasSubstr("flags=END_STREAM,"));
194 } else {
195 EXPECT_THAT(s.str(), HasSubstr("flags=,"));
196 }
197 }
198 break;
199 default:
200 EXPECT_DEBUG_DEATH(v.IsEndStream(), "DATA.*HEADERS") << v;
201 }
202}
203
204class IsACKTest : public Http2FrameHeaderTypeAndFlagTest {};
QUICHE team61940b42019-03-07 23:32:27 -0500205INSTANTIATE_TEST_SUITE_P(IsAck,
206 IsACKTest,
QUICHE team3cab5a92019-01-30 21:10:16 -0500207 Combine(ValuesIn(ValidFrameTypes()),
208 Values(~Http2FrameFlag::ACK, 0xff)));
QUICHE teamfd50a402018-12-07 22:54:05 -0500209TEST_P(IsACKTest, IsAck) {
210 const bool is_set = (flags_ & Http2FrameFlag::ACK) == Http2FrameFlag::ACK;
211 Http2String flags_string;
212 Http2FrameHeader v(0, type_, flags_, 0);
213 switch (type_) {
214 case Http2FrameType::SETTINGS:
215 case Http2FrameType::PING:
216 EXPECT_EQ(is_set, v.IsAck()) << v;
217 flags_string = v.FlagsToString();
218 if (is_set) {
219 EXPECT_THAT(flags_string, MatchesRegex(".*\\|?ACK\\|.*"));
220 } else {
221 EXPECT_THAT(flags_string, Not(HasSubstr("ACK")));
222 }
223 v.RetainFlags(Http2FrameFlag::ACK);
224 EXPECT_EQ(is_set, v.IsAck()) << v;
225 {
226 std::stringstream s;
227 s << v;
228 EXPECT_EQ(v.ToString(), s.str());
229 if (is_set) {
230 EXPECT_THAT(s.str(), HasSubstr("flags=ACK,"));
231 } else {
232 EXPECT_THAT(s.str(), HasSubstr("flags=,"));
233 }
234 }
235 break;
236 default:
237 EXPECT_DEBUG_DEATH(v.IsAck(), "SETTINGS.*PING") << v;
238 }
239}
240
241class IsEndHeadersTest : public Http2FrameHeaderTypeAndFlagTest {};
QUICHE team61940b42019-03-07 23:32:27 -0500242INSTANTIATE_TEST_SUITE_P(IsEndHeaders,
243 IsEndHeadersTest,
QUICHE team3cab5a92019-01-30 21:10:16 -0500244 Combine(ValuesIn(ValidFrameTypes()),
245 Values(~Http2FrameFlag::END_HEADERS, 0xff)));
QUICHE teamfd50a402018-12-07 22:54:05 -0500246TEST_P(IsEndHeadersTest, IsEndHeaders) {
247 const bool is_set =
248 (flags_ & Http2FrameFlag::END_HEADERS) == Http2FrameFlag::END_HEADERS;
249 Http2String flags_string;
250 Http2FrameHeader v(0, type_, flags_, 0);
251 switch (type_) {
252 case Http2FrameType::HEADERS:
253 case Http2FrameType::PUSH_PROMISE:
254 case Http2FrameType::CONTINUATION:
255 EXPECT_EQ(is_set, v.IsEndHeaders()) << v;
256 flags_string = v.FlagsToString();
257 if (is_set) {
258 EXPECT_THAT(flags_string, MatchesRegex(".*\\|?END_HEADERS\\|.*"));
259 } else {
260 EXPECT_THAT(flags_string, Not(HasSubstr("END_HEADERS")));
261 }
262 v.RetainFlags(Http2FrameFlag::END_HEADERS);
263 EXPECT_EQ(is_set, v.IsEndHeaders()) << v;
264 {
265 std::stringstream s;
266 s << v;
267 EXPECT_EQ(v.ToString(), s.str());
268 if (is_set) {
269 EXPECT_THAT(s.str(), HasSubstr("flags=END_HEADERS,"));
270 } else {
271 EXPECT_THAT(s.str(), HasSubstr("flags=,"));
272 }
273 }
274 break;
275 default:
276 EXPECT_DEBUG_DEATH(v.IsEndHeaders(),
277 "HEADERS.*PUSH_PROMISE.*CONTINUATION")
278 << v;
279 }
280}
281
282class IsPaddedTest : public Http2FrameHeaderTypeAndFlagTest {};
QUICHE team61940b42019-03-07 23:32:27 -0500283INSTANTIATE_TEST_SUITE_P(IsPadded,
284 IsPaddedTest,
QUICHE team3cab5a92019-01-30 21:10:16 -0500285 Combine(ValuesIn(ValidFrameTypes()),
286 Values(~Http2FrameFlag::PADDED, 0xff)));
QUICHE teamfd50a402018-12-07 22:54:05 -0500287TEST_P(IsPaddedTest, IsPadded) {
288 const bool is_set =
289 (flags_ & Http2FrameFlag::PADDED) == Http2FrameFlag::PADDED;
290 Http2String flags_string;
291 Http2FrameHeader v(0, type_, flags_, 0);
292 switch (type_) {
293 case Http2FrameType::DATA:
294 case Http2FrameType::HEADERS:
295 case Http2FrameType::PUSH_PROMISE:
296 EXPECT_EQ(is_set, v.IsPadded()) << v;
297 flags_string = v.FlagsToString();
298 if (is_set) {
299 EXPECT_THAT(flags_string, MatchesRegex(".*\\|?PADDED\\|.*"));
300 } else {
301 EXPECT_THAT(flags_string, Not(HasSubstr("PADDED")));
302 }
303 v.RetainFlags(Http2FrameFlag::PADDED);
304 EXPECT_EQ(is_set, v.IsPadded()) << v;
305 {
306 std::stringstream s;
307 s << v;
308 EXPECT_EQ(v.ToString(), s.str());
309 if (is_set) {
310 EXPECT_THAT(s.str(), HasSubstr("flags=PADDED,"));
311 } else {
312 EXPECT_THAT(s.str(), HasSubstr("flags=,"));
313 }
314 }
315 break;
316 default:
317 EXPECT_DEBUG_DEATH(v.IsPadded(), "DATA.*HEADERS.*PUSH_PROMISE") << v;
318 }
319}
320
321class HasPriorityTest : public Http2FrameHeaderTypeAndFlagTest {};
QUICHE team61940b42019-03-07 23:32:27 -0500322INSTANTIATE_TEST_SUITE_P(HasPriority,
323 HasPriorityTest,
QUICHE team3cab5a92019-01-30 21:10:16 -0500324 Combine(ValuesIn(ValidFrameTypes()),
325 Values(~Http2FrameFlag::PRIORITY, 0xff)));
QUICHE teamfd50a402018-12-07 22:54:05 -0500326TEST_P(HasPriorityTest, HasPriority) {
327 const bool is_set =
328 (flags_ & Http2FrameFlag::PRIORITY) == Http2FrameFlag::PRIORITY;
329 Http2String flags_string;
330 Http2FrameHeader v(0, type_, flags_, 0);
331 switch (type_) {
332 case Http2FrameType::HEADERS:
333 EXPECT_EQ(is_set, v.HasPriority()) << v;
334 flags_string = v.FlagsToString();
335 if (is_set) {
336 EXPECT_THAT(flags_string, MatchesRegex(".*\\|?PRIORITY\\|.*"));
337 } else {
338 EXPECT_THAT(flags_string, Not(HasSubstr("PRIORITY")));
339 }
340 v.RetainFlags(Http2FrameFlag::PRIORITY);
341 EXPECT_EQ(is_set, v.HasPriority()) << v;
342 {
343 std::stringstream s;
344 s << v;
345 EXPECT_EQ(v.ToString(), s.str());
346 if (is_set) {
347 EXPECT_THAT(s.str(), HasSubstr("flags=PRIORITY,"));
348 } else {
349 EXPECT_THAT(s.str(), HasSubstr("flags=,"));
350 }
351 }
352 break;
353 default:
354 EXPECT_DEBUG_DEATH(v.HasPriority(), "HEADERS") << v;
355 }
356}
357
358TEST(Http2PriorityFieldsTest, Constructor) {
359 Http2Random random;
360 uint32_t stream_dependency = random.Rand32() & StreamIdMask();
361 uint32_t weight = 1 + random.Rand8();
362 bool is_exclusive = random.OneIn(2);
363
364 Http2PriorityFields v(stream_dependency, weight, is_exclusive);
365
366 EXPECT_EQ(stream_dependency, v.stream_dependency);
367 EXPECT_EQ(weight, v.weight);
368 EXPECT_EQ(is_exclusive, v.is_exclusive);
369
370 // The high-bit must not be set on the stream id.
371 EXPECT_DEBUG_DEATH(
372 Http2PriorityFields(stream_dependency | 0x80000000, weight, is_exclusive),
373 "31-bit");
374
375 // The weight must be in the range 1-256.
376 EXPECT_DEBUG_DEATH(Http2PriorityFields(stream_dependency, 0, is_exclusive),
377 "too small");
378 EXPECT_DEBUG_DEATH(
379 Http2PriorityFields(stream_dependency, weight + 256, is_exclusive),
380 "too large");
381
382 EXPECT_TRUE(VerifyRandomCalls<Http2PriorityFields>());
383}
384#endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
385
386TEST(Http2RstStreamFieldsTest, IsSupported) {
387 Http2RstStreamFields v{Http2ErrorCode::HTTP2_NO_ERROR};
388 EXPECT_TRUE(v.IsSupportedErrorCode()) << v;
389
390 Http2RstStreamFields u{static_cast<Http2ErrorCode>(~0)};
391 EXPECT_FALSE(u.IsSupportedErrorCode()) << v;
392
393 EXPECT_TRUE(VerifyRandomCalls<Http2RstStreamFields>());
394}
395
396TEST(Http2SettingFieldsTest, Misc) {
397 Http2Random random;
398 Http2SettingsParameter parameter =
399 static_cast<Http2SettingsParameter>(random.Rand16());
400 uint32_t value = random.Rand32();
401
402 Http2SettingFields v(parameter, value);
403
404 EXPECT_EQ(v, v);
405 EXPECT_EQ(parameter, v.parameter);
406 EXPECT_EQ(value, v.value);
407
408 if (static_cast<uint16_t>(parameter) < 7) {
409 EXPECT_TRUE(v.IsSupportedParameter()) << v;
410 } else {
411 EXPECT_FALSE(v.IsSupportedParameter()) << v;
412 }
413
414 Http2SettingFields u(parameter, ~value);
415 EXPECT_NE(v, u);
416 EXPECT_EQ(v.parameter, u.parameter);
417 EXPECT_NE(v.value, u.value);
418
419 Http2SettingFields w(IncrementEnum(parameter), value);
420 EXPECT_NE(v, w);
421 EXPECT_NE(v.parameter, w.parameter);
422 EXPECT_EQ(v.value, w.value);
423
424 Http2SettingFields x(Http2SettingsParameter::MAX_FRAME_SIZE, 123);
425 std::stringstream s;
426 s << x;
427 EXPECT_EQ("parameter=MAX_FRAME_SIZE, value=123", s.str());
428
429 EXPECT_TRUE(VerifyRandomCalls<Http2SettingFields>());
430}
431
432TEST(Http2PushPromiseTest, Misc) {
433 Http2Random random;
434 uint32_t promised_stream_id = random.Rand32() & StreamIdMask();
435
436 Http2PushPromiseFields v{promised_stream_id};
437 EXPECT_EQ(promised_stream_id, v.promised_stream_id);
438 EXPECT_EQ(v, v);
439
440 std::stringstream s;
441 s << v;
442 EXPECT_EQ(Http2StrCat("promised_stream_id=", promised_stream_id), s.str());
443
444 // High-bit is reserved, but not used, so we can set it.
445 promised_stream_id |= 0x80000000;
446 Http2PushPromiseFields w{promised_stream_id};
447 EXPECT_EQ(w, w);
448 EXPECT_NE(v, w);
449
450 v.promised_stream_id = promised_stream_id;
451 EXPECT_EQ(v, w);
452
453 EXPECT_TRUE(VerifyRandomCalls<Http2PushPromiseFields>());
454}
455
456TEST(Http2PingFieldsTest, Misc) {
457 Http2PingFields v{{'8', ' ', 'b', 'y', 't', 'e', 's', '\0'}};
458 std::stringstream s;
459 s << v;
460 EXPECT_EQ("opaque_bytes=0x3820627974657300", s.str());
461
462 EXPECT_TRUE(VerifyRandomCalls<Http2PingFields>());
463}
464
465TEST(Http2GoAwayFieldsTest, Misc) {
466 Http2Random random;
467 uint32_t last_stream_id = random.Rand32() & StreamIdMask();
468 Http2ErrorCode error_code = static_cast<Http2ErrorCode>(random.Rand32());
469
470 Http2GoAwayFields v(last_stream_id, error_code);
471 EXPECT_EQ(v, v);
472 EXPECT_EQ(last_stream_id, v.last_stream_id);
473 EXPECT_EQ(error_code, v.error_code);
474
475 if (static_cast<uint32_t>(error_code) < 14) {
476 EXPECT_TRUE(v.IsSupportedErrorCode()) << v;
477 } else {
478 EXPECT_FALSE(v.IsSupportedErrorCode()) << v;
479 }
480
481 Http2GoAwayFields u(~last_stream_id, error_code);
482 EXPECT_NE(v, u);
483 EXPECT_NE(v.last_stream_id, u.last_stream_id);
484 EXPECT_EQ(v.error_code, u.error_code);
485
486 EXPECT_TRUE(VerifyRandomCalls<Http2GoAwayFields>());
487}
488
489TEST(Http2WindowUpdateTest, Misc) {
490 Http2Random random;
491 uint32_t window_size_increment = random.Rand32() & UInt31Mask();
492
493 Http2WindowUpdateFields v{window_size_increment};
494 EXPECT_EQ(window_size_increment, v.window_size_increment);
495 EXPECT_EQ(v, v);
496
497 std::stringstream s;
498 s << v;
499 EXPECT_EQ(Http2StrCat("window_size_increment=", window_size_increment),
500 s.str());
501
502 // High-bit is reserved, but not used, so we can set it.
503 window_size_increment |= 0x80000000;
504 Http2WindowUpdateFields w{window_size_increment};
505 EXPECT_EQ(w, w);
506 EXPECT_NE(v, w);
507
508 v.window_size_increment = window_size_increment;
509 EXPECT_EQ(v, w);
510
511 EXPECT_TRUE(VerifyRandomCalls<Http2WindowUpdateFields>());
512}
513
514TEST(Http2AltSvcTest, Misc) {
515 Http2Random random;
516 uint16_t origin_length = random.Rand16();
517
518 Http2AltSvcFields v{origin_length};
519 EXPECT_EQ(origin_length, v.origin_length);
520 EXPECT_EQ(v, v);
521
522 std::stringstream s;
523 s << v;
524 EXPECT_EQ(Http2StrCat("origin_length=", origin_length), s.str());
525
526 Http2AltSvcFields w{++origin_length};
527 EXPECT_EQ(w, w);
528 EXPECT_NE(v, w);
529
530 v.origin_length = w.origin_length;
531 EXPECT_EQ(v, w);
532
533 EXPECT_TRUE(VerifyRandomCalls<Http2AltSvcFields>());
534}
535
536} // namespace
537} // namespace test
538} // namespace http2