1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 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 // The rules for parsing content-types were borrowed from Firefox:
6*6777b538SAndroid Build Coastguard Worker // http://lxr.mozilla.org/mozilla/source/netwerk/base/src/nsURLHelper.cpp#834
7*6777b538SAndroid Build Coastguard Worker
8*6777b538SAndroid Build Coastguard Worker #include "net/http/http_util.h"
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Worker #include <algorithm>
11*6777b538SAndroid Build Coastguard Worker #include <string>
12*6777b538SAndroid Build Coastguard Worker #include <string_view>
13*6777b538SAndroid Build Coastguard Worker
14*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/strings/strcat.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_split.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_tokenizer.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h"
22*6777b538SAndroid Build Coastguard Worker #include "net/base/features.h"
23*6777b538SAndroid Build Coastguard Worker #include "net/base/mime_util.h"
24*6777b538SAndroid Build Coastguard Worker #include "net/base/parse_number.h"
25*6777b538SAndroid Build Coastguard Worker #include "net/base/url_util.h"
26*6777b538SAndroid Build Coastguard Worker #include "net/http/http_response_headers.h"
27*6777b538SAndroid Build Coastguard Worker
28*6777b538SAndroid Build Coastguard Worker namespace net {
29*6777b538SAndroid Build Coastguard Worker
30*6777b538SAndroid Build Coastguard Worker namespace {
31*6777b538SAndroid Build Coastguard Worker
32*6777b538SAndroid Build Coastguard Worker template <typename ConstIterator>
TrimLWSImplementation(ConstIterator * begin,ConstIterator * end)33*6777b538SAndroid Build Coastguard Worker void TrimLWSImplementation(ConstIterator* begin, ConstIterator* end) {
34*6777b538SAndroid Build Coastguard Worker // leading whitespace
35*6777b538SAndroid Build Coastguard Worker while (*begin < *end && HttpUtil::IsLWS((*begin)[0]))
36*6777b538SAndroid Build Coastguard Worker ++(*begin);
37*6777b538SAndroid Build Coastguard Worker
38*6777b538SAndroid Build Coastguard Worker // trailing whitespace
39*6777b538SAndroid Build Coastguard Worker while (*begin < *end && HttpUtil::IsLWS((*end)[-1]))
40*6777b538SAndroid Build Coastguard Worker --(*end);
41*6777b538SAndroid Build Coastguard Worker }
42*6777b538SAndroid Build Coastguard Worker
43*6777b538SAndroid Build Coastguard Worker // Helper class that builds the list of languages for the Accept-Language
44*6777b538SAndroid Build Coastguard Worker // headers.
45*6777b538SAndroid Build Coastguard Worker // The output is a comma-separated list of languages as string.
46*6777b538SAndroid Build Coastguard Worker // Duplicates are removed.
47*6777b538SAndroid Build Coastguard Worker class AcceptLanguageBuilder {
48*6777b538SAndroid Build Coastguard Worker public:
49*6777b538SAndroid Build Coastguard Worker // Adds a language to the string.
50*6777b538SAndroid Build Coastguard Worker // Duplicates are ignored.
AddLanguageCode(const std::string & language)51*6777b538SAndroid Build Coastguard Worker void AddLanguageCode(const std::string& language) {
52*6777b538SAndroid Build Coastguard Worker // No Q score supported, only supports ASCII.
53*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(std::string::npos, language.find_first_of("; "));
54*6777b538SAndroid Build Coastguard Worker DCHECK(base::IsStringASCII(language));
55*6777b538SAndroid Build Coastguard Worker if (seen_.find(language) == seen_.end()) {
56*6777b538SAndroid Build Coastguard Worker if (str_.empty()) {
57*6777b538SAndroid Build Coastguard Worker base::StringAppendF(&str_, "%s", language.c_str());
58*6777b538SAndroid Build Coastguard Worker } else {
59*6777b538SAndroid Build Coastguard Worker base::StringAppendF(&str_, ",%s", language.c_str());
60*6777b538SAndroid Build Coastguard Worker }
61*6777b538SAndroid Build Coastguard Worker seen_.insert(language);
62*6777b538SAndroid Build Coastguard Worker }
63*6777b538SAndroid Build Coastguard Worker }
64*6777b538SAndroid Build Coastguard Worker
65*6777b538SAndroid Build Coastguard Worker // Returns the string constructed up to this point.
GetString() const66*6777b538SAndroid Build Coastguard Worker std::string GetString() const { return str_; }
67*6777b538SAndroid Build Coastguard Worker
68*6777b538SAndroid Build Coastguard Worker private:
69*6777b538SAndroid Build Coastguard Worker // The string that contains the list of languages, comma-separated.
70*6777b538SAndroid Build Coastguard Worker std::string str_;
71*6777b538SAndroid Build Coastguard Worker // Set the remove duplicates.
72*6777b538SAndroid Build Coastguard Worker std::unordered_set<std::string> seen_;
73*6777b538SAndroid Build Coastguard Worker };
74*6777b538SAndroid Build Coastguard Worker
75*6777b538SAndroid Build Coastguard Worker // Extract the base language code from a language code.
76*6777b538SAndroid Build Coastguard Worker // If there is no '-' in the code, the original code is returned.
GetBaseLanguageCode(const std::string & language_code)77*6777b538SAndroid Build Coastguard Worker std::string GetBaseLanguageCode(const std::string& language_code) {
78*6777b538SAndroid Build Coastguard Worker const std::vector<std::string> tokens = base::SplitString(
79*6777b538SAndroid Build Coastguard Worker language_code, "-", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
80*6777b538SAndroid Build Coastguard Worker return tokens.empty() ? "" : tokens[0];
81*6777b538SAndroid Build Coastguard Worker }
82*6777b538SAndroid Build Coastguard Worker
83*6777b538SAndroid Build Coastguard Worker } // namespace
84*6777b538SAndroid Build Coastguard Worker
85*6777b538SAndroid Build Coastguard Worker // HttpUtil -------------------------------------------------------------------
86*6777b538SAndroid Build Coastguard Worker
87*6777b538SAndroid Build Coastguard Worker // static
SpecForRequest(const GURL & url)88*6777b538SAndroid Build Coastguard Worker std::string HttpUtil::SpecForRequest(const GURL& url) {
89*6777b538SAndroid Build Coastguard Worker DCHECK(url.is_valid() &&
90*6777b538SAndroid Build Coastguard Worker (url.SchemeIsHTTPOrHTTPS() || url.SchemeIsWSOrWSS()));
91*6777b538SAndroid Build Coastguard Worker return SimplifyUrlForRequest(url).spec();
92*6777b538SAndroid Build Coastguard Worker }
93*6777b538SAndroid Build Coastguard Worker
94*6777b538SAndroid Build Coastguard Worker // static
ParseContentType(const std::string & content_type_str,std::string * mime_type,std::string * charset,bool * had_charset,std::string * boundary)95*6777b538SAndroid Build Coastguard Worker void HttpUtil::ParseContentType(const std::string& content_type_str,
96*6777b538SAndroid Build Coastguard Worker std::string* mime_type,
97*6777b538SAndroid Build Coastguard Worker std::string* charset,
98*6777b538SAndroid Build Coastguard Worker bool* had_charset,
99*6777b538SAndroid Build Coastguard Worker std::string* boundary) {
100*6777b538SAndroid Build Coastguard Worker std::string mime_type_value;
101*6777b538SAndroid Build Coastguard Worker base::StringPairs params;
102*6777b538SAndroid Build Coastguard Worker bool result = ParseMimeType(content_type_str, &mime_type_value, ¶ms);
103*6777b538SAndroid Build Coastguard Worker // If the server sent "*/*", it is meaningless, so do not store it.
104*6777b538SAndroid Build Coastguard Worker // Also, reject a mime-type if it does not include a slash.
105*6777b538SAndroid Build Coastguard Worker // Some servers give junk after the charset parameter, which may
106*6777b538SAndroid Build Coastguard Worker // include a comma, so this check makes us a bit more tolerant.
107*6777b538SAndroid Build Coastguard Worker if (!result || content_type_str == "*/*")
108*6777b538SAndroid Build Coastguard Worker return;
109*6777b538SAndroid Build Coastguard Worker
110*6777b538SAndroid Build Coastguard Worker std::string charset_value;
111*6777b538SAndroid Build Coastguard Worker bool type_has_charset = false;
112*6777b538SAndroid Build Coastguard Worker bool type_has_boundary = false;
113*6777b538SAndroid Build Coastguard Worker for (const auto& param : params) {
114*6777b538SAndroid Build Coastguard Worker // Trim LWS from param value, ParseMimeType() leaves WS for quoted-string.
115*6777b538SAndroid Build Coastguard Worker // TODO(mmenke): Check that name has only valid characters.
116*6777b538SAndroid Build Coastguard Worker if (!type_has_charset &&
117*6777b538SAndroid Build Coastguard Worker base::EqualsCaseInsensitiveASCII(param.first, "charset")) {
118*6777b538SAndroid Build Coastguard Worker type_has_charset = true;
119*6777b538SAndroid Build Coastguard Worker charset_value = std::string(HttpUtil::TrimLWS(param.second));
120*6777b538SAndroid Build Coastguard Worker continue;
121*6777b538SAndroid Build Coastguard Worker }
122*6777b538SAndroid Build Coastguard Worker
123*6777b538SAndroid Build Coastguard Worker if (boundary && !type_has_boundary &&
124*6777b538SAndroid Build Coastguard Worker base::EqualsCaseInsensitiveASCII(param.first, "boundary")) {
125*6777b538SAndroid Build Coastguard Worker type_has_boundary = true;
126*6777b538SAndroid Build Coastguard Worker *boundary = std::string(HttpUtil::TrimLWS(param.second));
127*6777b538SAndroid Build Coastguard Worker continue;
128*6777b538SAndroid Build Coastguard Worker }
129*6777b538SAndroid Build Coastguard Worker }
130*6777b538SAndroid Build Coastguard Worker
131*6777b538SAndroid Build Coastguard Worker // If `mime_type_value` is the same as `mime_type`, then just update
132*6777b538SAndroid Build Coastguard Worker // `charset`. However, if `charset` is empty and `mime_type` hasn't changed,
133*6777b538SAndroid Build Coastguard Worker // then don't wipe-out an existing `charset`.
134*6777b538SAndroid Build Coastguard Worker bool eq = base::EqualsCaseInsensitiveASCII(mime_type_value, *mime_type);
135*6777b538SAndroid Build Coastguard Worker if (!eq) {
136*6777b538SAndroid Build Coastguard Worker *mime_type = base::ToLowerASCII(mime_type_value);
137*6777b538SAndroid Build Coastguard Worker }
138*6777b538SAndroid Build Coastguard Worker if ((!eq && *had_charset) || type_has_charset) {
139*6777b538SAndroid Build Coastguard Worker *had_charset = true;
140*6777b538SAndroid Build Coastguard Worker *charset = base::ToLowerASCII(charset_value);
141*6777b538SAndroid Build Coastguard Worker }
142*6777b538SAndroid Build Coastguard Worker }
143*6777b538SAndroid Build Coastguard Worker
144*6777b538SAndroid Build Coastguard Worker // static
ParseRangeHeader(const std::string & ranges_specifier,std::vector<HttpByteRange> * ranges)145*6777b538SAndroid Build Coastguard Worker bool HttpUtil::ParseRangeHeader(const std::string& ranges_specifier,
146*6777b538SAndroid Build Coastguard Worker std::vector<HttpByteRange>* ranges) {
147*6777b538SAndroid Build Coastguard Worker size_t equal_char_offset = ranges_specifier.find('=');
148*6777b538SAndroid Build Coastguard Worker if (equal_char_offset == std::string::npos)
149*6777b538SAndroid Build Coastguard Worker return false;
150*6777b538SAndroid Build Coastguard Worker
151*6777b538SAndroid Build Coastguard Worker // Try to extract bytes-unit part.
152*6777b538SAndroid Build Coastguard Worker std::string_view bytes_unit =
153*6777b538SAndroid Build Coastguard Worker std::string_view(ranges_specifier).substr(0, equal_char_offset);
154*6777b538SAndroid Build Coastguard Worker
155*6777b538SAndroid Build Coastguard Worker // "bytes" unit identifier is not found.
156*6777b538SAndroid Build Coastguard Worker bytes_unit = TrimLWS(bytes_unit);
157*6777b538SAndroid Build Coastguard Worker if (!base::EqualsCaseInsensitiveASCII(bytes_unit, "bytes")) {
158*6777b538SAndroid Build Coastguard Worker return false;
159*6777b538SAndroid Build Coastguard Worker }
160*6777b538SAndroid Build Coastguard Worker
161*6777b538SAndroid Build Coastguard Worker std::string::const_iterator byte_range_set_begin =
162*6777b538SAndroid Build Coastguard Worker ranges_specifier.begin() + equal_char_offset + 1;
163*6777b538SAndroid Build Coastguard Worker std::string::const_iterator byte_range_set_end = ranges_specifier.end();
164*6777b538SAndroid Build Coastguard Worker
165*6777b538SAndroid Build Coastguard Worker ValuesIterator byte_range_set_iterator(byte_range_set_begin,
166*6777b538SAndroid Build Coastguard Worker byte_range_set_end, ',');
167*6777b538SAndroid Build Coastguard Worker while (byte_range_set_iterator.GetNext()) {
168*6777b538SAndroid Build Coastguard Worker std::string_view value = byte_range_set_iterator.value_piece();
169*6777b538SAndroid Build Coastguard Worker size_t minus_char_offset = value.find('-');
170*6777b538SAndroid Build Coastguard Worker // If '-' character is not found, reports failure.
171*6777b538SAndroid Build Coastguard Worker if (minus_char_offset == std::string::npos)
172*6777b538SAndroid Build Coastguard Worker return false;
173*6777b538SAndroid Build Coastguard Worker
174*6777b538SAndroid Build Coastguard Worker std::string_view first_byte_pos = value.substr(0, minus_char_offset);
175*6777b538SAndroid Build Coastguard Worker first_byte_pos = TrimLWS(first_byte_pos);
176*6777b538SAndroid Build Coastguard Worker
177*6777b538SAndroid Build Coastguard Worker HttpByteRange range;
178*6777b538SAndroid Build Coastguard Worker // Try to obtain first-byte-pos.
179*6777b538SAndroid Build Coastguard Worker if (!first_byte_pos.empty()) {
180*6777b538SAndroid Build Coastguard Worker int64_t first_byte_position = -1;
181*6777b538SAndroid Build Coastguard Worker if (!base::StringToInt64(first_byte_pos, &first_byte_position))
182*6777b538SAndroid Build Coastguard Worker return false;
183*6777b538SAndroid Build Coastguard Worker range.set_first_byte_position(first_byte_position);
184*6777b538SAndroid Build Coastguard Worker }
185*6777b538SAndroid Build Coastguard Worker
186*6777b538SAndroid Build Coastguard Worker std::string_view last_byte_pos = value.substr(minus_char_offset + 1);
187*6777b538SAndroid Build Coastguard Worker last_byte_pos = TrimLWS(last_byte_pos);
188*6777b538SAndroid Build Coastguard Worker
189*6777b538SAndroid Build Coastguard Worker // We have last-byte-pos or suffix-byte-range-spec in this case.
190*6777b538SAndroid Build Coastguard Worker if (!last_byte_pos.empty()) {
191*6777b538SAndroid Build Coastguard Worker int64_t last_byte_position;
192*6777b538SAndroid Build Coastguard Worker if (!base::StringToInt64(last_byte_pos, &last_byte_position))
193*6777b538SAndroid Build Coastguard Worker return false;
194*6777b538SAndroid Build Coastguard Worker if (range.HasFirstBytePosition())
195*6777b538SAndroid Build Coastguard Worker range.set_last_byte_position(last_byte_position);
196*6777b538SAndroid Build Coastguard Worker else
197*6777b538SAndroid Build Coastguard Worker range.set_suffix_length(last_byte_position);
198*6777b538SAndroid Build Coastguard Worker } else if (!range.HasFirstBytePosition()) {
199*6777b538SAndroid Build Coastguard Worker return false;
200*6777b538SAndroid Build Coastguard Worker }
201*6777b538SAndroid Build Coastguard Worker
202*6777b538SAndroid Build Coastguard Worker // Do a final check on the HttpByteRange object.
203*6777b538SAndroid Build Coastguard Worker if (!range.IsValid())
204*6777b538SAndroid Build Coastguard Worker return false;
205*6777b538SAndroid Build Coastguard Worker ranges->push_back(range);
206*6777b538SAndroid Build Coastguard Worker }
207*6777b538SAndroid Build Coastguard Worker return !ranges->empty();
208*6777b538SAndroid Build Coastguard Worker }
209*6777b538SAndroid Build Coastguard Worker
210*6777b538SAndroid Build Coastguard Worker // static
211*6777b538SAndroid Build Coastguard Worker // From RFC 2616 14.16:
212*6777b538SAndroid Build Coastguard Worker // content-range-spec =
213*6777b538SAndroid Build Coastguard Worker // bytes-unit SP byte-range-resp-spec "/" ( instance-length | "*" )
214*6777b538SAndroid Build Coastguard Worker // byte-range-resp-spec = (first-byte-pos "-" last-byte-pos) | "*"
215*6777b538SAndroid Build Coastguard Worker // instance-length = 1*DIGIT
216*6777b538SAndroid Build Coastguard Worker // bytes-unit = "bytes"
ParseContentRangeHeaderFor206(std::string_view content_range_spec,int64_t * first_byte_position,int64_t * last_byte_position,int64_t * instance_length)217*6777b538SAndroid Build Coastguard Worker bool HttpUtil::ParseContentRangeHeaderFor206(
218*6777b538SAndroid Build Coastguard Worker std::string_view content_range_spec,
219*6777b538SAndroid Build Coastguard Worker int64_t* first_byte_position,
220*6777b538SAndroid Build Coastguard Worker int64_t* last_byte_position,
221*6777b538SAndroid Build Coastguard Worker int64_t* instance_length) {
222*6777b538SAndroid Build Coastguard Worker *first_byte_position = *last_byte_position = *instance_length = -1;
223*6777b538SAndroid Build Coastguard Worker content_range_spec = TrimLWS(content_range_spec);
224*6777b538SAndroid Build Coastguard Worker
225*6777b538SAndroid Build Coastguard Worker size_t space_position = content_range_spec.find(' ');
226*6777b538SAndroid Build Coastguard Worker if (space_position == std::string_view::npos) {
227*6777b538SAndroid Build Coastguard Worker return false;
228*6777b538SAndroid Build Coastguard Worker }
229*6777b538SAndroid Build Coastguard Worker
230*6777b538SAndroid Build Coastguard Worker // Invalid header if it doesn't contain "bytes-unit".
231*6777b538SAndroid Build Coastguard Worker if (!base::EqualsCaseInsensitiveASCII(
232*6777b538SAndroid Build Coastguard Worker TrimLWS(content_range_spec.substr(0, space_position)), "bytes")) {
233*6777b538SAndroid Build Coastguard Worker return false;
234*6777b538SAndroid Build Coastguard Worker }
235*6777b538SAndroid Build Coastguard Worker
236*6777b538SAndroid Build Coastguard Worker size_t minus_position = content_range_spec.find('-', space_position + 1);
237*6777b538SAndroid Build Coastguard Worker if (minus_position == std::string_view::npos) {
238*6777b538SAndroid Build Coastguard Worker return false;
239*6777b538SAndroid Build Coastguard Worker }
240*6777b538SAndroid Build Coastguard Worker size_t slash_position = content_range_spec.find('/', minus_position + 1);
241*6777b538SAndroid Build Coastguard Worker if (slash_position == std::string_view::npos) {
242*6777b538SAndroid Build Coastguard Worker return false;
243*6777b538SAndroid Build Coastguard Worker }
244*6777b538SAndroid Build Coastguard Worker
245*6777b538SAndroid Build Coastguard Worker if (base::StringToInt64(
246*6777b538SAndroid Build Coastguard Worker TrimLWS(content_range_spec.substr(
247*6777b538SAndroid Build Coastguard Worker space_position + 1, minus_position - (space_position + 1))),
248*6777b538SAndroid Build Coastguard Worker first_byte_position) &&
249*6777b538SAndroid Build Coastguard Worker *first_byte_position >= 0 &&
250*6777b538SAndroid Build Coastguard Worker base::StringToInt64(
251*6777b538SAndroid Build Coastguard Worker TrimLWS(content_range_spec.substr(
252*6777b538SAndroid Build Coastguard Worker minus_position + 1, slash_position - (minus_position + 1))),
253*6777b538SAndroid Build Coastguard Worker last_byte_position) &&
254*6777b538SAndroid Build Coastguard Worker *last_byte_position >= *first_byte_position &&
255*6777b538SAndroid Build Coastguard Worker base::StringToInt64(
256*6777b538SAndroid Build Coastguard Worker TrimLWS(content_range_spec.substr(slash_position + 1)),
257*6777b538SAndroid Build Coastguard Worker instance_length) &&
258*6777b538SAndroid Build Coastguard Worker *instance_length > *last_byte_position) {
259*6777b538SAndroid Build Coastguard Worker return true;
260*6777b538SAndroid Build Coastguard Worker }
261*6777b538SAndroid Build Coastguard Worker *first_byte_position = *last_byte_position = *instance_length = -1;
262*6777b538SAndroid Build Coastguard Worker return false;
263*6777b538SAndroid Build Coastguard Worker }
264*6777b538SAndroid Build Coastguard Worker
265*6777b538SAndroid Build Coastguard Worker // static
ParseRetryAfterHeader(const std::string & retry_after_string,base::Time now,base::TimeDelta * retry_after)266*6777b538SAndroid Build Coastguard Worker bool HttpUtil::ParseRetryAfterHeader(const std::string& retry_after_string,
267*6777b538SAndroid Build Coastguard Worker base::Time now,
268*6777b538SAndroid Build Coastguard Worker base::TimeDelta* retry_after) {
269*6777b538SAndroid Build Coastguard Worker uint32_t seconds;
270*6777b538SAndroid Build Coastguard Worker base::Time time;
271*6777b538SAndroid Build Coastguard Worker base::TimeDelta interval;
272*6777b538SAndroid Build Coastguard Worker
273*6777b538SAndroid Build Coastguard Worker if (net::ParseUint32(retry_after_string, ParseIntFormat::NON_NEGATIVE,
274*6777b538SAndroid Build Coastguard Worker &seconds)) {
275*6777b538SAndroid Build Coastguard Worker interval = base::Seconds(seconds);
276*6777b538SAndroid Build Coastguard Worker } else if (base::Time::FromUTCString(retry_after_string.c_str(), &time)) {
277*6777b538SAndroid Build Coastguard Worker interval = time - now;
278*6777b538SAndroid Build Coastguard Worker } else {
279*6777b538SAndroid Build Coastguard Worker return false;
280*6777b538SAndroid Build Coastguard Worker }
281*6777b538SAndroid Build Coastguard Worker
282*6777b538SAndroid Build Coastguard Worker if (interval < base::Seconds(0))
283*6777b538SAndroid Build Coastguard Worker return false;
284*6777b538SAndroid Build Coastguard Worker
285*6777b538SAndroid Build Coastguard Worker *retry_after = interval;
286*6777b538SAndroid Build Coastguard Worker return true;
287*6777b538SAndroid Build Coastguard Worker }
288*6777b538SAndroid Build Coastguard Worker
289*6777b538SAndroid Build Coastguard Worker // static
TimeFormatHTTP(base::Time time)290*6777b538SAndroid Build Coastguard Worker std::string HttpUtil::TimeFormatHTTP(base::Time time) {
291*6777b538SAndroid Build Coastguard Worker static constexpr char kWeekdayName[7][4] = {"Sun", "Mon", "Tue", "Wed",
292*6777b538SAndroid Build Coastguard Worker "Thu", "Fri", "Sat"};
293*6777b538SAndroid Build Coastguard Worker static constexpr char kMonthName[12][4] = {"Jan", "Feb", "Mar", "Apr",
294*6777b538SAndroid Build Coastguard Worker "May", "Jun", "Jul", "Aug",
295*6777b538SAndroid Build Coastguard Worker "Sep", "Oct", "Nov", "Dec"};
296*6777b538SAndroid Build Coastguard Worker base::Time::Exploded exploded;
297*6777b538SAndroid Build Coastguard Worker time.UTCExplode(&exploded);
298*6777b538SAndroid Build Coastguard Worker return base::StringPrintf(
299*6777b538SAndroid Build Coastguard Worker "%s, %02d %s %04d %02d:%02d:%02d GMT", kWeekdayName[exploded.day_of_week],
300*6777b538SAndroid Build Coastguard Worker exploded.day_of_month, kMonthName[exploded.month - 1], exploded.year,
301*6777b538SAndroid Build Coastguard Worker exploded.hour, exploded.minute, exploded.second);
302*6777b538SAndroid Build Coastguard Worker }
303*6777b538SAndroid Build Coastguard Worker
304*6777b538SAndroid Build Coastguard Worker namespace {
305*6777b538SAndroid Build Coastguard Worker
306*6777b538SAndroid Build Coastguard Worker // A header string containing any of the following fields will cause
307*6777b538SAndroid Build Coastguard Worker // an error. The list comes from the fetch standard.
308*6777b538SAndroid Build Coastguard Worker const char* const kForbiddenHeaderFields[] = {
309*6777b538SAndroid Build Coastguard Worker "accept-charset",
310*6777b538SAndroid Build Coastguard Worker "accept-encoding",
311*6777b538SAndroid Build Coastguard Worker "access-control-request-headers",
312*6777b538SAndroid Build Coastguard Worker "access-control-request-method",
313*6777b538SAndroid Build Coastguard Worker "access-control-request-private-network",
314*6777b538SAndroid Build Coastguard Worker "connection",
315*6777b538SAndroid Build Coastguard Worker "content-length",
316*6777b538SAndroid Build Coastguard Worker "cookie",
317*6777b538SAndroid Build Coastguard Worker "cookie2",
318*6777b538SAndroid Build Coastguard Worker "date",
319*6777b538SAndroid Build Coastguard Worker "dnt",
320*6777b538SAndroid Build Coastguard Worker "expect",
321*6777b538SAndroid Build Coastguard Worker "host",
322*6777b538SAndroid Build Coastguard Worker "keep-alive",
323*6777b538SAndroid Build Coastguard Worker "origin",
324*6777b538SAndroid Build Coastguard Worker "referer",
325*6777b538SAndroid Build Coastguard Worker "set-cookie",
326*6777b538SAndroid Build Coastguard Worker "te",
327*6777b538SAndroid Build Coastguard Worker "trailer",
328*6777b538SAndroid Build Coastguard Worker "transfer-encoding",
329*6777b538SAndroid Build Coastguard Worker "upgrade",
330*6777b538SAndroid Build Coastguard Worker // TODO(mmenke): This is no longer banned, but still here due to issues
331*6777b538SAndroid Build Coastguard Worker // mentioned in https://crbug.com/571722.
332*6777b538SAndroid Build Coastguard Worker "user-agent",
333*6777b538SAndroid Build Coastguard Worker "via",
334*6777b538SAndroid Build Coastguard Worker };
335*6777b538SAndroid Build Coastguard Worker
336*6777b538SAndroid Build Coastguard Worker // A header string containing any of the following fields with a forbidden
337*6777b538SAndroid Build Coastguard Worker // method name in the value will cause an error. The list comes from the fetch
338*6777b538SAndroid Build Coastguard Worker // standard.
339*6777b538SAndroid Build Coastguard Worker const char* const kForbiddenHeaderFieldsWithForbiddenMethod[] = {
340*6777b538SAndroid Build Coastguard Worker "x-http-method",
341*6777b538SAndroid Build Coastguard Worker "x-http-method-override",
342*6777b538SAndroid Build Coastguard Worker "x-method-override",
343*6777b538SAndroid Build Coastguard Worker };
344*6777b538SAndroid Build Coastguard Worker
345*6777b538SAndroid Build Coastguard Worker // The forbidden method names that is defined in the fetch standard, and used
346*6777b538SAndroid Build Coastguard Worker // to check the kForbiddenHeaderFileWithForbiddenMethod above.
347*6777b538SAndroid Build Coastguard Worker const char* const kForbiddenMethods[] = {
348*6777b538SAndroid Build Coastguard Worker "connect",
349*6777b538SAndroid Build Coastguard Worker "trace",
350*6777b538SAndroid Build Coastguard Worker "track",
351*6777b538SAndroid Build Coastguard Worker };
352*6777b538SAndroid Build Coastguard Worker
353*6777b538SAndroid Build Coastguard Worker } // namespace
354*6777b538SAndroid Build Coastguard Worker
355*6777b538SAndroid Build Coastguard Worker // static
IsMethodSafe(std::string_view method)356*6777b538SAndroid Build Coastguard Worker bool HttpUtil::IsMethodSafe(std::string_view method) {
357*6777b538SAndroid Build Coastguard Worker return method == "GET" || method == "HEAD" || method == "OPTIONS" ||
358*6777b538SAndroid Build Coastguard Worker method == "TRACE";
359*6777b538SAndroid Build Coastguard Worker }
360*6777b538SAndroid Build Coastguard Worker
361*6777b538SAndroid Build Coastguard Worker // static
IsMethodIdempotent(std::string_view method)362*6777b538SAndroid Build Coastguard Worker bool HttpUtil::IsMethodIdempotent(std::string_view method) {
363*6777b538SAndroid Build Coastguard Worker return IsMethodSafe(method) || method == "PUT" || method == "DELETE";
364*6777b538SAndroid Build Coastguard Worker }
365*6777b538SAndroid Build Coastguard Worker
366*6777b538SAndroid Build Coastguard Worker // static
IsSafeHeader(std::string_view name,std::string_view value)367*6777b538SAndroid Build Coastguard Worker bool HttpUtil::IsSafeHeader(std::string_view name, std::string_view value) {
368*6777b538SAndroid Build Coastguard Worker if (base::StartsWith(name, "proxy-", base::CompareCase::INSENSITIVE_ASCII) ||
369*6777b538SAndroid Build Coastguard Worker base::StartsWith(name, "sec-", base::CompareCase::INSENSITIVE_ASCII))
370*6777b538SAndroid Build Coastguard Worker return false;
371*6777b538SAndroid Build Coastguard Worker
372*6777b538SAndroid Build Coastguard Worker for (const char* field : kForbiddenHeaderFields) {
373*6777b538SAndroid Build Coastguard Worker if (base::EqualsCaseInsensitiveASCII(name, field))
374*6777b538SAndroid Build Coastguard Worker return false;
375*6777b538SAndroid Build Coastguard Worker }
376*6777b538SAndroid Build Coastguard Worker
377*6777b538SAndroid Build Coastguard Worker if (base::FeatureList::IsEnabled(features::kBlockNewForbiddenHeaders)) {
378*6777b538SAndroid Build Coastguard Worker bool is_forbidden_header_fields_with_forbidden_method = false;
379*6777b538SAndroid Build Coastguard Worker for (const char* field : kForbiddenHeaderFieldsWithForbiddenMethod) {
380*6777b538SAndroid Build Coastguard Worker if (base::EqualsCaseInsensitiveASCII(name, field)) {
381*6777b538SAndroid Build Coastguard Worker is_forbidden_header_fields_with_forbidden_method = true;
382*6777b538SAndroid Build Coastguard Worker break;
383*6777b538SAndroid Build Coastguard Worker }
384*6777b538SAndroid Build Coastguard Worker }
385*6777b538SAndroid Build Coastguard Worker if (is_forbidden_header_fields_with_forbidden_method) {
386*6777b538SAndroid Build Coastguard Worker std::string value_string(value);
387*6777b538SAndroid Build Coastguard Worker ValuesIterator method_iterator(value_string.begin(), value_string.end(),
388*6777b538SAndroid Build Coastguard Worker ',');
389*6777b538SAndroid Build Coastguard Worker while (method_iterator.GetNext()) {
390*6777b538SAndroid Build Coastguard Worker std::string_view method = method_iterator.value_piece();
391*6777b538SAndroid Build Coastguard Worker for (const char* forbidden_method : kForbiddenMethods) {
392*6777b538SAndroid Build Coastguard Worker if (base::EqualsCaseInsensitiveASCII(method, forbidden_method))
393*6777b538SAndroid Build Coastguard Worker return false;
394*6777b538SAndroid Build Coastguard Worker }
395*6777b538SAndroid Build Coastguard Worker }
396*6777b538SAndroid Build Coastguard Worker }
397*6777b538SAndroid Build Coastguard Worker }
398*6777b538SAndroid Build Coastguard Worker return true;
399*6777b538SAndroid Build Coastguard Worker }
400*6777b538SAndroid Build Coastguard Worker
401*6777b538SAndroid Build Coastguard Worker // static
IsValidHeaderName(std::string_view name)402*6777b538SAndroid Build Coastguard Worker bool HttpUtil::IsValidHeaderName(std::string_view name) {
403*6777b538SAndroid Build Coastguard Worker // Check whether the header name is RFC 2616-compliant.
404*6777b538SAndroid Build Coastguard Worker return HttpUtil::IsToken(name);
405*6777b538SAndroid Build Coastguard Worker }
406*6777b538SAndroid Build Coastguard Worker
407*6777b538SAndroid Build Coastguard Worker // static
IsValidHeaderValue(std::string_view value)408*6777b538SAndroid Build Coastguard Worker bool HttpUtil::IsValidHeaderValue(std::string_view value) {
409*6777b538SAndroid Build Coastguard Worker // Just a sanity check: disallow NUL, CR and LF.
410*6777b538SAndroid Build Coastguard Worker for (char c : value) {
411*6777b538SAndroid Build Coastguard Worker if (c == '\0' || c == '\r' || c == '\n')
412*6777b538SAndroid Build Coastguard Worker return false;
413*6777b538SAndroid Build Coastguard Worker }
414*6777b538SAndroid Build Coastguard Worker return true;
415*6777b538SAndroid Build Coastguard Worker }
416*6777b538SAndroid Build Coastguard Worker
417*6777b538SAndroid Build Coastguard Worker // static
IsNonCoalescingHeader(std::string_view name)418*6777b538SAndroid Build Coastguard Worker bool HttpUtil::IsNonCoalescingHeader(std::string_view name) {
419*6777b538SAndroid Build Coastguard Worker // NOTE: "set-cookie2" headers do not support expires attributes, so we don't
420*6777b538SAndroid Build Coastguard Worker // have to list them here.
421*6777b538SAndroid Build Coastguard Worker // As of 2023, using FlatSet here actually makes the lookup slower, and
422*6777b538SAndroid Build Coastguard Worker // unordered_set is even slower than that.
423*6777b538SAndroid Build Coastguard Worker static constexpr std::string_view kNonCoalescingHeaders[] = {
424*6777b538SAndroid Build Coastguard Worker "date", "expires", "last-modified",
425*6777b538SAndroid Build Coastguard Worker "location", // See bug 1050541 for details
426*6777b538SAndroid Build Coastguard Worker "retry-after", "set-cookie",
427*6777b538SAndroid Build Coastguard Worker // The format of auth-challenges mixes both space separated tokens and
428*6777b538SAndroid Build Coastguard Worker // comma separated properties, so coalescing on comma won't work.
429*6777b538SAndroid Build Coastguard Worker "www-authenticate", "proxy-authenticate",
430*6777b538SAndroid Build Coastguard Worker // STS specifies that UAs must not process any STS headers after the first
431*6777b538SAndroid Build Coastguard Worker // one.
432*6777b538SAndroid Build Coastguard Worker "strict-transport-security"};
433*6777b538SAndroid Build Coastguard Worker
434*6777b538SAndroid Build Coastguard Worker for (const std::string_view& header : kNonCoalescingHeaders) {
435*6777b538SAndroid Build Coastguard Worker if (base::EqualsCaseInsensitiveASCII(name, header)) {
436*6777b538SAndroid Build Coastguard Worker return true;
437*6777b538SAndroid Build Coastguard Worker }
438*6777b538SAndroid Build Coastguard Worker }
439*6777b538SAndroid Build Coastguard Worker return false;
440*6777b538SAndroid Build Coastguard Worker }
441*6777b538SAndroid Build Coastguard Worker
442*6777b538SAndroid Build Coastguard Worker // static
TrimLWS(std::string::const_iterator * begin,std::string::const_iterator * end)443*6777b538SAndroid Build Coastguard Worker void HttpUtil::TrimLWS(std::string::const_iterator* begin,
444*6777b538SAndroid Build Coastguard Worker std::string::const_iterator* end) {
445*6777b538SAndroid Build Coastguard Worker TrimLWSImplementation(begin, end);
446*6777b538SAndroid Build Coastguard Worker }
447*6777b538SAndroid Build Coastguard Worker
448*6777b538SAndroid Build Coastguard Worker // static
TrimLWS(std::string_view string)449*6777b538SAndroid Build Coastguard Worker std::string_view HttpUtil::TrimLWS(std::string_view string) {
450*6777b538SAndroid Build Coastguard Worker const char* begin = string.data();
451*6777b538SAndroid Build Coastguard Worker const char* end = string.data() + string.size();
452*6777b538SAndroid Build Coastguard Worker TrimLWSImplementation(&begin, &end);
453*6777b538SAndroid Build Coastguard Worker return std::string_view(begin, end - begin);
454*6777b538SAndroid Build Coastguard Worker }
455*6777b538SAndroid Build Coastguard Worker
IsTokenChar(char c)456*6777b538SAndroid Build Coastguard Worker bool HttpUtil::IsTokenChar(char c) {
457*6777b538SAndroid Build Coastguard Worker return !(c >= 0x7F || c <= 0x20 || c == '(' || c == ')' || c == '<' ||
458*6777b538SAndroid Build Coastguard Worker c == '>' || c == '@' || c == ',' || c == ';' || c == ':' ||
459*6777b538SAndroid Build Coastguard Worker c == '\\' || c == '"' || c == '/' || c == '[' || c == ']' ||
460*6777b538SAndroid Build Coastguard Worker c == '?' || c == '=' || c == '{' || c == '}');
461*6777b538SAndroid Build Coastguard Worker }
462*6777b538SAndroid Build Coastguard Worker
463*6777b538SAndroid Build Coastguard Worker // See RFC 7230 Sec 3.2.6 for the definition of |token|.
IsToken(std::string_view string)464*6777b538SAndroid Build Coastguard Worker bool HttpUtil::IsToken(std::string_view string) {
465*6777b538SAndroid Build Coastguard Worker if (string.empty())
466*6777b538SAndroid Build Coastguard Worker return false;
467*6777b538SAndroid Build Coastguard Worker for (char c : string) {
468*6777b538SAndroid Build Coastguard Worker if (!IsTokenChar(c))
469*6777b538SAndroid Build Coastguard Worker return false;
470*6777b538SAndroid Build Coastguard Worker }
471*6777b538SAndroid Build Coastguard Worker return true;
472*6777b538SAndroid Build Coastguard Worker }
473*6777b538SAndroid Build Coastguard Worker
474*6777b538SAndroid Build Coastguard Worker // See RFC 5987 Sec 3.2.1 for the definition of |parmname|.
IsParmName(std::string_view str)475*6777b538SAndroid Build Coastguard Worker bool HttpUtil::IsParmName(std::string_view str) {
476*6777b538SAndroid Build Coastguard Worker if (str.empty())
477*6777b538SAndroid Build Coastguard Worker return false;
478*6777b538SAndroid Build Coastguard Worker for (char c : str) {
479*6777b538SAndroid Build Coastguard Worker if (!IsTokenChar(c) || c == '*' || c == '\'' || c == '%')
480*6777b538SAndroid Build Coastguard Worker return false;
481*6777b538SAndroid Build Coastguard Worker }
482*6777b538SAndroid Build Coastguard Worker return true;
483*6777b538SAndroid Build Coastguard Worker }
484*6777b538SAndroid Build Coastguard Worker
485*6777b538SAndroid Build Coastguard Worker namespace {
486*6777b538SAndroid Build Coastguard Worker
IsQuote(char c)487*6777b538SAndroid Build Coastguard Worker bool IsQuote(char c) {
488*6777b538SAndroid Build Coastguard Worker return c == '"';
489*6777b538SAndroid Build Coastguard Worker }
490*6777b538SAndroid Build Coastguard Worker
UnquoteImpl(std::string_view str,bool strict_quotes,std::string * out)491*6777b538SAndroid Build Coastguard Worker bool UnquoteImpl(std::string_view str, bool strict_quotes, std::string* out) {
492*6777b538SAndroid Build Coastguard Worker if (str.empty())
493*6777b538SAndroid Build Coastguard Worker return false;
494*6777b538SAndroid Build Coastguard Worker
495*6777b538SAndroid Build Coastguard Worker // Nothing to unquote.
496*6777b538SAndroid Build Coastguard Worker if (!IsQuote(str[0]))
497*6777b538SAndroid Build Coastguard Worker return false;
498*6777b538SAndroid Build Coastguard Worker
499*6777b538SAndroid Build Coastguard Worker // No terminal quote mark.
500*6777b538SAndroid Build Coastguard Worker if (str.size() < 2 || str.front() != str.back())
501*6777b538SAndroid Build Coastguard Worker return false;
502*6777b538SAndroid Build Coastguard Worker
503*6777b538SAndroid Build Coastguard Worker // Strip quotemarks
504*6777b538SAndroid Build Coastguard Worker str.remove_prefix(1);
505*6777b538SAndroid Build Coastguard Worker str.remove_suffix(1);
506*6777b538SAndroid Build Coastguard Worker
507*6777b538SAndroid Build Coastguard Worker // Unescape quoted-pair (defined in RFC 2616 section 2.2)
508*6777b538SAndroid Build Coastguard Worker bool prev_escape = false;
509*6777b538SAndroid Build Coastguard Worker std::string unescaped;
510*6777b538SAndroid Build Coastguard Worker for (char c : str) {
511*6777b538SAndroid Build Coastguard Worker if (c == '\\' && !prev_escape) {
512*6777b538SAndroid Build Coastguard Worker prev_escape = true;
513*6777b538SAndroid Build Coastguard Worker continue;
514*6777b538SAndroid Build Coastguard Worker }
515*6777b538SAndroid Build Coastguard Worker if (strict_quotes && !prev_escape && IsQuote(c))
516*6777b538SAndroid Build Coastguard Worker return false;
517*6777b538SAndroid Build Coastguard Worker prev_escape = false;
518*6777b538SAndroid Build Coastguard Worker unescaped.push_back(c);
519*6777b538SAndroid Build Coastguard Worker }
520*6777b538SAndroid Build Coastguard Worker
521*6777b538SAndroid Build Coastguard Worker // Terminal quote is escaped.
522*6777b538SAndroid Build Coastguard Worker if (strict_quotes && prev_escape)
523*6777b538SAndroid Build Coastguard Worker return false;
524*6777b538SAndroid Build Coastguard Worker
525*6777b538SAndroid Build Coastguard Worker *out = std::move(unescaped);
526*6777b538SAndroid Build Coastguard Worker return true;
527*6777b538SAndroid Build Coastguard Worker }
528*6777b538SAndroid Build Coastguard Worker
529*6777b538SAndroid Build Coastguard Worker } // anonymous namespace
530*6777b538SAndroid Build Coastguard Worker
531*6777b538SAndroid Build Coastguard Worker // static
Unquote(std::string_view str)532*6777b538SAndroid Build Coastguard Worker std::string HttpUtil::Unquote(std::string_view str) {
533*6777b538SAndroid Build Coastguard Worker std::string result;
534*6777b538SAndroid Build Coastguard Worker if (!UnquoteImpl(str, false, &result))
535*6777b538SAndroid Build Coastguard Worker return std::string(str);
536*6777b538SAndroid Build Coastguard Worker
537*6777b538SAndroid Build Coastguard Worker return result;
538*6777b538SAndroid Build Coastguard Worker }
539*6777b538SAndroid Build Coastguard Worker
540*6777b538SAndroid Build Coastguard Worker // static
StrictUnquote(std::string_view str,std::string * out)541*6777b538SAndroid Build Coastguard Worker bool HttpUtil::StrictUnquote(std::string_view str, std::string* out) {
542*6777b538SAndroid Build Coastguard Worker return UnquoteImpl(str, true, out);
543*6777b538SAndroid Build Coastguard Worker }
544*6777b538SAndroid Build Coastguard Worker
545*6777b538SAndroid Build Coastguard Worker // static
Quote(std::string_view str)546*6777b538SAndroid Build Coastguard Worker std::string HttpUtil::Quote(std::string_view str) {
547*6777b538SAndroid Build Coastguard Worker std::string escaped;
548*6777b538SAndroid Build Coastguard Worker escaped.reserve(2 + str.size());
549*6777b538SAndroid Build Coastguard Worker
550*6777b538SAndroid Build Coastguard Worker // Esape any backslashes or quotemarks within the string, and
551*6777b538SAndroid Build Coastguard Worker // then surround with quotes.
552*6777b538SAndroid Build Coastguard Worker escaped.push_back('"');
553*6777b538SAndroid Build Coastguard Worker for (char c : str) {
554*6777b538SAndroid Build Coastguard Worker if (c == '"' || c == '\\')
555*6777b538SAndroid Build Coastguard Worker escaped.push_back('\\');
556*6777b538SAndroid Build Coastguard Worker escaped.push_back(c);
557*6777b538SAndroid Build Coastguard Worker }
558*6777b538SAndroid Build Coastguard Worker escaped.push_back('"');
559*6777b538SAndroid Build Coastguard Worker return escaped;
560*6777b538SAndroid Build Coastguard Worker }
561*6777b538SAndroid Build Coastguard Worker
562*6777b538SAndroid Build Coastguard Worker // Find the "http" substring in a status line. This allows for
563*6777b538SAndroid Build Coastguard Worker // some slop at the start. If the "http" string could not be found
564*6777b538SAndroid Build Coastguard Worker // then returns std::string::npos.
565*6777b538SAndroid Build Coastguard Worker // static
LocateStartOfStatusLine(const char * buf,size_t buf_len)566*6777b538SAndroid Build Coastguard Worker size_t HttpUtil::LocateStartOfStatusLine(const char* buf, size_t buf_len) {
567*6777b538SAndroid Build Coastguard Worker const size_t slop = 4;
568*6777b538SAndroid Build Coastguard Worker const size_t http_len = 4;
569*6777b538SAndroid Build Coastguard Worker
570*6777b538SAndroid Build Coastguard Worker if (buf_len >= http_len) {
571*6777b538SAndroid Build Coastguard Worker size_t i_max = std::min(buf_len - http_len, slop);
572*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i <= i_max; ++i) {
573*6777b538SAndroid Build Coastguard Worker if (base::EqualsCaseInsensitiveASCII(std::string_view(buf + i, http_len),
574*6777b538SAndroid Build Coastguard Worker "http")) {
575*6777b538SAndroid Build Coastguard Worker return i;
576*6777b538SAndroid Build Coastguard Worker }
577*6777b538SAndroid Build Coastguard Worker }
578*6777b538SAndroid Build Coastguard Worker }
579*6777b538SAndroid Build Coastguard Worker return std::string::npos; // Not found
580*6777b538SAndroid Build Coastguard Worker }
581*6777b538SAndroid Build Coastguard Worker
LocateEndOfHeadersHelper(const char * buf,size_t buf_len,size_t i,bool accept_empty_header_list)582*6777b538SAndroid Build Coastguard Worker static size_t LocateEndOfHeadersHelper(const char* buf,
583*6777b538SAndroid Build Coastguard Worker size_t buf_len,
584*6777b538SAndroid Build Coastguard Worker size_t i,
585*6777b538SAndroid Build Coastguard Worker bool accept_empty_header_list) {
586*6777b538SAndroid Build Coastguard Worker char last_c = '\0';
587*6777b538SAndroid Build Coastguard Worker bool was_lf = false;
588*6777b538SAndroid Build Coastguard Worker if (accept_empty_header_list) {
589*6777b538SAndroid Build Coastguard Worker // Normally two line breaks signal the end of a header list. An empty header
590*6777b538SAndroid Build Coastguard Worker // list ends with a single line break at the start of the buffer.
591*6777b538SAndroid Build Coastguard Worker last_c = '\n';
592*6777b538SAndroid Build Coastguard Worker was_lf = true;
593*6777b538SAndroid Build Coastguard Worker }
594*6777b538SAndroid Build Coastguard Worker
595*6777b538SAndroid Build Coastguard Worker for (; i < buf_len; ++i) {
596*6777b538SAndroid Build Coastguard Worker char c = buf[i];
597*6777b538SAndroid Build Coastguard Worker if (c == '\n') {
598*6777b538SAndroid Build Coastguard Worker if (was_lf)
599*6777b538SAndroid Build Coastguard Worker return i + 1;
600*6777b538SAndroid Build Coastguard Worker was_lf = true;
601*6777b538SAndroid Build Coastguard Worker } else if (c != '\r' || last_c != '\n') {
602*6777b538SAndroid Build Coastguard Worker was_lf = false;
603*6777b538SAndroid Build Coastguard Worker }
604*6777b538SAndroid Build Coastguard Worker last_c = c;
605*6777b538SAndroid Build Coastguard Worker }
606*6777b538SAndroid Build Coastguard Worker return std::string::npos;
607*6777b538SAndroid Build Coastguard Worker }
608*6777b538SAndroid Build Coastguard Worker
LocateEndOfAdditionalHeaders(const char * buf,size_t buf_len,size_t i)609*6777b538SAndroid Build Coastguard Worker size_t HttpUtil::LocateEndOfAdditionalHeaders(const char* buf,
610*6777b538SAndroid Build Coastguard Worker size_t buf_len,
611*6777b538SAndroid Build Coastguard Worker size_t i) {
612*6777b538SAndroid Build Coastguard Worker return LocateEndOfHeadersHelper(buf, buf_len, i, true);
613*6777b538SAndroid Build Coastguard Worker }
614*6777b538SAndroid Build Coastguard Worker
LocateEndOfHeaders(const char * buf,size_t buf_len,size_t i)615*6777b538SAndroid Build Coastguard Worker size_t HttpUtil::LocateEndOfHeaders(const char* buf, size_t buf_len, size_t i) {
616*6777b538SAndroid Build Coastguard Worker return LocateEndOfHeadersHelper(buf, buf_len, i, false);
617*6777b538SAndroid Build Coastguard Worker }
618*6777b538SAndroid Build Coastguard Worker
619*6777b538SAndroid Build Coastguard Worker // In order for a line to be continuable, it must specify a
620*6777b538SAndroid Build Coastguard Worker // non-blank header-name. Line continuations are specifically for
621*6777b538SAndroid Build Coastguard Worker // header values -- do not allow headers names to span lines.
IsLineSegmentContinuable(std::string_view line)622*6777b538SAndroid Build Coastguard Worker static bool IsLineSegmentContinuable(std::string_view line) {
623*6777b538SAndroid Build Coastguard Worker if (line.empty())
624*6777b538SAndroid Build Coastguard Worker return false;
625*6777b538SAndroid Build Coastguard Worker
626*6777b538SAndroid Build Coastguard Worker size_t colon = line.find(':');
627*6777b538SAndroid Build Coastguard Worker if (colon == std::string_view::npos) {
628*6777b538SAndroid Build Coastguard Worker return false;
629*6777b538SAndroid Build Coastguard Worker }
630*6777b538SAndroid Build Coastguard Worker
631*6777b538SAndroid Build Coastguard Worker std::string_view name = line.substr(0, colon);
632*6777b538SAndroid Build Coastguard Worker
633*6777b538SAndroid Build Coastguard Worker // Name can't be empty.
634*6777b538SAndroid Build Coastguard Worker if (name.empty())
635*6777b538SAndroid Build Coastguard Worker return false;
636*6777b538SAndroid Build Coastguard Worker
637*6777b538SAndroid Build Coastguard Worker // Can't start with LWS (this would imply the segment is a continuation)
638*6777b538SAndroid Build Coastguard Worker if (HttpUtil::IsLWS(name[0]))
639*6777b538SAndroid Build Coastguard Worker return false;
640*6777b538SAndroid Build Coastguard Worker
641*6777b538SAndroid Build Coastguard Worker return true;
642*6777b538SAndroid Build Coastguard Worker }
643*6777b538SAndroid Build Coastguard Worker
644*6777b538SAndroid Build Coastguard Worker // Helper used by AssembleRawHeaders, to find the end of the status line.
FindStatusLineEnd(std::string_view str)645*6777b538SAndroid Build Coastguard Worker static size_t FindStatusLineEnd(std::string_view str) {
646*6777b538SAndroid Build Coastguard Worker size_t i = str.find_first_of("\r\n");
647*6777b538SAndroid Build Coastguard Worker if (i == std::string_view::npos) {
648*6777b538SAndroid Build Coastguard Worker return str.size();
649*6777b538SAndroid Build Coastguard Worker }
650*6777b538SAndroid Build Coastguard Worker return i;
651*6777b538SAndroid Build Coastguard Worker }
652*6777b538SAndroid Build Coastguard Worker
653*6777b538SAndroid Build Coastguard Worker // Helper used by AssembleRawHeaders, to skip past leading LWS.
RemoveLeadingNonLWS(std::string_view str)654*6777b538SAndroid Build Coastguard Worker static std::string_view RemoveLeadingNonLWS(std::string_view str) {
655*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < str.size(); i++) {
656*6777b538SAndroid Build Coastguard Worker if (!HttpUtil::IsLWS(str[i]))
657*6777b538SAndroid Build Coastguard Worker return str.substr(i);
658*6777b538SAndroid Build Coastguard Worker }
659*6777b538SAndroid Build Coastguard Worker return std::string_view(); // Remove everything.
660*6777b538SAndroid Build Coastguard Worker }
661*6777b538SAndroid Build Coastguard Worker
AssembleRawHeaders(std::string_view input)662*6777b538SAndroid Build Coastguard Worker std::string HttpUtil::AssembleRawHeaders(std::string_view input) {
663*6777b538SAndroid Build Coastguard Worker std::string raw_headers;
664*6777b538SAndroid Build Coastguard Worker raw_headers.reserve(input.size());
665*6777b538SAndroid Build Coastguard Worker
666*6777b538SAndroid Build Coastguard Worker // Skip any leading slop, since the consumers of this output
667*6777b538SAndroid Build Coastguard Worker // (HttpResponseHeaders) don't deal with it.
668*6777b538SAndroid Build Coastguard Worker size_t status_begin_offset =
669*6777b538SAndroid Build Coastguard Worker LocateStartOfStatusLine(input.data(), input.size());
670*6777b538SAndroid Build Coastguard Worker if (status_begin_offset != std::string::npos)
671*6777b538SAndroid Build Coastguard Worker input.remove_prefix(status_begin_offset);
672*6777b538SAndroid Build Coastguard Worker
673*6777b538SAndroid Build Coastguard Worker // Copy the status line.
674*6777b538SAndroid Build Coastguard Worker size_t status_line_end = FindStatusLineEnd(input);
675*6777b538SAndroid Build Coastguard Worker raw_headers.append(input.data(), status_line_end);
676*6777b538SAndroid Build Coastguard Worker input.remove_prefix(status_line_end);
677*6777b538SAndroid Build Coastguard Worker
678*6777b538SAndroid Build Coastguard Worker // After the status line, every subsequent line is a header line segment.
679*6777b538SAndroid Build Coastguard Worker // Should a segment start with LWS, it is a continuation of the previous
680*6777b538SAndroid Build Coastguard Worker // line's field-value.
681*6777b538SAndroid Build Coastguard Worker
682*6777b538SAndroid Build Coastguard Worker // TODO(ericroman): is this too permissive? (delimits on [\r\n]+)
683*6777b538SAndroid Build Coastguard Worker base::CStringTokenizer lines(input.data(), input.data() + input.size(),
684*6777b538SAndroid Build Coastguard Worker "\r\n");
685*6777b538SAndroid Build Coastguard Worker
686*6777b538SAndroid Build Coastguard Worker // This variable is true when the previous line was continuable.
687*6777b538SAndroid Build Coastguard Worker bool prev_line_continuable = false;
688*6777b538SAndroid Build Coastguard Worker
689*6777b538SAndroid Build Coastguard Worker while (lines.GetNext()) {
690*6777b538SAndroid Build Coastguard Worker std::string_view line = lines.token_piece();
691*6777b538SAndroid Build Coastguard Worker
692*6777b538SAndroid Build Coastguard Worker if (prev_line_continuable && IsLWS(line[0])) {
693*6777b538SAndroid Build Coastguard Worker // Join continuation; reduce the leading LWS to a single SP.
694*6777b538SAndroid Build Coastguard Worker base::StrAppend(&raw_headers, {" ", RemoveLeadingNonLWS(line)});
695*6777b538SAndroid Build Coastguard Worker } else {
696*6777b538SAndroid Build Coastguard Worker // Terminate the previous line and copy the raw data to output.
697*6777b538SAndroid Build Coastguard Worker base::StrAppend(&raw_headers, {"\n", line});
698*6777b538SAndroid Build Coastguard Worker
699*6777b538SAndroid Build Coastguard Worker // Check if the current line can be continued.
700*6777b538SAndroid Build Coastguard Worker prev_line_continuable = IsLineSegmentContinuable(line);
701*6777b538SAndroid Build Coastguard Worker }
702*6777b538SAndroid Build Coastguard Worker }
703*6777b538SAndroid Build Coastguard Worker
704*6777b538SAndroid Build Coastguard Worker raw_headers.append("\n\n", 2);
705*6777b538SAndroid Build Coastguard Worker
706*6777b538SAndroid Build Coastguard Worker // Use '\0' as the canonical line terminator. If the input already contained
707*6777b538SAndroid Build Coastguard Worker // any embeded '\0' characters we will strip them first to avoid interpreting
708*6777b538SAndroid Build Coastguard Worker // them as line breaks.
709*6777b538SAndroid Build Coastguard Worker std::erase(raw_headers, '\0');
710*6777b538SAndroid Build Coastguard Worker
711*6777b538SAndroid Build Coastguard Worker std::replace(raw_headers.begin(), raw_headers.end(), '\n', '\0');
712*6777b538SAndroid Build Coastguard Worker
713*6777b538SAndroid Build Coastguard Worker return raw_headers;
714*6777b538SAndroid Build Coastguard Worker }
715*6777b538SAndroid Build Coastguard Worker
ConvertHeadersBackToHTTPResponse(const std::string & str)716*6777b538SAndroid Build Coastguard Worker std::string HttpUtil::ConvertHeadersBackToHTTPResponse(const std::string& str) {
717*6777b538SAndroid Build Coastguard Worker std::string disassembled_headers;
718*6777b538SAndroid Build Coastguard Worker base::StringTokenizer tokenizer(str, std::string(1, '\0'));
719*6777b538SAndroid Build Coastguard Worker while (tokenizer.GetNext()) {
720*6777b538SAndroid Build Coastguard Worker base::StrAppend(&disassembled_headers, {tokenizer.token_piece(), "\r\n"});
721*6777b538SAndroid Build Coastguard Worker }
722*6777b538SAndroid Build Coastguard Worker disassembled_headers.append("\r\n");
723*6777b538SAndroid Build Coastguard Worker
724*6777b538SAndroid Build Coastguard Worker return disassembled_headers;
725*6777b538SAndroid Build Coastguard Worker }
726*6777b538SAndroid Build Coastguard Worker
ExpandLanguageList(const std::string & language_prefs)727*6777b538SAndroid Build Coastguard Worker std::string HttpUtil::ExpandLanguageList(const std::string& language_prefs) {
728*6777b538SAndroid Build Coastguard Worker const std::vector<std::string> languages = base::SplitString(
729*6777b538SAndroid Build Coastguard Worker language_prefs, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
730*6777b538SAndroid Build Coastguard Worker
731*6777b538SAndroid Build Coastguard Worker if (languages.empty())
732*6777b538SAndroid Build Coastguard Worker return "";
733*6777b538SAndroid Build Coastguard Worker
734*6777b538SAndroid Build Coastguard Worker AcceptLanguageBuilder builder;
735*6777b538SAndroid Build Coastguard Worker
736*6777b538SAndroid Build Coastguard Worker const size_t size = languages.size();
737*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < size; ++i) {
738*6777b538SAndroid Build Coastguard Worker const std::string& language = languages[i];
739*6777b538SAndroid Build Coastguard Worker builder.AddLanguageCode(language);
740*6777b538SAndroid Build Coastguard Worker
741*6777b538SAndroid Build Coastguard Worker // Extract the primary language subtag.
742*6777b538SAndroid Build Coastguard Worker const std::string& base_language = GetBaseLanguageCode(language);
743*6777b538SAndroid Build Coastguard Worker
744*6777b538SAndroid Build Coastguard Worker // Skip 'x' and 'i' as a primary language subtag per RFC 5646 section 2.1.1.
745*6777b538SAndroid Build Coastguard Worker if (base_language == "x" || base_language == "i")
746*6777b538SAndroid Build Coastguard Worker continue;
747*6777b538SAndroid Build Coastguard Worker
748*6777b538SAndroid Build Coastguard Worker // Look ahead and add the primary language subtag as a language if the next
749*6777b538SAndroid Build Coastguard Worker // language is not part of the same family. This may not be perfect because
750*6777b538SAndroid Build Coastguard Worker // an input of "en-US,fr,en" will yield "en-US,en,fr,en" and later make "en"
751*6777b538SAndroid Build Coastguard Worker // a higher priority than "fr" despite the original preference.
752*6777b538SAndroid Build Coastguard Worker const size_t j = i + 1;
753*6777b538SAndroid Build Coastguard Worker if (j >= size || GetBaseLanguageCode(languages[j]) != base_language) {
754*6777b538SAndroid Build Coastguard Worker builder.AddLanguageCode(base_language);
755*6777b538SAndroid Build Coastguard Worker }
756*6777b538SAndroid Build Coastguard Worker }
757*6777b538SAndroid Build Coastguard Worker
758*6777b538SAndroid Build Coastguard Worker return builder.GetString();
759*6777b538SAndroid Build Coastguard Worker }
760*6777b538SAndroid Build Coastguard Worker
761*6777b538SAndroid Build Coastguard Worker // TODO(jungshik): This function assumes that the input is a comma separated
762*6777b538SAndroid Build Coastguard Worker // list without any whitespace. As long as it comes from the preference and
763*6777b538SAndroid Build Coastguard Worker // a user does not manually edit the preference file, it's the case. Still,
764*6777b538SAndroid Build Coastguard Worker // we may have to make it more robust.
GenerateAcceptLanguageHeader(const std::string & raw_language_list)765*6777b538SAndroid Build Coastguard Worker std::string HttpUtil::GenerateAcceptLanguageHeader(
766*6777b538SAndroid Build Coastguard Worker const std::string& raw_language_list) {
767*6777b538SAndroid Build Coastguard Worker // We use integers for qvalue and qvalue decrement that are 10 times
768*6777b538SAndroid Build Coastguard Worker // larger than actual values to avoid a problem with comparing
769*6777b538SAndroid Build Coastguard Worker // two floating point numbers.
770*6777b538SAndroid Build Coastguard Worker const unsigned int kQvalueDecrement10 = 1;
771*6777b538SAndroid Build Coastguard Worker unsigned int qvalue10 = 10;
772*6777b538SAndroid Build Coastguard Worker base::StringTokenizer t(raw_language_list, ",");
773*6777b538SAndroid Build Coastguard Worker std::string lang_list_with_q;
774*6777b538SAndroid Build Coastguard Worker while (t.GetNext()) {
775*6777b538SAndroid Build Coastguard Worker std::string language = t.token();
776*6777b538SAndroid Build Coastguard Worker if (qvalue10 == 10) {
777*6777b538SAndroid Build Coastguard Worker // q=1.0 is implicit.
778*6777b538SAndroid Build Coastguard Worker lang_list_with_q = language;
779*6777b538SAndroid Build Coastguard Worker } else {
780*6777b538SAndroid Build Coastguard Worker DCHECK_LT(qvalue10, 10U);
781*6777b538SAndroid Build Coastguard Worker base::StringAppendF(&lang_list_with_q, ",%s;q=0.%d", language.c_str(),
782*6777b538SAndroid Build Coastguard Worker qvalue10);
783*6777b538SAndroid Build Coastguard Worker }
784*6777b538SAndroid Build Coastguard Worker // It does not make sense to have 'q=0'.
785*6777b538SAndroid Build Coastguard Worker if (qvalue10 > kQvalueDecrement10)
786*6777b538SAndroid Build Coastguard Worker qvalue10 -= kQvalueDecrement10;
787*6777b538SAndroid Build Coastguard Worker }
788*6777b538SAndroid Build Coastguard Worker return lang_list_with_q;
789*6777b538SAndroid Build Coastguard Worker }
790*6777b538SAndroid Build Coastguard Worker
HasStrongValidators(HttpVersion version,const std::string & etag_header,const std::string & last_modified_header,const std::string & date_header)791*6777b538SAndroid Build Coastguard Worker bool HttpUtil::HasStrongValidators(HttpVersion version,
792*6777b538SAndroid Build Coastguard Worker const std::string& etag_header,
793*6777b538SAndroid Build Coastguard Worker const std::string& last_modified_header,
794*6777b538SAndroid Build Coastguard Worker const std::string& date_header) {
795*6777b538SAndroid Build Coastguard Worker if (!HasValidators(version, etag_header, last_modified_header))
796*6777b538SAndroid Build Coastguard Worker return false;
797*6777b538SAndroid Build Coastguard Worker
798*6777b538SAndroid Build Coastguard Worker if (version < HttpVersion(1, 1))
799*6777b538SAndroid Build Coastguard Worker return false;
800*6777b538SAndroid Build Coastguard Worker
801*6777b538SAndroid Build Coastguard Worker if (!etag_header.empty()) {
802*6777b538SAndroid Build Coastguard Worker size_t slash = etag_header.find('/');
803*6777b538SAndroid Build Coastguard Worker if (slash == std::string::npos || slash == 0)
804*6777b538SAndroid Build Coastguard Worker return true;
805*6777b538SAndroid Build Coastguard Worker
806*6777b538SAndroid Build Coastguard Worker std::string::const_iterator i = etag_header.begin();
807*6777b538SAndroid Build Coastguard Worker std::string::const_iterator j = etag_header.begin() + slash;
808*6777b538SAndroid Build Coastguard Worker TrimLWS(&i, &j);
809*6777b538SAndroid Build Coastguard Worker if (!base::EqualsCaseInsensitiveASCII(base::MakeStringPiece(i, j), "w"))
810*6777b538SAndroid Build Coastguard Worker return true;
811*6777b538SAndroid Build Coastguard Worker }
812*6777b538SAndroid Build Coastguard Worker
813*6777b538SAndroid Build Coastguard Worker base::Time last_modified;
814*6777b538SAndroid Build Coastguard Worker if (!base::Time::FromString(last_modified_header.c_str(), &last_modified))
815*6777b538SAndroid Build Coastguard Worker return false;
816*6777b538SAndroid Build Coastguard Worker
817*6777b538SAndroid Build Coastguard Worker base::Time date;
818*6777b538SAndroid Build Coastguard Worker if (!base::Time::FromString(date_header.c_str(), &date))
819*6777b538SAndroid Build Coastguard Worker return false;
820*6777b538SAndroid Build Coastguard Worker
821*6777b538SAndroid Build Coastguard Worker // Last-Modified is implicitly weak unless it is at least 60 seconds before
822*6777b538SAndroid Build Coastguard Worker // the Date value.
823*6777b538SAndroid Build Coastguard Worker return ((date - last_modified).InSeconds() >= 60);
824*6777b538SAndroid Build Coastguard Worker }
825*6777b538SAndroid Build Coastguard Worker
HasValidators(HttpVersion version,const std::string & etag_header,const std::string & last_modified_header)826*6777b538SAndroid Build Coastguard Worker bool HttpUtil::HasValidators(HttpVersion version,
827*6777b538SAndroid Build Coastguard Worker const std::string& etag_header,
828*6777b538SAndroid Build Coastguard Worker const std::string& last_modified_header) {
829*6777b538SAndroid Build Coastguard Worker if (version < HttpVersion(1, 0))
830*6777b538SAndroid Build Coastguard Worker return false;
831*6777b538SAndroid Build Coastguard Worker
832*6777b538SAndroid Build Coastguard Worker base::Time last_modified;
833*6777b538SAndroid Build Coastguard Worker if (base::Time::FromString(last_modified_header.c_str(), &last_modified))
834*6777b538SAndroid Build Coastguard Worker return true;
835*6777b538SAndroid Build Coastguard Worker
836*6777b538SAndroid Build Coastguard Worker // It is OK to consider an empty string in etag_header to be a missing header
837*6777b538SAndroid Build Coastguard Worker // since valid ETags are always quoted-strings (see RFC 2616 3.11) and thus
838*6777b538SAndroid Build Coastguard Worker // empty ETags aren't empty strings (i.e., an empty ETag might be "\"\"").
839*6777b538SAndroid Build Coastguard Worker return version >= HttpVersion(1, 1) && !etag_header.empty();
840*6777b538SAndroid Build Coastguard Worker }
841*6777b538SAndroid Build Coastguard Worker
842*6777b538SAndroid Build Coastguard Worker // Functions for histogram initialization. The code 0 is put in the map to
843*6777b538SAndroid Build Coastguard Worker // track status codes that are invalid.
844*6777b538SAndroid Build Coastguard Worker // TODO(gavinp): Greatly prune the collected codes once we learn which
845*6777b538SAndroid Build Coastguard Worker // ones are not sent in practice, to reduce upload size & memory use.
846*6777b538SAndroid Build Coastguard Worker
847*6777b538SAndroid Build Coastguard Worker enum {
848*6777b538SAndroid Build Coastguard Worker HISTOGRAM_MIN_HTTP_STATUS_CODE = 100,
849*6777b538SAndroid Build Coastguard Worker HISTOGRAM_MAX_HTTP_STATUS_CODE = 599,
850*6777b538SAndroid Build Coastguard Worker };
851*6777b538SAndroid Build Coastguard Worker
852*6777b538SAndroid Build Coastguard Worker // static
GetStatusCodesForHistogram()853*6777b538SAndroid Build Coastguard Worker std::vector<int> HttpUtil::GetStatusCodesForHistogram() {
854*6777b538SAndroid Build Coastguard Worker std::vector<int> codes;
855*6777b538SAndroid Build Coastguard Worker codes.reserve(
856*6777b538SAndroid Build Coastguard Worker HISTOGRAM_MAX_HTTP_STATUS_CODE - HISTOGRAM_MIN_HTTP_STATUS_CODE + 2);
857*6777b538SAndroid Build Coastguard Worker codes.push_back(0);
858*6777b538SAndroid Build Coastguard Worker for (int i = HISTOGRAM_MIN_HTTP_STATUS_CODE;
859*6777b538SAndroid Build Coastguard Worker i <= HISTOGRAM_MAX_HTTP_STATUS_CODE; ++i)
860*6777b538SAndroid Build Coastguard Worker codes.push_back(i);
861*6777b538SAndroid Build Coastguard Worker return codes;
862*6777b538SAndroid Build Coastguard Worker }
863*6777b538SAndroid Build Coastguard Worker
864*6777b538SAndroid Build Coastguard Worker // static
MapStatusCodeForHistogram(int code)865*6777b538SAndroid Build Coastguard Worker int HttpUtil::MapStatusCodeForHistogram(int code) {
866*6777b538SAndroid Build Coastguard Worker if (HISTOGRAM_MIN_HTTP_STATUS_CODE <= code &&
867*6777b538SAndroid Build Coastguard Worker code <= HISTOGRAM_MAX_HTTP_STATUS_CODE)
868*6777b538SAndroid Build Coastguard Worker return code;
869*6777b538SAndroid Build Coastguard Worker return 0;
870*6777b538SAndroid Build Coastguard Worker }
871*6777b538SAndroid Build Coastguard Worker
872*6777b538SAndroid Build Coastguard Worker // BNF from section 4.2 of RFC 2616:
873*6777b538SAndroid Build Coastguard Worker //
874*6777b538SAndroid Build Coastguard Worker // message-header = field-name ":" [ field-value ]
875*6777b538SAndroid Build Coastguard Worker // field-name = token
876*6777b538SAndroid Build Coastguard Worker // field-value = *( field-content | LWS )
877*6777b538SAndroid Build Coastguard Worker // field-content = <the OCTETs making up the field-value
878*6777b538SAndroid Build Coastguard Worker // and consisting of either *TEXT or combinations
879*6777b538SAndroid Build Coastguard Worker // of token, separators, and quoted-string>
880*6777b538SAndroid Build Coastguard Worker //
881*6777b538SAndroid Build Coastguard Worker
HeadersIterator(std::string::const_iterator headers_begin,std::string::const_iterator headers_end,const std::string & line_delimiter)882*6777b538SAndroid Build Coastguard Worker HttpUtil::HeadersIterator::HeadersIterator(
883*6777b538SAndroid Build Coastguard Worker std::string::const_iterator headers_begin,
884*6777b538SAndroid Build Coastguard Worker std::string::const_iterator headers_end,
885*6777b538SAndroid Build Coastguard Worker const std::string& line_delimiter)
886*6777b538SAndroid Build Coastguard Worker : lines_(headers_begin, headers_end, line_delimiter) {
887*6777b538SAndroid Build Coastguard Worker }
888*6777b538SAndroid Build Coastguard Worker
889*6777b538SAndroid Build Coastguard Worker HttpUtil::HeadersIterator::~HeadersIterator() = default;
890*6777b538SAndroid Build Coastguard Worker
GetNext()891*6777b538SAndroid Build Coastguard Worker bool HttpUtil::HeadersIterator::GetNext() {
892*6777b538SAndroid Build Coastguard Worker while (lines_.GetNext()) {
893*6777b538SAndroid Build Coastguard Worker name_begin_ = lines_.token_begin();
894*6777b538SAndroid Build Coastguard Worker values_end_ = lines_.token_end();
895*6777b538SAndroid Build Coastguard Worker
896*6777b538SAndroid Build Coastguard Worker std::string::const_iterator colon(std::find(name_begin_, values_end_, ':'));
897*6777b538SAndroid Build Coastguard Worker if (colon == values_end_)
898*6777b538SAndroid Build Coastguard Worker continue; // skip malformed header
899*6777b538SAndroid Build Coastguard Worker
900*6777b538SAndroid Build Coastguard Worker name_end_ = colon;
901*6777b538SAndroid Build Coastguard Worker
902*6777b538SAndroid Build Coastguard Worker // If the name starts with LWS, it is an invalid line.
903*6777b538SAndroid Build Coastguard Worker // Leading LWS implies a line continuation, and these should have
904*6777b538SAndroid Build Coastguard Worker // already been joined by AssembleRawHeaders().
905*6777b538SAndroid Build Coastguard Worker if (name_begin_ == name_end_ || IsLWS(*name_begin_))
906*6777b538SAndroid Build Coastguard Worker continue;
907*6777b538SAndroid Build Coastguard Worker
908*6777b538SAndroid Build Coastguard Worker TrimLWS(&name_begin_, &name_end_);
909*6777b538SAndroid Build Coastguard Worker DCHECK(name_begin_ < name_end_);
910*6777b538SAndroid Build Coastguard Worker if (!IsToken(base::MakeStringPiece(name_begin_, name_end_)))
911*6777b538SAndroid Build Coastguard Worker continue; // skip malformed header
912*6777b538SAndroid Build Coastguard Worker
913*6777b538SAndroid Build Coastguard Worker values_begin_ = colon + 1;
914*6777b538SAndroid Build Coastguard Worker TrimLWS(&values_begin_, &values_end_);
915*6777b538SAndroid Build Coastguard Worker
916*6777b538SAndroid Build Coastguard Worker // if we got a header name, then we are done.
917*6777b538SAndroid Build Coastguard Worker return true;
918*6777b538SAndroid Build Coastguard Worker }
919*6777b538SAndroid Build Coastguard Worker return false;
920*6777b538SAndroid Build Coastguard Worker }
921*6777b538SAndroid Build Coastguard Worker
AdvanceTo(const char * name)922*6777b538SAndroid Build Coastguard Worker bool HttpUtil::HeadersIterator::AdvanceTo(const char* name) {
923*6777b538SAndroid Build Coastguard Worker DCHECK(name != nullptr);
924*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(0, base::ToLowerASCII(name).compare(name))
925*6777b538SAndroid Build Coastguard Worker << "the header name must be in all lower case";
926*6777b538SAndroid Build Coastguard Worker
927*6777b538SAndroid Build Coastguard Worker while (GetNext()) {
928*6777b538SAndroid Build Coastguard Worker if (base::EqualsCaseInsensitiveASCII(
929*6777b538SAndroid Build Coastguard Worker base::MakeStringPiece(name_begin_, name_end_), name)) {
930*6777b538SAndroid Build Coastguard Worker return true;
931*6777b538SAndroid Build Coastguard Worker }
932*6777b538SAndroid Build Coastguard Worker }
933*6777b538SAndroid Build Coastguard Worker
934*6777b538SAndroid Build Coastguard Worker return false;
935*6777b538SAndroid Build Coastguard Worker }
936*6777b538SAndroid Build Coastguard Worker
ValuesIterator(std::string::const_iterator values_begin,std::string::const_iterator values_end,char delimiter,bool ignore_empty_values)937*6777b538SAndroid Build Coastguard Worker HttpUtil::ValuesIterator::ValuesIterator(
938*6777b538SAndroid Build Coastguard Worker std::string::const_iterator values_begin,
939*6777b538SAndroid Build Coastguard Worker std::string::const_iterator values_end,
940*6777b538SAndroid Build Coastguard Worker char delimiter,
941*6777b538SAndroid Build Coastguard Worker bool ignore_empty_values)
942*6777b538SAndroid Build Coastguard Worker : values_(values_begin, values_end, std::string(1, delimiter)),
943*6777b538SAndroid Build Coastguard Worker ignore_empty_values_(ignore_empty_values) {
944*6777b538SAndroid Build Coastguard Worker values_.set_quote_chars("\"");
945*6777b538SAndroid Build Coastguard Worker // Could set this unconditionally, since code below has to check for empty
946*6777b538SAndroid Build Coastguard Worker // values after trimming, anyways, but may provide a minor performance
947*6777b538SAndroid Build Coastguard Worker // improvement.
948*6777b538SAndroid Build Coastguard Worker if (!ignore_empty_values_)
949*6777b538SAndroid Build Coastguard Worker values_.set_options(base::StringTokenizer::RETURN_EMPTY_TOKENS);
950*6777b538SAndroid Build Coastguard Worker }
951*6777b538SAndroid Build Coastguard Worker
952*6777b538SAndroid Build Coastguard Worker HttpUtil::ValuesIterator::ValuesIterator(const ValuesIterator& other) = default;
953*6777b538SAndroid Build Coastguard Worker
954*6777b538SAndroid Build Coastguard Worker HttpUtil::ValuesIterator::~ValuesIterator() = default;
955*6777b538SAndroid Build Coastguard Worker
GetNext()956*6777b538SAndroid Build Coastguard Worker bool HttpUtil::ValuesIterator::GetNext() {
957*6777b538SAndroid Build Coastguard Worker while (values_.GetNext()) {
958*6777b538SAndroid Build Coastguard Worker value_begin_ = values_.token_begin();
959*6777b538SAndroid Build Coastguard Worker value_end_ = values_.token_end();
960*6777b538SAndroid Build Coastguard Worker TrimLWS(&value_begin_, &value_end_);
961*6777b538SAndroid Build Coastguard Worker
962*6777b538SAndroid Build Coastguard Worker if (!ignore_empty_values_ || value_begin_ != value_end_)
963*6777b538SAndroid Build Coastguard Worker return true;
964*6777b538SAndroid Build Coastguard Worker }
965*6777b538SAndroid Build Coastguard Worker return false;
966*6777b538SAndroid Build Coastguard Worker }
967*6777b538SAndroid Build Coastguard Worker
NameValuePairsIterator(std::string::const_iterator begin,std::string::const_iterator end,char delimiter,Values optional_values,Quotes strict_quotes)968*6777b538SAndroid Build Coastguard Worker HttpUtil::NameValuePairsIterator::NameValuePairsIterator(
969*6777b538SAndroid Build Coastguard Worker std::string::const_iterator begin,
970*6777b538SAndroid Build Coastguard Worker std::string::const_iterator end,
971*6777b538SAndroid Build Coastguard Worker char delimiter,
972*6777b538SAndroid Build Coastguard Worker Values optional_values,
973*6777b538SAndroid Build Coastguard Worker Quotes strict_quotes)
974*6777b538SAndroid Build Coastguard Worker : props_(begin, end, delimiter),
975*6777b538SAndroid Build Coastguard Worker name_begin_(end),
976*6777b538SAndroid Build Coastguard Worker name_end_(end),
977*6777b538SAndroid Build Coastguard Worker value_begin_(end),
978*6777b538SAndroid Build Coastguard Worker value_end_(end),
979*6777b538SAndroid Build Coastguard Worker values_optional_(optional_values == Values::NOT_REQUIRED),
980*6777b538SAndroid Build Coastguard Worker strict_quotes_(strict_quotes == Quotes::STRICT_QUOTES) {}
981*6777b538SAndroid Build Coastguard Worker
NameValuePairsIterator(std::string::const_iterator begin,std::string::const_iterator end,char delimiter)982*6777b538SAndroid Build Coastguard Worker HttpUtil::NameValuePairsIterator::NameValuePairsIterator(
983*6777b538SAndroid Build Coastguard Worker std::string::const_iterator begin,
984*6777b538SAndroid Build Coastguard Worker std::string::const_iterator end,
985*6777b538SAndroid Build Coastguard Worker char delimiter)
986*6777b538SAndroid Build Coastguard Worker : NameValuePairsIterator(begin,
987*6777b538SAndroid Build Coastguard Worker end,
988*6777b538SAndroid Build Coastguard Worker delimiter,
989*6777b538SAndroid Build Coastguard Worker Values::REQUIRED,
990*6777b538SAndroid Build Coastguard Worker Quotes::NOT_STRICT) {}
991*6777b538SAndroid Build Coastguard Worker
992*6777b538SAndroid Build Coastguard Worker HttpUtil::NameValuePairsIterator::NameValuePairsIterator(
993*6777b538SAndroid Build Coastguard Worker const NameValuePairsIterator& other) = default;
994*6777b538SAndroid Build Coastguard Worker
995*6777b538SAndroid Build Coastguard Worker HttpUtil::NameValuePairsIterator::~NameValuePairsIterator() = default;
996*6777b538SAndroid Build Coastguard Worker
997*6777b538SAndroid Build Coastguard Worker // We expect properties to be formatted as one of:
998*6777b538SAndroid Build Coastguard Worker // name="value"
999*6777b538SAndroid Build Coastguard Worker // name='value'
1000*6777b538SAndroid Build Coastguard Worker // name='\'value\''
1001*6777b538SAndroid Build Coastguard Worker // name=value
1002*6777b538SAndroid Build Coastguard Worker // name = value
1003*6777b538SAndroid Build Coastguard Worker // name (if values_optional_ is true)
1004*6777b538SAndroid Build Coastguard Worker // Due to buggy implementations found in some embedded devices, we also
1005*6777b538SAndroid Build Coastguard Worker // accept values with missing close quotemark (http://crbug.com/39836):
1006*6777b538SAndroid Build Coastguard Worker // name="value
GetNext()1007*6777b538SAndroid Build Coastguard Worker bool HttpUtil::NameValuePairsIterator::GetNext() {
1008*6777b538SAndroid Build Coastguard Worker if (!props_.GetNext())
1009*6777b538SAndroid Build Coastguard Worker return false;
1010*6777b538SAndroid Build Coastguard Worker
1011*6777b538SAndroid Build Coastguard Worker // Set the value as everything. Next we will split out the name.
1012*6777b538SAndroid Build Coastguard Worker value_begin_ = props_.value_begin();
1013*6777b538SAndroid Build Coastguard Worker value_end_ = props_.value_end();
1014*6777b538SAndroid Build Coastguard Worker name_begin_ = name_end_ = value_end_;
1015*6777b538SAndroid Build Coastguard Worker
1016*6777b538SAndroid Build Coastguard Worker // Scan for the equals sign.
1017*6777b538SAndroid Build Coastguard Worker std::string::const_iterator equals = std::find(value_begin_, value_end_, '=');
1018*6777b538SAndroid Build Coastguard Worker if (equals == value_begin_)
1019*6777b538SAndroid Build Coastguard Worker return valid_ = false; // Malformed, no name
1020*6777b538SAndroid Build Coastguard Worker if (equals == value_end_ && !values_optional_)
1021*6777b538SAndroid Build Coastguard Worker return valid_ = false; // Malformed, no equals sign and values are required
1022*6777b538SAndroid Build Coastguard Worker
1023*6777b538SAndroid Build Coastguard Worker // If an equals sign was found, verify that it wasn't inside of quote marks.
1024*6777b538SAndroid Build Coastguard Worker if (equals != value_end_) {
1025*6777b538SAndroid Build Coastguard Worker for (std::string::const_iterator it = value_begin_; it != equals; ++it) {
1026*6777b538SAndroid Build Coastguard Worker if (IsQuote(*it))
1027*6777b538SAndroid Build Coastguard Worker return valid_ = false; // Malformed, quote appears before equals sign
1028*6777b538SAndroid Build Coastguard Worker }
1029*6777b538SAndroid Build Coastguard Worker }
1030*6777b538SAndroid Build Coastguard Worker
1031*6777b538SAndroid Build Coastguard Worker name_begin_ = value_begin_;
1032*6777b538SAndroid Build Coastguard Worker name_end_ = equals;
1033*6777b538SAndroid Build Coastguard Worker value_begin_ = (equals == value_end_) ? value_end_ : equals + 1;
1034*6777b538SAndroid Build Coastguard Worker
1035*6777b538SAndroid Build Coastguard Worker TrimLWS(&name_begin_, &name_end_);
1036*6777b538SAndroid Build Coastguard Worker TrimLWS(&value_begin_, &value_end_);
1037*6777b538SAndroid Build Coastguard Worker value_is_quoted_ = false;
1038*6777b538SAndroid Build Coastguard Worker unquoted_value_.clear();
1039*6777b538SAndroid Build Coastguard Worker
1040*6777b538SAndroid Build Coastguard Worker if (equals != value_end_ && value_begin_ == value_end_) {
1041*6777b538SAndroid Build Coastguard Worker // Malformed; value is empty
1042*6777b538SAndroid Build Coastguard Worker return valid_ = false;
1043*6777b538SAndroid Build Coastguard Worker }
1044*6777b538SAndroid Build Coastguard Worker
1045*6777b538SAndroid Build Coastguard Worker if (value_begin_ != value_end_ && IsQuote(*value_begin_)) {
1046*6777b538SAndroid Build Coastguard Worker value_is_quoted_ = true;
1047*6777b538SAndroid Build Coastguard Worker
1048*6777b538SAndroid Build Coastguard Worker if (strict_quotes_) {
1049*6777b538SAndroid Build Coastguard Worker if (!HttpUtil::StrictUnquote(
1050*6777b538SAndroid Build Coastguard Worker base::MakeStringPiece(value_begin_, value_end_),
1051*6777b538SAndroid Build Coastguard Worker &unquoted_value_))
1052*6777b538SAndroid Build Coastguard Worker return valid_ = false;
1053*6777b538SAndroid Build Coastguard Worker return true;
1054*6777b538SAndroid Build Coastguard Worker }
1055*6777b538SAndroid Build Coastguard Worker
1056*6777b538SAndroid Build Coastguard Worker // Trim surrounding quotemarks off the value
1057*6777b538SAndroid Build Coastguard Worker if (*value_begin_ != *(value_end_ - 1) || value_begin_ + 1 == value_end_) {
1058*6777b538SAndroid Build Coastguard Worker // NOTE: This is not as graceful as it sounds:
1059*6777b538SAndroid Build Coastguard Worker // * quoted-pairs will no longer be unquoted
1060*6777b538SAndroid Build Coastguard Worker // (["\"hello] should give ["hello]).
1061*6777b538SAndroid Build Coastguard Worker // * Does not detect when the final quote is escaped
1062*6777b538SAndroid Build Coastguard Worker // (["value\"] should give [value"])
1063*6777b538SAndroid Build Coastguard Worker value_is_quoted_ = false;
1064*6777b538SAndroid Build Coastguard Worker ++value_begin_; // Gracefully recover from mismatching quotes.
1065*6777b538SAndroid Build Coastguard Worker } else {
1066*6777b538SAndroid Build Coastguard Worker // Do not store iterators into this. See declaration of unquoted_value_.
1067*6777b538SAndroid Build Coastguard Worker unquoted_value_ =
1068*6777b538SAndroid Build Coastguard Worker HttpUtil::Unquote(base::MakeStringPiece(value_begin_, value_end_));
1069*6777b538SAndroid Build Coastguard Worker }
1070*6777b538SAndroid Build Coastguard Worker }
1071*6777b538SAndroid Build Coastguard Worker
1072*6777b538SAndroid Build Coastguard Worker return true;
1073*6777b538SAndroid Build Coastguard Worker }
1074*6777b538SAndroid Build Coastguard Worker
ParseAcceptEncoding(const std::string & accept_encoding,std::set<std::string> * allowed_encodings)1075*6777b538SAndroid Build Coastguard Worker bool HttpUtil::ParseAcceptEncoding(const std::string& accept_encoding,
1076*6777b538SAndroid Build Coastguard Worker std::set<std::string>* allowed_encodings) {
1077*6777b538SAndroid Build Coastguard Worker DCHECK(allowed_encodings);
1078*6777b538SAndroid Build Coastguard Worker if (accept_encoding.find_first_of("\"") != std::string::npos)
1079*6777b538SAndroid Build Coastguard Worker return false;
1080*6777b538SAndroid Build Coastguard Worker allowed_encodings->clear();
1081*6777b538SAndroid Build Coastguard Worker
1082*6777b538SAndroid Build Coastguard Worker base::StringTokenizer tokenizer(accept_encoding.begin(),
1083*6777b538SAndroid Build Coastguard Worker accept_encoding.end(), ",");
1084*6777b538SAndroid Build Coastguard Worker while (tokenizer.GetNext()) {
1085*6777b538SAndroid Build Coastguard Worker std::string_view entry = tokenizer.token_piece();
1086*6777b538SAndroid Build Coastguard Worker entry = TrimLWS(entry);
1087*6777b538SAndroid Build Coastguard Worker size_t semicolon_pos = entry.find(';');
1088*6777b538SAndroid Build Coastguard Worker if (semicolon_pos == std::string_view::npos) {
1089*6777b538SAndroid Build Coastguard Worker if (entry.find_first_of(HTTP_LWS) != std::string_view::npos) {
1090*6777b538SAndroid Build Coastguard Worker return false;
1091*6777b538SAndroid Build Coastguard Worker }
1092*6777b538SAndroid Build Coastguard Worker allowed_encodings->insert(base::ToLowerASCII(entry));
1093*6777b538SAndroid Build Coastguard Worker continue;
1094*6777b538SAndroid Build Coastguard Worker }
1095*6777b538SAndroid Build Coastguard Worker std::string_view encoding = entry.substr(0, semicolon_pos);
1096*6777b538SAndroid Build Coastguard Worker encoding = TrimLWS(encoding);
1097*6777b538SAndroid Build Coastguard Worker if (encoding.find_first_of(HTTP_LWS) != std::string_view::npos) {
1098*6777b538SAndroid Build Coastguard Worker return false;
1099*6777b538SAndroid Build Coastguard Worker }
1100*6777b538SAndroid Build Coastguard Worker std::string_view params = entry.substr(semicolon_pos + 1);
1101*6777b538SAndroid Build Coastguard Worker params = TrimLWS(params);
1102*6777b538SAndroid Build Coastguard Worker size_t equals_pos = params.find('=');
1103*6777b538SAndroid Build Coastguard Worker if (equals_pos == std::string_view::npos) {
1104*6777b538SAndroid Build Coastguard Worker return false;
1105*6777b538SAndroid Build Coastguard Worker }
1106*6777b538SAndroid Build Coastguard Worker std::string_view param_name = params.substr(0, equals_pos);
1107*6777b538SAndroid Build Coastguard Worker param_name = TrimLWS(param_name);
1108*6777b538SAndroid Build Coastguard Worker if (!base::EqualsCaseInsensitiveASCII(param_name, "q"))
1109*6777b538SAndroid Build Coastguard Worker return false;
1110*6777b538SAndroid Build Coastguard Worker std::string_view qvalue = params.substr(equals_pos + 1);
1111*6777b538SAndroid Build Coastguard Worker qvalue = TrimLWS(qvalue);
1112*6777b538SAndroid Build Coastguard Worker if (qvalue.empty())
1113*6777b538SAndroid Build Coastguard Worker return false;
1114*6777b538SAndroid Build Coastguard Worker if (qvalue[0] == '1') {
1115*6777b538SAndroid Build Coastguard Worker if (std::string_view("1.000").starts_with(qvalue)) {
1116*6777b538SAndroid Build Coastguard Worker allowed_encodings->insert(base::ToLowerASCII(encoding));
1117*6777b538SAndroid Build Coastguard Worker continue;
1118*6777b538SAndroid Build Coastguard Worker }
1119*6777b538SAndroid Build Coastguard Worker return false;
1120*6777b538SAndroid Build Coastguard Worker }
1121*6777b538SAndroid Build Coastguard Worker if (qvalue[0] != '0')
1122*6777b538SAndroid Build Coastguard Worker return false;
1123*6777b538SAndroid Build Coastguard Worker if (qvalue.length() == 1)
1124*6777b538SAndroid Build Coastguard Worker continue;
1125*6777b538SAndroid Build Coastguard Worker if (qvalue.length() <= 2 || qvalue.length() > 5)
1126*6777b538SAndroid Build Coastguard Worker return false;
1127*6777b538SAndroid Build Coastguard Worker if (qvalue[1] != '.')
1128*6777b538SAndroid Build Coastguard Worker return false;
1129*6777b538SAndroid Build Coastguard Worker bool nonzero_number = false;
1130*6777b538SAndroid Build Coastguard Worker for (size_t i = 2; i < qvalue.length(); ++i) {
1131*6777b538SAndroid Build Coastguard Worker if (!base::IsAsciiDigit(qvalue[i]))
1132*6777b538SAndroid Build Coastguard Worker return false;
1133*6777b538SAndroid Build Coastguard Worker if (qvalue[i] != '0')
1134*6777b538SAndroid Build Coastguard Worker nonzero_number = true;
1135*6777b538SAndroid Build Coastguard Worker }
1136*6777b538SAndroid Build Coastguard Worker if (nonzero_number)
1137*6777b538SAndroid Build Coastguard Worker allowed_encodings->insert(base::ToLowerASCII(encoding));
1138*6777b538SAndroid Build Coastguard Worker }
1139*6777b538SAndroid Build Coastguard Worker
1140*6777b538SAndroid Build Coastguard Worker // RFC 7231 5.3.4 "A request without an Accept-Encoding header field implies
1141*6777b538SAndroid Build Coastguard Worker // that the user agent has no preferences regarding content-codings."
1142*6777b538SAndroid Build Coastguard Worker if (allowed_encodings->empty()) {
1143*6777b538SAndroid Build Coastguard Worker allowed_encodings->insert("*");
1144*6777b538SAndroid Build Coastguard Worker return true;
1145*6777b538SAndroid Build Coastguard Worker }
1146*6777b538SAndroid Build Coastguard Worker
1147*6777b538SAndroid Build Coastguard Worker // Any browser must support "identity".
1148*6777b538SAndroid Build Coastguard Worker allowed_encodings->insert("identity");
1149*6777b538SAndroid Build Coastguard Worker
1150*6777b538SAndroid Build Coastguard Worker // RFC says gzip == x-gzip; mirror it here for easier matching.
1151*6777b538SAndroid Build Coastguard Worker if (allowed_encodings->find("gzip") != allowed_encodings->end())
1152*6777b538SAndroid Build Coastguard Worker allowed_encodings->insert("x-gzip");
1153*6777b538SAndroid Build Coastguard Worker if (allowed_encodings->find("x-gzip") != allowed_encodings->end())
1154*6777b538SAndroid Build Coastguard Worker allowed_encodings->insert("gzip");
1155*6777b538SAndroid Build Coastguard Worker
1156*6777b538SAndroid Build Coastguard Worker // RFC says compress == x-compress; mirror it here for easier matching.
1157*6777b538SAndroid Build Coastguard Worker if (allowed_encodings->find("compress") != allowed_encodings->end())
1158*6777b538SAndroid Build Coastguard Worker allowed_encodings->insert("x-compress");
1159*6777b538SAndroid Build Coastguard Worker if (allowed_encodings->find("x-compress") != allowed_encodings->end())
1160*6777b538SAndroid Build Coastguard Worker allowed_encodings->insert("compress");
1161*6777b538SAndroid Build Coastguard Worker return true;
1162*6777b538SAndroid Build Coastguard Worker }
1163*6777b538SAndroid Build Coastguard Worker
ParseContentEncoding(const std::string & content_encoding,std::set<std::string> * used_encodings)1164*6777b538SAndroid Build Coastguard Worker bool HttpUtil::ParseContentEncoding(const std::string& content_encoding,
1165*6777b538SAndroid Build Coastguard Worker std::set<std::string>* used_encodings) {
1166*6777b538SAndroid Build Coastguard Worker DCHECK(used_encodings);
1167*6777b538SAndroid Build Coastguard Worker if (content_encoding.find_first_of("\"=;*") != std::string::npos)
1168*6777b538SAndroid Build Coastguard Worker return false;
1169*6777b538SAndroid Build Coastguard Worker used_encodings->clear();
1170*6777b538SAndroid Build Coastguard Worker
1171*6777b538SAndroid Build Coastguard Worker base::StringTokenizer encoding_tokenizer(content_encoding.begin(),
1172*6777b538SAndroid Build Coastguard Worker content_encoding.end(), ",");
1173*6777b538SAndroid Build Coastguard Worker while (encoding_tokenizer.GetNext()) {
1174*6777b538SAndroid Build Coastguard Worker std::string_view encoding = TrimLWS(encoding_tokenizer.token_piece());
1175*6777b538SAndroid Build Coastguard Worker if (encoding.find_first_of(HTTP_LWS) != std::string_view::npos) {
1176*6777b538SAndroid Build Coastguard Worker return false;
1177*6777b538SAndroid Build Coastguard Worker }
1178*6777b538SAndroid Build Coastguard Worker used_encodings->insert(base::ToLowerASCII(encoding));
1179*6777b538SAndroid Build Coastguard Worker }
1180*6777b538SAndroid Build Coastguard Worker return true;
1181*6777b538SAndroid Build Coastguard Worker }
1182*6777b538SAndroid Build Coastguard Worker
HeadersContainMultipleCopiesOfField(const HttpResponseHeaders & headers,const std::string & field_name)1183*6777b538SAndroid Build Coastguard Worker bool HttpUtil::HeadersContainMultipleCopiesOfField(
1184*6777b538SAndroid Build Coastguard Worker const HttpResponseHeaders& headers,
1185*6777b538SAndroid Build Coastguard Worker const std::string& field_name) {
1186*6777b538SAndroid Build Coastguard Worker size_t it = 0;
1187*6777b538SAndroid Build Coastguard Worker std::string field_value;
1188*6777b538SAndroid Build Coastguard Worker if (!headers.EnumerateHeader(&it, field_name, &field_value))
1189*6777b538SAndroid Build Coastguard Worker return false;
1190*6777b538SAndroid Build Coastguard Worker // There's at least one `field_name` header. Check if there are any more
1191*6777b538SAndroid Build Coastguard Worker // such headers, and if so, return true if they have different values.
1192*6777b538SAndroid Build Coastguard Worker std::string field_value2;
1193*6777b538SAndroid Build Coastguard Worker while (headers.EnumerateHeader(&it, field_name, &field_value2)) {
1194*6777b538SAndroid Build Coastguard Worker if (field_value != field_value2)
1195*6777b538SAndroid Build Coastguard Worker return true;
1196*6777b538SAndroid Build Coastguard Worker }
1197*6777b538SAndroid Build Coastguard Worker return false;
1198*6777b538SAndroid Build Coastguard Worker }
1199*6777b538SAndroid Build Coastguard Worker
1200*6777b538SAndroid Build Coastguard Worker } // namespace net
1201