1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be 3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file. 4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// The rules for parsing content-types were borrowed from Firefox: 6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// http://lxr.mozilla.org/mozilla/source/netwerk/base/src/nsURLHelper.cpp#834 7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_util.h" 9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <algorithm> 11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/basictypes.h" 13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h" 143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h" 15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_piece.h" 16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_util.h" 17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottusing std::string; 19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace net { 21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//----------------------------------------------------------------------------- 23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Return the index of the closing quote of the string, if any. 25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic size_t FindStringEnd(const string& line, size_t start, char delim) { 26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(start < line.length() && line[start] == delim && 27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott (delim == '"' || delim == '\'')); 28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const char set[] = { delim, '\\', '\0' }; 30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott for (;;) { 31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // start points to either the start quote or the last 32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // escaped char (the char following a '\\') 33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t end = line.find_first_of(set, start + 1); 35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (end == string::npos) 36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return line.length(); 37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (line[end] == '\\') { 39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Hit a backslash-escaped char. Need to skip over it. 40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott start = end + 1; 41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (start == line.length()) 42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return start; 43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Go back to looking for the next escape or the string end 45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott continue; 46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return end; 49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NOTREACHED(); 52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return line.length(); 53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//----------------------------------------------------------------------------- 56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottsize_t HttpUtil::FindDelimiter(const string& line, size_t search_start, 59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char delimiter) { 60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott do { 61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // search_start points to the spot from which we should start looking 62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // for the delimiter. 63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const char delim_str[] = { delimiter, '"', '\'', '\0' }; 64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t cur_delim_pos = line.find_first_of(delim_str, search_start); 65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (cur_delim_pos == string::npos) 66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return line.length(); 67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char ch = line[cur_delim_pos]; 69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (ch == delimiter) { 70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Found delimiter 71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return cur_delim_pos; 72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // We hit the start of a quoted string. Look for its end. 75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott search_start = FindStringEnd(line, cur_delim_pos, ch); 76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (search_start == line.length()) 77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return search_start; 78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ++search_start; 80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // search_start now points to the first char after the end of the 82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // string, so just go back to the top of the loop and look for 83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // |delimiter| again. 84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } while (true); 85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NOTREACHED(); 87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return line.length(); 88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid HttpUtil::ParseContentType(const string& content_type_str, 92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott string* mime_type, string* charset, 93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott bool *had_charset) { 94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Trim leading and trailing whitespace from type. We include '(' in 95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // the trailing trim set to catch media-type comments, which are not at all 96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // standard, but may occur in rare cases. 97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t type_val = content_type_str.find_first_not_of(HTTP_LWS); 98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott type_val = std::min(type_val, content_type_str.length()); 99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t type_end = content_type_str.find_first_of(HTTP_LWS ";(", type_val); 100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (string::npos == type_end) 101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott type_end = content_type_str.length(); 102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t charset_val = 0; 104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t charset_end = 0; 105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Iterate over parameters 107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott bool type_has_charset = false; 108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t param_start = content_type_str.find_first_of(';', type_end); 109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (param_start != string::npos) { 110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // We have parameters. Iterate over them. 111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t cur_param_start = param_start + 1; 112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott do { 113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t cur_param_end = 114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott FindDelimiter(content_type_str, cur_param_start, ';'); 115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t param_name_start = content_type_str.find_first_not_of( 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch HTTP_LWS, cur_param_start); 118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott param_name_start = std::min(param_name_start, cur_param_end); 119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott static const char charset_str[] = "charset="; 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t charset_end_offset = std::min( 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch param_name_start + sizeof(charset_str) - 1, cur_param_end); 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (LowerCaseEqualsASCII( 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch content_type_str.begin() + param_name_start, 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch content_type_str.begin() + charset_end_offset, charset_str)) { 126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott charset_val = param_name_start + sizeof(charset_str) - 1; 127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott charset_end = cur_param_end; 128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott type_has_charset = true; 129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott cur_param_start = cur_param_end + 1; 132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } while (cur_param_start < content_type_str.length()); 133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (type_has_charset) { 136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Trim leading and trailing whitespace from charset_val. We include 137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // '(' in the trailing trim set to catch media-type comments, which are 138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // not at all standard, but may occur in rare cases. 139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott charset_val = content_type_str.find_first_not_of(HTTP_LWS, charset_val); 140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott charset_val = std::min(charset_val, charset_end); 141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char first_char = content_type_str[charset_val]; 142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (first_char == '"' || first_char == '\'') { 143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott charset_end = FindStringEnd(content_type_str, charset_val, first_char); 144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ++charset_val; 145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(charset_end >= charset_val); 146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else { 147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott charset_end = std::min(content_type_str.find_first_of(HTTP_LWS ";(", 148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott charset_val), 149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott charset_end); 150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // if the server sent "*/*", it is meaningless, so do not store it. 154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // also, if type_val is the same as mime_type, then just update the 155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // charset. however, if charset is empty and mime_type hasn't 156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // changed, then don't wipe-out an existing charset. We 157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // also want to reject a mime-type if it does not include a slash. 158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // some servers give junk after the charset parameter, which may 159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // include a comma, so this check makes us a bit more tolerant. 160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (content_type_str.length() != 0 && 161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott content_type_str != "*/*" && 162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott content_type_str.find_first_of('/') != string::npos) { 163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Common case here is that mime_type is empty 164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott bool eq = !mime_type->empty() && 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LowerCaseEqualsASCII(content_type_str.begin() + type_val, 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch content_type_str.begin() + type_end, 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch mime_type->data()); 168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!eq) { 169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott mime_type->assign(content_type_str.begin() + type_val, 170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott content_type_str.begin() + type_end); 171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott StringToLowerASCII(mime_type); 172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if ((!eq && *had_charset) || type_has_charset) { 174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *had_charset = true; 175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott charset->assign(content_type_str.begin() + charset_val, 176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott content_type_str.begin() + charset_end); 177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott StringToLowerASCII(charset); 178c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Parse the Range header according to RFC 2616 14.35.1 184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// ranges-specifier = byte-ranges-specifier 185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// byte-ranges-specifier = bytes-unit "=" byte-range-set 186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// byte-range-set = 1#( byte-range-spec | suffix-byte-range-spec ) 187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// byte-range-spec = first-byte-pos "-" [last-byte-pos] 188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// first-byte-pos = 1*DIGIT 189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// last-byte-pos = 1*DIGIT 190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool HttpUtil::ParseRanges(const std::string& headers, 191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::vector<HttpByteRange>* ranges) { 192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string ranges_specifier; 193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n"); 194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while (it.GetNext()) { 196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Look for "Range" header. 197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!LowerCaseEqualsASCII(it.name(), "range")) 198c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott continue; 199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ranges_specifier = it.values(); 200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // We just care about the first "Range" header, so break here. 201c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott break; 202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (ranges_specifier.empty()) 205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return ParseRangeHeader(ranges_specifier, ranges); 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool HttpUtil::ParseRangeHeader(const std::string& ranges_specifier, 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<HttpByteRange>* ranges) { 213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t equal_char_offset = ranges_specifier.find('='); 214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (equal_char_offset == std::string::npos) 215c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Try to extract bytes-unit part. 218c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string::const_iterator bytes_unit_begin = ranges_specifier.begin(); 219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string::const_iterator bytes_unit_end = bytes_unit_begin + 220c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott equal_char_offset; 221c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string::const_iterator byte_range_set_begin = bytes_unit_end + 1; 222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string::const_iterator byte_range_set_end = ranges_specifier.end(); 223c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 224c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott TrimLWS(&bytes_unit_begin, &bytes_unit_end); 225c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // "bytes" unit identifier is not found. 226c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!LowerCaseEqualsASCII(bytes_unit_begin, bytes_unit_end, "bytes")) 227c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 228c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 229c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ValuesIterator byte_range_set_iterator(byte_range_set_begin, 230c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott byte_range_set_end, ','); 231c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while (byte_range_set_iterator.GetNext()) { 232c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t minus_char_offset = byte_range_set_iterator.value().find('-'); 233c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // If '-' character is not found, reports failure. 234c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (minus_char_offset == std::string::npos) 235c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 236c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 237c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string::const_iterator first_byte_pos_begin = 238c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott byte_range_set_iterator.value_begin(); 239c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string::const_iterator first_byte_pos_end = 240c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott first_byte_pos_begin + minus_char_offset; 241c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott TrimLWS(&first_byte_pos_begin, &first_byte_pos_end); 242c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string first_byte_pos(first_byte_pos_begin, first_byte_pos_end); 243c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 244c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott HttpByteRange range; 245c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Try to obtain first-byte-pos. 246c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!first_byte_pos.empty()) { 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int64 first_byte_position = -1; 2483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!base::StringToInt64(first_byte_pos, &first_byte_position)) 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch range.set_first_byte_position(first_byte_position); 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 252c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 253c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string::const_iterator last_byte_pos_begin = 254c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott byte_range_set_iterator.value_begin() + minus_char_offset + 1; 255c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string::const_iterator last_byte_pos_end = 256c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott byte_range_set_iterator.value_end(); 257c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott TrimLWS(&last_byte_pos_begin, &last_byte_pos_end); 258c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string last_byte_pos(last_byte_pos_begin, last_byte_pos_end); 259c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 260c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // We have last-byte-pos or suffix-byte-range-spec in this case. 261c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!last_byte_pos.empty()) { 262c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int64 last_byte_position; 2633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!base::StringToInt64(last_byte_pos, &last_byte_position)) 264c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 265c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (range.HasFirstBytePosition()) 266c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott range.set_last_byte_position(last_byte_position); 267c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott else 268c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott range.set_suffix_length(last_byte_position); 269c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else if (!range.HasFirstBytePosition()) { 270c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 271c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 272c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 273c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Do a final check on the HttpByteRange object. 274c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!range.IsValid()) 275c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 276c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ranges->push_back(range); 277c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 278dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return !ranges->empty(); 279c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 280c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 281c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 282c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool HttpUtil::HasHeader(const std::string& headers, const char* name) { 283c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t name_len = strlen(name); 284c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott string::const_iterator it = 285c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::search(headers.begin(), 286c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott headers.end(), 287c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott name, 288c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott name + name_len, 289513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch base::CaseInsensitiveCompareASCII<char>()); 290c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (it == headers.end()) 291c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 292c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 293c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // ensure match is prefixed by newline 294c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (it != headers.begin() && it[-1] != '\n') 295c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 296c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 297c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // ensure match is suffixed by colon 298c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (it + name_len >= headers.end() || it[name_len] != ':') 299c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 300c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 301c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 302c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 303c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 304c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 305c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstd::string HttpUtil::StripHeaders(const std::string& headers, 306c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const char* const headers_to_remove[], 307c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t headers_to_remove_len) { 308c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string stripped_headers; 309c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n"); 310c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 311c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while (it.GetNext()) { 312c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott bool should_remove = false; 313c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott for (size_t i = 0; i < headers_to_remove_len; ++i) { 314c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (LowerCaseEqualsASCII(it.name_begin(), it.name_end(), 315c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott headers_to_remove[i])) { 316c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott should_remove = true; 317c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott break; 318c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 319c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 320c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!should_remove) { 321c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Assume that name and values are on the same line. 322c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott stripped_headers.append(it.name_begin(), it.values_end()); 323c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott stripped_headers.append("\r\n"); 324c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 325c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 326c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return stripped_headers; 327c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 328c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 329c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 330c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool HttpUtil::IsNonCoalescingHeader(string::const_iterator name_begin, 331c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott string::const_iterator name_end) { 332c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // NOTE: "set-cookie2" headers do not support expires attributes, so we don't 333c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // have to list them here. 334c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const char* kNonCoalescingHeaders[] = { 335c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott "date", 336c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott "expires", 337c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott "last-modified", 338c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott "location", // See bug 1050541 for details 339c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott "retry-after", 340c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott "set-cookie", 341c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // The format of auth-challenges mixes both space separated tokens and 342c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // comma separated properties, so coalescing on comma won't work. 343c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott "www-authenticate", 344c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott "proxy-authenticate" 345c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott }; 346c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott for (size_t i = 0; i < arraysize(kNonCoalescingHeaders); ++i) { 347c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (LowerCaseEqualsASCII(name_begin, name_end, kNonCoalescingHeaders[i])) 348c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 349c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 350c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 351c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 352c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 353c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool HttpUtil::IsLWS(char c) { 354c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return strchr(HTTP_LWS, c) != NULL; 355c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 356c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 357c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid HttpUtil::TrimLWS(string::const_iterator* begin, 358c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott string::const_iterator* end) { 359c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // leading whitespace 360c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while (*begin < *end && IsLWS((*begin)[0])) 361c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ++(*begin); 362c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 363c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // trailing whitespace 364c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while (*begin < *end && IsLWS((*end)[-1])) 365c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott --(*end); 366c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 367c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 368c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 369c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool HttpUtil::IsQuote(char c) { 370c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Single quote mark isn't actually part of quoted-text production, 371c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // but apparently some servers rely on this. 372c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return c == '"' || c == '\''; 373c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 374c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 375c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 376c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstd::string HttpUtil::Unquote(std::string::const_iterator begin, 377c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string::const_iterator end) { 378c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Empty string 379c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (begin == end) 380c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return std::string(); 381c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 382c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Nothing to unquote. 383c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!IsQuote(*begin)) 384c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return std::string(begin, end); 385c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 386c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // No terminal quote mark. 387c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (end - begin < 2 || *begin != *(end - 1)) 388c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return std::string(begin, end); 389c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 390c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Strip quotemarks 391c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ++begin; 392c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott --end; 393c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 394c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Unescape quoted-pair (defined in RFC 2616 section 2.2) 395c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string unescaped; 396c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott bool prev_escape = false; 397c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott for (; begin != end; ++begin) { 398c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char c = *begin; 399c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (c == '\\' && !prev_escape) { 400c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott prev_escape = true; 401c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott continue; 402c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 403c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott prev_escape = false; 404c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott unescaped.push_back(c); 405c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 406c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return unescaped; 407c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 408c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 409c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 410c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstd::string HttpUtil::Unquote(const std::string& str) { 411c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return Unquote(str.begin(), str.end()); 412c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 413c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 414c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 415c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstd::string HttpUtil::Quote(const std::string& str) { 416c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string escaped; 417c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott escaped.reserve(2 + str.size()); 418c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 419c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string::const_iterator begin = str.begin(); 420c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string::const_iterator end = str.end(); 421c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 422c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Esape any backslashes or quotemarks within the string, and 423c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // then surround with quotes. 424c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott escaped.push_back('"'); 425c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott for (; begin != end; ++begin) { 426c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char c = *begin; 427c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (c == '"' || c == '\\') 428c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott escaped.push_back('\\'); 429c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott escaped.push_back(c); 430c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 431c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott escaped.push_back('"'); 432c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return escaped; 433c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 434c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 435c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Find the "http" substring in a status line. This allows for 436c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// some slop at the start. If the "http" string could not be found 437c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// then returns -1. 438c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 439c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint HttpUtil::LocateStartOfStatusLine(const char* buf, int buf_len) { 440c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const int slop = 4; 441c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const int http_len = 4; 442872788f42523a0c05bc2fb43623d42344a247f2aKristian Monsen#ifdef ANDROID 443872788f42523a0c05bc2fb43623d42344a247f2aKristian Monsen const int icy_len = 3; 444872788f42523a0c05bc2fb43623d42344a247f2aKristian Monsen#endif 445c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 446c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (buf_len >= http_len) { 447c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int i_max = std::min(buf_len - http_len, slop); 448c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott for (int i = 0; i <= i_max; ++i) { 449c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (LowerCaseEqualsASCII(buf + i, buf + i + http_len, "http")) 450c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return i; 451872788f42523a0c05bc2fb43623d42344a247f2aKristian Monsen#ifdef ANDROID 452872788f42523a0c05bc2fb43623d42344a247f2aKristian Monsen if (LowerCaseEqualsASCII(buf + i, buf + i + icy_len, "icy")) 453872788f42523a0c05bc2fb43623d42344a247f2aKristian Monsen return i; 454872788f42523a0c05bc2fb43623d42344a247f2aKristian Monsen#endif 455c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 456c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 457c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return -1; // Not found 458c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 459c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 460c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint HttpUtil::LocateEndOfHeaders(const char* buf, int buf_len, int i) { 461c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott bool was_lf = false; 462c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char last_c = '\0'; 463c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott for (; i < buf_len; ++i) { 464c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char c = buf[i]; 465c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (c == '\n') { 466c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (was_lf) 467c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return i + 1; 468c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott was_lf = true; 469c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else if (c != '\r' || last_c != '\n') { 470c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott was_lf = false; 471c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 472c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott last_c = c; 473c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 474c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return -1; 475c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 476c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 477c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// In order for a line to be continuable, it must specify a 478c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// non-blank header-name. Line continuations are specifically for 479c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// header values -- do not allow headers names to span lines. 480c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic bool IsLineSegmentContinuable(const char* begin, const char* end) { 481c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (begin == end) 482c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 483c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 484c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const char* colon = std::find(begin, end, ':'); 485c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (colon == end) 486c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 487c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 488c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const char* name_begin = begin; 489c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const char* name_end = colon; 490c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 491c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Name can't be empty. 492c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (name_begin == name_end) 493c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 494c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 495c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Can't start with LWS (this would imply the segment is a continuation) 496c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (HttpUtil::IsLWS(*name_begin)) 497c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 498c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 499c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 500c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 501c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 502c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Helper used by AssembleRawHeaders, to find the end of the status line. 503c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const char* FindStatusLineEnd(const char* begin, const char* end) { 504c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t i = base::StringPiece(begin, end - begin).find_first_of("\r\n"); 505c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (i == base::StringPiece::npos) 506c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return end; 507c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return begin + i; 508c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 509c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 510c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Helper used by AssembleRawHeaders, to skip past leading LWS. 511c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const char* FindFirstNonLWS(const char* begin, const char* end) { 512c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott for (const char* cur = begin; cur != end; ++cur) { 513c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!HttpUtil::IsLWS(*cur)) 514c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return cur; 515c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 516c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return end; // Not found. 517c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 518c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 519c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstd::string HttpUtil::AssembleRawHeaders(const char* input_begin, 520c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int input_len) { 521c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string raw_headers; 522c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott raw_headers.reserve(input_len); 523c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 524c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const char* input_end = input_begin + input_len; 525c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 526c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Skip any leading slop, since the consumers of this output 527c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // (HttpResponseHeaders) don't deal with it. 528c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int status_begin_offset = LocateStartOfStatusLine(input_begin, input_len); 529c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (status_begin_offset != -1) 530c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott input_begin += status_begin_offset; 531c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 532c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Copy the status line. 533c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const char* status_line_end = FindStatusLineEnd(input_begin, input_end); 534c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott raw_headers.append(input_begin, status_line_end); 535c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 536c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // After the status line, every subsequent line is a header line segment. 537c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Should a segment start with LWS, it is a continuation of the previous 538c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // line's field-value. 539c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 540c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // TODO(ericroman): is this too permissive? (delimits on [\r\n]+) 541c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott CStringTokenizer lines(status_line_end, input_end, "\r\n"); 542c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 543c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // This variable is true when the previous line was continuable. 544c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott bool prev_line_continuable = false; 545c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 546c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while (lines.GetNext()) { 547c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const char* line_begin = lines.token_begin(); 548c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const char* line_end = lines.token_end(); 549c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 550c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (prev_line_continuable && IsLWS(*line_begin)) { 551c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Join continuation; reduce the leading LWS to a single SP. 552c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott raw_headers.push_back(' '); 553c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott raw_headers.append(FindFirstNonLWS(line_begin, line_end), line_end); 554c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else { 555c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Terminate the previous line. 556c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott raw_headers.push_back('\0'); 557c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 558c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Copy the raw data to output. 559c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott raw_headers.append(line_begin, line_end); 560c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 561c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Check if the current line can be continued. 562c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott prev_line_continuable = IsLineSegmentContinuable(line_begin, line_end); 563c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 564c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 565c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 566c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott raw_headers.append("\0\0", 2); 567c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return raw_headers; 568c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 569c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 570c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// TODO(jungshik): 1. If the list is 'fr-CA,fr-FR,en,de', we have to add 571c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 'fr' after 'fr-CA' with the same q-value as 'fr-CA' because 572c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// web servers, in general, do not fall back to 'fr' and may end up picking 573c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 'en' which has a lower preference than 'fr-CA' and 'fr-FR'. 574c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 2. This function assumes that the input is a comma separated list 575c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// without any whitespace. As long as it comes from the preference and 576c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// a user does not manually edit the preference file, it's the case. Still, 577c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// we may have to make it more robust. 578c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstd::string HttpUtil::GenerateAcceptLanguageHeader( 579c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const std::string& raw_language_list) { 580c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // We use integers for qvalue and qvalue decrement that are 10 times 581c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // larger than actual values to avoid a problem with comparing 582c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // two floating point numbers. 583c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const unsigned int kQvalueDecrement10 = 2; 584c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott unsigned int qvalue10 = 10; 585c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott StringTokenizer t(raw_language_list, ","); 586c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string lang_list_with_q; 587c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while (t.GetNext()) { 588c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string language = t.token(); 589c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (qvalue10 == 10) { 590c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // q=1.0 is implicit. 591c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott lang_list_with_q = language; 592c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else { 593c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_LT(qvalue10, 10U); 5944a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch base::StringAppendF(&lang_list_with_q, ",%s;q=0.%d", language.c_str(), 5954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch qvalue10); 596c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 597c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // It does not make sense to have 'q=0'. 598c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (qvalue10 > kQvalueDecrement10) 599c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott qvalue10 -= kQvalueDecrement10; 600c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 601c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return lang_list_with_q; 602c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 603c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 604c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstd::string HttpUtil::GenerateAcceptCharsetHeader(const std::string& charset) { 605c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string charset_with_q = charset; 606c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (LowerCaseEqualsASCII(charset, "utf-8")) { 607c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott charset_with_q += ",*;q=0.5"; 608c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else { 609c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott charset_with_q += ",utf-8;q=0.7,*;q=0.3"; 610c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 611c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return charset_with_q; 612c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 613c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 614c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid HttpUtil::AppendHeaderIfMissing(const char* header_name, 615c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const std::string& header_value, 616c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::string* headers) { 617c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (header_value.empty()) 618c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 619c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (net::HttpUtil::HasHeader(*headers, header_name)) 620c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 621c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *headers += std::string(header_name) + ": " + header_value + "\r\n"; 622c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 623c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 624c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// BNF from section 4.2 of RFC 2616: 625c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 626c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// message-header = field-name ":" [ field-value ] 627c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// field-name = token 628c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// field-value = *( field-content | LWS ) 629c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// field-content = <the OCTETs making up the field-value 630c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// and consisting of either *TEXT or combinations 631c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// of token, separators, and quoted-string> 632c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 633c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 634c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottHttpUtil::HeadersIterator::HeadersIterator(string::const_iterator headers_begin, 635c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott string::const_iterator headers_end, 636c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const std::string& line_delimiter) 637c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott : lines_(headers_begin, headers_end, line_delimiter) { 638c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 639c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 6403345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickHttpUtil::HeadersIterator::~HeadersIterator() { 6413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 6423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 643c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool HttpUtil::HeadersIterator::GetNext() { 644c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while (lines_.GetNext()) { 645c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott name_begin_ = lines_.token_begin(); 646c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott values_end_ = lines_.token_end(); 647c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 648c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott string::const_iterator colon = find(name_begin_, values_end_, ':'); 649c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (colon == values_end_) 650c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott continue; // skip malformed header 651c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 652c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott name_end_ = colon; 653c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 654c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // If the name starts with LWS, it is an invalid line. 655c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Leading LWS implies a line continuation, and these should have 656c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // already been joined by AssembleRawHeaders(). 657c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (name_begin_ == name_end_ || IsLWS(*name_begin_)) 658c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott continue; 659c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 660c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott TrimLWS(&name_begin_, &name_end_); 661c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (name_begin_ == name_end_) 662c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott continue; // skip malformed header 663c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 664c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott values_begin_ = colon + 1; 665c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott TrimLWS(&values_begin_, &values_end_); 666c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 667c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // if we got a header name, then we are done. 668c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 669c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 670c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 671c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 672c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 673c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool HttpUtil::HeadersIterator::AdvanceTo(const char* name) { 674c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(name != NULL); 675c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_EQ(0, StringToLowerASCII<std::string>(name).compare(name)) 676c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott << "the header name must be in all lower case"; 677c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 678c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while (GetNext()) { 679c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (LowerCaseEqualsASCII(name_begin_, name_end_, name)) { 680c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 681c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 682c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 683c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 684c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 685c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 686c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 687c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottHttpUtil::ValuesIterator::ValuesIterator( 688c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott string::const_iterator values_begin, 689c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott string::const_iterator values_end, 690c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char delimiter) 691c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott : values_(values_begin, values_end, string(1, delimiter)) { 692c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott values_.set_quote_chars("\'\""); 693c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 694c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 6953345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickHttpUtil::ValuesIterator::~ValuesIterator() { 6963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 6973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 698c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool HttpUtil::ValuesIterator::GetNext() { 699c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while (values_.GetNext()) { 700c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott value_begin_ = values_.token_begin(); 701c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott value_end_ = values_.token_end(); 702c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott TrimLWS(&value_begin_, &value_end_); 703c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 704c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // bypass empty values. 705c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (value_begin_ != value_end_) 706c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 707c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 708c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 709c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 710c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 711731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickHttpUtil::NameValuePairsIterator::NameValuePairsIterator( 712731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick string::const_iterator begin, 713731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick string::const_iterator end, 714731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick char delimiter) 715731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick : props_(begin, end, delimiter), 716731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick valid_(true), 717731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick begin_(begin), 718731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick end_(end), 719731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick name_begin_(end), 720731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick name_end_(end), 721731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick value_begin_(end), 722731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick value_end_(end), 723731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick value_is_quoted_(false) { 724731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 725731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 7263f50c38dc070f4bb515c1b64450dae14f316474eKristian MonsenHttpUtil::NameValuePairsIterator::~NameValuePairsIterator() {} 7273f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 728731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// We expect properties to be formatted as one of: 729731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// name="value" 730731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// name='value' 731731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// name='\'value\'' 732731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// name=value 733731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// name = value 734731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// name= 735731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Due to buggy implementations found in some embedded devices, we also 736731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// accept values with missing close quotemark (http://crbug.com/39836): 737731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// name="value 738731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool HttpUtil::NameValuePairsIterator::GetNext() { 739731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (!props_.GetNext()) 740731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return false; 741731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 742731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Set the value as everything. Next we will split out the name. 743731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick value_begin_ = props_.value_begin(); 744731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick value_end_ = props_.value_end(); 745731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick name_begin_ = name_end_ = value_end_; 746731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 747731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Scan for the equals sign. 748731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick std::string::const_iterator equals = std::find(value_begin_, value_end_, '='); 749731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (equals == value_end_ || equals == value_begin_) 750513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch return valid_ = false; // Malformed, no equals sign 751731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 752731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Verify that the equals sign we found wasn't inside of quote marks. 753731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick for (std::string::const_iterator it = value_begin_; it != equals; ++it) { 754731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (HttpUtil::IsQuote(*it)) 755513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch return valid_ = false; // Malformed, quote appears before equals sign 756731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 757731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 758731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick name_begin_ = value_begin_; 759731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick name_end_ = equals; 760731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick value_begin_ = equals + 1; 761731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 762731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick TrimLWS(&name_begin_, &name_end_); 763731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick TrimLWS(&value_begin_, &value_end_); 764731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick value_is_quoted_ = false; 765513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch unquoted_value_.clear(); 766513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 767513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (value_begin_ == value_end_) 768513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch return valid_ = false; // Malformed, value is empty 769513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 770513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (HttpUtil::IsQuote(*value_begin_)) { 771731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Trim surrounding quotemarks off the value 772513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (*value_begin_ != *(value_end_ - 1) || value_begin_ + 1 == value_end_) { 773731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // NOTE: This is not as graceful as it sounds: 774731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // * quoted-pairs will no longer be unquoted 775731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // (["\"hello] should give ["hello]). 776731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // * Does not detect when the final quote is escaped 777731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // (["value\"] should give [value"]) 778731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ++value_begin_; // Gracefully recover from mismatching quotes. 779513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch } else { 780731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick value_is_quoted_ = true; 781513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // Do not store iterators into this. See declaration of unquoted_value_. 782513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch unquoted_value_ = HttpUtil::Unquote(value_begin_, value_end_); 783513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch } 784731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 785731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 786731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return true; 787731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 788731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 789c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} // namespace net 790