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