http_util.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The rules for parsing content-types were borrowed from Firefox: 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://lxr.mozilla.org/mozilla/source/netwerk/base/src/nsURLHelper.cpp#834 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_util.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_number_conversions.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_piece.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_util.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/stringprintf.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_tokenizer.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/time.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::string; 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//----------------------------------------------------------------------------- 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return the index of the closing quote of the string, if any. 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static size_t FindStringEnd(const string& line, size_t start, char delim) { 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(start < line.length() && line[start] == delim && 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (delim == '"' || delim == '\'')); 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char set[] = { delim, '\\', '\0' }; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (;;) { 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // start points to either the start quote or the last 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // escaped char (the char following a '\\') 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t end = line.find_first_of(set, start + 1); 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (end == string::npos) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return line.length(); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (line[end] == '\\') { 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Hit a backslash-escaped char. Need to skip over it. 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start = end + 1; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (start == line.length()) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return start; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Go back to looking for the next escape or the string end 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return end; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return line.length(); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//----------------------------------------------------------------------------- 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t HttpUtil::FindDelimiter(const string& line, size_t search_start, 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char delimiter) { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // search_start points to the spot from which we should start looking 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for the delimiter. 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char delim_str[] = { delimiter, '"', '\'', '\0' }; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t cur_delim_pos = line.find_first_of(delim_str, search_start); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (cur_delim_pos == string::npos) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return line.length(); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char ch = line[cur_delim_pos]; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ch == delimiter) { 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Found delimiter 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return cur_delim_pos; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We hit the start of a quoted string. Look for its end. 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) search_start = FindStringEnd(line, cur_delim_pos, ch); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (search_start == line.length()) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return search_start; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++search_start; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // search_start now points to the first char after the end of the 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // string, so just go back to the top of the loop and look for 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |delimiter| again. 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (true); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return line.length(); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpUtil::ParseContentType(const string& content_type_str, 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string* mime_type, 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string* charset, 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* had_charset, 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string* boundary) { 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const string::const_iterator begin = content_type_str.begin(); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Trim leading and trailing whitespace from type. We include '(' in 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the trailing trim set to catch media-type comments, which are not at all 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // standard, but may occur in rare cases. 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t type_val = content_type_str.find_first_not_of(HTTP_LWS); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type_val = std::min(type_val, content_type_str.length()); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t type_end = content_type_str.find_first_of(HTTP_LWS ";(", type_val); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (string::npos == type_end) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type_end = content_type_str.length(); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t charset_val = 0; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t charset_end = 0; 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool type_has_charset = false; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Iterate over parameters 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t param_start = content_type_str.find_first_of(';', type_end); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (param_start != string::npos) { 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::StringTokenizer tokenizer(begin + param_start, content_type_str.end(), 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ";"); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tokenizer.set_quote_chars("\""); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (tokenizer.GetNext()) { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string::const_iterator equals_sign = 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::find(tokenizer.token_begin(), tokenizer.token_end(), '='); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (equals_sign == tokenizer.token_end()) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string::const_iterator param_name_begin = tokenizer.token_begin(); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string::const_iterator param_name_end = equals_sign; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrimLWS(¶m_name_begin, ¶m_name_end); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string::const_iterator param_value_begin = equals_sign + 1; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string::const_iterator param_value_end = tokenizer.token_end(); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(param_value_begin <= tokenizer.token_end()); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrimLWS(¶m_value_begin, ¶m_value_end); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (LowerCaseEqualsASCII(param_name_begin, param_name_end, "charset")) { 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(abarth): Refactor this function to consistently use iterators. 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) charset_val = param_value_begin - begin; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) charset_end = param_value_end - begin; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type_has_charset = true; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (LowerCaseEqualsASCII(param_name_begin, param_name_end, 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "boundary")) { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (boundary) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) boundary->assign(param_value_begin, param_value_end); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type_has_charset) { 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Trim leading and trailing whitespace from charset_val. We include 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // '(' in the trailing trim set to catch media-type comments, which are 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // not at all standard, but may occur in rare cases. 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) charset_val = content_type_str.find_first_not_of(HTTP_LWS, charset_val); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) charset_val = std::min(charset_val, charset_end); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char first_char = content_type_str[charset_val]; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (first_char == '"' || first_char == '\'') { 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) charset_end = FindStringEnd(content_type_str, charset_val, first_char); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++charset_val; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(charset_end >= charset_val); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) charset_end = std::min(content_type_str.find_first_of(HTTP_LWS ";(", 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) charset_val), 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) charset_end); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // if the server sent "*/*", it is meaningless, so do not store it. 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // also, if type_val is the same as mime_type, then just update the 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // charset. however, if charset is empty and mime_type hasn't 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // changed, then don't wipe-out an existing charset. We 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // also want to reject a mime-type if it does not include a slash. 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // some servers give junk after the charset parameter, which may 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // include a comma, so this check makes us a bit more tolerant. 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (content_type_str.length() != 0 && 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_type_str != "*/*" && 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_type_str.find_first_of('/') != string::npos) { 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Common case here is that mime_type is empty 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool eq = !mime_type->empty() && LowerCaseEqualsASCII(begin + type_val, 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) begin + type_end, 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mime_type->data()); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!eq) { 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mime_type->assign(begin + type_val, begin + type_end); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StringToLowerASCII(mime_type); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((!eq && *had_charset) || type_has_charset) { 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *had_charset = true; 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) charset->assign(begin + charset_val, begin + charset_end); 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StringToLowerASCII(charset); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Parse the Range header according to RFC 2616 14.35.1 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ranges-specifier = byte-ranges-specifier 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// byte-ranges-specifier = bytes-unit "=" byte-range-set 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// byte-range-set = 1#( byte-range-spec | suffix-byte-range-spec ) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// byte-range-spec = first-byte-pos "-" [last-byte-pos] 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// first-byte-pos = 1*DIGIT 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// last-byte-pos = 1*DIGIT 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpUtil::ParseRanges(const std::string& headers, 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<HttpByteRange>* ranges) { 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string ranges_specifier; 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n"); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (it.GetNext()) { 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Look for "Range" header. 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!LowerCaseEqualsASCII(it.name(), "range")) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ranges_specifier = it.values(); 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We just care about the first "Range" header, so break here. 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ranges_specifier.empty()) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ParseRangeHeader(ranges_specifier, ranges); 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpUtil::ParseRangeHeader(const std::string& ranges_specifier, 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<HttpByteRange>* ranges) { 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t equal_char_offset = ranges_specifier.find('='); 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (equal_char_offset == std::string::npos) 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Try to extract bytes-unit part. 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator bytes_unit_begin = ranges_specifier.begin(); 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator bytes_unit_end = bytes_unit_begin + 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) equal_char_offset; 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator byte_range_set_begin = bytes_unit_end + 1; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator byte_range_set_end = ranges_specifier.end(); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrimLWS(&bytes_unit_begin, &bytes_unit_end); 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "bytes" unit identifier is not found. 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!LowerCaseEqualsASCII(bytes_unit_begin, bytes_unit_end, "bytes")) 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ValuesIterator byte_range_set_iterator(byte_range_set_begin, 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) byte_range_set_end, ','); 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (byte_range_set_iterator.GetNext()) { 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t minus_char_offset = byte_range_set_iterator.value().find('-'); 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If '-' character is not found, reports failure. 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (minus_char_offset == std::string::npos) 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator first_byte_pos_begin = 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) byte_range_set_iterator.value_begin(); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator first_byte_pos_end = 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) first_byte_pos_begin + minus_char_offset; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrimLWS(&first_byte_pos_begin, &first_byte_pos_end); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string first_byte_pos(first_byte_pos_begin, first_byte_pos_end); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpByteRange range; 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Try to obtain first-byte-pos. 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!first_byte_pos.empty()) { 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 first_byte_position = -1; 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!base::StringToInt64(first_byte_pos, &first_byte_position)) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) range.set_first_byte_position(first_byte_position); 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator last_byte_pos_begin = 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) byte_range_set_iterator.value_begin() + minus_char_offset + 1; 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator last_byte_pos_end = 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) byte_range_set_iterator.value_end(); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrimLWS(&last_byte_pos_begin, &last_byte_pos_end); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string last_byte_pos(last_byte_pos_begin, last_byte_pos_end); 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have last-byte-pos or suffix-byte-range-spec in this case. 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!last_byte_pos.empty()) { 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 last_byte_position; 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!base::StringToInt64(last_byte_pos, &last_byte_position)) 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (range.HasFirstBytePosition()) 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) range.set_last_byte_position(last_byte_position); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) range.set_suffix_length(last_byte_position); 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!range.HasFirstBytePosition()) { 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Do a final check on the HttpByteRange object. 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!range.IsValid()) 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ranges->push_back(range); 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !ranges->empty(); 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpUtil::HasHeader(const std::string& headers, const char* name) { 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t name_len = strlen(name); 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string::const_iterator it = 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::search(headers.begin(), 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers.end(), 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name, 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name + name_len, 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::CaseInsensitiveCompareASCII<char>()); 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it == headers.end()) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ensure match is prefixed by newline 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it != headers.begin() && it[-1] != '\n') 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ensure match is suffixed by colon 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it + name_len >= headers.end() || it[name_len] != ':') 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A header string containing any of the following fields will cause 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// an error. The list comes from the XMLHttpRequest standard. 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader-method 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* const kForbiddenHeaderFields[] = { 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "accept-charset", 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "accept-encoding", 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "access-control-request-headers", 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "access-control-request-method", 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "connection", 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "content-length", 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "cookie", 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "cookie2", 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "content-transfer-encoding", 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "date", 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "expect", 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "host", 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "keep-alive", 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "origin", 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "referer", 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "te", 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "trailer", 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "transfer-encoding", 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "upgrade", 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "user-agent", 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "via", 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // anonymous namespace 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpUtil::IsSafeHeader(const std::string& name) { 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string lower_name(StringToLowerASCII(name)); 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (StartsWithASCII(lower_name, "proxy-", true) || 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartsWithASCII(lower_name, "sec-", true)) 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < arraysize(kForbiddenHeaderFields); ++i) { 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (lower_name == kForbiddenHeaderFields[i]) 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string HttpUtil::StripHeaders(const std::string& headers, 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* const headers_to_remove[], 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t headers_to_remove_len) { 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string stripped_headers; 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n"); 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (it.GetNext()) { 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool should_remove = false; 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < headers_to_remove_len; ++i) { 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (LowerCaseEqualsASCII(it.name_begin(), it.name_end(), 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_to_remove[i])) { 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) should_remove = true; 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!should_remove) { 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Assume that name and values are on the same line. 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stripped_headers.append(it.name_begin(), it.values_end()); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stripped_headers.append("\r\n"); 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return stripped_headers; 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpUtil::IsNonCoalescingHeader(string::const_iterator name_begin, 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string::const_iterator name_end) { 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NOTE: "set-cookie2" headers do not support expires attributes, so we don't 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // have to list them here. 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* kNonCoalescingHeaders[] = { 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "date", 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "expires", 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "last-modified", 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "location", // See bug 1050541 for details 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "retry-after", 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "set-cookie", 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The format of auth-challenges mixes both space separated tokens and 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // comma separated properties, so coalescing on comma won't work. 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "www-authenticate", 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "proxy-authenticate", 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // STS specifies that UAs must not process any STS headers after the first 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // one. 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "strict-transport-security" 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < arraysize(kNonCoalescingHeaders); ++i) { 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (LowerCaseEqualsASCII(name_begin, name_end, kNonCoalescingHeaders[i])) 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpUtil::IsLWS(char c) { 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return strchr(HTTP_LWS, c) != NULL; 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpUtil::TrimLWS(string::const_iterator* begin, 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string::const_iterator* end) { 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // leading whitespace 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (*begin < *end && IsLWS((*begin)[0])) 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++(*begin); 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // trailing whitespace 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (*begin < *end && IsLWS((*end)[-1])) 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --(*end); 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpUtil::IsQuote(char c) { 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Single quote mark isn't actually part of quoted-text production, 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // but apparently some servers rely on this. 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return c == '"' || c == '\''; 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// See RFC 2616 Sec 2.2 for the definition of |token|. 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpUtil::IsToken(string::const_iterator begin, 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string::const_iterator end) { 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (begin == end) 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::string::const_iterator iter = begin; iter != end; ++iter) { 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char c = *iter; 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (c >= 0x80 || c <= 0x1F || c == 0x7F || 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c == '(' || c == ')' || c == '<' || c == '>' || c == '@' || 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c == ',' || c == ';' || c == ':' || c == '\\' || c == '"' || 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c == '/' || c == '[' || c == ']' || c == '?' || c == '=' || 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c == '{' || c == '}' || c == ' ' || c == '\t') 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string HttpUtil::Unquote(std::string::const_iterator begin, 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator end) { 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Empty string 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (begin == end) 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::string(); 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Nothing to unquote. 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsQuote(*begin)) 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::string(begin, end); 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No terminal quote mark. 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (end - begin < 2 || *begin != *(end - 1)) 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::string(begin, end); 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Strip quotemarks 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++begin; 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --end; 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Unescape quoted-pair (defined in RFC 2616 section 2.2) 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string unescaped; 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool prev_escape = false; 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; begin != end; ++begin) { 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char c = *begin; 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (c == '\\' && !prev_escape) { 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prev_escape = true; 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prev_escape = false; 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unescaped.push_back(c); 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return unescaped; 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string HttpUtil::Unquote(const std::string& str) { 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Unquote(str.begin(), str.end()); 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string HttpUtil::Quote(const std::string& str) { 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string escaped; 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) escaped.reserve(2 + str.size()); 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator begin = str.begin(); 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator end = str.end(); 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Esape any backslashes or quotemarks within the string, and 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // then surround with quotes. 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) escaped.push_back('"'); 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; begin != end; ++begin) { 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char c = *begin; 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (c == '"' || c == '\\') 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) escaped.push_back('\\'); 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) escaped.push_back(c); 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) escaped.push_back('"'); 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return escaped; 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Find the "http" substring in a status line. This allows for 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// some slop at the start. If the "http" string could not be found 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// then returns -1. 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HttpUtil::LocateStartOfStatusLine(const char* buf, int buf_len) { 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int slop = 4; 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int http_len = 4; 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (buf_len >= http_len) { 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i_max = std::min(buf_len - http_len, slop); 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i <= i_max; ++i) { 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (LowerCaseEqualsASCII(buf + i, buf + i + http_len, "http")) 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return i; 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return -1; // Not found 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HttpUtil::LocateEndOfHeaders(const char* buf, int buf_len, int i) { 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool was_lf = false; 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char last_c = '\0'; 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; i < buf_len; ++i) { 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char c = buf[i]; 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (c == '\n') { 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (was_lf) 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return i + 1; 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) was_lf = true; 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (c != '\r' || last_c != '\n') { 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) was_lf = false; 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_c = c; 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return -1; 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// In order for a line to be continuable, it must specify a 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// non-blank header-name. Line continuations are specifically for 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// header values -- do not allow headers names to span lines. 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool IsLineSegmentContinuable(const char* begin, const char* end) { 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (begin == end) 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* colon = std::find(begin, end, ':'); 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (colon == end) 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* name_begin = begin; 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* name_end = colon; 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Name can't be empty. 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (name_begin == name_end) 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Can't start with LWS (this would imply the segment is a continuation) 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (HttpUtil::IsLWS(*name_begin)) 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper used by AssembleRawHeaders, to find the end of the status line. 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char* FindStatusLineEnd(const char* begin, const char* end) { 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t i = base::StringPiece(begin, end - begin).find_first_of("\r\n"); 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i == base::StringPiece::npos) 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return end; 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return begin + i; 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper used by AssembleRawHeaders, to skip past leading LWS. 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char* FindFirstNonLWS(const char* begin, const char* end) { 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (const char* cur = begin; cur != end; ++cur) { 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!HttpUtil::IsLWS(*cur)) 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return cur; 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return end; // Not found. 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string HttpUtil::AssembleRawHeaders(const char* input_begin, 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int input_len) { 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string raw_headers; 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raw_headers.reserve(input_len); 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* input_end = input_begin + input_len; 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Skip any leading slop, since the consumers of this output 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (HttpResponseHeaders) don't deal with it. 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int status_begin_offset = LocateStartOfStatusLine(input_begin, input_len); 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (status_begin_offset != -1) 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) input_begin += status_begin_offset; 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Copy the status line. 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* status_line_end = FindStatusLineEnd(input_begin, input_end); 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raw_headers.append(input_begin, status_line_end); 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // After the status line, every subsequent line is a header line segment. 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Should a segment start with LWS, it is a continuation of the previous 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // line's field-value. 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(ericroman): is this too permissive? (delimits on [\r\n]+) 6042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::CStringTokenizer lines(status_line_end, input_end, "\r\n"); 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This variable is true when the previous line was continuable. 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool prev_line_continuable = false; 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (lines.GetNext()) { 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* line_begin = lines.token_begin(); 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* line_end = lines.token_end(); 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (prev_line_continuable && IsLWS(*line_begin)) { 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Join continuation; reduce the leading LWS to a single SP. 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raw_headers.push_back(' '); 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raw_headers.append(FindFirstNonLWS(line_begin, line_end), line_end); 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Terminate the previous line. 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raw_headers.push_back('\n'); 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Copy the raw data to output. 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raw_headers.append(line_begin, line_end); 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if the current line can be continued. 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prev_line_continuable = IsLineSegmentContinuable(line_begin, line_end); 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raw_headers.append("\n\n", 2); 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Use '\0' as the canonical line terminator. If the input already contained 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // any embeded '\0' characters we will strip them first to avoid interpreting 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // them as line breaks. 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raw_headers.erase(std::remove(raw_headers.begin(), raw_headers.end(), '\0'), 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raw_headers.end()); 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::replace(raw_headers.begin(), raw_headers.end(), '\n', '\0'); 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return raw_headers; 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string HttpUtil::ConvertHeadersBackToHTTPResponse(const std::string& str) { 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string disassembled_headers; 6432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::StringTokenizer tokenizer(str, std::string(1, '\0')); 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (tokenizer.GetNext()) { 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) disassembled_headers.append(tokenizer.token_begin(), tokenizer.token_end()); 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) disassembled_headers.append("\r\n"); 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) disassembled_headers.append("\r\n"); 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return disassembled_headers; 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(jungshik): 1. If the list is 'fr-CA,fr-FR,en,de', we have to add 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 'fr' after 'fr-CA' with the same q-value as 'fr-CA' because 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// web servers, in general, do not fall back to 'fr' and may end up picking 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 'en' which has a lower preference than 'fr-CA' and 'fr-FR'. 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 2. This function assumes that the input is a comma separated list 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// without any whitespace. As long as it comes from the preference and 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a user does not manually edit the preference file, it's the case. Still, 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we may have to make it more robust. 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string HttpUtil::GenerateAcceptLanguageHeader( 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& raw_language_list) { 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We use integers for qvalue and qvalue decrement that are 10 times 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // larger than actual values to avoid a problem with comparing 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // two floating point numbers. 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const unsigned int kQvalueDecrement10 = 2; 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int qvalue10 = 10; 6682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::StringTokenizer t(raw_language_list, ","); 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string lang_list_with_q; 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (t.GetNext()) { 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string language = t.token(); 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (qvalue10 == 10) { 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // q=1.0 is implicit. 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lang_list_with_q = language; 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_LT(qvalue10, 10U); 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::StringAppendF(&lang_list_with_q, ",%s;q=0.%d", language.c_str(), 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qvalue10); 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It does not make sense to have 'q=0'. 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (qvalue10 > kQvalueDecrement10) 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qvalue10 -= kQvalueDecrement10; 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return lang_list_with_q; 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpUtil::AppendHeaderIfMissing(const char* header_name, 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& header_value, 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* headers) { 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (header_value.empty()) 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (net::HttpUtil::HasHeader(*headers, header_name)) 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *headers += std::string(header_name) + ": " + header_value + "\r\n"; 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpUtil::HasStrongValidators(HttpVersion version, 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& etag_header, 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& last_modified_header, 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& date_header) { 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (version < HttpVersion(1, 1)) 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!etag_header.empty()) { 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t slash = etag_header.find('/'); 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (slash == std::string::npos || slash == 0) 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator i = etag_header.begin(); 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator j = etag_header.begin() + slash; 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrimLWS(&i, &j); 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!LowerCaseEqualsASCII(i, j, "w")) 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Time last_modified; 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!base::Time::FromString(last_modified_header.c_str(), &last_modified)) 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Time date; 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!base::Time::FromString(date_header.c_str(), &date)) 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ((date - last_modified).InSeconds() >= 60); 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Functions for histogram initialization. The code 0 is put in the map to 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// track status codes that are invalid. 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(gavinp): Greatly prune the collected codes once we learn which 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ones are not sent in practice, to reduce upload size & memory use. 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum { 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HISTOGRAM_MIN_HTTP_STATUS_CODE = 100, 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HISTOGRAM_MAX_HTTP_STATUS_CODE = 599, 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<int> HttpUtil::GetStatusCodesForHistogram() { 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<int> codes; 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) codes.reserve( 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HISTOGRAM_MAX_HTTP_STATUS_CODE - HISTOGRAM_MIN_HTTP_STATUS_CODE + 2); 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) codes.push_back(0); 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = HISTOGRAM_MIN_HTTP_STATUS_CODE; 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i <= HISTOGRAM_MAX_HTTP_STATUS_CODE; ++i) 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) codes.push_back(i); 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return codes; 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HttpUtil::MapStatusCodeForHistogram(int code) { 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (HISTOGRAM_MIN_HTTP_STATUS_CODE <= code && 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) code <= HISTOGRAM_MAX_HTTP_STATUS_CODE) 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return code; 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BNF from section 4.2 of RFC 2616: 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// message-header = field-name ":" [ field-value ] 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// field-name = token 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// field-value = *( field-content | LWS ) 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// field-content = <the OCTETs making up the field-value 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and consisting of either *TEXT or combinations 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of token, separators, and quoted-string> 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpUtil::HeadersIterator::HeadersIterator(string::const_iterator headers_begin, 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string::const_iterator headers_end, 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& line_delimiter) 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : lines_(headers_begin, headers_end, line_delimiter) { 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpUtil::HeadersIterator::~HeadersIterator() { 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpUtil::HeadersIterator::GetNext() { 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (lines_.GetNext()) { 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name_begin_ = lines_.token_begin(); 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) values_end_ = lines_.token_end(); 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string::const_iterator colon = std::find(name_begin_, values_end_, ':'); 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (colon == values_end_) 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; // skip malformed header 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name_end_ = colon; 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the name starts with LWS, it is an invalid line. 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Leading LWS implies a line continuation, and these should have 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // already been joined by AssembleRawHeaders(). 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (name_begin_ == name_end_ || IsLWS(*name_begin_)) 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrimLWS(&name_begin_, &name_end_); 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (name_begin_ == name_end_) 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; // skip malformed header 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) values_begin_ = colon + 1; 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrimLWS(&values_begin_, &values_end_); 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // if we got a header name, then we are done. 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpUtil::HeadersIterator::AdvanceTo(const char* name) { 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(name != NULL); 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(0, StringToLowerASCII<std::string>(name).compare(name)) 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "the header name must be in all lower case"; 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (GetNext()) { 8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (LowerCaseEqualsASCII(name_begin_, name_end_, name)) { 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpUtil::ValuesIterator::ValuesIterator( 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string::const_iterator values_begin, 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string::const_iterator values_end, 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char delimiter) 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : values_(values_begin, values_end, string(1, delimiter)) { 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) values_.set_quote_chars("\'\""); 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpUtil::ValuesIterator::~ValuesIterator() { 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpUtil::ValuesIterator::GetNext() { 8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (values_.GetNext()) { 8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_begin_ = values_.token_begin(); 8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_end_ = values_.token_end(); 8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrimLWS(&value_begin_, &value_end_); 8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // bypass empty values. 8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (value_begin_ != value_end_) 8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpUtil::NameValuePairsIterator::NameValuePairsIterator( 8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string::const_iterator begin, 8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string::const_iterator end, 8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char delimiter) 8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : props_(begin, end, delimiter), 8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) valid_(true), 8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name_begin_(end), 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name_end_(end), 8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_begin_(end), 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_end_(end), 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_is_quoted_(false) { 8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpUtil::NameValuePairsIterator::~NameValuePairsIterator() {} 8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We expect properties to be formatted as one of: 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// name="value" 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// name='value' 8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// name='\'value\'' 8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// name=value 8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// name = value 8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// name= 8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Due to buggy implementations found in some embedded devices, we also 8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// accept values with missing close quotemark (http://crbug.com/39836): 8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// name="value 8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpUtil::NameValuePairsIterator::GetNext() { 8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!props_.GetNext()) 8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set the value as everything. Next we will split out the name. 8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_begin_ = props_.value_begin(); 8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_end_ = props_.value_end(); 8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name_begin_ = name_end_ = value_end_; 8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Scan for the equals sign. 8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator equals = std::find(value_begin_, value_end_, '='); 8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (equals == value_end_ || equals == value_begin_) 8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return valid_ = false; // Malformed, no equals sign 8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Verify that the equals sign we found wasn't inside of quote marks. 8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::string::const_iterator it = value_begin_; it != equals; ++it) { 8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (HttpUtil::IsQuote(*it)) 8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return valid_ = false; // Malformed, quote appears before equals sign 8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name_begin_ = value_begin_; 8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name_end_ = equals; 8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_begin_ = equals + 1; 8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrimLWS(&name_begin_, &name_end_); 8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrimLWS(&value_begin_, &value_end_); 8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_is_quoted_ = false; 8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unquoted_value_.clear(); 8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (value_begin_ == value_end_) 8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return valid_ = false; // Malformed, value is empty 9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (HttpUtil::IsQuote(*value_begin_)) { 9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Trim surrounding quotemarks off the value 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*value_begin_ != *(value_end_ - 1) || value_begin_ + 1 == value_end_) { 9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NOTE: This is not as graceful as it sounds: 9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // * quoted-pairs will no longer be unquoted 9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (["\"hello] should give ["hello]). 9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // * Does not detect when the final quote is escaped 9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (["value\"] should give [value"]) 9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++value_begin_; // Gracefully recover from mismatching quotes. 9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_is_quoted_ = true; 9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Do not store iterators into this. See declaration of unquoted_value_. 9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unquoted_value_ = HttpUtil::Unquote(value_begin_, value_end_); 9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 921