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