1 // Copyright 2016 The Chromium Authors
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 "net/spdy/header_coalescer.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "net/log/net_log.h"
11 #include "net/log/test_net_log.h"
12 #include "net/log/test_net_log_util.h"
13 #include "net/spdy/spdy_test_util_common.h"
14 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 using ::testing::ElementsAre;
18 using ::testing::Pair;
19
20 namespace net::test {
21
22 class HeaderCoalescerTest : public ::testing::Test {
23 public:
HeaderCoalescerTest()24 HeaderCoalescerTest()
25 : header_coalescer_(kMaxHeaderListSizeForTest, net_log_with_source_) {}
26
ExpectEntry(base::StringPiece expected_header_name,base::StringPiece expected_header_value,base::StringPiece expected_error_message)27 void ExpectEntry(base::StringPiece expected_header_name,
28 base::StringPiece expected_header_value,
29 base::StringPiece expected_error_message) {
30 auto entry_list = net_log_observer_.GetEntries();
31 ASSERT_EQ(1u, entry_list.size());
32 EXPECT_EQ(entry_list[0].type,
33 NetLogEventType::HTTP2_SESSION_RECV_INVALID_HEADER);
34 EXPECT_EQ(entry_list[0].source.id, net_log_with_source_.source().id);
35 std::string value;
36 EXPECT_EQ(expected_header_name,
37 GetStringValueFromParams(entry_list[0], "header_name"));
38 EXPECT_EQ(expected_header_value,
39 GetStringValueFromParams(entry_list[0], "header_value"));
40 EXPECT_EQ(expected_error_message,
41 GetStringValueFromParams(entry_list[0], "error"));
42 }
43
44 protected:
45 NetLogWithSource net_log_with_source_{
46 NetLogWithSource::Make(NetLog::Get(), NetLogSourceType::NONE)};
47 RecordingNetLogObserver net_log_observer_;
48 HeaderCoalescer header_coalescer_;
49 };
50
TEST_F(HeaderCoalescerTest,CorrectHeaders)51 TEST_F(HeaderCoalescerTest, CorrectHeaders) {
52 header_coalescer_.OnHeader(":foo", "bar");
53 header_coalescer_.OnHeader("baz", "qux");
54 EXPECT_FALSE(header_coalescer_.error_seen());
55
56 spdy::Http2HeaderBlock header_block = header_coalescer_.release_headers();
57 EXPECT_THAT(header_block,
58 ElementsAre(Pair(":foo", "bar"), Pair("baz", "qux")));
59 }
60
TEST_F(HeaderCoalescerTest,EmptyHeaderKey)61 TEST_F(HeaderCoalescerTest, EmptyHeaderKey) {
62 header_coalescer_.OnHeader("", "foo");
63 EXPECT_TRUE(header_coalescer_.error_seen());
64 ExpectEntry("", "foo", "Header name must not be empty.");
65 }
66
TEST_F(HeaderCoalescerTest,HeaderBlockTooLarge)67 TEST_F(HeaderCoalescerTest, HeaderBlockTooLarge) {
68 // key + value + overhead = 3 + kMaxHeaderListSizeForTest - 40 + 32
69 // = kMaxHeaderListSizeForTest - 5
70 std::string data(kMaxHeaderListSizeForTest - 40, 'a');
71 header_coalescer_.OnHeader("foo", data);
72 EXPECT_FALSE(header_coalescer_.error_seen());
73
74 // Another 3 + 4 + 32 bytes: too large.
75 header_coalescer_.OnHeader("bar", "abcd");
76 EXPECT_TRUE(header_coalescer_.error_seen());
77 ExpectEntry("bar", "abcd", "Header list too large.");
78 }
79
TEST_F(HeaderCoalescerTest,PseudoHeadersMustNotFollowRegularHeaders)80 TEST_F(HeaderCoalescerTest, PseudoHeadersMustNotFollowRegularHeaders) {
81 header_coalescer_.OnHeader("foo", "bar");
82 EXPECT_FALSE(header_coalescer_.error_seen());
83 header_coalescer_.OnHeader(":baz", "qux");
84 EXPECT_TRUE(header_coalescer_.error_seen());
85 ExpectEntry(":baz", "qux", "Pseudo header must not follow regular headers.");
86 }
87
TEST_F(HeaderCoalescerTest,Append)88 TEST_F(HeaderCoalescerTest, Append) {
89 header_coalescer_.OnHeader("foo", "bar");
90 header_coalescer_.OnHeader("cookie", "baz");
91 header_coalescer_.OnHeader("foo", "quux");
92 header_coalescer_.OnHeader("cookie", "qux");
93 EXPECT_FALSE(header_coalescer_.error_seen());
94
95 spdy::Http2HeaderBlock header_block = header_coalescer_.release_headers();
96 EXPECT_THAT(header_block,
97 ElementsAre(Pair("foo", std::string_view("bar\0quux", 8)),
98 Pair("cookie", "baz; qux")));
99 }
100
TEST_F(HeaderCoalescerTest,HeaderNameNotValid)101 TEST_F(HeaderCoalescerTest, HeaderNameNotValid) {
102 std::string_view header_name("\x1\x7F\x80\xFF");
103 header_coalescer_.OnHeader(header_name, "foo");
104 EXPECT_TRUE(header_coalescer_.error_seen());
105 ExpectEntry("%ESCAPED:\xE2\x80\x8B \x1\x7F%80%FF", "foo",
106 "Invalid character in header name.");
107 }
108
109 // RFC 7540 Section 8.1.2.6. Uppercase in header name is invalid.
TEST_F(HeaderCoalescerTest,HeaderNameHasUppercase)110 TEST_F(HeaderCoalescerTest, HeaderNameHasUppercase) {
111 std::string_view header_name("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
112 header_coalescer_.OnHeader(header_name, "foo");
113 EXPECT_TRUE(header_coalescer_.error_seen());
114 ExpectEntry("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "foo",
115 "Upper case characters in header name.");
116 }
117
118 // RFC 7230 Section 3.2. Valid header name is defined as:
119 // field-name = token
120 // token = 1*tchar
121 // tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
122 // "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
TEST_F(HeaderCoalescerTest,HeaderNameValid)123 TEST_F(HeaderCoalescerTest, HeaderNameValid) {
124 // Due to RFC 7540 Section 8.1.2.6. Uppercase characters are not included.
125 std::string_view header_name(
126 "abcdefghijklmnopqrstuvwxyz0123456789!#$%&'*+-."
127 "^_`|~");
128 header_coalescer_.OnHeader(header_name, "foo");
129 EXPECT_FALSE(header_coalescer_.error_seen());
130 spdy::Http2HeaderBlock header_block = header_coalescer_.release_headers();
131 EXPECT_THAT(header_block, ElementsAre(Pair(header_name, "foo")));
132 }
133
134 // According to RFC 7540 Section 10.3 and RFC 7230 Section 3.2, allowed
135 // characters in header values are '\t', ' ', 0x21 to 0x7E, and 0x80 to 0xFF.
TEST_F(HeaderCoalescerTest,HeaderValueValid)136 TEST_F(HeaderCoalescerTest, HeaderValueValid) {
137 header_coalescer_.OnHeader("foo", " bar \x21 \x7e baz\tqux\x80\xff ");
138 EXPECT_FALSE(header_coalescer_.error_seen());
139 }
140
TEST_F(HeaderCoalescerTest,HeaderValueContainsLF)141 TEST_F(HeaderCoalescerTest, HeaderValueContainsLF) {
142 header_coalescer_.OnHeader("foo", "bar\nbaz");
143 EXPECT_TRUE(header_coalescer_.error_seen());
144 ExpectEntry("foo", "bar\nbaz", "Invalid character 0x0A in header value.");
145 }
146
TEST_F(HeaderCoalescerTest,HeaderValueContainsCR)147 TEST_F(HeaderCoalescerTest, HeaderValueContainsCR) {
148 header_coalescer_.OnHeader("foo", "bar\rbaz");
149 EXPECT_TRUE(header_coalescer_.error_seen());
150 ExpectEntry("foo", "bar\rbaz", "Invalid character 0x0D in header value.");
151 }
152
TEST_F(HeaderCoalescerTest,HeaderValueContains0x7f)153 TEST_F(HeaderCoalescerTest, HeaderValueContains0x7f) {
154 header_coalescer_.OnHeader("foo", "bar\x7f baz");
155 EXPECT_TRUE(header_coalescer_.error_seen());
156 ExpectEntry("foo", "bar\x7F baz", "Invalid character 0x7F in header value.");
157 }
158
159 } // namespace net::test
160