| // Copyright 2016 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include <memory> | |
| #include <string> | |
| #include "net/third_party/quiche/src/quic/core/http/spdy_utils.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" | |
| using spdy::SpdyHeaderBlock; | |
| using testing::Pair; | |
| using testing::UnorderedElementsAre; | |
| namespace quic { | |
| namespace test { | |
| namespace { | |
| const bool kExpectFinalByteOffset = true; | |
| const bool kDoNotExpectFinalByteOffset = false; | |
| static std::unique_ptr<QuicHeaderList> FromList( | |
| const QuicHeaderList::ListType& src) { | |
| std::unique_ptr<QuicHeaderList> headers(new QuicHeaderList); | |
| headers->OnHeaderBlockStart(); | |
| for (const auto& p : src) { | |
| headers->OnHeader(p.first, p.second); | |
| } | |
| headers->OnHeaderBlockEnd(0, 0); | |
| return headers; | |
| } | |
| } // anonymous namespace | |
| using CopyAndValidateHeaders = QuicTest; | |
| TEST_F(CopyAndValidateHeaders, NormalUsage) { | |
| auto headers = FromList({// All cookie crumbs are joined. | |
| {"cookie", " part 1"}, | |
| {"cookie", "part 2 "}, | |
| {"cookie", "part3"}, | |
| // Already-delimited headers are passed through. | |
| {"passed-through", std::string("foo\0baz", 7)}, | |
| // Other headers are joined on \0. | |
| {"joined", "value 1"}, | |
| {"joined", "value 2"}, | |
| // Empty headers remain empty. | |
| {"empty", ""}, | |
| // Joined empty headers work as expected. | |
| {"empty-joined", ""}, | |
| {"empty-joined", "foo"}, | |
| {"empty-joined", ""}, | |
| {"empty-joined", ""}, | |
| // Non-continguous cookie crumb. | |
| {"cookie", " fin!"}}); | |
| int64_t content_length = -1; | |
| SpdyHeaderBlock block; | |
| ASSERT_TRUE( | |
| SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block)); | |
| EXPECT_THAT(block, | |
| UnorderedElementsAre( | |
| Pair("cookie", " part 1; part 2 ; part3; fin!"), | |
| Pair("passed-through", QuicStringPiece("foo\0baz", 7)), | |
| Pair("joined", QuicStringPiece("value 1\0value 2", 15)), | |
| Pair("empty", ""), | |
| Pair("empty-joined", QuicStringPiece("\0foo\0\0", 6)))); | |
| EXPECT_EQ(-1, content_length); | |
| } | |
| TEST_F(CopyAndValidateHeaders, EmptyName) { | |
| auto headers = FromList({{"foo", "foovalue"}, {"", "barvalue"}, {"baz", ""}}); | |
| int64_t content_length = -1; | |
| SpdyHeaderBlock block; | |
| ASSERT_FALSE( | |
| SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block)); | |
| } | |
| TEST_F(CopyAndValidateHeaders, UpperCaseName) { | |
| auto headers = | |
| FromList({{"foo", "foovalue"}, {"bar", "barvalue"}, {"bAz", ""}}); | |
| int64_t content_length = -1; | |
| SpdyHeaderBlock block; | |
| ASSERT_FALSE( | |
| SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block)); | |
| } | |
| TEST_F(CopyAndValidateHeaders, MultipleContentLengths) { | |
| auto headers = FromList({{"content-length", "9"}, | |
| {"foo", "foovalue"}, | |
| {"content-length", "9"}, | |
| {"bar", "barvalue"}, | |
| {"baz", ""}}); | |
| int64_t content_length = -1; | |
| SpdyHeaderBlock block; | |
| ASSERT_TRUE( | |
| SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block)); | |
| EXPECT_THAT(block, UnorderedElementsAre( | |
| Pair("foo", "foovalue"), Pair("bar", "barvalue"), | |
| Pair("content-length", QuicStringPiece("9\09", 3)), | |
| Pair("baz", ""))); | |
| EXPECT_EQ(9, content_length); | |
| } | |
| TEST_F(CopyAndValidateHeaders, InconsistentContentLengths) { | |
| auto headers = FromList({{"content-length", "9"}, | |
| {"foo", "foovalue"}, | |
| {"content-length", "8"}, | |
| {"bar", "barvalue"}, | |
| {"baz", ""}}); | |
| int64_t content_length = -1; | |
| SpdyHeaderBlock block; | |
| ASSERT_FALSE( | |
| SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block)); | |
| } | |
| TEST_F(CopyAndValidateHeaders, LargeContentLength) { | |
| auto headers = FromList({{"content-length", "9000000000"}, | |
| {"foo", "foovalue"}, | |
| {"bar", "barvalue"}, | |
| {"baz", ""}}); | |
| int64_t content_length = -1; | |
| SpdyHeaderBlock block; | |
| ASSERT_TRUE( | |
| SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block)); | |
| EXPECT_THAT(block, UnorderedElementsAre( | |
| Pair("foo", "foovalue"), Pair("bar", "barvalue"), | |
| Pair("content-length", QuicStringPiece("9000000000")), | |
| Pair("baz", ""))); | |
| EXPECT_EQ(9000000000, content_length); | |
| } | |
| TEST_F(CopyAndValidateHeaders, MultipleValues) { | |
| auto headers = FromList({{"foo", "foovalue"}, | |
| {"bar", "barvalue"}, | |
| {"baz", ""}, | |
| {"foo", "boo"}, | |
| {"baz", "buzz"}}); | |
| int64_t content_length = -1; | |
| SpdyHeaderBlock block; | |
| ASSERT_TRUE( | |
| SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block)); | |
| EXPECT_THAT(block, UnorderedElementsAre( | |
| Pair("foo", QuicStringPiece("foovalue\0boo", 12)), | |
| Pair("bar", "barvalue"), | |
| Pair("baz", QuicStringPiece("\0buzz", 5)))); | |
| EXPECT_EQ(-1, content_length); | |
| } | |
| TEST_F(CopyAndValidateHeaders, MoreThanTwoValues) { | |
| auto headers = FromList({{"set-cookie", "value1"}, | |
| {"set-cookie", "value2"}, | |
| {"set-cookie", "value3"}}); | |
| int64_t content_length = -1; | |
| SpdyHeaderBlock block; | |
| ASSERT_TRUE( | |
| SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block)); | |
| EXPECT_THAT( | |
| block, UnorderedElementsAre(Pair( | |
| "set-cookie", QuicStringPiece("value1\0value2\0value3", 20)))); | |
| EXPECT_EQ(-1, content_length); | |
| } | |
| TEST_F(CopyAndValidateHeaders, Cookie) { | |
| auto headers = FromList({{"foo", "foovalue"}, | |
| {"bar", "barvalue"}, | |
| {"cookie", "value1"}, | |
| {"baz", ""}}); | |
| int64_t content_length = -1; | |
| SpdyHeaderBlock block; | |
| ASSERT_TRUE( | |
| SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block)); | |
| EXPECT_THAT(block, UnorderedElementsAre( | |
| Pair("foo", "foovalue"), Pair("bar", "barvalue"), | |
| Pair("cookie", "value1"), Pair("baz", ""))); | |
| EXPECT_EQ(-1, content_length); | |
| } | |
| TEST_F(CopyAndValidateHeaders, MultipleCookies) { | |
| auto headers = FromList({{"foo", "foovalue"}, | |
| {"bar", "barvalue"}, | |
| {"cookie", "value1"}, | |
| {"baz", ""}, | |
| {"cookie", "value2"}}); | |
| int64_t content_length = -1; | |
| SpdyHeaderBlock block; | |
| ASSERT_TRUE( | |
| SpdyUtils::CopyAndValidateHeaders(*headers, &content_length, &block)); | |
| EXPECT_THAT(block, UnorderedElementsAre( | |
| Pair("foo", "foovalue"), Pair("bar", "barvalue"), | |
| Pair("cookie", "value1; value2"), Pair("baz", ""))); | |
| EXPECT_EQ(-1, content_length); | |
| } | |
| using CopyAndValidateTrailers = QuicTest; | |
| TEST_F(CopyAndValidateTrailers, SimplestValidList) { | |
| // Verify that the simplest trailers are valid: just a final byte offset that | |
| // gets parsed successfully. | |
| auto trailers = FromList({{kFinalOffsetHeaderKey, "1234"}}); | |
| size_t final_byte_offset = 0; | |
| SpdyHeaderBlock block; | |
| EXPECT_TRUE(SpdyUtils::CopyAndValidateTrailers( | |
| *trailers, kExpectFinalByteOffset, &final_byte_offset, &block)); | |
| EXPECT_EQ(1234u, final_byte_offset); | |
| } | |
| TEST_F(CopyAndValidateTrailers, EmptyTrailerListWithFinalByteOffsetExpected) { | |
| // An empty trailer list will fail as expected key kFinalOffsetHeaderKey is | |
| // not present. | |
| QuicHeaderList trailers; | |
| size_t final_byte_offset = 0; | |
| SpdyHeaderBlock block; | |
| EXPECT_FALSE(SpdyUtils::CopyAndValidateTrailers( | |
| trailers, kExpectFinalByteOffset, &final_byte_offset, &block)); | |
| } | |
| TEST_F(CopyAndValidateTrailers, | |
| EmptyTrailerListWithFinalByteOffsetNotExpected) { | |
| // An empty trailer list will pass successfully if kFinalOffsetHeaderKey is | |
| // not expected. | |
| QuicHeaderList trailers; | |
| size_t final_byte_offset = 0; | |
| SpdyHeaderBlock block; | |
| EXPECT_TRUE(SpdyUtils::CopyAndValidateTrailers( | |
| trailers, kDoNotExpectFinalByteOffset, &final_byte_offset, &block)); | |
| EXPECT_TRUE(block.empty()); | |
| } | |
| TEST_F(CopyAndValidateTrailers, FinalByteOffsetExpectedButNotPresent) { | |
| // Validation fails if expected kFinalOffsetHeaderKey is not present, even if | |
| // the rest of the header block is valid. | |
| auto trailers = FromList({{"key", "value"}}); | |
| size_t final_byte_offset = 0; | |
| SpdyHeaderBlock block; | |
| EXPECT_FALSE(SpdyUtils::CopyAndValidateTrailers( | |
| *trailers, kExpectFinalByteOffset, &final_byte_offset, &block)); | |
| } | |
| TEST_F(CopyAndValidateTrailers, FinalByteOffsetNotExpectedButPresent) { | |
| // Validation fails if kFinalOffsetHeaderKey is present but should not be, | |
| // even if the rest of the header block is valid. | |
| auto trailers = FromList({{"key", "value"}, {kFinalOffsetHeaderKey, "1234"}}); | |
| size_t final_byte_offset = 0; | |
| SpdyHeaderBlock block; | |
| EXPECT_FALSE(SpdyUtils::CopyAndValidateTrailers( | |
| *trailers, kDoNotExpectFinalByteOffset, &final_byte_offset, &block)); | |
| } | |
| TEST_F(CopyAndValidateTrailers, FinalByteOffsetNotExpectedAndNotPresent) { | |
| // Validation succeeds if kFinalOffsetHeaderKey is not expected and not | |
| // present. | |
| auto trailers = FromList({{"key", "value"}}); | |
| size_t final_byte_offset = 0; | |
| SpdyHeaderBlock block; | |
| EXPECT_TRUE(SpdyUtils::CopyAndValidateTrailers( | |
| *trailers, kDoNotExpectFinalByteOffset, &final_byte_offset, &block)); | |
| EXPECT_THAT(block, UnorderedElementsAre(Pair("key", "value"))); | |
| } | |
| TEST_F(CopyAndValidateTrailers, EmptyName) { | |
| // Trailer validation will fail with an empty header key, in an otherwise | |
| // valid block of trailers. | |
| auto trailers = FromList({{"", "value"}, {kFinalOffsetHeaderKey, "1234"}}); | |
| size_t final_byte_offset = 0; | |
| SpdyHeaderBlock block; | |
| EXPECT_FALSE(SpdyUtils::CopyAndValidateTrailers( | |
| *trailers, kExpectFinalByteOffset, &final_byte_offset, &block)); | |
| } | |
| TEST_F(CopyAndValidateTrailers, PseudoHeaderInTrailers) { | |
| // Pseudo headers are illegal in trailers. | |
| auto trailers = | |
| FromList({{":pseudo_key", "value"}, {kFinalOffsetHeaderKey, "1234"}}); | |
| size_t final_byte_offset = 0; | |
| SpdyHeaderBlock block; | |
| EXPECT_FALSE(SpdyUtils::CopyAndValidateTrailers( | |
| *trailers, kExpectFinalByteOffset, &final_byte_offset, &block)); | |
| } | |
| TEST_F(CopyAndValidateTrailers, DuplicateTrailers) { | |
| // Duplicate trailers are allowed, and their values are concatenated into a | |
| // single string delimted with '\0'. Some of the duplicate headers | |
| // deliberately have an empty value. | |
| auto trailers = FromList({{"key", "value0"}, | |
| {"key", "value1"}, | |
| {"key", ""}, | |
| {"key", ""}, | |
| {"key", "value2"}, | |
| {"key", ""}, | |
| {kFinalOffsetHeaderKey, "1234"}, | |
| {"other_key", "value"}, | |
| {"key", "non_contiguous_duplicate"}}); | |
| size_t final_byte_offset = 0; | |
| SpdyHeaderBlock block; | |
| EXPECT_TRUE(SpdyUtils::CopyAndValidateTrailers( | |
| *trailers, kExpectFinalByteOffset, &final_byte_offset, &block)); | |
| EXPECT_THAT( | |
| block, | |
| UnorderedElementsAre( | |
| Pair("key", | |
| QuicStringPiece( | |
| "value0\0value1\0\0\0value2\0\0non_contiguous_duplicate", | |
| 48)), | |
| Pair("other_key", "value"))); | |
| } | |
| TEST_F(CopyAndValidateTrailers, DuplicateCookies) { | |
| // Duplicate cookie headers in trailers should be concatenated into a single | |
| // "; " delimted string. | |
| auto headers = FromList({{"cookie", " part 1"}, | |
| {"cookie", "part 2 "}, | |
| {"cookie", "part3"}, | |
| {"key", "value"}, | |
| {kFinalOffsetHeaderKey, "1234"}, | |
| {"cookie", " non_contiguous_cookie!"}}); | |
| size_t final_byte_offset = 0; | |
| SpdyHeaderBlock block; | |
| EXPECT_TRUE(SpdyUtils::CopyAndValidateTrailers( | |
| *headers, kExpectFinalByteOffset, &final_byte_offset, &block)); | |
| EXPECT_THAT( | |
| block, | |
| UnorderedElementsAre( | |
| Pair("cookie", " part 1; part 2 ; part3; non_contiguous_cookie!"), | |
| Pair("key", "value"))); | |
| } | |
| using GetPromisedUrlFromHeaders = QuicTest; | |
| TEST_F(GetPromisedUrlFromHeaders, Basic) { | |
| SpdyHeaderBlock headers; | |
| headers[":method"] = "GET"; | |
| EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), ""); | |
| headers[":scheme"] = "https"; | |
| EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), ""); | |
| headers[":authority"] = "www.google.com"; | |
| EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), ""); | |
| headers[":path"] = "/index.html"; | |
| EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), | |
| "https://www.google.com/index.html"); | |
| headers["key1"] = "value1"; | |
| headers["key2"] = "value2"; | |
| EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), | |
| "https://www.google.com/index.html"); | |
| } | |
| TEST_F(GetPromisedUrlFromHeaders, Connect) { | |
| SpdyHeaderBlock headers; | |
| headers[":method"] = "CONNECT"; | |
| EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), ""); | |
| headers[":authority"] = "www.google.com"; | |
| EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), ""); | |
| headers[":scheme"] = "https"; | |
| EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), ""); | |
| headers[":path"] = "https"; | |
| EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), ""); | |
| } | |
| TEST_F(GetPromisedUrlFromHeaders, InvalidUserinfo) { | |
| SpdyHeaderBlock headers; | |
| headers[":method"] = "GET"; | |
| headers[":authority"] = "user@www.google.com"; | |
| headers[":scheme"] = "https"; | |
| headers[":path"] = "/"; | |
| EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), ""); | |
| } | |
| TEST_F(GetPromisedUrlFromHeaders, InvalidPath) { | |
| SpdyHeaderBlock headers; | |
| headers[":method"] = "GET"; | |
| headers[":authority"] = "www.google.com"; | |
| headers[":scheme"] = "https"; | |
| headers[":path"] = ""; | |
| EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), ""); | |
| } | |
| using GetPromisedHostNameFromHeaders = QuicTest; | |
| TEST_F(GetPromisedHostNameFromHeaders, NormalUsage) { | |
| SpdyHeaderBlock headers; | |
| headers[":method"] = "GET"; | |
| EXPECT_EQ(SpdyUtils::GetPromisedHostNameFromHeaders(headers), ""); | |
| headers[":scheme"] = "https"; | |
| EXPECT_EQ(SpdyUtils::GetPromisedHostNameFromHeaders(headers), ""); | |
| headers[":authority"] = "www.google.com"; | |
| EXPECT_EQ(SpdyUtils::GetPromisedHostNameFromHeaders(headers), ""); | |
| headers[":path"] = "/index.html"; | |
| EXPECT_EQ(SpdyUtils::GetPromisedHostNameFromHeaders(headers), | |
| "www.google.com"); | |
| headers["key1"] = "value1"; | |
| headers["key2"] = "value2"; | |
| EXPECT_EQ(SpdyUtils::GetPromisedHostNameFromHeaders(headers), | |
| "www.google.com"); | |
| headers[":authority"] = "www.google.com:6666"; | |
| EXPECT_EQ(SpdyUtils::GetPromisedHostNameFromHeaders(headers), | |
| "www.google.com"); | |
| headers[":authority"] = "192.168.1.1"; | |
| EXPECT_EQ(SpdyUtils::GetPromisedHostNameFromHeaders(headers), "192.168.1.1"); | |
| headers[":authority"] = "192.168.1.1:6666"; | |
| EXPECT_EQ(SpdyUtils::GetPromisedHostNameFromHeaders(headers), "192.168.1.1"); | |
| } | |
| using PopulateHeaderBlockFromUrl = QuicTest; | |
| TEST_F(PopulateHeaderBlockFromUrl, NormalUsage) { | |
| std::string url = "https://www.google.com/index.html"; | |
| SpdyHeaderBlock headers; | |
| EXPECT_TRUE(SpdyUtils::PopulateHeaderBlockFromUrl(url, &headers)); | |
| EXPECT_EQ("https", headers[":scheme"].as_string()); | |
| EXPECT_EQ("www.google.com", headers[":authority"].as_string()); | |
| EXPECT_EQ("/index.html", headers[":path"].as_string()); | |
| } | |
| TEST_F(PopulateHeaderBlockFromUrl, UrlWithNoPath) { | |
| std::string url = "https://www.google.com"; | |
| SpdyHeaderBlock headers; | |
| EXPECT_TRUE(SpdyUtils::PopulateHeaderBlockFromUrl(url, &headers)); | |
| EXPECT_EQ("https", headers[":scheme"].as_string()); | |
| EXPECT_EQ("www.google.com", headers[":authority"].as_string()); | |
| EXPECT_EQ("/", headers[":path"].as_string()); | |
| } | |
| TEST_F(PopulateHeaderBlockFromUrl, Failure) { | |
| SpdyHeaderBlock headers; | |
| EXPECT_FALSE(SpdyUtils::PopulateHeaderBlockFromUrl("/", &headers)); | |
| EXPECT_FALSE(SpdyUtils::PopulateHeaderBlockFromUrl("/index.html", &headers)); | |
| EXPECT_FALSE( | |
| SpdyUtils::PopulateHeaderBlockFromUrl("www.google.com/", &headers)); | |
| } | |
| using PushPromiseUrlTest = QuicTest; | |
| TEST_F(PushPromiseUrlTest, GetPushPromiseUrl) { | |
| // Test rejection of various inputs. | |
| EXPECT_EQ("", | |
| SpdyUtils::GetPushPromiseUrl("file", "localhost", "/etc/password")); | |
| EXPECT_EQ("", SpdyUtils::GetPushPromiseUrl("file", "", | |
| "/C:/Windows/System32/Config/")); | |
| EXPECT_EQ("", | |
| SpdyUtils::GetPushPromiseUrl("", "https://www.google.com", "/")); | |
| EXPECT_EQ("", SpdyUtils::GetPushPromiseUrl("https://www.google.com", | |
| "www.google.com", "/")); | |
| EXPECT_EQ("", | |
| SpdyUtils::GetPushPromiseUrl("https://", "www.google.com", "/")); | |
| EXPECT_EQ("", SpdyUtils::GetPushPromiseUrl("https", "", "/")); | |
| EXPECT_EQ("", SpdyUtils::GetPushPromiseUrl("https", "", "www.google.com/")); | |
| EXPECT_EQ("", SpdyUtils::GetPushPromiseUrl("https", "www.google.com/", "/")); | |
| EXPECT_EQ("", SpdyUtils::GetPushPromiseUrl("https", "www.google.com", "")); | |
| EXPECT_EQ("", SpdyUtils::GetPushPromiseUrl("https", "www.google", ".com/")); | |
| // Test acception/rejection of various input combinations. | |
| // |input_headers| is an array of pairs. The first value of each pair is a | |
| // string that will be used as one of the inputs of GetPushPromiseUrl(). The | |
| // second value of each pair is a bitfield where the lowest 3 bits indicate | |
| // for which headers that string is valid (in a PUSH_PROMISE). For example, | |
| // the string "http" would be valid for both the ":scheme" and ":authority" | |
| // headers, so the bitfield paired with it is set to SCHEME | AUTH. | |
| const unsigned char SCHEME = (1u << 0); | |
| const unsigned char AUTH = (1u << 1); | |
| const unsigned char PATH = (1u << 2); | |
| const std::pair<const char*, unsigned char> input_headers[] = { | |
| {"http", SCHEME | AUTH}, | |
| {"https", SCHEME | AUTH}, | |
| {"hTtP", SCHEME | AUTH}, | |
| {"HTTPS", SCHEME | AUTH}, | |
| {"www.google.com", AUTH}, | |
| {"90af90e0", AUTH}, | |
| {"12foo%20-bar:00001233", AUTH}, | |
| {"GOO\u200b\u2060\ufeffgoo", AUTH}, | |
| {"192.168.0.5", AUTH}, | |
| {"[::ffff:192.168.0.1.]", AUTH}, | |
| {"http:", AUTH}, | |
| {"bife l", AUTH}, | |
| {"/", PATH}, | |
| {"/foo/bar/baz", PATH}, | |
| {"/%20-2DVdkj.cie/foe_.iif/", PATH}, | |
| {"http://", 0}, | |
| {":443", 0}, | |
| {":80/eddd", 0}, | |
| {"google.com:-0", 0}, | |
| {"google.com:65536", 0}, | |
| {"http://google.com", 0}, | |
| {"http://google.com:39", 0}, | |
| {"//google.com/foo", 0}, | |
| {".com/", 0}, | |
| {"http://www.google.com/", 0}, | |
| {"http://foo:439", 0}, | |
| {"[::ffff:192.168", 0}, | |
| {"]/", 0}, | |
| {"//", 0}}; | |
| for (size_t i = 0; i < QUIC_ARRAYSIZE(input_headers); ++i) { | |
| bool should_accept = (input_headers[i].second & SCHEME); | |
| for (size_t j = 0; j < QUIC_ARRAYSIZE(input_headers); ++j) { | |
| bool should_accept_2 = should_accept && (input_headers[j].second & AUTH); | |
| for (size_t k = 0; k < QUIC_ARRAYSIZE(input_headers); ++k) { | |
| // |should_accept_3| indicates whether or not GetPushPromiseUrl() is | |
| // expected to accept this input combination. | |
| bool should_accept_3 = | |
| should_accept_2 && (input_headers[k].second & PATH); | |
| std::string url = SpdyUtils::GetPushPromiseUrl(input_headers[i].first, | |
| input_headers[j].first, | |
| input_headers[k].first); | |
| ::testing::AssertionResult result = ::testing::AssertionSuccess(); | |
| if (url.empty() == should_accept_3) { | |
| result = ::testing::AssertionFailure() | |
| << "GetPushPromiseUrl() accepted/rejected the inputs when " | |
| "it shouldn't have." | |
| << std::endl | |
| << " scheme: " << input_headers[i].first << std::endl | |
| << " authority: " << input_headers[j].first << std::endl | |
| << " path: " << input_headers[k].first << std::endl | |
| << "Output: " << url << std::endl; | |
| } | |
| ASSERT_TRUE(result); | |
| } | |
| } | |
| } | |
| // Test canonicalization of various valid inputs. | |
| EXPECT_EQ("http://www.google.com/", | |
| SpdyUtils::GetPushPromiseUrl("http", "www.google.com", "/")); | |
| EXPECT_EQ( | |
| "https://www.goo-gle.com/fOOo/baRR", | |
| SpdyUtils::GetPushPromiseUrl("hTtPs", "wWw.gOo-gLE.cOm", "/fOOo/baRR")); | |
| EXPECT_EQ("https://www.goo-gle.com:3278/pAth/To/reSOurce", | |
| SpdyUtils::GetPushPromiseUrl("hTtPs", "Www.gOo-Gle.Com:000003278", | |
| "/pAth/To/reSOurce")); | |
| EXPECT_EQ("https://foo%20bar/foo/bar/baz", | |
| SpdyUtils::GetPushPromiseUrl("https", "foo bar", "/foo/bar/baz")); | |
| EXPECT_EQ("http://foo.com:70/e/", | |
| SpdyUtils::GetPushPromiseUrl("http", "foo.com:0000070", "/e/")); | |
| EXPECT_EQ( | |
| "http://192.168.0.1:70/e/", | |
| SpdyUtils::GetPushPromiseUrl("http", "0300.0250.00.01:0070", "/e/")); | |
| EXPECT_EQ("http://192.168.0.1/e/", | |
| SpdyUtils::GetPushPromiseUrl("http", "0xC0a80001", "/e/")); | |
| EXPECT_EQ("http://[::c0a8:1]/", | |
| SpdyUtils::GetPushPromiseUrl("http", "[::192.168.0.1]", "/")); | |
| EXPECT_EQ( | |
| "https://[::ffff:c0a8:1]/", | |
| SpdyUtils::GetPushPromiseUrl("https", "[::ffff:0xC0.0Xa8.0x0.0x1]", "/")); | |
| } | |
| } // namespace test | |
| } // namespace quic |