| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // The rules for parsing content-types were borrowed from Firefox: | 5 // The rules for parsing content-types were borrowed from Firefox: |
| 6 // http://lxr.mozilla.org/mozilla/source/netwerk/base/src/nsURLHelper.cpp#834 | 6 // http://lxr.mozilla.org/mozilla/source/netwerk/base/src/nsURLHelper.cpp#834 |
| 7 | 7 |
| 8 #include "net/http/http_util.h" | 8 #include "net/http/http_util.h" |
| 9 | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| 11 | 11 |
| 12 #include "base/basictypes.h" | 12 #include "base/basictypes.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/strings/string_number_conversions.h" | 14 #include "base/strings/string_number_conversions.h" |
| 15 #include "base/strings/string_piece.h" | 15 #include "base/strings/string_piece.h" |
| 16 #include "base/strings/string_tokenizer.h" | 16 #include "base/strings/string_tokenizer.h" |
| 17 #include "base/strings/string_util.h" | 17 #include "base/strings/string_util.h" |
| 18 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
| 19 #include "base/time/time.h" | 19 #include "base/time/time.h" |
| 20 | 20 |
| 21 | |
| 22 namespace net { | 21 namespace net { |
| 23 | 22 |
| 24 // Helpers -------------------------------------------------------------------- | 23 // Helpers -------------------------------------------------------------------- |
| 25 | 24 |
| 26 // Returns the index of the closing quote of the string, if any. |start| points | 25 // Returns the index of the closing quote of the string, if any. |start| points |
| 27 // at the opening quote. | 26 // at the opening quote. |
| 28 static size_t FindStringEnd(const std::string& line, size_t start, char delim) { | 27 static size_t FindStringEnd(const std::string& line, size_t start, char delim) { |
| 29 DCHECK_LT(start, line.length()); | 28 DCHECK_LT(start, line.length()); |
| 30 DCHECK_EQ(line[start], delim); | 29 DCHECK_EQ(line[start], delim); |
| 31 DCHECK((delim == '"') || (delim == '\'')); | 30 DCHECK((delim == '"') || (delim == '\'')); |
| 32 | 31 |
| 33 const char set[] = { delim, '\\', '\0' }; | 32 const char set[] = {delim, '\\', '\0'}; |
| 34 for (size_t end = line.find_first_of(set, start + 1); | 33 for (size_t end = line.find_first_of(set, start + 1); |
| 35 end != std::string::npos; end = line.find_first_of(set, end + 2)) { | 34 end != std::string::npos; |
| 35 end = line.find_first_of(set, end + 2)) { |
| 36 if (line[end] != '\\') | 36 if (line[end] != '\\') |
| 37 return end; | 37 return end; |
| 38 } | 38 } |
| 39 return line.length(); | 39 return line.length(); |
| 40 } | 40 } |
| 41 | 41 |
| 42 | |
| 43 // HttpUtil ------------------------------------------------------------------- | 42 // HttpUtil ------------------------------------------------------------------- |
| 44 | 43 |
| 45 // static | 44 // static |
| 46 size_t HttpUtil::FindDelimiter(const std::string& line, | 45 size_t HttpUtil::FindDelimiter(const std::string& line, |
| 47 size_t search_start, | 46 size_t search_start, |
| 48 char delimiter) { | 47 char delimiter) { |
| 49 do { | 48 do { |
| 50 // search_start points to the spot from which we should start looking | 49 // search_start points to the spot from which we should start looking |
| 51 // for the delimiter. | 50 // for the delimiter. |
| 52 const char delim_str[] = { delimiter, '"', '\'', '\0' }; | 51 const char delim_str[] = {delimiter, '"', '\'', '\0'}; |
| 53 size_t cur_delim_pos = line.find_first_of(delim_str, search_start); | 52 size_t cur_delim_pos = line.find_first_of(delim_str, search_start); |
| 54 if (cur_delim_pos == std::string::npos) | 53 if (cur_delim_pos == std::string::npos) |
| 55 return line.length(); | 54 return line.length(); |
| 56 | 55 |
| 57 char ch = line[cur_delim_pos]; | 56 char ch = line[cur_delim_pos]; |
| 58 if (ch == delimiter) { | 57 if (ch == delimiter) { |
| 59 // Found delimiter | 58 // Found delimiter |
| 60 return cur_delim_pos; | 59 return cur_delim_pos; |
| 61 } | 60 } |
| 62 | 61 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 93 if (type_end == std::string::npos) | 92 if (type_end == std::string::npos) |
| 94 type_end = content_type_str.length(); | 93 type_end = content_type_str.length(); |
| 95 | 94 |
| 96 size_t charset_val = 0; | 95 size_t charset_val = 0; |
| 97 size_t charset_end = 0; | 96 size_t charset_end = 0; |
| 98 bool type_has_charset = false; | 97 bool type_has_charset = false; |
| 99 | 98 |
| 100 // Iterate over parameters | 99 // Iterate over parameters |
| 101 size_t param_start = content_type_str.find_first_of(';', type_end); | 100 size_t param_start = content_type_str.find_first_of(';', type_end); |
| 102 if (param_start != std::string::npos) { | 101 if (param_start != std::string::npos) { |
| 103 base::StringTokenizer tokenizer(begin + param_start, content_type_str.end(), | 102 base::StringTokenizer tokenizer( |
| 104 ";"); | 103 begin + param_start, content_type_str.end(), ";"); |
| 105 tokenizer.set_quote_chars("\""); | 104 tokenizer.set_quote_chars("\""); |
| 106 while (tokenizer.GetNext()) { | 105 while (tokenizer.GetNext()) { |
| 107 std::string::const_iterator equals_sign = | 106 std::string::const_iterator equals_sign = |
| 108 std::find(tokenizer.token_begin(), tokenizer.token_end(), '='); | 107 std::find(tokenizer.token_begin(), tokenizer.token_end(), '='); |
| 109 if (equals_sign == tokenizer.token_end()) | 108 if (equals_sign == tokenizer.token_end()) |
| 110 continue; | 109 continue; |
| 111 | 110 |
| 112 std::string::const_iterator param_name_begin = tokenizer.token_begin(); | 111 std::string::const_iterator param_name_begin = tokenizer.token_begin(); |
| 113 std::string::const_iterator param_name_end = equals_sign; | 112 std::string::const_iterator param_name_end = equals_sign; |
| 114 TrimLWS(¶m_name_begin, ¶m_name_end); | 113 TrimLWS(¶m_name_begin, ¶m_name_end); |
| 115 | 114 |
| 116 std::string::const_iterator param_value_begin = equals_sign + 1; | 115 std::string::const_iterator param_value_begin = equals_sign + 1; |
| 117 std::string::const_iterator param_value_end = tokenizer.token_end(); | 116 std::string::const_iterator param_value_end = tokenizer.token_end(); |
| 118 DCHECK(param_value_begin <= tokenizer.token_end()); | 117 DCHECK(param_value_begin <= tokenizer.token_end()); |
| 119 TrimLWS(¶m_value_begin, ¶m_value_end); | 118 TrimLWS(¶m_value_begin, ¶m_value_end); |
| 120 | 119 |
| 121 if (LowerCaseEqualsASCII(param_name_begin, param_name_end, "charset")) { | 120 if (LowerCaseEqualsASCII(param_name_begin, param_name_end, "charset")) { |
| 122 // TODO(abarth): Refactor this function to consistently use iterators. | 121 // TODO(abarth): Refactor this function to consistently use iterators. |
| 123 charset_val = param_value_begin - begin; | 122 charset_val = param_value_begin - begin; |
| 124 charset_end = param_value_end - begin; | 123 charset_end = param_value_end - begin; |
| 125 type_has_charset = true; | 124 type_has_charset = true; |
| 126 } else if (LowerCaseEqualsASCII(param_name_begin, param_name_end, | 125 } else if (LowerCaseEqualsASCII( |
| 127 "boundary")) { | 126 param_name_begin, param_name_end, "boundary")) { |
| 128 if (boundary) | 127 if (boundary) |
| 129 boundary->assign(param_value_begin, param_value_end); | 128 boundary->assign(param_value_begin, param_value_end); |
| 130 } | 129 } |
| 131 } | 130 } |
| 132 } | 131 } |
| 133 | 132 |
| 134 if (type_has_charset) { | 133 if (type_has_charset) { |
| 135 // Trim leading and trailing whitespace from charset_val. We include | 134 // Trim leading and trailing whitespace from charset_val. We include |
| 136 // '(' in the trailing trim set to catch media-type comments, which are | 135 // '(' in the trailing trim set to catch media-type comments, which are |
| 137 // not at all standard, but may occur in rare cases. | 136 // not at all standard, but may occur in rare cases. |
| 138 charset_val = content_type_str.find_first_not_of(HTTP_LWS, charset_val); | 137 charset_val = content_type_str.find_first_not_of(HTTP_LWS, charset_val); |
| 139 charset_val = std::min(charset_val, charset_end); | 138 charset_val = std::min(charset_val, charset_end); |
| 140 char first_char = content_type_str[charset_val]; | 139 char first_char = content_type_str[charset_val]; |
| 141 if (first_char == '"' || first_char == '\'') { | 140 if (first_char == '"' || first_char == '\'') { |
| 142 charset_end = FindStringEnd(content_type_str, charset_val, first_char); | 141 charset_end = FindStringEnd(content_type_str, charset_val, first_char); |
| 143 ++charset_val; | 142 ++charset_val; |
| 144 DCHECK(charset_end >= charset_val); | 143 DCHECK(charset_end >= charset_val); |
| 145 } else { | 144 } else { |
| 146 charset_end = std::min(content_type_str.find_first_of(HTTP_LWS ";(", | 145 charset_end = |
| 147 charset_val), | 146 std::min(content_type_str.find_first_of(HTTP_LWS ";(", charset_val), |
| 148 charset_end); | 147 charset_end); |
| 149 } | 148 } |
| 150 } | 149 } |
| 151 | 150 |
| 152 // if the server sent "*/*", it is meaningless, so do not store it. | 151 // if the server sent "*/*", it is meaningless, so do not store it. |
| 153 // also, if type_val is the same as mime_type, then just update the | 152 // also, if type_val is the same as mime_type, then just update the |
| 154 // charset. however, if charset is empty and mime_type hasn't | 153 // charset. however, if charset is empty and mime_type hasn't |
| 155 // changed, then don't wipe-out an existing charset. We | 154 // changed, then don't wipe-out an existing charset. We |
| 156 // also want to reject a mime-type if it does not include a slash. | 155 // also want to reject a mime-type if it does not include a slash. |
| 157 // some servers give junk after the charset parameter, which may | 156 // some servers give junk after the charset parameter, which may |
| 158 // include a comma, so this check makes us a bit more tolerant. | 157 // include a comma, so this check makes us a bit more tolerant. |
| 159 if (content_type_str.length() != 0 && | 158 if (content_type_str.length() != 0 && content_type_str != "*/*" && |
| 160 content_type_str != "*/*" && | |
| 161 content_type_str.find_first_of('/') != std::string::npos) { | 159 content_type_str.find_first_of('/') != std::string::npos) { |
| 162 // Common case here is that mime_type is empty | 160 // Common case here is that mime_type is empty |
| 163 bool eq = !mime_type->empty() && LowerCaseEqualsASCII(begin + type_val, | 161 bool eq = !mime_type->empty() && |
| 164 begin + type_end, | 162 LowerCaseEqualsASCII( |
| 165 mime_type->data()); | 163 begin + type_val, begin + type_end, mime_type->data()); |
| 166 if (!eq) { | 164 if (!eq) { |
| 167 mime_type->assign(begin + type_val, begin + type_end); | 165 mime_type->assign(begin + type_val, begin + type_end); |
| 168 StringToLowerASCII(mime_type); | 166 StringToLowerASCII(mime_type); |
| 169 } | 167 } |
| 170 if ((!eq && *had_charset) || type_has_charset) { | 168 if ((!eq && *had_charset) || type_has_charset) { |
| 171 *had_charset = true; | 169 *had_charset = true; |
| 172 charset->assign(begin + charset_val, begin + charset_end); | 170 charset->assign(begin + charset_val, begin + charset_end); |
| 173 StringToLowerASCII(charset); | 171 StringToLowerASCII(charset); |
| 174 } | 172 } |
| 175 } | 173 } |
| (...skipping 29 matching lines...) Expand all Loading... |
| 205 | 203 |
| 206 // static | 204 // static |
| 207 bool HttpUtil::ParseRangeHeader(const std::string& ranges_specifier, | 205 bool HttpUtil::ParseRangeHeader(const std::string& ranges_specifier, |
| 208 std::vector<HttpByteRange>* ranges) { | 206 std::vector<HttpByteRange>* ranges) { |
| 209 size_t equal_char_offset = ranges_specifier.find('='); | 207 size_t equal_char_offset = ranges_specifier.find('='); |
| 210 if (equal_char_offset == std::string::npos) | 208 if (equal_char_offset == std::string::npos) |
| 211 return false; | 209 return false; |
| 212 | 210 |
| 213 // Try to extract bytes-unit part. | 211 // Try to extract bytes-unit part. |
| 214 std::string::const_iterator bytes_unit_begin = ranges_specifier.begin(); | 212 std::string::const_iterator bytes_unit_begin = ranges_specifier.begin(); |
| 215 std::string::const_iterator bytes_unit_end = bytes_unit_begin + | 213 std::string::const_iterator bytes_unit_end = |
| 216 equal_char_offset; | 214 bytes_unit_begin + equal_char_offset; |
| 217 std::string::const_iterator byte_range_set_begin = bytes_unit_end + 1; | 215 std::string::const_iterator byte_range_set_begin = bytes_unit_end + 1; |
| 218 std::string::const_iterator byte_range_set_end = ranges_specifier.end(); | 216 std::string::const_iterator byte_range_set_end = ranges_specifier.end(); |
| 219 | 217 |
| 220 TrimLWS(&bytes_unit_begin, &bytes_unit_end); | 218 TrimLWS(&bytes_unit_begin, &bytes_unit_end); |
| 221 // "bytes" unit identifier is not found. | 219 // "bytes" unit identifier is not found. |
| 222 if (!LowerCaseEqualsASCII(bytes_unit_begin, bytes_unit_end, "bytes")) | 220 if (!LowerCaseEqualsASCII(bytes_unit_begin, bytes_unit_end, "bytes")) |
| 223 return false; | 221 return false; |
| 224 | 222 |
| 225 ValuesIterator byte_range_set_iterator(byte_range_set_begin, | 223 ValuesIterator byte_range_set_iterator( |
| 226 byte_range_set_end, ','); | 224 byte_range_set_begin, byte_range_set_end, ','); |
| 227 while (byte_range_set_iterator.GetNext()) { | 225 while (byte_range_set_iterator.GetNext()) { |
| 228 size_t minus_char_offset = byte_range_set_iterator.value().find('-'); | 226 size_t minus_char_offset = byte_range_set_iterator.value().find('-'); |
| 229 // If '-' character is not found, reports failure. | 227 // If '-' character is not found, reports failure. |
| 230 if (minus_char_offset == std::string::npos) | 228 if (minus_char_offset == std::string::npos) |
| 231 return false; | 229 return false; |
| 232 | 230 |
| 233 std::string::const_iterator first_byte_pos_begin = | 231 std::string::const_iterator first_byte_pos_begin = |
| 234 byte_range_set_iterator.value_begin(); | 232 byte_range_set_iterator.value_begin(); |
| 235 std::string::const_iterator first_byte_pos_end = | 233 std::string::const_iterator first_byte_pos_end = |
| 236 first_byte_pos_begin + minus_char_offset; | 234 first_byte_pos_begin + minus_char_offset; |
| 237 TrimLWS(&first_byte_pos_begin, &first_byte_pos_end); | 235 TrimLWS(&first_byte_pos_begin, &first_byte_pos_end); |
| 238 std::string first_byte_pos(first_byte_pos_begin, first_byte_pos_end); | 236 std::string first_byte_pos(first_byte_pos_begin, first_byte_pos_end); |
| 239 | 237 |
| 240 HttpByteRange range; | 238 HttpByteRange range; |
| 241 // Try to obtain first-byte-pos. | 239 // Try to obtain first-byte-pos. |
| 242 if (!first_byte_pos.empty()) { | 240 if (!first_byte_pos.empty()) { |
| 243 int64 first_byte_position = -1; | 241 int64 first_byte_position = -1; |
| 244 if (!base::StringToInt64(first_byte_pos, &first_byte_position)) | 242 if (!base::StringToInt64(first_byte_pos, &first_byte_position)) |
| 245 return false; | 243 return false; |
| 246 range.set_first_byte_position(first_byte_position); | 244 range.set_first_byte_position(first_byte_position); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 295 return false; | 293 return false; |
| 296 | 294 |
| 297 return true; | 295 return true; |
| 298 } | 296 } |
| 299 | 297 |
| 300 namespace { | 298 namespace { |
| 301 // A header string containing any of the following fields will cause | 299 // A header string containing any of the following fields will cause |
| 302 // an error. The list comes from the XMLHttpRequest standard. | 300 // an error. The list comes from the XMLHttpRequest standard. |
| 303 // http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader-method | 301 // http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader-method |
| 304 const char* const kForbiddenHeaderFields[] = { | 302 const char* const kForbiddenHeaderFields[] = { |
| 305 "accept-charset", | 303 "accept-charset", "accept-encoding", |
| 306 "accept-encoding", | 304 "access-control-request-headers", "access-control-request-method", |
| 307 "access-control-request-headers", | 305 "connection", "content-length", |
| 308 "access-control-request-method", | 306 "cookie", "cookie2", |
| 309 "connection", | 307 "content-transfer-encoding", "date", |
| 310 "content-length", | 308 "expect", "host", |
| 311 "cookie", | 309 "keep-alive", "origin", |
| 312 "cookie2", | 310 "referer", "te", |
| 313 "content-transfer-encoding", | 311 "trailer", "transfer-encoding", |
| 314 "date", | 312 "upgrade", "user-agent", |
| 315 "expect", | 313 "via", |
| 316 "host", | |
| 317 "keep-alive", | |
| 318 "origin", | |
| 319 "referer", | |
| 320 "te", | |
| 321 "trailer", | |
| 322 "transfer-encoding", | |
| 323 "upgrade", | |
| 324 "user-agent", | |
| 325 "via", | |
| 326 }; | 314 }; |
| 327 } // anonymous namespace | 315 } // anonymous namespace |
| 328 | 316 |
| 329 // static | 317 // static |
| 330 bool HttpUtil::IsSafeHeader(const std::string& name) { | 318 bool HttpUtil::IsSafeHeader(const std::string& name) { |
| 331 std::string lower_name(StringToLowerASCII(name)); | 319 std::string lower_name(StringToLowerASCII(name)); |
| 332 if (StartsWithASCII(lower_name, "proxy-", true) || | 320 if (StartsWithASCII(lower_name, "proxy-", true) || |
| 333 StartsWithASCII(lower_name, "sec-", true)) | 321 StartsWithASCII(lower_name, "sec-", true)) |
| 334 return false; | 322 return false; |
| 335 for (size_t i = 0; i < arraysize(kForbiddenHeaderFields); ++i) { | 323 for (size_t i = 0; i < arraysize(kForbiddenHeaderFields); ++i) { |
| 336 if (lower_name == kForbiddenHeaderFields[i]) | 324 if (lower_name == kForbiddenHeaderFields[i]) |
| 337 return false; | 325 return false; |
| 338 } | 326 } |
| 339 return true; | 327 return true; |
| 340 } | 328 } |
| 341 | 329 |
| 342 // static | 330 // static |
| 343 std::string HttpUtil::StripHeaders(const std::string& headers, | 331 std::string HttpUtil::StripHeaders(const std::string& headers, |
| 344 const char* const headers_to_remove[], | 332 const char* const headers_to_remove[], |
| 345 size_t headers_to_remove_len) { | 333 size_t headers_to_remove_len) { |
| 346 std::string stripped_headers; | 334 std::string stripped_headers; |
| 347 net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n"); | 335 net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n"); |
| 348 | 336 |
| 349 while (it.GetNext()) { | 337 while (it.GetNext()) { |
| 350 bool should_remove = false; | 338 bool should_remove = false; |
| 351 for (size_t i = 0; i < headers_to_remove_len; ++i) { | 339 for (size_t i = 0; i < headers_to_remove_len; ++i) { |
| 352 if (LowerCaseEqualsASCII(it.name_begin(), it.name_end(), | 340 if (LowerCaseEqualsASCII( |
| 353 headers_to_remove[i])) { | 341 it.name_begin(), it.name_end(), headers_to_remove[i])) { |
| 354 should_remove = true; | 342 should_remove = true; |
| 355 break; | 343 break; |
| 356 } | 344 } |
| 357 } | 345 } |
| 358 if (!should_remove) { | 346 if (!should_remove) { |
| 359 // Assume that name and values are on the same line. | 347 // Assume that name and values are on the same line. |
| 360 stripped_headers.append(it.name_begin(), it.values_end()); | 348 stripped_headers.append(it.name_begin(), it.values_end()); |
| 361 stripped_headers.append("\r\n"); | 349 stripped_headers.append("\r\n"); |
| 362 } | 350 } |
| 363 } | 351 } |
| 364 return stripped_headers; | 352 return stripped_headers; |
| 365 } | 353 } |
| 366 | 354 |
| 367 // static | 355 // static |
| 368 bool HttpUtil::IsNonCoalescingHeader(std::string::const_iterator name_begin, | 356 bool HttpUtil::IsNonCoalescingHeader(std::string::const_iterator name_begin, |
| 369 std::string::const_iterator name_end) { | 357 std::string::const_iterator name_end) { |
| 370 // NOTE: "set-cookie2" headers do not support expires attributes, so we don't | 358 // NOTE: "set-cookie2" headers do not support expires attributes, so we don't |
| 371 // have to list them here. | 359 // have to list them here. |
| 372 const char* kNonCoalescingHeaders[] = { | 360 const char* kNonCoalescingHeaders[] = { |
| 373 "date", | 361 "date", "expires", "last-modified", |
| 374 "expires", | 362 "location", // See bug 1050541 for details |
| 375 "last-modified", | 363 "retry-after", "set-cookie", |
| 376 "location", // See bug 1050541 for details | 364 // The format of auth-challenges mixes both space separated tokens and |
| 377 "retry-after", | 365 // comma separated properties, so coalescing on comma won't work. |
| 378 "set-cookie", | 366 "www-authenticate", "proxy-authenticate", |
| 379 // The format of auth-challenges mixes both space separated tokens and | 367 // STS specifies that UAs must not process any STS headers after the first |
| 380 // comma separated properties, so coalescing on comma won't work. | 368 // one. |
| 381 "www-authenticate", | 369 "strict-transport-security"}; |
| 382 "proxy-authenticate", | |
| 383 // STS specifies that UAs must not process any STS headers after the first | |
| 384 // one. | |
| 385 "strict-transport-security" | |
| 386 }; | |
| 387 for (size_t i = 0; i < arraysize(kNonCoalescingHeaders); ++i) { | 370 for (size_t i = 0; i < arraysize(kNonCoalescingHeaders); ++i) { |
| 388 if (LowerCaseEqualsASCII(name_begin, name_end, kNonCoalescingHeaders[i])) | 371 if (LowerCaseEqualsASCII(name_begin, name_end, kNonCoalescingHeaders[i])) |
| 389 return true; | 372 return true; |
| 390 } | 373 } |
| 391 return false; | 374 return false; |
| 392 } | 375 } |
| 393 | 376 |
| 394 bool HttpUtil::IsLWS(char c) { | 377 bool HttpUtil::IsLWS(char c) { |
| 395 return strchr(HTTP_LWS, c) != NULL; | 378 return strchr(HTTP_LWS, c) != NULL; |
| 396 } | 379 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 412 return c == '"' || c == '\''; | 395 return c == '"' || c == '\''; |
| 413 } | 396 } |
| 414 | 397 |
| 415 // See RFC 2616 Sec 2.2 for the definition of |token|. | 398 // See RFC 2616 Sec 2.2 for the definition of |token|. |
| 416 bool HttpUtil::IsToken(std::string::const_iterator begin, | 399 bool HttpUtil::IsToken(std::string::const_iterator begin, |
| 417 std::string::const_iterator end) { | 400 std::string::const_iterator end) { |
| 418 if (begin == end) | 401 if (begin == end) |
| 419 return false; | 402 return false; |
| 420 for (std::string::const_iterator iter = begin; iter != end; ++iter) { | 403 for (std::string::const_iterator iter = begin; iter != end; ++iter) { |
| 421 unsigned char c = *iter; | 404 unsigned char c = *iter; |
| 422 if (c >= 0x80 || c <= 0x1F || c == 0x7F || | 405 if (c >= 0x80 || c <= 0x1F || c == 0x7F || c == '(' || c == ')' || |
| 423 c == '(' || c == ')' || c == '<' || c == '>' || c == '@' || | 406 c == '<' || c == '>' || c == '@' || c == ',' || c == ';' || c == ':' || |
| 424 c == ',' || c == ';' || c == ':' || c == '\\' || c == '"' || | 407 c == '\\' || c == '"' || c == '/' || c == '[' || c == ']' || c == '?' || |
| 425 c == '/' || c == '[' || c == ']' || c == '?' || c == '=' || | 408 c == '=' || c == '{' || c == '}' || c == ' ' || c == '\t') |
| 426 c == '{' || c == '}' || c == ' ' || c == '\t') | |
| 427 return false; | 409 return false; |
| 428 } | 410 } |
| 429 return true; | 411 return true; |
| 430 } | 412 } |
| 431 | 413 |
| 432 std::string HttpUtil::Unquote(std::string::const_iterator begin, | 414 std::string HttpUtil::Unquote(std::string::const_iterator begin, |
| 433 std::string::const_iterator end) { | 415 std::string::const_iterator end) { |
| 434 // Empty string | 416 // Empty string |
| 435 if (begin == end) | 417 if (begin == end) |
| 436 return std::string(); | 418 return std::string(); |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 653 unsigned int qvalue10 = 10; | 635 unsigned int qvalue10 = 10; |
| 654 base::StringTokenizer t(raw_language_list, ","); | 636 base::StringTokenizer t(raw_language_list, ","); |
| 655 std::string lang_list_with_q; | 637 std::string lang_list_with_q; |
| 656 while (t.GetNext()) { | 638 while (t.GetNext()) { |
| 657 std::string language = t.token(); | 639 std::string language = t.token(); |
| 658 if (qvalue10 == 10) { | 640 if (qvalue10 == 10) { |
| 659 // q=1.0 is implicit. | 641 // q=1.0 is implicit. |
| 660 lang_list_with_q = language; | 642 lang_list_with_q = language; |
| 661 } else { | 643 } else { |
| 662 DCHECK_LT(qvalue10, 10U); | 644 DCHECK_LT(qvalue10, 10U); |
| 663 base::StringAppendF(&lang_list_with_q, ",%s;q=0.%d", language.c_str(), | 645 base::StringAppendF( |
| 664 qvalue10); | 646 &lang_list_with_q, ",%s;q=0.%d", language.c_str(), qvalue10); |
| 665 } | 647 } |
| 666 // It does not make sense to have 'q=0'. | 648 // It does not make sense to have 'q=0'. |
| 667 if (qvalue10 > kQvalueDecrement10) | 649 if (qvalue10 > kQvalueDecrement10) |
| 668 qvalue10 -= kQvalueDecrement10; | 650 qvalue10 -= kQvalueDecrement10; |
| 669 } | 651 } |
| 670 return lang_list_with_q; | 652 return lang_list_with_q; |
| 671 } | 653 } |
| 672 | 654 |
| 673 void HttpUtil::AppendHeaderIfMissing(const char* header_name, | 655 void HttpUtil::AppendHeaderIfMissing(const char* header_name, |
| 674 const std::string& header_value, | 656 const std::string& header_value, |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 716 // ones are not sent in practice, to reduce upload size & memory use. | 698 // ones are not sent in practice, to reduce upload size & memory use. |
| 717 | 699 |
| 718 enum { | 700 enum { |
| 719 HISTOGRAM_MIN_HTTP_STATUS_CODE = 100, | 701 HISTOGRAM_MIN_HTTP_STATUS_CODE = 100, |
| 720 HISTOGRAM_MAX_HTTP_STATUS_CODE = 599, | 702 HISTOGRAM_MAX_HTTP_STATUS_CODE = 599, |
| 721 }; | 703 }; |
| 722 | 704 |
| 723 // static | 705 // static |
| 724 std::vector<int> HttpUtil::GetStatusCodesForHistogram() { | 706 std::vector<int> HttpUtil::GetStatusCodesForHistogram() { |
| 725 std::vector<int> codes; | 707 std::vector<int> codes; |
| 726 codes.reserve( | 708 codes.reserve(HISTOGRAM_MAX_HTTP_STATUS_CODE - |
| 727 HISTOGRAM_MAX_HTTP_STATUS_CODE - HISTOGRAM_MIN_HTTP_STATUS_CODE + 2); | 709 HISTOGRAM_MIN_HTTP_STATUS_CODE + 2); |
| 728 codes.push_back(0); | 710 codes.push_back(0); |
| 729 for (int i = HISTOGRAM_MIN_HTTP_STATUS_CODE; | 711 for (int i = HISTOGRAM_MIN_HTTP_STATUS_CODE; |
| 730 i <= HISTOGRAM_MAX_HTTP_STATUS_CODE; ++i) | 712 i <= HISTOGRAM_MAX_HTTP_STATUS_CODE; |
| 713 ++i) |
| 731 codes.push_back(i); | 714 codes.push_back(i); |
| 732 return codes; | 715 return codes; |
| 733 } | 716 } |
| 734 | 717 |
| 735 // static | 718 // static |
| 736 int HttpUtil::MapStatusCodeForHistogram(int code) { | 719 int HttpUtil::MapStatusCodeForHistogram(int code) { |
| 737 if (HISTOGRAM_MIN_HTTP_STATUS_CODE <= code && | 720 if (HISTOGRAM_MIN_HTTP_STATUS_CODE <= code && |
| 738 code <= HISTOGRAM_MAX_HTTP_STATUS_CODE) | 721 code <= HISTOGRAM_MAX_HTTP_STATUS_CODE) |
| 739 return code; | 722 return code; |
| 740 return 0; | 723 return 0; |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 834 char delimiter) | 817 char delimiter) |
| 835 : props_(begin, end, delimiter), | 818 : props_(begin, end, delimiter), |
| 836 valid_(true), | 819 valid_(true), |
| 837 name_begin_(end), | 820 name_begin_(end), |
| 838 name_end_(end), | 821 name_end_(end), |
| 839 value_begin_(end), | 822 value_begin_(end), |
| 840 value_end_(end), | 823 value_end_(end), |
| 841 value_is_quoted_(false) { | 824 value_is_quoted_(false) { |
| 842 } | 825 } |
| 843 | 826 |
| 844 HttpUtil::NameValuePairsIterator::~NameValuePairsIterator() {} | 827 HttpUtil::NameValuePairsIterator::~NameValuePairsIterator() { |
| 828 } |
| 845 | 829 |
| 846 // We expect properties to be formatted as one of: | 830 // We expect properties to be formatted as one of: |
| 847 // name="value" | 831 // name="value" |
| 848 // name='value' | 832 // name='value' |
| 849 // name='\'value\'' | 833 // name='\'value\'' |
| 850 // name=value | 834 // name=value |
| 851 // name = value | 835 // name = value |
| 852 // name= | 836 // name= |
| 853 // Due to buggy implementations found in some embedded devices, we also | 837 // Due to buggy implementations found in some embedded devices, we also |
| 854 // accept values with missing close quotemark (http://crbug.com/39836): | 838 // accept values with missing close quotemark (http://crbug.com/39836): |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 898 value_is_quoted_ = true; | 882 value_is_quoted_ = true; |
| 899 // Do not store iterators into this. See declaration of unquoted_value_. | 883 // Do not store iterators into this. See declaration of unquoted_value_. |
| 900 unquoted_value_ = HttpUtil::Unquote(value_begin_, value_end_); | 884 unquoted_value_ = HttpUtil::Unquote(value_begin_, value_end_); |
| 901 } | 885 } |
| 902 } | 886 } |
| 903 | 887 |
| 904 return true; | 888 return true; |
| 905 } | 889 } |
| 906 | 890 |
| 907 } // namespace net | 891 } // namespace net |
| OLD | NEW |