1*6777b538SAndroid Build Coastguard Worker // Copyright 2016 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "net/spdy/header_coalescer.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <memory>
8*6777b538SAndroid Build Coastguard Worker #include <string>
9*6777b538SAndroid Build Coastguard Worker #include <string_view>
10*6777b538SAndroid Build Coastguard Worker #include <utility>
11*6777b538SAndroid Build Coastguard Worker
12*6777b538SAndroid Build Coastguard Worker #include "base/ranges/algorithm.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/trace_event/memory_usage_estimator.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/values.h"
17*6777b538SAndroid Build Coastguard Worker #include "net/http/http_log_util.h"
18*6777b538SAndroid Build Coastguard Worker #include "net/http/http_util.h"
19*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log_values.h"
20*6777b538SAndroid Build Coastguard Worker
21*6777b538SAndroid Build Coastguard Worker namespace net {
22*6777b538SAndroid Build Coastguard Worker namespace {
23*6777b538SAndroid Build Coastguard Worker
NetLogInvalidHeader(const NetLogWithSource & net_log,std::string_view header_name,std::string_view header_value,const char * error_message)24*6777b538SAndroid Build Coastguard Worker void NetLogInvalidHeader(const NetLogWithSource& net_log,
25*6777b538SAndroid Build Coastguard Worker std::string_view header_name,
26*6777b538SAndroid Build Coastguard Worker std::string_view header_value,
27*6777b538SAndroid Build Coastguard Worker const char* error_message) {
28*6777b538SAndroid Build Coastguard Worker net_log.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_INVALID_HEADER,
29*6777b538SAndroid Build Coastguard Worker [&](NetLogCaptureMode capture_mode) {
30*6777b538SAndroid Build Coastguard Worker return base::Value::Dict()
31*6777b538SAndroid Build Coastguard Worker .Set("header_name", NetLogStringValue(header_name))
32*6777b538SAndroid Build Coastguard Worker .Set("header_value",
33*6777b538SAndroid Build Coastguard Worker NetLogStringValue(ElideHeaderValueForNetLog(
34*6777b538SAndroid Build Coastguard Worker capture_mode, std::string(header_name),
35*6777b538SAndroid Build Coastguard Worker std::string(header_value))))
36*6777b538SAndroid Build Coastguard Worker .Set("error", error_message);
37*6777b538SAndroid Build Coastguard Worker });
38*6777b538SAndroid Build Coastguard Worker }
39*6777b538SAndroid Build Coastguard Worker
ContainsUppercaseAscii(std::string_view str)40*6777b538SAndroid Build Coastguard Worker bool ContainsUppercaseAscii(std::string_view str) {
41*6777b538SAndroid Build Coastguard Worker return base::ranges::any_of(str, base::IsAsciiUpper<char>);
42*6777b538SAndroid Build Coastguard Worker }
43*6777b538SAndroid Build Coastguard Worker
44*6777b538SAndroid Build Coastguard Worker } // namespace
45*6777b538SAndroid Build Coastguard Worker
HeaderCoalescer(uint32_t max_header_list_size,const NetLogWithSource & net_log)46*6777b538SAndroid Build Coastguard Worker HeaderCoalescer::HeaderCoalescer(uint32_t max_header_list_size,
47*6777b538SAndroid Build Coastguard Worker const NetLogWithSource& net_log)
48*6777b538SAndroid Build Coastguard Worker : max_header_list_size_(max_header_list_size), net_log_(net_log) {}
49*6777b538SAndroid Build Coastguard Worker
OnHeader(std::string_view key,absl::string_view value)50*6777b538SAndroid Build Coastguard Worker void HeaderCoalescer::OnHeader(std::string_view key, absl::string_view value) {
51*6777b538SAndroid Build Coastguard Worker if (error_seen_)
52*6777b538SAndroid Build Coastguard Worker return;
53*6777b538SAndroid Build Coastguard Worker if (!AddHeader(key, value)) {
54*6777b538SAndroid Build Coastguard Worker error_seen_ = true;
55*6777b538SAndroid Build Coastguard Worker }
56*6777b538SAndroid Build Coastguard Worker }
57*6777b538SAndroid Build Coastguard Worker
release_headers()58*6777b538SAndroid Build Coastguard Worker spdy::Http2HeaderBlock HeaderCoalescer::release_headers() {
59*6777b538SAndroid Build Coastguard Worker DCHECK(headers_valid_);
60*6777b538SAndroid Build Coastguard Worker headers_valid_ = false;
61*6777b538SAndroid Build Coastguard Worker return std::move(headers_);
62*6777b538SAndroid Build Coastguard Worker }
63*6777b538SAndroid Build Coastguard Worker
AddHeader(std::string_view key,std::string_view value)64*6777b538SAndroid Build Coastguard Worker bool HeaderCoalescer::AddHeader(std::string_view key, std::string_view value) {
65*6777b538SAndroid Build Coastguard Worker if (key.empty()) {
66*6777b538SAndroid Build Coastguard Worker NetLogInvalidHeader(net_log_, key, value, "Header name must not be empty.");
67*6777b538SAndroid Build Coastguard Worker return false;
68*6777b538SAndroid Build Coastguard Worker }
69*6777b538SAndroid Build Coastguard Worker
70*6777b538SAndroid Build Coastguard Worker std::string_view key_name = key;
71*6777b538SAndroid Build Coastguard Worker if (key[0] == ':') {
72*6777b538SAndroid Build Coastguard Worker if (regular_header_seen_) {
73*6777b538SAndroid Build Coastguard Worker NetLogInvalidHeader(net_log_, key, value,
74*6777b538SAndroid Build Coastguard Worker "Pseudo header must not follow regular headers.");
75*6777b538SAndroid Build Coastguard Worker return false;
76*6777b538SAndroid Build Coastguard Worker }
77*6777b538SAndroid Build Coastguard Worker key_name.remove_prefix(1);
78*6777b538SAndroid Build Coastguard Worker } else if (!regular_header_seen_) {
79*6777b538SAndroid Build Coastguard Worker regular_header_seen_ = true;
80*6777b538SAndroid Build Coastguard Worker }
81*6777b538SAndroid Build Coastguard Worker
82*6777b538SAndroid Build Coastguard Worker if (!HttpUtil::IsValidHeaderName(key_name)) {
83*6777b538SAndroid Build Coastguard Worker NetLogInvalidHeader(net_log_, key, value,
84*6777b538SAndroid Build Coastguard Worker "Invalid character in header name.");
85*6777b538SAndroid Build Coastguard Worker return false;
86*6777b538SAndroid Build Coastguard Worker }
87*6777b538SAndroid Build Coastguard Worker
88*6777b538SAndroid Build Coastguard Worker if (ContainsUppercaseAscii(key_name)) {
89*6777b538SAndroid Build Coastguard Worker NetLogInvalidHeader(net_log_, key, value,
90*6777b538SAndroid Build Coastguard Worker "Upper case characters in header name.");
91*6777b538SAndroid Build Coastguard Worker return false;
92*6777b538SAndroid Build Coastguard Worker }
93*6777b538SAndroid Build Coastguard Worker
94*6777b538SAndroid Build Coastguard Worker // 32 byte overhead according to RFC 7540 Section 6.5.2.
95*6777b538SAndroid Build Coastguard Worker header_list_size_ += key.size() + value.size() + 32;
96*6777b538SAndroid Build Coastguard Worker if (header_list_size_ > max_header_list_size_) {
97*6777b538SAndroid Build Coastguard Worker NetLogInvalidHeader(net_log_, key, value, "Header list too large.");
98*6777b538SAndroid Build Coastguard Worker return false;
99*6777b538SAndroid Build Coastguard Worker }
100*6777b538SAndroid Build Coastguard Worker
101*6777b538SAndroid Build Coastguard Worker // RFC 7540 Section 10.3: "Any request or response that contains a character
102*6777b538SAndroid Build Coastguard Worker // not permitted in a header field value MUST be treated as malformed (Section
103*6777b538SAndroid Build Coastguard Worker // 8.1.2.6). Valid characters are defined by the field-content ABNF rule in
104*6777b538SAndroid Build Coastguard Worker // Section 3.2 of [RFC7230]." RFC 7230 Section 3.2 says:
105*6777b538SAndroid Build Coastguard Worker // field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
106*6777b538SAndroid Build Coastguard Worker // field-vchar = VCHAR / obs-text
107*6777b538SAndroid Build Coastguard Worker // RFC 5234 Appendix B.1 defines |VCHAR|:
108*6777b538SAndroid Build Coastguard Worker // VCHAR = %x21-7E
109*6777b538SAndroid Build Coastguard Worker // RFC 7230 Section 3.2.6 defines |obs-text|:
110*6777b538SAndroid Build Coastguard Worker // obs-text = %x80-FF
111*6777b538SAndroid Build Coastguard Worker // Therefore allowed characters are '\t' (HTAB), x20 (SP), x21-7E, and x80-FF.
112*6777b538SAndroid Build Coastguard Worker for (const unsigned char c : value) {
113*6777b538SAndroid Build Coastguard Worker if (c < '\t' || ('\t' < c && c < 0x20) || c == 0x7f) {
114*6777b538SAndroid Build Coastguard Worker std::string error_line;
115*6777b538SAndroid Build Coastguard Worker base::StringAppendF(&error_line,
116*6777b538SAndroid Build Coastguard Worker "Invalid character 0x%02X in header value.", c);
117*6777b538SAndroid Build Coastguard Worker NetLogInvalidHeader(net_log_, key, value, error_line.c_str());
118*6777b538SAndroid Build Coastguard Worker return false;
119*6777b538SAndroid Build Coastguard Worker }
120*6777b538SAndroid Build Coastguard Worker }
121*6777b538SAndroid Build Coastguard Worker
122*6777b538SAndroid Build Coastguard Worker headers_.AppendValueOrAddHeader(key, value);
123*6777b538SAndroid Build Coastguard Worker return true;
124*6777b538SAndroid Build Coastguard Worker }
125*6777b538SAndroid Build Coastguard Worker
126*6777b538SAndroid Build Coastguard Worker } // namespace net
127