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 <memory>
6 #include <string>
7
8 #include "absl/base/macros.h"
9 #include "absl/strings/string_view.h"
10 #include "net/third_party/quiche/src/quic/core/http/spdy_utils.h"
11 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
12 #include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
13
14 using spdy::SpdyHeaderBlock;
15 using testing::Pair;
16 using testing::UnorderedElementsAre;
17
18 namespace quic {
19 namespace test {
20 namespace {
21
22 const bool kExpectFinalByteOffset = true;
23 const bool kDoNotExpectFinalByteOffset = false;
24
FromList(const QuicHeaderList::ListType & src)25 static 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
36 } // anonymous namespace
37
38 using CopyAndValidateHeaders = QuicTest;
39
TEST_F(CopyAndValidateHeaders,NormalUsage)40 TEST_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.
47 {"passed-through", std::string("foo\0baz", 7)},
48
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));
69 EXPECT_THAT(block,
70 UnorderedElementsAre(
71 Pair("cookie", " part 1; part 2 ; part3; fin!"),
72 Pair("passed-through", absl::string_view("foo\0baz", 7)),
73 Pair("joined", absl::string_view("value 1\0value 2", 15)),
74 Pair("empty", ""),
75 Pair("empty-joined", absl::string_view("\0foo\0\0", 6))));
76 EXPECT_EQ(-1, content_length);
77 }
78
TEST_F(CopyAndValidateHeaders,EmptyName)79 TEST_F(CopyAndValidateHeaders, EmptyName) {
80 auto headers = FromList({{"foo", "foovalue"}, {"", "barvalue"}, {"baz", ""}});
81 int64_t content_length = -1;
82 SpdyHeaderBlock block;
83 ASSERT_FALSE(
84 SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
85 }
86
TEST_F(CopyAndValidateHeaders,UpperCaseName)87 TEST_F(CopyAndValidateHeaders, UpperCaseName) {
88 auto headers =
89 FromList({{"foo", "foovalue"}, {"bar", "barvalue"}, {"bAz", ""}});
90 int64_t content_length = -1;
91 SpdyHeaderBlock block;
92 ASSERT_FALSE(
93 SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
94 }
95
TEST_F(CopyAndValidateHeaders,MultipleContentLengths)96 TEST_F(CopyAndValidateHeaders, MultipleContentLengths) {
97 auto headers = FromList({{"content-length", "9"},
98 {"foo", "foovalue"},
99 {"content-length", "9"},
100 {"bar", "barvalue"},
101 {"baz", ""}});
102 int64_t content_length = -1;
103 SpdyHeaderBlock block;
104 ASSERT_TRUE(
105 SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
106 EXPECT_THAT(block, UnorderedElementsAre(
107 Pair("foo", "foovalue"), Pair("bar", "barvalue"),
108 Pair("content-length", absl::string_view("9\09", 3)),
109 Pair("baz", "")));
110 EXPECT_EQ(9, content_length);
111 }
112
TEST_F(CopyAndValidateHeaders,InconsistentContentLengths)113 TEST_F(CopyAndValidateHeaders, InconsistentContentLengths) {
114 auto headers = FromList({{"content-length", "9"},
115 {"foo", "foovalue"},
116 {"content-length", "8"},
117 {"bar", "barvalue"},
118 {"baz", ""}});
119 int64_t content_length = -1;
120 SpdyHeaderBlock block;
121 ASSERT_FALSE(
122 SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
123 }
124
TEST_F(CopyAndValidateHeaders,LargeContentLength)125 TEST_F(CopyAndValidateHeaders, LargeContentLength) {
126 auto headers = FromList({{"content-length", "9000000000"},
127 {"foo", "foovalue"},
128 {"bar", "barvalue"},
129 {"baz", ""}});
130 int64_t content_length = -1;
131 SpdyHeaderBlock block;
132 ASSERT_TRUE(
133 SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
134 EXPECT_THAT(block,
135 UnorderedElementsAre(
136 Pair("foo", "foovalue"), Pair("bar", "barvalue"),
137 Pair("content-length", absl::string_view("9000000000")),
138 Pair("baz", "")));
139 EXPECT_EQ(9000000000, content_length);
140 }
141
TEST_F(CopyAndValidateHeaders,NonDigitContentLength)142 TEST_F(CopyAndValidateHeaders, NonDigitContentLength) {
143 // Section 3.3.2 of RFC 7230 defines content-length as being only digits.
144 // Number parsers might accept symbols like a leading plus; test that this
145 // fails to parse.
146 auto headers = FromList({{"content-length", "+123"},
147 {"foo", "foovalue"},
148 {"bar", "barvalue"},
149 {"baz", ""}});
150 int64_t content_length = -1;
151 SpdyHeaderBlock block;
152 EXPECT_FALSE(
153 SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
154 }
155
TEST_F(CopyAndValidateHeaders,MultipleValues)156 TEST_F(CopyAndValidateHeaders, MultipleValues) {
157 auto headers = FromList({{"foo", "foovalue"},
158 {"bar", "barvalue"},
159 {"baz", ""},
160 {"foo", "boo"},
161 {"baz", "buzz"}});
162 int64_t content_length = -1;
163 SpdyHeaderBlock block;
164 ASSERT_TRUE(
165 SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
166 EXPECT_THAT(block, UnorderedElementsAre(
167 Pair("foo", absl::string_view("foovalue\0boo", 12)),
168 Pair("bar", "barvalue"),
169 Pair("baz", absl::string_view("\0buzz", 5))));
170 EXPECT_EQ(-1, content_length);
171 }
172
TEST_F(CopyAndValidateHeaders,MoreThanTwoValues)173 TEST_F(CopyAndValidateHeaders, MoreThanTwoValues) {
174 auto headers = FromList({{"set-cookie", "value1"},
175 {"set-cookie", "value2"},
176 {"set-cookie", "value3"}});
177 int64_t content_length = -1;
178 SpdyHeaderBlock block;
179 ASSERT_TRUE(
180 SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
181 EXPECT_THAT(block, UnorderedElementsAre(Pair(
182 "set-cookie",
183 absl::string_view("value1\0value2\0value3", 20))));
184 EXPECT_EQ(-1, content_length);
185 }
186
TEST_F(CopyAndValidateHeaders,Cookie)187 TEST_F(CopyAndValidateHeaders, Cookie) {
188 auto headers = FromList({{"foo", "foovalue"},
189 {"bar", "barvalue"},
190 {"cookie", "value1"},
191 {"baz", ""}});
192 int64_t content_length = -1;
193 SpdyHeaderBlock block;
194 ASSERT_TRUE(
195 SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
196 EXPECT_THAT(block, UnorderedElementsAre(
197 Pair("foo", "foovalue"), Pair("bar", "barvalue"),
198 Pair("cookie", "value1"), Pair("baz", "")));
199 EXPECT_EQ(-1, content_length);
200 }
201
TEST_F(CopyAndValidateHeaders,MultipleCookies)202 TEST_F(CopyAndValidateHeaders, MultipleCookies) {
203 auto headers = FromList({{"foo", "foovalue"},
204 {"bar", "barvalue"},
205 {"cookie", "value1"},
206 {"baz", ""},
207 {"cookie", "value2"}});
208 int64_t content_length = -1;
209 SpdyHeaderBlock block;
210 ASSERT_TRUE(
211 SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block));
212 EXPECT_THAT(block, UnorderedElementsAre(
213 Pair("foo", "foovalue"), Pair("bar", "barvalue"),
214 Pair("cookie", "value1; value2"), Pair("baz", "")));
215 EXPECT_EQ(-1, content_length);
216 }
217
218 using CopyAndValidateTrailers = QuicTest;
219
TEST_F(CopyAndValidateTrailers,SimplestValidList)220 TEST_F(CopyAndValidateTrailers, SimplestValidList) {
221 // Verify that the simplest trailers are valid: just a final byte offset that
222 // gets parsed successfully.
223 auto trailers = FromList({{kFinalOffsetHeaderKey, "1234"}});
224 size_t final_byte_offset = 0;
225 SpdyHeaderBlock block;
226 EXPECT_TRUE(SpdyUtils::CopyAndValidateTrailers(
227 *trailers, kExpectFinalByteOffset, &final_byte_offset, &block));
228 EXPECT_EQ(1234u, final_byte_offset);
229 }
230
TEST_F(CopyAndValidateTrailers,EmptyTrailerListWithFinalByteOffsetExpected)231 TEST_F(CopyAndValidateTrailers, EmptyTrailerListWithFinalByteOffsetExpected) {
232 // An empty trailer list will fail as expected key kFinalOffsetHeaderKey is
233 // not present.
234 QuicHeaderList trailers;
235 size_t final_byte_offset = 0;
236 SpdyHeaderBlock block;
237 EXPECT_FALSE(SpdyUtils::CopyAndValidateTrailers(
238 trailers, kExpectFinalByteOffset, &final_byte_offset, &block));
239 }
240
TEST_F(CopyAndValidateTrailers,EmptyTrailerListWithFinalByteOffsetNotExpected)241 TEST_F(CopyAndValidateTrailers,
242 EmptyTrailerListWithFinalByteOffsetNotExpected) {
243 // An empty trailer list will pass successfully if kFinalOffsetHeaderKey is
244 // not expected.
245 QuicHeaderList trailers;
246 size_t final_byte_offset = 0;
247 SpdyHeaderBlock block;
248 EXPECT_TRUE(SpdyUtils::CopyAndValidateTrailers(
249 trailers, kDoNotExpectFinalByteOffset, &final_byte_offset, &block));
250 EXPECT_TRUE(block.empty());
251 }
252
TEST_F(CopyAndValidateTrailers,FinalByteOffsetExpectedButNotPresent)253 TEST_F(CopyAndValidateTrailers, FinalByteOffsetExpectedButNotPresent) {
254 // Validation fails if expected kFinalOffsetHeaderKey is not present, even if
255 // the rest of the header block is valid.
256 auto trailers = FromList({{"key", "value"}});
257 size_t final_byte_offset = 0;
258 SpdyHeaderBlock block;
259 EXPECT_FALSE(SpdyUtils::CopyAndValidateTrailers(
260 *trailers, kExpectFinalByteOffset, &final_byte_offset, &block));
261 }
262
TEST_F(CopyAndValidateTrailers,FinalByteOffsetNotExpectedButPresent)263 TEST_F(CopyAndValidateTrailers, FinalByteOffsetNotExpectedButPresent) {
264 // Validation fails if kFinalOffsetHeaderKey is present but should not be,
265 // even if the rest of the header block is valid.
266 auto trailers = FromList({{"key", "value"}, {kFinalOffsetHeaderKey, "1234"}});
267 size_t final_byte_offset = 0;
268 SpdyHeaderBlock block;
269 EXPECT_FALSE(SpdyUtils::CopyAndValidateTrailers(
270 *trailers, kDoNotExpectFinalByteOffset, &final_byte_offset, &block));
271 }
272
TEST_F(CopyAndValidateTrailers,FinalByteOffsetNotExpectedAndNotPresent)273 TEST_F(CopyAndValidateTrailers, FinalByteOffsetNotExpectedAndNotPresent) {
274 // Validation succeeds if kFinalOffsetHeaderKey is not expected and not
275 // present.
276 auto trailers = FromList({{"key", "value"}});
277 size_t final_byte_offset = 0;
278 SpdyHeaderBlock block;
279 EXPECT_TRUE(SpdyUtils::CopyAndValidateTrailers(
280 *trailers, kDoNotExpectFinalByteOffset, &final_byte_offset, &block));
281 EXPECT_THAT(block, UnorderedElementsAre(Pair("key", "value")));
282 }
283
TEST_F(CopyAndValidateTrailers,EmptyName)284 TEST_F(CopyAndValidateTrailers, EmptyName) {
285 // Trailer validation will fail with an empty header key, in an otherwise
286 // valid block of trailers.
287 auto trailers = FromList({{"", "value"}, {kFinalOffsetHeaderKey, "1234"}});
288 size_t final_byte_offset = 0;
289 SpdyHeaderBlock block;
290 EXPECT_FALSE(SpdyUtils::CopyAndValidateTrailers(
291 *trailers, kExpectFinalByteOffset, &final_byte_offset, &block));
292 }
293
TEST_F(CopyAndValidateTrailers,PseudoHeaderInTrailers)294 TEST_F(CopyAndValidateTrailers, PseudoHeaderInTrailers) {
295 // Pseudo headers are illegal in trailers.
296 auto trailers =
297 FromList({{":pseudo_key", "value"}, {kFinalOffsetHeaderKey, "1234"}});
298 size_t final_byte_offset = 0;
299 SpdyHeaderBlock block;
300 EXPECT_FALSE(SpdyUtils::CopyAndValidateTrailers(
301 *trailers, kExpectFinalByteOffset, &final_byte_offset, &block));
302 }
303
TEST_F(CopyAndValidateTrailers,DuplicateTrailers)304 TEST_F(CopyAndValidateTrailers, DuplicateTrailers) {
305 // Duplicate trailers are allowed, and their values are concatenated into a
306 // single string delimted with '\0'. Some of the duplicate headers
307 // deliberately have an empty value.
308 auto trailers = FromList({{"key", "value0"},
309 {"key", "value1"},
310 {"key", ""},
311 {"key", ""},
312 {"key", "value2"},
313 {"key", ""},
314 {kFinalOffsetHeaderKey, "1234"},
315 {"other_key", "value"},
316 {"key", "non_contiguous_duplicate"}});
317 size_t final_byte_offset = 0;
318 SpdyHeaderBlock block;
319 EXPECT_TRUE(SpdyUtils::CopyAndValidateTrailers(
320 *trailers, kExpectFinalByteOffset, &final_byte_offset, &block));
321 EXPECT_THAT(
322 block,
323 UnorderedElementsAre(
324 Pair("key",
325 absl::string_view(
326 "value0\0value1\0\0\0value2\0\0non_contiguous_duplicate",
327 48)),
328 Pair("other_key", "value")));
329 }
330
TEST_F(CopyAndValidateTrailers,DuplicateCookies)331 TEST_F(CopyAndValidateTrailers, DuplicateCookies) {
332 // Duplicate cookie headers in trailers should be concatenated into a single
333 // "; " delimted string.
334 auto headers = FromList({{"cookie", " part 1"},
335 {"cookie", "part 2 "},
336 {"cookie", "part3"},
337 {"key", "value"},
338 {kFinalOffsetHeaderKey, "1234"},
339 {"cookie", " non_contiguous_cookie!"}});
340
341 size_t final_byte_offset = 0;
342 SpdyHeaderBlock block;
343 EXPECT_TRUE(SpdyUtils::CopyAndValidateTrailers(
344 *headers, kExpectFinalByteOffset, &final_byte_offset, &block));
345 EXPECT_THAT(
346 block,
347 UnorderedElementsAre(
348 Pair("cookie", " part 1; part 2 ; part3; non_contiguous_cookie!"),
349 Pair("key", "value")));
350 }
351
352 using PopulateHeaderBlockFromUrl = QuicTest;
353
TEST_F(PopulateHeaderBlockFromUrl,NormalUsage)354 TEST_F(PopulateHeaderBlockFromUrl, NormalUsage) {
355 std::string url = "https://www.google.com/index.html";
356 SpdyHeaderBlock headers;
357 EXPECT_TRUE(SpdyUtils::PopulateHeaderBlockFromUrl(url, &headers));
358 EXPECT_EQ("https", headers[":scheme"].as_string());
359 EXPECT_EQ("www.google.com", headers[":authority"].as_string());
360 EXPECT_EQ("/index.html", headers[":path"].as_string());
361 }
362
TEST_F(PopulateHeaderBlockFromUrl,UrlWithNoPath)363 TEST_F(PopulateHeaderBlockFromUrl, UrlWithNoPath) {
364 std::string url = "https://www.google.com";
365 SpdyHeaderBlock headers;
366 EXPECT_TRUE(SpdyUtils::PopulateHeaderBlockFromUrl(url, &headers));
367 EXPECT_EQ("https", headers[":scheme"].as_string());
368 EXPECT_EQ("www.google.com", headers[":authority"].as_string());
369 EXPECT_EQ("/", headers[":path"].as_string());
370 }
371
TEST_F(PopulateHeaderBlockFromUrl,Failure)372 TEST_F(PopulateHeaderBlockFromUrl, Failure) {
373 SpdyHeaderBlock headers;
374 EXPECT_FALSE(SpdyUtils::PopulateHeaderBlockFromUrl("/", &headers));
375 EXPECT_FALSE(SpdyUtils::PopulateHeaderBlockFromUrl("/index.html", &headers));
376 EXPECT_FALSE(
377 SpdyUtils::PopulateHeaderBlockFromUrl("www.google.com/", &headers));
378 }
379
380 } // namespace test
381 } // namespace quic
382