• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 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/http/http_request_headers.h"
6 
7 #include <string_view>
8 #include <utility>
9 
10 #include "base/logging.h"
11 #include "base/metrics/histogram_macros.h"
12 #include "base/notreached.h"
13 #include "base/strings/escape.h"
14 #include "base/strings/strcat.h"
15 #include "base/strings/string_split.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/values.h"
19 #include "net/base/url_util.h"
20 #include "net/http/http_log_util.h"
21 #include "net/http/http_util.h"
22 #include "net/log/net_log_capture_mode.h"
23 #include "net/log/net_log_values.h"
24 
25 namespace net {
26 
27 namespace {
28 
SupportsStreamType(const std::optional<base::flat_set<SourceStream::SourceType>> & accepted_stream_types,SourceStream::SourceType type)29 bool SupportsStreamType(
30     const std::optional<base::flat_set<SourceStream::SourceType>>&
31         accepted_stream_types,
32     SourceStream::SourceType type) {
33   if (!accepted_stream_types)
34     return true;
35   return accepted_stream_types->contains(type);
36 }
37 
38 }  // namespace
39 
40 const char HttpRequestHeaders::kConnectMethod[] = "CONNECT";
41 const char HttpRequestHeaders::kDeleteMethod[] = "DELETE";
42 const char HttpRequestHeaders::kGetMethod[] = "GET";
43 const char HttpRequestHeaders::kHeadMethod[] = "HEAD";
44 const char HttpRequestHeaders::kOptionsMethod[] = "OPTIONS";
45 const char HttpRequestHeaders::kPatchMethod[] = "PATCH";
46 const char HttpRequestHeaders::kPostMethod[] = "POST";
47 const char HttpRequestHeaders::kPutMethod[] = "PUT";
48 const char HttpRequestHeaders::kTraceMethod[] = "TRACE";
49 const char HttpRequestHeaders::kTrackMethod[] = "TRACK";
50 const char HttpRequestHeaders::kAccept[] = "Accept";
51 const char HttpRequestHeaders::kAcceptCharset[] = "Accept-Charset";
52 const char HttpRequestHeaders::kAcceptEncoding[] = "Accept-Encoding";
53 const char HttpRequestHeaders::kAcceptLanguage[] = "Accept-Language";
54 const char HttpRequestHeaders::kAuthorization[] = "Authorization";
55 const char HttpRequestHeaders::kCacheControl[] = "Cache-Control";
56 const char HttpRequestHeaders::kConnection[] = "Connection";
57 const char HttpRequestHeaders::kContentLength[] = "Content-Length";
58 const char HttpRequestHeaders::kContentType[] = "Content-Type";
59 const char HttpRequestHeaders::kCookie[] = "Cookie";
60 const char HttpRequestHeaders::kHost[] = "Host";
61 const char HttpRequestHeaders::kIfMatch[] = "If-Match";
62 const char HttpRequestHeaders::kIfModifiedSince[] = "If-Modified-Since";
63 const char HttpRequestHeaders::kIfNoneMatch[] = "If-None-Match";
64 const char HttpRequestHeaders::kIfRange[] = "If-Range";
65 const char HttpRequestHeaders::kIfUnmodifiedSince[] = "If-Unmodified-Since";
66 const char HttpRequestHeaders::kOrigin[] = "Origin";
67 const char HttpRequestHeaders::kPragma[] = "Pragma";
68 const char HttpRequestHeaders::kPriority[] = "Priority";
69 const char HttpRequestHeaders::kProxyAuthorization[] = "Proxy-Authorization";
70 const char HttpRequestHeaders::kProxyConnection[] = "Proxy-Connection";
71 const char HttpRequestHeaders::kRange[] = "Range";
72 const char HttpRequestHeaders::kReferer[] = "Referer";
73 const char HttpRequestHeaders::kTransferEncoding[] = "Transfer-Encoding";
74 const char HttpRequestHeaders::kUserAgent[] = "User-Agent";
75 
76 HttpRequestHeaders::HeaderKeyValuePair::HeaderKeyValuePair() = default;
77 
HeaderKeyValuePair(std::string_view key,std::string_view value)78 HttpRequestHeaders::HeaderKeyValuePair::HeaderKeyValuePair(
79     std::string_view key,
80     std::string_view value)
81     : HeaderKeyValuePair(key, std::string(value)) {}
82 
HeaderKeyValuePair(std::string_view key,std::string && value)83 HttpRequestHeaders::HeaderKeyValuePair::HeaderKeyValuePair(std::string_view key,
84                                                            std::string&& value)
85     : key(key), value(std::move(value)) {}
86 
Iterator(const HttpRequestHeaders & headers)87 HttpRequestHeaders::Iterator::Iterator(const HttpRequestHeaders& headers)
88     : curr_(headers.headers_.begin()), end_(headers.headers_.end()) {}
89 
90 HttpRequestHeaders::Iterator::~Iterator() = default;
91 
GetNext()92 bool HttpRequestHeaders::Iterator::GetNext() {
93   if (!started_) {
94     started_ = true;
95     return curr_ != end_;
96   }
97 
98   if (curr_ == end_)
99     return false;
100 
101   ++curr_;
102   return curr_ != end_;
103 }
104 
105 HttpRequestHeaders::HttpRequestHeaders() = default;
106 HttpRequestHeaders::HttpRequestHeaders(const HttpRequestHeaders& other) =
107     default;
108 HttpRequestHeaders::HttpRequestHeaders(HttpRequestHeaders&& other) = default;
109 HttpRequestHeaders::~HttpRequestHeaders() = default;
110 
111 HttpRequestHeaders& HttpRequestHeaders::operator=(
112     const HttpRequestHeaders& other) = default;
113 HttpRequestHeaders& HttpRequestHeaders::operator=(HttpRequestHeaders&& other) =
114     default;
115 
GetHeader(std::string_view key) const116 std::optional<std::string> HttpRequestHeaders::GetHeader(
117     std::string_view key) const {
118   auto it = FindHeader(key);
119   if (it == headers_.end())
120     return std::nullopt;
121   return it->value;
122 }
123 
Clear()124 void HttpRequestHeaders::Clear() {
125   headers_.clear();
126 }
127 
SetHeader(std::string_view key,std::string_view value)128 void HttpRequestHeaders::SetHeader(std::string_view key,
129                                    std::string_view value) {
130   SetHeader(key, std::string(value));
131 }
132 
SetHeader(std::string_view key,std::string && value)133 void HttpRequestHeaders::SetHeader(std::string_view key, std::string&& value) {
134   // Invalid header names or values could mean clients can attach
135   // browser-internal headers.
136   CHECK(HttpUtil::IsValidHeaderName(key)) << key;
137   CHECK(HttpUtil::IsValidHeaderValue(value)) << key << " has invalid value.";
138 
139   SetHeaderInternal(key, std::move(value));
140 }
141 
SetHeaderWithoutCheckForTesting(std::string_view key,std::string_view value)142 void HttpRequestHeaders::SetHeaderWithoutCheckForTesting(
143     std::string_view key,
144     std::string_view value) {
145   SetHeaderInternal(key, std::string(value));
146 }
147 
SetHeaderIfMissing(std::string_view key,std::string_view value)148 void HttpRequestHeaders::SetHeaderIfMissing(std::string_view key,
149                                             std::string_view value) {
150   // Invalid header names or values could mean clients can attach
151   // browser-internal headers.
152   CHECK(HttpUtil::IsValidHeaderName(key));
153   CHECK(HttpUtil::IsValidHeaderValue(value));
154   auto it = FindHeader(key);
155   if (it == headers_.end())
156     headers_.push_back(HeaderKeyValuePair(key, value));
157 }
158 
RemoveHeader(std::string_view key)159 void HttpRequestHeaders::RemoveHeader(std::string_view key) {
160   auto it = FindHeader(key);
161   if (it != headers_.end())
162     headers_.erase(it);
163 }
164 
AddHeaderFromString(std::string_view header_line)165 void HttpRequestHeaders::AddHeaderFromString(std::string_view header_line) {
166   DCHECK_EQ(std::string::npos, header_line.find("\r\n"))
167       << "\"" << header_line << "\" contains CRLF.";
168 
169   const std::string::size_type key_end_index = header_line.find(":");
170   if (key_end_index == std::string::npos) {
171     LOG(DFATAL) << "\"" << header_line << "\" is missing colon delimiter.";
172     return;
173   }
174 
175   if (key_end_index == 0) {
176     LOG(DFATAL) << "\"" << header_line << "\" is missing header key.";
177     return;
178   }
179 
180   const std::string_view header_key = header_line.substr(0, key_end_index);
181   if (!HttpUtil::IsValidHeaderName(header_key)) {
182     LOG(DFATAL) << "\"" << header_line << "\" has invalid header key.";
183     return;
184   }
185 
186   const std::string::size_type value_index = key_end_index + 1;
187 
188   if (value_index < header_line.size()) {
189     std::string_view header_value = header_line.substr(value_index);
190     header_value = HttpUtil::TrimLWS(header_value);
191     if (!HttpUtil::IsValidHeaderValue(header_value)) {
192       LOG(DFATAL) << "\"" << header_line << "\" has invalid header value.";
193       return;
194     }
195     SetHeader(header_key, header_value);
196   } else if (value_index == header_line.size()) {
197     SetHeader(header_key, "");
198   } else {
199     NOTREACHED();
200   }
201 }
202 
AddHeadersFromString(std::string_view headers)203 void HttpRequestHeaders::AddHeadersFromString(std::string_view headers) {
204   for (std::string_view header : base::SplitStringPieceUsingSubstr(
205            headers, "\r\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
206     AddHeaderFromString(header);
207   }
208 }
209 
MergeFrom(const HttpRequestHeaders & other)210 void HttpRequestHeaders::MergeFrom(const HttpRequestHeaders& other) {
211   for (const auto& header : other.headers_) {
212     SetHeader(header.key, header.value);
213   }
214 }
215 
ToString() const216 std::string HttpRequestHeaders::ToString() const {
217   std::string output;
218   for (const auto& header : headers_) {
219     base::StringAppendF(&output, "%s: %s\r\n", header.key.c_str(),
220                         header.value.c_str());
221   }
222   output.append("\r\n");
223   return output;
224 }
225 
NetLogParams(const std::string & request_line,NetLogCaptureMode capture_mode) const226 base::Value::Dict HttpRequestHeaders::NetLogParams(
227     const std::string& request_line,
228     NetLogCaptureMode capture_mode) const {
229   base::Value::Dict dict;
230   dict.Set("line", NetLogStringValue(request_line));
231   base::Value::List headers;
232   for (const auto& header : headers_) {
233     std::string log_value =
234         ElideHeaderValueForNetLog(capture_mode, header.key, header.value);
235     headers.Append(
236         NetLogStringValue(base::StrCat({header.key, ": ", log_value})));
237   }
238   dict.Set("headers", std::move(headers));
239   return dict;
240 }
241 
SetAcceptEncodingIfMissing(const GURL & url,const std::optional<base::flat_set<SourceStream::SourceType>> & accepted_stream_types,bool enable_brotli,bool enable_zstd)242 void HttpRequestHeaders::SetAcceptEncodingIfMissing(
243     const GURL& url,
244     const std::optional<base::flat_set<SourceStream::SourceType>>&
245         accepted_stream_types,
246     bool enable_brotli,
247     bool enable_zstd) {
248   if (HasHeader(kAcceptEncoding))
249     return;
250 
251   // If a range is specifically requested, set the "Accepted Encoding" header to
252   // "identity".
253   if (HasHeader(kRange)) {
254     SetHeader(kAcceptEncoding, "identity");
255     return;
256   }
257 
258   // Supply Accept-Encoding headers first so that it is more likely that they
259   // will be in the first transmitted packet. This can sometimes make it easier
260   // to filter and analyze the streams to assure that a proxy has not damaged
261   // these headers. Some proxies deliberately corrupt Accept-Encoding headers.
262   std::vector<std::string> advertised_encoding_names;
263   if (SupportsStreamType(accepted_stream_types,
264                          SourceStream::SourceType::TYPE_GZIP)) {
265     advertised_encoding_names.push_back("gzip");
266   }
267   if (SupportsStreamType(accepted_stream_types,
268                          SourceStream::SourceType::TYPE_DEFLATE)) {
269     advertised_encoding_names.push_back("deflate");
270   }
271 
272   const bool can_use_advanced_encodings =
273       (url.SchemeIsCryptographic() || IsLocalhost(url));
274 
275   // Advertise "br" encoding only if transferred data is opaque to proxy.
276   if (enable_brotli &&
277       SupportsStreamType(accepted_stream_types,
278                          SourceStream::SourceType::TYPE_BROTLI) &&
279       can_use_advanced_encodings) {
280     advertised_encoding_names.push_back("br");
281   }
282   // Advertise "zstd" encoding only if transferred data is opaque to proxy.
283   if (enable_zstd &&
284       SupportsStreamType(accepted_stream_types,
285                          SourceStream::SourceType::TYPE_ZSTD) &&
286       can_use_advanced_encodings) {
287     advertised_encoding_names.push_back("zstd");
288   }
289   if (!advertised_encoding_names.empty()) {
290     // Tell the server what compression formats are supported.
291     SetHeader(kAcceptEncoding,
292               base::JoinString(base::span(advertised_encoding_names), ", "));
293   }
294 }
295 
FindHeader(std::string_view key)296 HttpRequestHeaders::HeaderVector::iterator HttpRequestHeaders::FindHeader(
297     std::string_view key) {
298   for (auto it = headers_.begin(); it != headers_.end(); ++it) {
299     if (base::EqualsCaseInsensitiveASCII(key, it->key))
300       return it;
301   }
302 
303   return headers_.end();
304 }
305 
FindHeader(std::string_view key) const306 HttpRequestHeaders::HeaderVector::const_iterator HttpRequestHeaders::FindHeader(
307     std::string_view key) const {
308   for (auto it = headers_.begin(); it != headers_.end(); ++it) {
309     if (base::EqualsCaseInsensitiveASCII(key, it->key))
310       return it;
311   }
312 
313   return headers_.end();
314 }
315 
SetHeaderInternal(std::string_view key,std::string && value)316 void HttpRequestHeaders::SetHeaderInternal(std::string_view key,
317                                            std::string&& value) {
318   auto it = FindHeader(key);
319   if (it != headers_.end())
320     it->value = std::move(value);
321   else
322     headers_.emplace_back(key, std::move(value));
323 }
324 
325 }  // namespace net
326