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