xref: /aosp_15_r20/external/cronet/net/http/http_util.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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, &params);
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