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" 147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string_number_conversions.h" 15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_piece.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_tokenizer.h" 177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string_util.h" 187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/stringprintf.h" 19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// Helpers -------------------------------------------------------------------- 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// Returns the index of the closing quote of the string, if any. |start| points 2723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// at the opening quote. 2823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)static size_t FindStringEnd(const std::string& line, size_t start, char delim) { 2923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) DCHECK_LT(start, line.length()); 3023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) DCHECK_EQ(line[start], delim); 3123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) DCHECK((delim == '"') || (delim == '\'')); 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char set[] = { delim, '\\', '\0' }; 3423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) for (size_t end = line.find_first_of(set, start + 1); 3523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) end != std::string::npos; end = line.find_first_of(set, end + 2)) { 3623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (line[end] != '\\') 3723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) return end; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return line.length(); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 4323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)// HttpUtil ------------------------------------------------------------------- 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 4623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)size_t HttpUtil::FindDelimiter(const std::string& line, 4723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) size_t search_start, 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char delimiter) { 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // search_start points to the spot from which we should start looking 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for the delimiter. 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char delim_str[] = { delimiter, '"', '\'', '\0' }; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t cur_delim_pos = line.find_first_of(delim_str, search_start); 5423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (cur_delim_pos == std::string::npos) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return line.length(); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char ch = line[cur_delim_pos]; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ch == delimiter) { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Found delimiter 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return cur_delim_pos; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We hit the start of a quoted string. Look for its end. 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) search_start = FindStringEnd(line, cur_delim_pos, ch); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (search_start == line.length()) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return search_start; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++search_start; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // search_start now points to the first char after the end of the 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // string, so just go back to the top of the loop and look for 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |delimiter| again. 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (true); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return line.length(); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 8023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void HttpUtil::ParseContentType(const std::string& content_type_str, 8123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) std::string* mime_type, 8223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) std::string* charset, 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* had_charset, 8423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) std::string* boundary) { 8523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) const std::string::const_iterator begin = content_type_str.begin(); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Trim leading and trailing whitespace from type. We include '(' in 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the trailing trim set to catch media-type comments, which are not at all 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // standard, but may occur in rare cases. 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t type_val = content_type_str.find_first_not_of(HTTP_LWS); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type_val = std::min(type_val, content_type_str.length()); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t type_end = content_type_str.find_first_of(HTTP_LWS ";(", type_val); 9323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (type_end == std::string::npos) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type_end = content_type_str.length(); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t charset_val = 0; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t charset_end = 0; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool type_has_charset = false; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Iterate over parameters 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t param_start = content_type_str.find_first_of(';', type_end); 10223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (param_start != std::string::npos) { 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::StringTokenizer tokenizer(begin + param_start, content_type_str.end(), 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ";"); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tokenizer.set_quote_chars("\""); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (tokenizer.GetNext()) { 10723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) std::string::const_iterator equals_sign = 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::find(tokenizer.token_begin(), tokenizer.token_end(), '='); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (equals_sign == tokenizer.token_end()) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) std::string::const_iterator param_name_begin = tokenizer.token_begin(); 11323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) std::string::const_iterator param_name_end = equals_sign; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrimLWS(¶m_name_begin, ¶m_name_end); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) std::string::const_iterator param_value_begin = equals_sign + 1; 11723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) std::string::const_iterator param_value_end = tokenizer.token_end(); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(param_value_begin <= tokenizer.token_end()); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrimLWS(¶m_value_begin, ¶m_value_end); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (LowerCaseEqualsASCII(param_name_begin, param_name_end, "charset")) { 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(abarth): Refactor this function to consistently use iterators. 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) charset_val = param_value_begin - begin; 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) charset_end = param_value_end - begin; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type_has_charset = true; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (LowerCaseEqualsASCII(param_name_begin, param_name_end, 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "boundary")) { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (boundary) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) boundary->assign(param_value_begin, param_value_end); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (type_has_charset) { 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Trim leading and trailing whitespace from charset_val. We include 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // '(' in the trailing trim set to catch media-type comments, which are 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // not at all standard, but may occur in rare cases. 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) charset_val = content_type_str.find_first_not_of(HTTP_LWS, charset_val); 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) charset_val = std::min(charset_val, charset_end); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char first_char = content_type_str[charset_val]; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (first_char == '"' || first_char == '\'') { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) charset_end = FindStringEnd(content_type_str, charset_val, first_char); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++charset_val; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(charset_end >= charset_val); 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) charset_end = std::min(content_type_str.find_first_of(HTTP_LWS ";(", 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) charset_val), 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) charset_end); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // if the server sent "*/*", it is meaningless, so do not store it. 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // also, if type_val is the same as mime_type, then just update the 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // charset. however, if charset is empty and mime_type hasn't 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // changed, then don't wipe-out an existing charset. We 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // also want to reject a mime-type if it does not include a slash. 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // some servers give junk after the charset parameter, which may 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // include a comma, so this check makes us a bit more tolerant. 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (content_type_str.length() != 0 && 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_type_str != "*/*" && 16123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) content_type_str.find_first_of('/') != std::string::npos) { 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Common case here is that mime_type is empty 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool eq = !mime_type->empty() && LowerCaseEqualsASCII(begin + type_val, 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) begin + type_end, 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mime_type->data()); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!eq) { 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mime_type->assign(begin + type_val, begin + type_end); 1686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::StringToLowerASCII(mime_type); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((!eq && *had_charset) || type_has_charset) { 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *had_charset = true; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) charset->assign(begin + charset_val, begin + charset_end); 1736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) base::StringToLowerASCII(charset); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Parse the Range header according to RFC 2616 14.35.1 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ranges-specifier = byte-ranges-specifier 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// byte-ranges-specifier = bytes-unit "=" byte-range-set 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// byte-range-set = 1#( byte-range-spec | suffix-byte-range-spec ) 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// byte-range-spec = first-byte-pos "-" [last-byte-pos] 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// first-byte-pos = 1*DIGIT 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// last-byte-pos = 1*DIGIT 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpUtil::ParseRanges(const std::string& headers, 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<HttpByteRange>* ranges) { 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string ranges_specifier; 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n"); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (it.GetNext()) { 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Look for "Range" header. 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!LowerCaseEqualsASCII(it.name(), "range")) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ranges_specifier = it.values(); 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We just care about the first "Range" header, so break here. 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ranges_specifier.empty()) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ParseRangeHeader(ranges_specifier, ranges); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpUtil::ParseRangeHeader(const std::string& ranges_specifier, 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<HttpByteRange>* ranges) { 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t equal_char_offset = ranges_specifier.find('='); 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (equal_char_offset == std::string::npos) 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Try to extract bytes-unit part. 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator bytes_unit_begin = ranges_specifier.begin(); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator bytes_unit_end = bytes_unit_begin + 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) equal_char_offset; 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator byte_range_set_begin = bytes_unit_end + 1; 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator byte_range_set_end = ranges_specifier.end(); 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrimLWS(&bytes_unit_begin, &bytes_unit_end); 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "bytes" unit identifier is not found. 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!LowerCaseEqualsASCII(bytes_unit_begin, bytes_unit_end, "bytes")) 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ValuesIterator byte_range_set_iterator(byte_range_set_begin, 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) byte_range_set_end, ','); 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (byte_range_set_iterator.GetNext()) { 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t minus_char_offset = byte_range_set_iterator.value().find('-'); 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If '-' character is not found, reports failure. 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (minus_char_offset == std::string::npos) 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator first_byte_pos_begin = 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) byte_range_set_iterator.value_begin(); 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator first_byte_pos_end = 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) first_byte_pos_begin + minus_char_offset; 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrimLWS(&first_byte_pos_begin, &first_byte_pos_end); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string first_byte_pos(first_byte_pos_begin, first_byte_pos_end); 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpByteRange range; 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Try to obtain first-byte-pos. 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!first_byte_pos.empty()) { 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 first_byte_position = -1; 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!base::StringToInt64(first_byte_pos, &first_byte_position)) 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) range.set_first_byte_position(first_byte_position); 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator last_byte_pos_begin = 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) byte_range_set_iterator.value_begin() + minus_char_offset + 1; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator last_byte_pos_end = 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) byte_range_set_iterator.value_end(); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrimLWS(&last_byte_pos_begin, &last_byte_pos_end); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string last_byte_pos(last_byte_pos_begin, last_byte_pos_end); 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have last-byte-pos or suffix-byte-range-spec in this case. 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!last_byte_pos.empty()) { 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 last_byte_position; 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!base::StringToInt64(last_byte_pos, &last_byte_position)) 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (range.HasFirstBytePosition()) 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) range.set_last_byte_position(last_byte_position); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) range.set_suffix_length(last_byte_position); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!range.HasFirstBytePosition()) { 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Do a final check on the HttpByteRange object. 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!range.IsValid()) 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ranges->push_back(range); 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !ranges->empty(); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpUtil::HasHeader(const std::string& headers, const char* name) { 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t name_len = strlen(name); 28023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) std::string::const_iterator it = 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::search(headers.begin(), 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers.end(), 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name, 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name + name_len, 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::CaseInsensitiveCompareASCII<char>()); 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it == headers.end()) 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ensure match is prefixed by newline 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it != headers.begin() && it[-1] != '\n') 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ensure match is suffixed by colon 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it + name_len >= headers.end() || it[name_len] != ':') 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A header string containing any of the following fields will cause 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// an error. The list comes from the XMLHttpRequest standard. 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader-method 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* const kForbiddenHeaderFields[] = { 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "accept-charset", 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "accept-encoding", 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "access-control-request-headers", 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "access-control-request-method", 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "connection", 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "content-length", 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "cookie", 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "cookie2", 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "content-transfer-encoding", 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "date", 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "expect", 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "host", 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "keep-alive", 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "origin", 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "referer", 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "te", 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "trailer", 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "transfer-encoding", 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "upgrade", 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "user-agent", 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "via", 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // anonymous namespace 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpUtil::IsSafeHeader(const std::string& name) { 3316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) std::string lower_name(base::StringToLowerASCII(name)); 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (StartsWithASCII(lower_name, "proxy-", true) || 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StartsWithASCII(lower_name, "sec-", true)) 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < arraysize(kForbiddenHeaderFields); ++i) { 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (lower_name == kForbiddenHeaderFields[i]) 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 3431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool HttpUtil::IsValidHeaderName(const std::string& name) { 3441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Check whether the header name is RFC 2616-compliant. 3451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return HttpUtil::IsToken(name); 3461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 3471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// static 3491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool HttpUtil::IsValidHeaderValue(const std::string& value) { 3501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Just a sanity check: disallow NUL and CRLF. 3511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return value.find('\0') == std::string::npos && 3521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci value.find("\r\n") == std::string::npos; 3531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 3541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// static 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string HttpUtil::StripHeaders(const std::string& headers, 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* const headers_to_remove[], 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t headers_to_remove_len) { 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string stripped_headers; 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n"); 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (it.GetNext()) { 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool should_remove = false; 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < headers_to_remove_len; ++i) { 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (LowerCaseEqualsASCII(it.name_begin(), it.name_end(), 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_to_remove[i])) { 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) should_remove = true; 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!should_remove) { 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Assume that name and values are on the same line. 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stripped_headers.append(it.name_begin(), it.values_end()); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stripped_headers.append("\r\n"); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return stripped_headers; 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 38123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)bool HttpUtil::IsNonCoalescingHeader(std::string::const_iterator name_begin, 38223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) std::string::const_iterator name_end) { 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NOTE: "set-cookie2" headers do not support expires attributes, so we don't 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // have to list them here. 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* kNonCoalescingHeaders[] = { 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "date", 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "expires", 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "last-modified", 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "location", // See bug 1050541 for details 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "retry-after", 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "set-cookie", 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The format of auth-challenges mixes both space separated tokens and 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // comma separated properties, so coalescing on comma won't work. 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "www-authenticate", 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "proxy-authenticate", 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // STS specifies that UAs must not process any STS headers after the first 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // one. 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "strict-transport-security" 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < arraysize(kNonCoalescingHeaders); ++i) { 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (LowerCaseEqualsASCII(name_begin, name_end, kNonCoalescingHeaders[i])) 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpUtil::IsLWS(char c) { 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return strchr(HTTP_LWS, c) != NULL; 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 41123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)void HttpUtil::TrimLWS(std::string::const_iterator* begin, 41223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) std::string::const_iterator* end) { 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // leading whitespace 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (*begin < *end && IsLWS((*begin)[0])) 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++(*begin); 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // trailing whitespace 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (*begin < *end && IsLWS((*end)[-1])) 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --(*end); 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpUtil::IsQuote(char c) { 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Single quote mark isn't actually part of quoted-text production, 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // but apparently some servers rely on this. 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return c == '"' || c == '\''; 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// See RFC 2616 Sec 2.2 for the definition of |token|. 42923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)bool HttpUtil::IsToken(std::string::const_iterator begin, 43023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) std::string::const_iterator end) { 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (begin == end) 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::string::const_iterator iter = begin; iter != end; ++iter) { 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned char c = *iter; 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (c >= 0x80 || c <= 0x1F || c == 0x7F || 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c == '(' || c == ')' || c == '<' || c == '>' || c == '@' || 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c == ',' || c == ';' || c == ':' || c == '\\' || c == '"' || 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c == '/' || c == '[' || c == ']' || c == '?' || c == '=' || 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) c == '{' || c == '}' || c == ' ' || c == '\t') 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string HttpUtil::Unquote(std::string::const_iterator begin, 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator end) { 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Empty string 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (begin == end) 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::string(); 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Nothing to unquote. 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsQuote(*begin)) 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::string(begin, end); 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No terminal quote mark. 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (end - begin < 2 || *begin != *(end - 1)) 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::string(begin, end); 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Strip quotemarks 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++begin; 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --end; 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Unescape quoted-pair (defined in RFC 2616 section 2.2) 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string unescaped; 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool prev_escape = false; 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; begin != end; ++begin) { 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char c = *begin; 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (c == '\\' && !prev_escape) { 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prev_escape = true; 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prev_escape = false; 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unescaped.push_back(c); 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return unescaped; 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string HttpUtil::Unquote(const std::string& str) { 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Unquote(str.begin(), str.end()); 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string HttpUtil::Quote(const std::string& str) { 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string escaped; 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) escaped.reserve(2 + str.size()); 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator begin = str.begin(); 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator end = str.end(); 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Esape any backslashes or quotemarks within the string, and 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // then surround with quotes. 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) escaped.push_back('"'); 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; begin != end; ++begin) { 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char c = *begin; 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (c == '"' || c == '\\') 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) escaped.push_back('\\'); 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) escaped.push_back(c); 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) escaped.push_back('"'); 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return escaped; 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Find the "http" substring in a status line. This allows for 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// some slop at the start. If the "http" string could not be found 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// then returns -1. 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HttpUtil::LocateStartOfStatusLine(const char* buf, int buf_len) { 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int slop = 4; 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int http_len = 4; 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (buf_len >= http_len) { 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int i_max = std::min(buf_len - http_len, slop); 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i <= i_max; ++i) { 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (LowerCaseEqualsASCII(buf + i, buf + i + http_len, "http")) 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return i; 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return -1; // Not found 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HttpUtil::LocateEndOfHeaders(const char* buf, int buf_len, int i) { 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool was_lf = false; 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char last_c = '\0'; 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; i < buf_len; ++i) { 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char c = buf[i]; 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (c == '\n') { 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (was_lf) 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return i + 1; 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) was_lf = true; 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (c != '\r' || last_c != '\n') { 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) was_lf = false; 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_c = c; 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return -1; 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// In order for a line to be continuable, it must specify a 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// non-blank header-name. Line continuations are specifically for 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// header values -- do not allow headers names to span lines. 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool IsLineSegmentContinuable(const char* begin, const char* end) { 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (begin == end) 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* colon = std::find(begin, end, ':'); 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (colon == end) 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* name_begin = begin; 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* name_end = colon; 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Name can't be empty. 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (name_begin == name_end) 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Can't start with LWS (this would imply the segment is a continuation) 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (HttpUtil::IsLWS(*name_begin)) 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper used by AssembleRawHeaders, to find the end of the status line. 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char* FindStatusLineEnd(const char* begin, const char* end) { 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t i = base::StringPiece(begin, end - begin).find_first_of("\r\n"); 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i == base::StringPiece::npos) 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return end; 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return begin + i; 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper used by AssembleRawHeaders, to skip past leading LWS. 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char* FindFirstNonLWS(const char* begin, const char* end) { 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (const char* cur = begin; cur != end; ++cur) { 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!HttpUtil::IsLWS(*cur)) 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return cur; 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return end; // Not found. 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string HttpUtil::AssembleRawHeaders(const char* input_begin, 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int input_len) { 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string raw_headers; 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raw_headers.reserve(input_len); 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* input_end = input_begin + input_len; 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Skip any leading slop, since the consumers of this output 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (HttpResponseHeaders) don't deal with it. 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int status_begin_offset = LocateStartOfStatusLine(input_begin, input_len); 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (status_begin_offset != -1) 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) input_begin += status_begin_offset; 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Copy the status line. 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* status_line_end = FindStatusLineEnd(input_begin, input_end); 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raw_headers.append(input_begin, status_line_end); 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // After the status line, every subsequent line is a header line segment. 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Should a segment start with LWS, it is a continuation of the previous 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // line's field-value. 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(ericroman): is this too permissive? (delimits on [\r\n]+) 6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::CStringTokenizer lines(status_line_end, input_end, "\r\n"); 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This variable is true when the previous line was continuable. 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool prev_line_continuable = false; 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (lines.GetNext()) { 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* line_begin = lines.token_begin(); 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* line_end = lines.token_end(); 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (prev_line_continuable && IsLWS(*line_begin)) { 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Join continuation; reduce the leading LWS to a single SP. 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raw_headers.push_back(' '); 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raw_headers.append(FindFirstNonLWS(line_begin, line_end), line_end); 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Terminate the previous line. 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raw_headers.push_back('\n'); 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Copy the raw data to output. 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raw_headers.append(line_begin, line_end); 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if the current line can be continued. 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prev_line_continuable = IsLineSegmentContinuable(line_begin, line_end); 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raw_headers.append("\n\n", 2); 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Use '\0' as the canonical line terminator. If the input already contained 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // any embeded '\0' characters we will strip them first to avoid interpreting 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // them as line breaks. 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raw_headers.erase(std::remove(raw_headers.begin(), raw_headers.end(), '\0'), 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raw_headers.end()); 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::replace(raw_headers.begin(), raw_headers.end(), '\n', '\0'); 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return raw_headers; 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string HttpUtil::ConvertHeadersBackToHTTPResponse(const std::string& str) { 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string disassembled_headers; 6422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::StringTokenizer tokenizer(str, std::string(1, '\0')); 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (tokenizer.GetNext()) { 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) disassembled_headers.append(tokenizer.token_begin(), tokenizer.token_end()); 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) disassembled_headers.append("\r\n"); 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) disassembled_headers.append("\r\n"); 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return disassembled_headers; 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(jungshik): 1. If the list is 'fr-CA,fr-FR,en,de', we have to add 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 'fr' after 'fr-CA' with the same q-value as 'fr-CA' because 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// web servers, in general, do not fall back to 'fr' and may end up picking 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 'en' which has a lower preference than 'fr-CA' and 'fr-FR'. 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 2. This function assumes that the input is a comma separated list 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// without any whitespace. As long as it comes from the preference and 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a user does not manually edit the preference file, it's the case. Still, 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we may have to make it more robust. 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string HttpUtil::GenerateAcceptLanguageHeader( 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& raw_language_list) { 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We use integers for qvalue and qvalue decrement that are 10 times 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // larger than actual values to avoid a problem with comparing 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // two floating point numbers. 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const unsigned int kQvalueDecrement10 = 2; 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int qvalue10 = 10; 6672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::StringTokenizer t(raw_language_list, ","); 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string lang_list_with_q; 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (t.GetNext()) { 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string language = t.token(); 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (qvalue10 == 10) { 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // q=1.0 is implicit. 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lang_list_with_q = language; 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_LT(qvalue10, 10U); 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::StringAppendF(&lang_list_with_q, ",%s;q=0.%d", language.c_str(), 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qvalue10); 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It does not make sense to have 'q=0'. 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (qvalue10 > kQvalueDecrement10) 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) qvalue10 -= kQvalueDecrement10; 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return lang_list_with_q; 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpUtil::AppendHeaderIfMissing(const char* header_name, 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& header_value, 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* headers) { 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (header_value.empty()) 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (net::HttpUtil::HasHeader(*headers, header_name)) 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *headers += std::string(header_name) + ": " + header_value + "\r\n"; 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HttpUtil::HasStrongValidators(HttpVersion version, 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& etag_header, 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& last_modified_header, 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& date_header) { 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (version < HttpVersion(1, 1)) 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!etag_header.empty()) { 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t slash = etag_header.find('/'); 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (slash == std::string::npos || slash == 0) 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator i = etag_header.begin(); 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator j = etag_header.begin() + slash; 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TrimLWS(&i, &j); 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!LowerCaseEqualsASCII(i, j, "w")) 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Time last_modified; 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!base::Time::FromString(last_modified_header.c_str(), &last_modified)) 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Time date; 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!base::Time::FromString(date_header.c_str(), &date)) 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ((date - last_modified).InSeconds() >= 60); 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Functions for histogram initialization. The code 0 is put in the map to 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// track status codes that are invalid. 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(gavinp): Greatly prune the collected codes once we learn which 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ones are not sent in practice, to reduce upload size & memory use. 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum { 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HISTOGRAM_MIN_HTTP_STATUS_CODE = 100, 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HISTOGRAM_MAX_HTTP_STATUS_CODE = 599, 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<int> HttpUtil::GetStatusCodesForHistogram() { 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<int> codes; 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) codes.reserve( 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HISTOGRAM_MAX_HTTP_STATUS_CODE - HISTOGRAM_MIN_HTTP_STATUS_CODE + 2); 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) codes.push_back(0); 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = HISTOGRAM_MIN_HTTP_STATUS_CODE; 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i <= HISTOGRAM_MAX_HTTP_STATUS_CODE; ++i) 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) codes.push_back(i); 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return codes; 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int HttpUtil::MapStatusCodeForHistogram(int code) { 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (HISTOGRAM_MIN_HTTP_STATUS_CODE <= code && 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) code <= HISTOGRAM_MAX_HTTP_STATUS_CODE) 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return code; 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BNF from section 4.2 of RFC 2616: 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// message-header = field-name ":" [ field-value ] 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// field-name = token 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// field-value = *( field-content | LWS ) 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// field-content = <the OCTETs making up the field-value 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and consisting of either *TEXT or combinations 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of token, separators, and quoted-string> 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 76623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)HttpUtil::HeadersIterator::HeadersIterator( 76723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) std::string::const_iterator headers_begin, 76823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) std::string::const_iterator headers_end, 76923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (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) 78123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) std::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); 8086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) DCHECK_EQ(0, base::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( 82123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) std::string::const_iterator values_begin, 82223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) std::string::const_iterator values_end, 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char delimiter) 82423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) : values_(values_begin, values_end, std::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( 84523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) std::string::const_iterator begin, 84623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) std::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