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 <string>
6 #include <tuple>
7
8 #include "absl/strings/string_view.h"
9 #include "quiche/quic/core/qpack/qpack_decoder.h"
10 #include "quiche/quic/core/qpack/qpack_encoder.h"
11 #include "quiche/quic/platform/api/quic_test.h"
12 #include "quiche/quic/test_tools/qpack/qpack_decoder_test_utils.h"
13 #include "quiche/quic/test_tools/qpack/qpack_test_utils.h"
14 #include "quiche/spdy/core/http2_header_block.h"
15
16 using ::testing::Values;
17
18 namespace quic {
19 namespace test {
20 namespace {
21
22 class QpackRoundTripTest : public QuicTestWithParam<FragmentMode> {
23 public:
24 QpackRoundTripTest() = default;
25 ~QpackRoundTripTest() override = default;
26
EncodeThenDecode(const spdy::Http2HeaderBlock & header_list)27 spdy::Http2HeaderBlock EncodeThenDecode(
28 const spdy::Http2HeaderBlock& header_list) {
29 NoopDecoderStreamErrorDelegate decoder_stream_error_delegate;
30 NoopQpackStreamSenderDelegate encoder_stream_sender_delegate;
31 QpackEncoder encoder(&decoder_stream_error_delegate,
32 HuffmanEncoding::kEnabled);
33 encoder.set_qpack_stream_sender_delegate(&encoder_stream_sender_delegate);
34 std::string encoded_header_block =
35 encoder.EncodeHeaderList(/* stream_id = */ 1, header_list, nullptr);
36
37 TestHeadersHandler handler;
38 NoopEncoderStreamErrorDelegate encoder_stream_error_delegate;
39 NoopQpackStreamSenderDelegate decoder_stream_sender_delegate;
40 // TODO(b/112770235): Test dynamic table and blocked streams.
41 QpackDecode(
42 /* maximum_dynamic_table_capacity = */ 0,
43 /* maximum_blocked_streams = */ 0, &encoder_stream_error_delegate,
44 &decoder_stream_sender_delegate, &handler,
45 FragmentModeToFragmentSizeGenerator(GetParam()), encoded_header_block);
46
47 EXPECT_TRUE(handler.decoding_completed());
48 EXPECT_FALSE(handler.decoding_error_detected());
49
50 return handler.ReleaseHeaderList();
51 }
52 };
53
54 INSTANTIATE_TEST_SUITE_P(All, QpackRoundTripTest,
55 Values(FragmentMode::kSingleChunk,
56 FragmentMode::kOctetByOctet));
57
TEST_P(QpackRoundTripTest,Empty)58 TEST_P(QpackRoundTripTest, Empty) {
59 spdy::Http2HeaderBlock header_list;
60 spdy::Http2HeaderBlock output = EncodeThenDecode(header_list);
61 EXPECT_EQ(header_list, output);
62 }
63
TEST_P(QpackRoundTripTest,EmptyName)64 TEST_P(QpackRoundTripTest, EmptyName) {
65 spdy::Http2HeaderBlock header_list;
66 header_list["foo"] = "bar";
67 header_list[""] = "bar";
68
69 spdy::Http2HeaderBlock output = EncodeThenDecode(header_list);
70 EXPECT_EQ(header_list, output);
71 }
72
TEST_P(QpackRoundTripTest,EmptyValue)73 TEST_P(QpackRoundTripTest, EmptyValue) {
74 spdy::Http2HeaderBlock header_list;
75 header_list["foo"] = "";
76 header_list[""] = "";
77
78 spdy::Http2HeaderBlock output = EncodeThenDecode(header_list);
79 EXPECT_EQ(header_list, output);
80 }
81
TEST_P(QpackRoundTripTest,MultipleWithLongEntries)82 TEST_P(QpackRoundTripTest, MultipleWithLongEntries) {
83 spdy::Http2HeaderBlock header_list;
84 header_list["foo"] = "bar";
85 header_list[":path"] = "/";
86 header_list["foobaar"] = std::string(127, 'Z');
87 header_list[std::string(1000, 'b')] = std::string(1000, 'c');
88
89 spdy::Http2HeaderBlock output = EncodeThenDecode(header_list);
90 EXPECT_EQ(header_list, output);
91 }
92
TEST_P(QpackRoundTripTest,StaticTable)93 TEST_P(QpackRoundTripTest, StaticTable) {
94 {
95 spdy::Http2HeaderBlock header_list;
96 header_list[":method"] = "GET";
97 header_list["accept-encoding"] = "gzip, deflate";
98 header_list["cache-control"] = "";
99 header_list["foo"] = "bar";
100 header_list[":path"] = "/";
101
102 spdy::Http2HeaderBlock output = EncodeThenDecode(header_list);
103 EXPECT_EQ(header_list, output);
104 }
105 {
106 spdy::Http2HeaderBlock header_list;
107 header_list[":method"] = "POST";
108 header_list["accept-encoding"] = "brotli";
109 header_list["cache-control"] = "foo";
110 header_list["foo"] = "bar";
111 header_list[":path"] = "/";
112
113 spdy::Http2HeaderBlock output = EncodeThenDecode(header_list);
114 EXPECT_EQ(header_list, output);
115 }
116 {
117 spdy::Http2HeaderBlock header_list;
118 header_list[":method"] = "CONNECT";
119 header_list["accept-encoding"] = "";
120 header_list["foo"] = "bar";
121 header_list[":path"] = "/";
122
123 spdy::Http2HeaderBlock output = EncodeThenDecode(header_list);
124 EXPECT_EQ(header_list, output);
125 }
126 }
127
TEST_P(QpackRoundTripTest,ValueHasNullCharacter)128 TEST_P(QpackRoundTripTest, ValueHasNullCharacter) {
129 spdy::Http2HeaderBlock header_list;
130 header_list["foo"] = absl::string_view("bar\0bar\0baz", 11);
131
132 spdy::Http2HeaderBlock output = EncodeThenDecode(header_list);
133 EXPECT_EQ(header_list, output);
134 }
135
136 } // namespace
137 } // namespace test
138 } // namespace quic
139