| 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> |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 111 | 111 |
| 112 std::string::const_iterator param_name_begin = tokenizer.token_begin(); | 112 std::string::const_iterator param_name_begin = tokenizer.token_begin(); |
| 113 std::string::const_iterator param_name_end = equals_sign; | 113 std::string::const_iterator param_name_end = equals_sign; |
| 114 TrimLWS(¶m_name_begin, ¶m_name_end); | 114 TrimLWS(¶m_name_begin, ¶m_name_end); |
| 115 | 115 |
| 116 std::string::const_iterator param_value_begin = equals_sign + 1; | 116 std::string::const_iterator param_value_begin = equals_sign + 1; |
| 117 std::string::const_iterator param_value_end = tokenizer.token_end(); | 117 std::string::const_iterator param_value_end = tokenizer.token_end(); |
| 118 DCHECK(param_value_begin <= tokenizer.token_end()); | 118 DCHECK(param_value_begin <= tokenizer.token_end()); |
| 119 TrimLWS(¶m_value_begin, ¶m_value_end); | 119 TrimLWS(¶m_value_begin, ¶m_value_end); |
| 120 | 120 |
| 121 if (base::LowerCaseEqualsASCII(param_name_begin, param_name_end, | 121 if (LowerCaseEqualsASCII(param_name_begin, param_name_end, "charset")) { |
| 122 "charset")) { | |
| 123 // TODO(abarth): Refactor this function to consistently use iterators. | 122 // TODO(abarth): Refactor this function to consistently use iterators. |
| 124 charset_val = param_value_begin - begin; | 123 charset_val = param_value_begin - begin; |
| 125 charset_end = param_value_end - begin; | 124 charset_end = param_value_end - begin; |
| 126 type_has_charset = true; | 125 type_has_charset = true; |
| 127 } else if (base::LowerCaseEqualsASCII(param_name_begin, param_name_end, | 126 } else if (LowerCaseEqualsASCII(param_name_begin, param_name_end, |
| 128 "boundary")) { | 127 "boundary")) { |
| 129 if (boundary) | 128 if (boundary) |
| 130 boundary->assign(param_value_begin, param_value_end); | 129 boundary->assign(param_value_begin, param_value_end); |
| 131 } | 130 } |
| 132 } | 131 } |
| 133 } | 132 } |
| 134 | 133 |
| 135 if (type_has_charset) { | 134 if (type_has_charset) { |
| 136 // Trim leading and trailing whitespace from charset_val. We include | 135 // Trim leading and trailing whitespace from charset_val. We include |
| 137 // '(' in the trailing trim set to catch media-type comments, which are | 136 // '(' in the trailing trim set to catch media-type comments, which are |
| 138 // not at all standard, but may occur in rare cases. | 137 // not at all standard, but may occur in rare cases. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 154 // also, if type_val is the same as mime_type, then just update the | 153 // also, if type_val is the same as mime_type, then just update the |
| 155 // charset. however, if charset is empty and mime_type hasn't | 154 // charset. however, if charset is empty and mime_type hasn't |
| 156 // changed, then don't wipe-out an existing charset. We | 155 // changed, then don't wipe-out an existing charset. We |
| 157 // also want to reject a mime-type if it does not include a slash. | 156 // also want to reject a mime-type if it does not include a slash. |
| 158 // some servers give junk after the charset parameter, which may | 157 // some servers give junk after the charset parameter, which may |
| 159 // include a comma, so this check makes us a bit more tolerant. | 158 // include a comma, so this check makes us a bit more tolerant. |
| 160 if (content_type_str.length() != 0 && | 159 if (content_type_str.length() != 0 && |
| 161 content_type_str != "*/*" && | 160 content_type_str != "*/*" && |
| 162 content_type_str.find_first_of('/') != std::string::npos) { | 161 content_type_str.find_first_of('/') != std::string::npos) { |
| 163 // Common case here is that mime_type is empty | 162 // Common case here is that mime_type is empty |
| 164 bool eq = !mime_type->empty() && | 163 bool eq = !mime_type->empty() && LowerCaseEqualsASCII(begin + type_val, |
| 165 base::LowerCaseEqualsASCII(begin + type_val, begin + type_end, | 164 begin + type_end, |
| 166 mime_type->data()); | 165 mime_type->data()); |
| 167 if (!eq) { | 166 if (!eq) { |
| 168 mime_type->assign(begin + type_val, begin + type_end); | 167 mime_type->assign(begin + type_val, begin + type_end); |
| 169 base::StringToLowerASCII(mime_type); | 168 base::StringToLowerASCII(mime_type); |
| 170 } | 169 } |
| 171 if ((!eq && *had_charset) || type_has_charset) { | 170 if ((!eq && *had_charset) || type_has_charset) { |
| 172 *had_charset = true; | 171 *had_charset = true; |
| 173 charset->assign(begin + charset_val, begin + charset_end); | 172 charset->assign(begin + charset_val, begin + charset_end); |
| 174 base::StringToLowerASCII(charset); | 173 base::StringToLowerASCII(charset); |
| 175 } | 174 } |
| 176 } | 175 } |
| 177 } | 176 } |
| 178 | 177 |
| 179 // static | 178 // static |
| 180 // Parse the Range header according to RFC 2616 14.35.1 | 179 // Parse the Range header according to RFC 2616 14.35.1 |
| 181 // ranges-specifier = byte-ranges-specifier | 180 // ranges-specifier = byte-ranges-specifier |
| 182 // byte-ranges-specifier = bytes-unit "=" byte-range-set | 181 // byte-ranges-specifier = bytes-unit "=" byte-range-set |
| 183 // byte-range-set = 1#( byte-range-spec | suffix-byte-range-spec ) | 182 // byte-range-set = 1#( byte-range-spec | suffix-byte-range-spec ) |
| 184 // byte-range-spec = first-byte-pos "-" [last-byte-pos] | 183 // byte-range-spec = first-byte-pos "-" [last-byte-pos] |
| 185 // first-byte-pos = 1*DIGIT | 184 // first-byte-pos = 1*DIGIT |
| 186 // last-byte-pos = 1*DIGIT | 185 // last-byte-pos = 1*DIGIT |
| 187 bool HttpUtil::ParseRanges(const std::string& headers, | 186 bool HttpUtil::ParseRanges(const std::string& headers, |
| 188 std::vector<HttpByteRange>* ranges) { | 187 std::vector<HttpByteRange>* ranges) { |
| 189 std::string ranges_specifier; | 188 std::string ranges_specifier; |
| 190 HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n"); | 189 HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n"); |
| 191 | 190 |
| 192 while (it.GetNext()) { | 191 while (it.GetNext()) { |
| 193 // Look for "Range" header. | 192 // Look for "Range" header. |
| 194 if (!base::LowerCaseEqualsASCII(it.name(), "range")) | 193 if (!LowerCaseEqualsASCII(it.name(), "range")) |
| 195 continue; | 194 continue; |
| 196 ranges_specifier = it.values(); | 195 ranges_specifier = it.values(); |
| 197 // We just care about the first "Range" header, so break here. | 196 // We just care about the first "Range" header, so break here. |
| 198 break; | 197 break; |
| 199 } | 198 } |
| 200 | 199 |
| 201 if (ranges_specifier.empty()) | 200 if (ranges_specifier.empty()) |
| 202 return false; | 201 return false; |
| 203 | 202 |
| 204 return ParseRangeHeader(ranges_specifier, ranges); | 203 return ParseRangeHeader(ranges_specifier, ranges); |
| 205 } | 204 } |
| 206 | 205 |
| 207 // static | 206 // static |
| 208 bool HttpUtil::ParseRangeHeader(const std::string& ranges_specifier, | 207 bool HttpUtil::ParseRangeHeader(const std::string& ranges_specifier, |
| 209 std::vector<HttpByteRange>* ranges) { | 208 std::vector<HttpByteRange>* ranges) { |
| 210 size_t equal_char_offset = ranges_specifier.find('='); | 209 size_t equal_char_offset = ranges_specifier.find('='); |
| 211 if (equal_char_offset == std::string::npos) | 210 if (equal_char_offset == std::string::npos) |
| 212 return false; | 211 return false; |
| 213 | 212 |
| 214 // Try to extract bytes-unit part. | 213 // Try to extract bytes-unit part. |
| 215 std::string::const_iterator bytes_unit_begin = ranges_specifier.begin(); | 214 std::string::const_iterator bytes_unit_begin = ranges_specifier.begin(); |
| 216 std::string::const_iterator bytes_unit_end = bytes_unit_begin + | 215 std::string::const_iterator bytes_unit_end = bytes_unit_begin + |
| 217 equal_char_offset; | 216 equal_char_offset; |
| 218 std::string::const_iterator byte_range_set_begin = bytes_unit_end + 1; | 217 std::string::const_iterator byte_range_set_begin = bytes_unit_end + 1; |
| 219 std::string::const_iterator byte_range_set_end = ranges_specifier.end(); | 218 std::string::const_iterator byte_range_set_end = ranges_specifier.end(); |
| 220 | 219 |
| 221 TrimLWS(&bytes_unit_begin, &bytes_unit_end); | 220 TrimLWS(&bytes_unit_begin, &bytes_unit_end); |
| 222 // "bytes" unit identifier is not found. | 221 // "bytes" unit identifier is not found. |
| 223 if (!base::LowerCaseEqualsASCII(bytes_unit_begin, bytes_unit_end, "bytes")) | 222 if (!LowerCaseEqualsASCII(bytes_unit_begin, bytes_unit_end, "bytes")) |
| 224 return false; | 223 return false; |
| 225 | 224 |
| 226 ValuesIterator byte_range_set_iterator(byte_range_set_begin, | 225 ValuesIterator byte_range_set_iterator(byte_range_set_begin, |
| 227 byte_range_set_end, ','); | 226 byte_range_set_end, ','); |
| 228 while (byte_range_set_iterator.GetNext()) { | 227 while (byte_range_set_iterator.GetNext()) { |
| 229 size_t minus_char_offset = byte_range_set_iterator.value().find('-'); | 228 size_t minus_char_offset = byte_range_set_iterator.value().find('-'); |
| 230 // If '-' character is not found, reports failure. | 229 // If '-' character is not found, reports failure. |
| 231 if (minus_char_offset == std::string::npos) | 230 if (minus_char_offset == std::string::npos) |
| 232 return false; | 231 return false; |
| 233 | 232 |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 // static | 342 // static |
| 344 std::string HttpUtil::StripHeaders(const std::string& headers, | 343 std::string HttpUtil::StripHeaders(const std::string& headers, |
| 345 const char* const headers_to_remove[], | 344 const char* const headers_to_remove[], |
| 346 size_t headers_to_remove_len) { | 345 size_t headers_to_remove_len) { |
| 347 std::string stripped_headers; | 346 std::string stripped_headers; |
| 348 net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n"); | 347 net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n"); |
| 349 | 348 |
| 350 while (it.GetNext()) { | 349 while (it.GetNext()) { |
| 351 bool should_remove = false; | 350 bool should_remove = false; |
| 352 for (size_t i = 0; i < headers_to_remove_len; ++i) { | 351 for (size_t i = 0; i < headers_to_remove_len; ++i) { |
| 353 if (base::LowerCaseEqualsASCII(it.name_begin(), it.name_end(), | 352 if (LowerCaseEqualsASCII(it.name_begin(), it.name_end(), |
| 354 headers_to_remove[i])) { | 353 headers_to_remove[i])) { |
| 355 should_remove = true; | 354 should_remove = true; |
| 356 break; | 355 break; |
| 357 } | 356 } |
| 358 } | 357 } |
| 359 if (!should_remove) { | 358 if (!should_remove) { |
| 360 // Assume that name and values are on the same line. | 359 // Assume that name and values are on the same line. |
| 361 stripped_headers.append(it.name_begin(), it.values_end()); | 360 stripped_headers.append(it.name_begin(), it.values_end()); |
| 362 stripped_headers.append("\r\n"); | 361 stripped_headers.append("\r\n"); |
| 363 } | 362 } |
| 364 } | 363 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 379 "set-cookie", | 378 "set-cookie", |
| 380 // The format of auth-challenges mixes both space separated tokens and | 379 // The format of auth-challenges mixes both space separated tokens and |
| 381 // comma separated properties, so coalescing on comma won't work. | 380 // comma separated properties, so coalescing on comma won't work. |
| 382 "www-authenticate", | 381 "www-authenticate", |
| 383 "proxy-authenticate", | 382 "proxy-authenticate", |
| 384 // STS specifies that UAs must not process any STS headers after the first | 383 // STS specifies that UAs must not process any STS headers after the first |
| 385 // one. | 384 // one. |
| 386 "strict-transport-security" | 385 "strict-transport-security" |
| 387 }; | 386 }; |
| 388 for (size_t i = 0; i < arraysize(kNonCoalescingHeaders); ++i) { | 387 for (size_t i = 0; i < arraysize(kNonCoalescingHeaders); ++i) { |
| 389 if (base::LowerCaseEqualsASCII(name_begin, name_end, | 388 if (LowerCaseEqualsASCII(name_begin, name_end, kNonCoalescingHeaders[i])) |
| 390 kNonCoalescingHeaders[i])) | |
| 391 return true; | 389 return true; |
| 392 } | 390 } |
| 393 return false; | 391 return false; |
| 394 } | 392 } |
| 395 | 393 |
| 396 bool HttpUtil::IsLWS(char c) { | 394 bool HttpUtil::IsLWS(char c) { |
| 397 return strchr(HTTP_LWS, c) != NULL; | 395 return strchr(HTTP_LWS, c) != NULL; |
| 398 } | 396 } |
| 399 | 397 |
| 400 void HttpUtil::TrimLWS(std::string::const_iterator* begin, | 398 void HttpUtil::TrimLWS(std::string::const_iterator* begin, |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 494 // some slop at the start. If the "http" string could not be found | 492 // some slop at the start. If the "http" string could not be found |
| 495 // then returns -1. | 493 // then returns -1. |
| 496 // static | 494 // static |
| 497 int HttpUtil::LocateStartOfStatusLine(const char* buf, int buf_len) { | 495 int HttpUtil::LocateStartOfStatusLine(const char* buf, int buf_len) { |
| 498 const int slop = 4; | 496 const int slop = 4; |
| 499 const int http_len = 4; | 497 const int http_len = 4; |
| 500 | 498 |
| 501 if (buf_len >= http_len) { | 499 if (buf_len >= http_len) { |
| 502 int i_max = std::min(buf_len - http_len, slop); | 500 int i_max = std::min(buf_len - http_len, slop); |
| 503 for (int i = 0; i <= i_max; ++i) { | 501 for (int i = 0; i <= i_max; ++i) { |
| 504 if (base::LowerCaseEqualsASCII(buf + i, buf + i + http_len, "http")) | 502 if (LowerCaseEqualsASCII(buf + i, buf + i + http_len, "http")) |
| 505 return i; | 503 return i; |
| 506 } | 504 } |
| 507 } | 505 } |
| 508 return -1; // Not found | 506 return -1; // Not found |
| 509 } | 507 } |
| 510 | 508 |
| 511 int HttpUtil::LocateEndOfHeaders(const char* buf, int buf_len, int i) { | 509 int HttpUtil::LocateEndOfHeaders(const char* buf, int buf_len, int i) { |
| 512 bool was_lf = false; | 510 bool was_lf = false; |
| 513 char last_c = '\0'; | 511 char last_c = '\0'; |
| 514 for (; i < buf_len; ++i) { | 512 for (; i < buf_len; ++i) { |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 690 return false; | 688 return false; |
| 691 | 689 |
| 692 if (!etag_header.empty()) { | 690 if (!etag_header.empty()) { |
| 693 size_t slash = etag_header.find('/'); | 691 size_t slash = etag_header.find('/'); |
| 694 if (slash == std::string::npos || slash == 0) | 692 if (slash == std::string::npos || slash == 0) |
| 695 return true; | 693 return true; |
| 696 | 694 |
| 697 std::string::const_iterator i = etag_header.begin(); | 695 std::string::const_iterator i = etag_header.begin(); |
| 698 std::string::const_iterator j = etag_header.begin() + slash; | 696 std::string::const_iterator j = etag_header.begin() + slash; |
| 699 TrimLWS(&i, &j); | 697 TrimLWS(&i, &j); |
| 700 if (!base::LowerCaseEqualsASCII(i, j, "w")) | 698 if (!LowerCaseEqualsASCII(i, j, "w")) |
| 701 return true; | 699 return true; |
| 702 } | 700 } |
| 703 | 701 |
| 704 base::Time last_modified; | 702 base::Time last_modified; |
| 705 if (!base::Time::FromString(last_modified_header.c_str(), &last_modified)) | 703 if (!base::Time::FromString(last_modified_header.c_str(), &last_modified)) |
| 706 return false; | 704 return false; |
| 707 | 705 |
| 708 base::Time date; | 706 base::Time date; |
| 709 if (!base::Time::FromString(date_header.c_str(), &date)) | 707 if (!base::Time::FromString(date_header.c_str(), &date)) |
| 710 return false; | 708 return false; |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 791 } | 789 } |
| 792 return false; | 790 return false; |
| 793 } | 791 } |
| 794 | 792 |
| 795 bool HttpUtil::HeadersIterator::AdvanceTo(const char* name) { | 793 bool HttpUtil::HeadersIterator::AdvanceTo(const char* name) { |
| 796 DCHECK(name != NULL); | 794 DCHECK(name != NULL); |
| 797 DCHECK_EQ(0, base::StringToLowerASCII<std::string>(name).compare(name)) | 795 DCHECK_EQ(0, base::StringToLowerASCII<std::string>(name).compare(name)) |
| 798 << "the header name must be in all lower case"; | 796 << "the header name must be in all lower case"; |
| 799 | 797 |
| 800 while (GetNext()) { | 798 while (GetNext()) { |
| 801 if (base::LowerCaseEqualsASCII(name_begin_, name_end_, name)) { | 799 if (LowerCaseEqualsASCII(name_begin_, name_end_, name)) { |
| 802 return true; | 800 return true; |
| 803 } | 801 } |
| 804 } | 802 } |
| 805 | 803 |
| 806 return false; | 804 return false; |
| 807 } | 805 } |
| 808 | 806 |
| 809 HttpUtil::ValuesIterator::ValuesIterator( | 807 HttpUtil::ValuesIterator::ValuesIterator( |
| 810 std::string::const_iterator values_begin, | 808 std::string::const_iterator values_begin, |
| 811 std::string::const_iterator values_end, | 809 std::string::const_iterator values_end, |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 900 value_is_quoted_ = true; | 898 value_is_quoted_ = true; |
| 901 // Do not store iterators into this. See declaration of unquoted_value_. | 899 // Do not store iterators into this. See declaration of unquoted_value_. |
| 902 unquoted_value_ = HttpUtil::Unquote(value_begin_, value_end_); | 900 unquoted_value_ = HttpUtil::Unquote(value_begin_, value_end_); |
| 903 } | 901 } |
| 904 } | 902 } |
| 905 | 903 |
| 906 return true; | 904 return true; |
| 907 } | 905 } |
| 908 | 906 |
| 909 } // namespace net | 907 } // namespace net |
| OLD | NEW |