| // Copyright (c) 2019 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 "quiche/quic/core/qpack/value_splitting_header_list.h" |
| |
| #include "absl/base/macros.h" |
| #include "absl/strings/string_view.h" |
| #include "quiche/quic/platform/api/quic_test.h" |
| |
| namespace quic { |
| namespace test { |
| namespace { |
| |
| using ::testing::ElementsAre; |
| using ::testing::Pair; |
| |
| TEST(ValueSplittingHeaderListTest, Comparison) { |
| spdy::Http2HeaderBlock block; |
| block["foo"] = absl::string_view("bar\0baz", 7); |
| block["baz"] = "qux"; |
| block["cookie"] = "foo; bar"; |
| |
| ValueSplittingHeaderList headers(&block); |
| ValueSplittingHeaderList::const_iterator it1 = headers.begin(); |
| const int kEnd = 6; |
| for (int i = 0; i < kEnd; ++i) { |
| // Compare to begin(). |
| if (i == 0) { |
| EXPECT_TRUE(it1 == headers.begin()); |
| EXPECT_TRUE(headers.begin() == it1); |
| EXPECT_FALSE(it1 != headers.begin()); |
| EXPECT_FALSE(headers.begin() != it1); |
| } else { |
| EXPECT_FALSE(it1 == headers.begin()); |
| EXPECT_FALSE(headers.begin() == it1); |
| EXPECT_TRUE(it1 != headers.begin()); |
| EXPECT_TRUE(headers.begin() != it1); |
| } |
| |
| // Compare to end(). |
| if (i == kEnd - 1) { |
| EXPECT_TRUE(it1 == headers.end()); |
| EXPECT_TRUE(headers.end() == it1); |
| EXPECT_FALSE(it1 != headers.end()); |
| EXPECT_FALSE(headers.end() != it1); |
| } else { |
| EXPECT_FALSE(it1 == headers.end()); |
| EXPECT_FALSE(headers.end() == it1); |
| EXPECT_TRUE(it1 != headers.end()); |
| EXPECT_TRUE(headers.end() != it1); |
| } |
| |
| // Compare to another iterator walking through the container. |
| ValueSplittingHeaderList::const_iterator it2 = headers.begin(); |
| for (int j = 0; j < kEnd; ++j) { |
| if (i == j) { |
| EXPECT_TRUE(it1 == it2); |
| EXPECT_FALSE(it1 != it2); |
| } else { |
| EXPECT_FALSE(it1 == it2); |
| EXPECT_TRUE(it1 != it2); |
| } |
| if (j < kEnd - 1) { |
| ASSERT_NE(it2, headers.end()); |
| ++it2; |
| } |
| } |
| |
| if (i < kEnd - 1) { |
| ASSERT_NE(it1, headers.end()); |
| ++it1; |
| } |
| } |
| } |
| |
| TEST(ValueSplittingHeaderListTest, Empty) { |
| spdy::Http2HeaderBlock block; |
| |
| ValueSplittingHeaderList headers(&block); |
| EXPECT_THAT(headers, ElementsAre()); |
| EXPECT_EQ(headers.begin(), headers.end()); |
| } |
| |
| TEST(ValueSplittingHeaderListTest, Split) { |
| struct { |
| const char* name; |
| absl::string_view value; |
| std::vector<const char*> expected_values; |
| } kTestData[]{ |
| // Empty value. |
| {"foo", "", {""}}, |
| // Trivial case. |
| {"foo", "bar", {"bar"}}, |
| // Simple split. |
| {"foo", {"bar\0baz", 7}, {"bar", "baz"}}, |
| {"cookie", "foo;bar", {"foo", "bar"}}, |
| {"cookie", "foo; bar", {"foo", "bar"}}, |
| // Empty fragments with \0 separator. |
| {"foo", {"\0", 1}, {"", ""}}, |
| {"bar", {"foo\0", 4}, {"foo", ""}}, |
| {"baz", {"\0bar", 4}, {"", "bar"}}, |
| {"qux", {"\0foobar\0", 8}, {"", "foobar", ""}}, |
| // Empty fragments with ";" separator. |
| {"cookie", ";", {"", ""}}, |
| {"cookie", "foo;", {"foo", ""}}, |
| {"cookie", ";bar", {"", "bar"}}, |
| {"cookie", ";foobar;", {"", "foobar", ""}}, |
| // Empty fragments with "; " separator. |
| {"cookie", "; ", {"", ""}}, |
| {"cookie", "foo; ", {"foo", ""}}, |
| {"cookie", "; bar", {"", "bar"}}, |
| {"cookie", "; foobar; ", {"", "foobar", ""}}, |
| }; |
| |
| for (size_t i = 0; i < ABSL_ARRAYSIZE(kTestData); ++i) { |
| spdy::Http2HeaderBlock block; |
| block[kTestData[i].name] = kTestData[i].value; |
| |
| ValueSplittingHeaderList headers(&block); |
| auto it = headers.begin(); |
| for (const char* expected_value : kTestData[i].expected_values) { |
| ASSERT_NE(it, headers.end()); |
| EXPECT_EQ(it->first, kTestData[i].name); |
| EXPECT_EQ(it->second, expected_value); |
| ++it; |
| } |
| EXPECT_EQ(it, headers.end()); |
| } |
| } |
| |
| TEST(ValueSplittingHeaderListTest, MultipleFields) { |
| spdy::Http2HeaderBlock block; |
| block["foo"] = absl::string_view("bar\0baz\0", 8); |
| block["cookie"] = "foo; bar"; |
| block["bar"] = absl::string_view("qux\0foo", 7); |
| |
| ValueSplittingHeaderList headers(&block); |
| EXPECT_THAT(headers, ElementsAre(Pair("foo", "bar"), Pair("foo", "baz"), |
| Pair("foo", ""), Pair("cookie", "foo"), |
| Pair("cookie", "bar"), Pair("bar", "qux"), |
| Pair("bar", "foo"))); |
| } |
| |
| TEST(ValueSplittingHeaderListTest, CookieStartsWithSpace) { |
| spdy::Http2HeaderBlock block; |
| block["foo"] = "bar"; |
| block["cookie"] = " foo"; |
| block["bar"] = "baz"; |
| |
| ValueSplittingHeaderList headers(&block); |
| EXPECT_THAT(headers, ElementsAre(Pair("foo", "bar"), Pair("cookie", " foo"), |
| Pair("bar", "baz"))); |
| } |
| |
| } // namespace |
| } // namespace test |
| } // namespace quic |