blob: dd8079e63207984229ffeeaa8f49cdb5b5347785 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -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 <memory>
vasilvv872e7a32019-03-12 16:42:44 -07006#include <string>
QUICHE teama6ef0a62019-03-07 20:34:33 -05007
QUICHE teama6ef0a62019-03-07 20:34:33 -05008#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -05009#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
bnc4e9283d2019-12-17 07:08:57 -080010#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h"
dmcardleba2fb7e2019-12-13 07:44:34 -080011#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
12#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050013
14using spdy::SpdyHeaderBlock;
15using testing::Pair;
16using testing::UnorderedElementsAre;
17
18namespace quic {
19namespace test {
bnc5231ee22019-04-15 19:02:13 -070020namespace {
21
22const bool kExpectFinalByteOffset = true;
23const bool kDoNotExpectFinalByteOffset = false;
QUICHE teama6ef0a62019-03-07 20:34:33 -050024
25static std::unique_ptr<QuicHeaderList> FromList(
26 const QuicHeaderList::ListType& src) {
27 std::unique_ptr<QuicHeaderList> headers(new QuicHeaderList);
28 headers->OnHeaderBlockStart();
29 for (const auto& p : src) {
30 headers->OnHeader(p.first, p.second);
31 }
32 headers->OnHeaderBlockEnd(0, 0);
33 return headers;
34}
35
bnc5231ee22019-04-15 19:02:13 -070036} // anonymous namespace
37
QUICHE teama6ef0a62019-03-07 20:34:33 -050038using CopyAndValidateHeaders = QuicTest;
39
40TEST_F(CopyAndValidateHeaders, NormalUsage) {
41 auto headers = FromList({// All cookie crumbs are joined.
42 {"cookie", " part 1"},
43 {"cookie", "part 2 "},
44 {"cookie", "part3"},
45
46 // Already-delimited headers are passed through.
vasilvvc48c8712019-03-11 13:38:16 -070047 {"passed-through", std::string("foo\0baz", 7)},
QUICHE teama6ef0a62019-03-07 20:34:33 -050048
49 // Other headers are joined on \0.
50 {"joined", "value 1"},
51 {"joined", "value 2"},
52
53 // Empty headers remain empty.
54 {"empty", ""},
55
56 // Joined empty headers work as expected.
57 {"empty-joined", ""},
58 {"empty-joined", "foo"},
59 {"empty-joined", ""},
60 {"empty-joined", ""},
61
62 // Non-continguous cookie crumb.
63 {"cookie", " fin!"}});
64
65 int64_t content_length = -1;
66 SpdyHeaderBlock block;
67 ASSERT_TRUE(
68 SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
dmcardleba2fb7e2019-12-13 07:44:34 -080069 EXPECT_THAT(
70 block,
71 UnorderedElementsAre(
72 Pair("cookie", " part 1; part 2 ; part3; fin!"),
73 Pair("passed-through", quiche::QuicheStringPiece("foo\0baz", 7)),
74 Pair("joined", quiche::QuicheStringPiece("value 1\0value 2", 15)),
75 Pair("empty", ""),
76 Pair("empty-joined", quiche::QuicheStringPiece("\0foo\0\0", 6))));
QUICHE teama6ef0a62019-03-07 20:34:33 -050077 EXPECT_EQ(-1, content_length);
78}
79
80TEST_F(CopyAndValidateHeaders, EmptyName) {
81 auto headers = FromList({{"foo", "foovalue"}, {"", "barvalue"}, {"baz", ""}});
82 int64_t content_length = -1;
83 SpdyHeaderBlock block;
84 ASSERT_FALSE(
85 SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
86}
87
88TEST_F(CopyAndValidateHeaders, UpperCaseName) {
89 auto headers =
90 FromList({{"foo", "foovalue"}, {"bar", "barvalue"}, {"bAz", ""}});
91 int64_t content_length = -1;
92 SpdyHeaderBlock block;
93 ASSERT_FALSE(
94 SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
95}
96
97TEST_F(CopyAndValidateHeaders, MultipleContentLengths) {
98 auto headers = FromList({{"content-length", "9"},
99 {"foo", "foovalue"},
100 {"content-length", "9"},
101 {"bar", "barvalue"},
102 {"baz", ""}});
103 int64_t content_length = -1;
104 SpdyHeaderBlock block;
105 ASSERT_TRUE(
106 SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
dmcardleba2fb7e2019-12-13 07:44:34 -0800107 EXPECT_THAT(block,
108 UnorderedElementsAre(
109 Pair("foo", "foovalue"), Pair("bar", "barvalue"),
110 Pair("content-length", quiche::QuicheStringPiece("9\09", 3)),
111 Pair("baz", "")));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500112 EXPECT_EQ(9, content_length);
113}
114
115TEST_F(CopyAndValidateHeaders, InconsistentContentLengths) {
116 auto headers = FromList({{"content-length", "9"},
117 {"foo", "foovalue"},
118 {"content-length", "8"},
119 {"bar", "barvalue"},
120 {"baz", ""}});
121 int64_t content_length = -1;
122 SpdyHeaderBlock block;
123 ASSERT_FALSE(
124 SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
125}
126
127TEST_F(CopyAndValidateHeaders, LargeContentLength) {
128 auto headers = FromList({{"content-length", "9000000000"},
129 {"foo", "foovalue"},
130 {"bar", "barvalue"},
131 {"baz", ""}});
132 int64_t content_length = -1;
133 SpdyHeaderBlock block;
134 ASSERT_TRUE(
135 SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
136 EXPECT_THAT(block, UnorderedElementsAre(
137 Pair("foo", "foovalue"), Pair("bar", "barvalue"),
dmcardleba2fb7e2019-12-13 07:44:34 -0800138 Pair("content-length",
139 quiche::QuicheStringPiece("9000000000")),
QUICHE teama6ef0a62019-03-07 20:34:33 -0500140 Pair("baz", "")));
141 EXPECT_EQ(9000000000, content_length);
142}
143
nharperd89ad8d2020-08-07 15:05:36 -0700144TEST_F(CopyAndValidateHeaders, NonDigitContentLength) {
145 // Section 3.3.2 of RFC 7230 defines content-length as being only digits.
146 // Number parsers might accept symbols like a leading plus; test that this
147 // fails to parse.
148 auto headers = FromList({{"content-length", "+123"},
149 {"foo", "foovalue"},
150 {"bar", "barvalue"},
151 {"baz", ""}});
152 int64_t content_length = -1;
153 SpdyHeaderBlock block;
154 EXPECT_FALSE(
155 SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
156}
157
QUICHE teama6ef0a62019-03-07 20:34:33 -0500158TEST_F(CopyAndValidateHeaders, MultipleValues) {
159 auto headers = FromList({{"foo", "foovalue"},
160 {"bar", "barvalue"},
161 {"baz", ""},
162 {"foo", "boo"},
163 {"baz", "buzz"}});
164 int64_t content_length = -1;
165 SpdyHeaderBlock block;
166 ASSERT_TRUE(
167 SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
dmcardleba2fb7e2019-12-13 07:44:34 -0800168 EXPECT_THAT(block,
169 UnorderedElementsAre(
170 Pair("foo", quiche::QuicheStringPiece("foovalue\0boo", 12)),
171 Pair("bar", "barvalue"),
172 Pair("baz", quiche::QuicheStringPiece("\0buzz", 5))));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500173 EXPECT_EQ(-1, content_length);
174}
175
176TEST_F(CopyAndValidateHeaders, MoreThanTwoValues) {
177 auto headers = FromList({{"set-cookie", "value1"},
178 {"set-cookie", "value2"},
179 {"set-cookie", "value3"}});
180 int64_t content_length = -1;
181 SpdyHeaderBlock block;
182 ASSERT_TRUE(
183 SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
dmcardleba2fb7e2019-12-13 07:44:34 -0800184 EXPECT_THAT(block, UnorderedElementsAre(Pair(
185 "set-cookie", quiche::QuicheStringPiece(
186 "value1\0value2\0value3", 20))));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500187 EXPECT_EQ(-1, content_length);
188}
189
190TEST_F(CopyAndValidateHeaders, Cookie) {
191 auto headers = FromList({{"foo", "foovalue"},
192 {"bar", "barvalue"},
193 {"cookie", "value1"},
194 {"baz", ""}});
195 int64_t content_length = -1;
196 SpdyHeaderBlock block;
197 ASSERT_TRUE(
198 SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
199 EXPECT_THAT(block, UnorderedElementsAre(
200 Pair("foo", "foovalue"), Pair("bar", "barvalue"),
201 Pair("cookie", "value1"), Pair("baz", "")));
202 EXPECT_EQ(-1, content_length);
203}
204
205TEST_F(CopyAndValidateHeaders, MultipleCookies) {
206 auto headers = FromList({{"foo", "foovalue"},
207 {"bar", "barvalue"},
208 {"cookie", "value1"},
209 {"baz", ""},
210 {"cookie", "value2"}});
211 int64_t content_length = -1;
212 SpdyHeaderBlock block;
213 ASSERT_TRUE(
214 SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
215 EXPECT_THAT(block, UnorderedElementsAre(
216 Pair("foo", "foovalue"), Pair("bar", "barvalue"),
217 Pair("cookie", "value1; value2"), Pair("baz", "")));
218 EXPECT_EQ(-1, content_length);
219}
220
221using CopyAndValidateTrailers = QuicTest;
222
223TEST_F(CopyAndValidateTrailers, SimplestValidList) {
224 // Verify that the simplest trailers are valid: just a final byte offset that
225 // gets parsed successfully.
226 auto trailers = FromList({{kFinalOffsetHeaderKey, "1234"}});
227 size_t final_byte_offset = 0;
228 SpdyHeaderBlock block;
bnc5231ee22019-04-15 19:02:13 -0700229 EXPECT_TRUE(SpdyUtils::CopyAndValidateTrailers(
230 *trailers, kExpectFinalByteOffset, &final_byte_offset, &block));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500231 EXPECT_EQ(1234u, final_byte_offset);
232}
233
bnc5231ee22019-04-15 19:02:13 -0700234TEST_F(CopyAndValidateTrailers, EmptyTrailerListWithFinalByteOffsetExpected) {
235 // An empty trailer list will fail as expected key kFinalOffsetHeaderKey is
QUICHE teama6ef0a62019-03-07 20:34:33 -0500236 // not present.
237 QuicHeaderList trailers;
238 size_t final_byte_offset = 0;
239 SpdyHeaderBlock block;
bnc5231ee22019-04-15 19:02:13 -0700240 EXPECT_FALSE(SpdyUtils::CopyAndValidateTrailers(
241 trailers, kExpectFinalByteOffset, &final_byte_offset, &block));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500242}
243
bnc5231ee22019-04-15 19:02:13 -0700244TEST_F(CopyAndValidateTrailers,
245 EmptyTrailerListWithFinalByteOffsetNotExpected) {
246 // An empty trailer list will pass successfully if kFinalOffsetHeaderKey is
247 // not expected.
248 QuicHeaderList trailers;
249 size_t final_byte_offset = 0;
250 SpdyHeaderBlock block;
251 EXPECT_TRUE(SpdyUtils::CopyAndValidateTrailers(
252 trailers, kDoNotExpectFinalByteOffset, &final_byte_offset, &block));
253 EXPECT_TRUE(block.empty());
254}
255
256TEST_F(CopyAndValidateTrailers, FinalByteOffsetExpectedButNotPresent) {
257 // Validation fails if expected kFinalOffsetHeaderKey is not present, even if
QUICHE teama6ef0a62019-03-07 20:34:33 -0500258 // the rest of the header block is valid.
259 auto trailers = FromList({{"key", "value"}});
260 size_t final_byte_offset = 0;
261 SpdyHeaderBlock block;
bnc5231ee22019-04-15 19:02:13 -0700262 EXPECT_FALSE(SpdyUtils::CopyAndValidateTrailers(
263 *trailers, kExpectFinalByteOffset, &final_byte_offset, &block));
264}
265
266TEST_F(CopyAndValidateTrailers, FinalByteOffsetNotExpectedButPresent) {
267 // Validation fails if kFinalOffsetHeaderKey is present but should not be,
268 // even if the rest of the header block is valid.
269 auto trailers = FromList({{"key", "value"}, {kFinalOffsetHeaderKey, "1234"}});
270 size_t final_byte_offset = 0;
271 SpdyHeaderBlock block;
272 EXPECT_FALSE(SpdyUtils::CopyAndValidateTrailers(
273 *trailers, kDoNotExpectFinalByteOffset, &final_byte_offset, &block));
274}
275
276TEST_F(CopyAndValidateTrailers, FinalByteOffsetNotExpectedAndNotPresent) {
277 // Validation succeeds if kFinalOffsetHeaderKey is not expected and not
278 // present.
279 auto trailers = FromList({{"key", "value"}});
280 size_t final_byte_offset = 0;
281 SpdyHeaderBlock block;
282 EXPECT_TRUE(SpdyUtils::CopyAndValidateTrailers(
283 *trailers, kDoNotExpectFinalByteOffset, &final_byte_offset, &block));
284 EXPECT_THAT(block, UnorderedElementsAre(Pair("key", "value")));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500285}
286
287TEST_F(CopyAndValidateTrailers, EmptyName) {
288 // Trailer validation will fail with an empty header key, in an otherwise
289 // valid block of trailers.
290 auto trailers = FromList({{"", "value"}, {kFinalOffsetHeaderKey, "1234"}});
291 size_t final_byte_offset = 0;
292 SpdyHeaderBlock block;
bnc5231ee22019-04-15 19:02:13 -0700293 EXPECT_FALSE(SpdyUtils::CopyAndValidateTrailers(
294 *trailers, kExpectFinalByteOffset, &final_byte_offset, &block));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500295}
296
297TEST_F(CopyAndValidateTrailers, PseudoHeaderInTrailers) {
298 // Pseudo headers are illegal in trailers.
299 auto trailers =
300 FromList({{":pseudo_key", "value"}, {kFinalOffsetHeaderKey, "1234"}});
301 size_t final_byte_offset = 0;
302 SpdyHeaderBlock block;
bnc5231ee22019-04-15 19:02:13 -0700303 EXPECT_FALSE(SpdyUtils::CopyAndValidateTrailers(
304 *trailers, kExpectFinalByteOffset, &final_byte_offset, &block));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500305}
306
307TEST_F(CopyAndValidateTrailers, DuplicateTrailers) {
308 // Duplicate trailers are allowed, and their values are concatenated into a
309 // single string delimted with '\0'. Some of the duplicate headers
310 // deliberately have an empty value.
311 auto trailers = FromList({{"key", "value0"},
312 {"key", "value1"},
313 {"key", ""},
314 {"key", ""},
315 {"key", "value2"},
316 {"key", ""},
317 {kFinalOffsetHeaderKey, "1234"},
318 {"other_key", "value"},
319 {"key", "non_contiguous_duplicate"}});
320 size_t final_byte_offset = 0;
321 SpdyHeaderBlock block;
bnc5231ee22019-04-15 19:02:13 -0700322 EXPECT_TRUE(SpdyUtils::CopyAndValidateTrailers(
323 *trailers, kExpectFinalByteOffset, &final_byte_offset, &block));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500324 EXPECT_THAT(
325 block,
326 UnorderedElementsAre(
327 Pair("key",
dmcardleba2fb7e2019-12-13 07:44:34 -0800328 quiche::QuicheStringPiece(
QUICHE teama6ef0a62019-03-07 20:34:33 -0500329 "value0\0value1\0\0\0value2\0\0non_contiguous_duplicate",
330 48)),
331 Pair("other_key", "value")));
332}
333
334TEST_F(CopyAndValidateTrailers, DuplicateCookies) {
335 // Duplicate cookie headers in trailers should be concatenated into a single
336 // "; " delimted string.
337 auto headers = FromList({{"cookie", " part 1"},
338 {"cookie", "part 2 "},
339 {"cookie", "part3"},
340 {"key", "value"},
341 {kFinalOffsetHeaderKey, "1234"},
342 {"cookie", " non_contiguous_cookie!"}});
343
344 size_t final_byte_offset = 0;
345 SpdyHeaderBlock block;
bnc5231ee22019-04-15 19:02:13 -0700346 EXPECT_TRUE(SpdyUtils::CopyAndValidateTrailers(
347 *headers, kExpectFinalByteOffset, &final_byte_offset, &block));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500348 EXPECT_THAT(
349 block,
350 UnorderedElementsAre(
351 Pair("cookie", " part 1; part 2 ; part3; non_contiguous_cookie!"),
352 Pair("key", "value")));
353}
354
QUICHE teama6ef0a62019-03-07 20:34:33 -0500355using PopulateHeaderBlockFromUrl = QuicTest;
356
357TEST_F(PopulateHeaderBlockFromUrl, NormalUsage) {
vasilvvc48c8712019-03-11 13:38:16 -0700358 std::string url = "https://www.google.com/index.html";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500359 SpdyHeaderBlock headers;
360 EXPECT_TRUE(SpdyUtils::PopulateHeaderBlockFromUrl(url, &headers));
361 EXPECT_EQ("https", headers[":scheme"].as_string());
362 EXPECT_EQ("www.google.com", headers[":authority"].as_string());
363 EXPECT_EQ("/index.html", headers[":path"].as_string());
364}
365
366TEST_F(PopulateHeaderBlockFromUrl, UrlWithNoPath) {
vasilvvc48c8712019-03-11 13:38:16 -0700367 std::string url = "https://www.google.com";
QUICHE teama6ef0a62019-03-07 20:34:33 -0500368 SpdyHeaderBlock headers;
369 EXPECT_TRUE(SpdyUtils::PopulateHeaderBlockFromUrl(url, &headers));
370 EXPECT_EQ("https", headers[":scheme"].as_string());
371 EXPECT_EQ("www.google.com", headers[":authority"].as_string());
372 EXPECT_EQ("/", headers[":path"].as_string());
373}
374
375TEST_F(PopulateHeaderBlockFromUrl, Failure) {
376 SpdyHeaderBlock headers;
377 EXPECT_FALSE(SpdyUtils::PopulateHeaderBlockFromUrl("/", &headers));
378 EXPECT_FALSE(SpdyUtils::PopulateHeaderBlockFromUrl("/index.html", &headers));
379 EXPECT_FALSE(
380 SpdyUtils::PopulateHeaderBlockFromUrl("www.google.com/", &headers));
381}
382
QUICHE teama6ef0a62019-03-07 20:34:33 -0500383} // namespace test
384} // namespace quic