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 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
378 // static | 379 // static |
379 std::string HttpUtil::StripHeaders(const std::string& headers, | 380 std::string HttpUtil::StripHeaders(const std::string& headers, |
380 const char* const headers_to_remove[], | 381 const char* const headers_to_remove[], |
381 size_t headers_to_remove_len) { | 382 size_t headers_to_remove_len) { |
382 std::string stripped_headers; | 383 std::string stripped_headers; |
383 HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n"); | 384 HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n"); |
384 | 385 |
385 while (it.GetNext()) { | 386 while (it.GetNext()) { |
386 bool should_remove = false; | 387 bool should_remove = false; |
387 for (size_t i = 0; i < headers_to_remove_len; ++i) { | 388 for (size_t i = 0; i < headers_to_remove_len; ++i) { |
388 if (LowerCaseEqualsASCII(it.name_begin(), it.name_end(), | 389 if (base::LowerCaseEqualsASCII(it.name_begin(), it.name_end(), |
389 headers_to_remove[i])) { | 390 headers_to_remove[i])) { |
390 should_remove = true; | 391 should_remove = true; |
391 break; | 392 break; |
392 } | 393 } |
393 } | 394 } |
394 if (!should_remove) { | 395 if (!should_remove) { |
395 // Assume that name and values are on the same line. | 396 // Assume that name and values are on the same line. |
396 stripped_headers.append(it.name_begin(), it.values_end()); | 397 stripped_headers.append(it.name_begin(), it.values_end()); |
397 stripped_headers.append("\r\n"); | 398 stripped_headers.append("\r\n"); |
398 } | 399 } |
399 } | 400 } |
(...skipping 14 matching lines...) Expand all Loading... |
414 "set-cookie", | 415 "set-cookie", |
415 // The format of auth-challenges mixes both space separated tokens and | 416 // The format of auth-challenges mixes both space separated tokens and |
416 // comma separated properties, so coalescing on comma won't work. | 417 // comma separated properties, so coalescing on comma won't work. |
417 "www-authenticate", | 418 "www-authenticate", |
418 "proxy-authenticate", | 419 "proxy-authenticate", |
419 // STS specifies that UAs must not process any STS headers after the first | 420 // STS specifies that UAs must not process any STS headers after the first |
420 // one. | 421 // one. |
421 "strict-transport-security" | 422 "strict-transport-security" |
422 }; | 423 }; |
423 for (size_t i = 0; i < arraysize(kNonCoalescingHeaders); ++i) { | 424 for (size_t i = 0; i < arraysize(kNonCoalescingHeaders); ++i) { |
424 if (LowerCaseEqualsASCII(name_begin, name_end, kNonCoalescingHeaders[i])) | 425 if (base::LowerCaseEqualsASCII(name_begin, name_end, |
| 426 kNonCoalescingHeaders[i])) |
425 return true; | 427 return true; |
426 } | 428 } |
427 return false; | 429 return false; |
428 } | 430 } |
429 | 431 |
430 bool HttpUtil::IsLWS(char c) { | 432 bool HttpUtil::IsLWS(char c) { |
431 return strchr(HTTP_LWS, c) != NULL; | 433 return strchr(HTTP_LWS, c) != NULL; |
432 } | 434 } |
433 | 435 |
434 void HttpUtil::TrimLWS(std::string::const_iterator* begin, | 436 void HttpUtil::TrimLWS(std::string::const_iterator* begin, |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
528 // some slop at the start. If the "http" string could not be found | 530 // some slop at the start. If the "http" string could not be found |
529 // then returns -1. | 531 // then returns -1. |
530 // static | 532 // static |
531 int HttpUtil::LocateStartOfStatusLine(const char* buf, int buf_len) { | 533 int HttpUtil::LocateStartOfStatusLine(const char* buf, int buf_len) { |
532 const int slop = 4; | 534 const int slop = 4; |
533 const int http_len = 4; | 535 const int http_len = 4; |
534 | 536 |
535 if (buf_len >= http_len) { | 537 if (buf_len >= http_len) { |
536 int i_max = std::min(buf_len - http_len, slop); | 538 int i_max = std::min(buf_len - http_len, slop); |
537 for (int i = 0; i <= i_max; ++i) { | 539 for (int i = 0; i <= i_max; ++i) { |
538 if (LowerCaseEqualsASCII(buf + i, buf + i + http_len, "http")) | 540 if (base::LowerCaseEqualsASCII(buf + i, buf + i + http_len, "http")) |
539 return i; | 541 return i; |
540 } | 542 } |
541 } | 543 } |
542 return -1; // Not found | 544 return -1; // Not found |
543 } | 545 } |
544 | 546 |
545 int HttpUtil::LocateEndOfHeaders(const char* buf, int buf_len, int i) { | 547 int HttpUtil::LocateEndOfHeaders(const char* buf, int buf_len, int i) { |
546 bool was_lf = false; | 548 bool was_lf = false; |
547 char last_c = '\0'; | 549 char last_c = '\0'; |
548 for (; i < buf_len; ++i) { | 550 for (; i < buf_len; ++i) { |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
724 return false; | 726 return false; |
725 | 727 |
726 if (!etag_header.empty()) { | 728 if (!etag_header.empty()) { |
727 size_t slash = etag_header.find('/'); | 729 size_t slash = etag_header.find('/'); |
728 if (slash == std::string::npos || slash == 0) | 730 if (slash == std::string::npos || slash == 0) |
729 return true; | 731 return true; |
730 | 732 |
731 std::string::const_iterator i = etag_header.begin(); | 733 std::string::const_iterator i = etag_header.begin(); |
732 std::string::const_iterator j = etag_header.begin() + slash; | 734 std::string::const_iterator j = etag_header.begin() + slash; |
733 TrimLWS(&i, &j); | 735 TrimLWS(&i, &j); |
734 if (!LowerCaseEqualsASCII(i, j, "w")) | 736 if (!base::LowerCaseEqualsASCII(i, j, "w")) |
735 return true; | 737 return true; |
736 } | 738 } |
737 | 739 |
738 base::Time last_modified; | 740 base::Time last_modified; |
739 if (!base::Time::FromString(last_modified_header.c_str(), &last_modified)) | 741 if (!base::Time::FromString(last_modified_header.c_str(), &last_modified)) |
740 return false; | 742 return false; |
741 | 743 |
742 base::Time date; | 744 base::Time date; |
743 if (!base::Time::FromString(date_header.c_str(), &date)) | 745 if (!base::Time::FromString(date_header.c_str(), &date)) |
744 return false; | 746 return false; |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
825 } | 827 } |
826 return false; | 828 return false; |
827 } | 829 } |
828 | 830 |
829 bool HttpUtil::HeadersIterator::AdvanceTo(const char* name) { | 831 bool HttpUtil::HeadersIterator::AdvanceTo(const char* name) { |
830 DCHECK(name != NULL); | 832 DCHECK(name != NULL); |
831 DCHECK_EQ(0, base::StringToLowerASCII<std::string>(name).compare(name)) | 833 DCHECK_EQ(0, base::StringToLowerASCII<std::string>(name).compare(name)) |
832 << "the header name must be in all lower case"; | 834 << "the header name must be in all lower case"; |
833 | 835 |
834 while (GetNext()) { | 836 while (GetNext()) { |
835 if (LowerCaseEqualsASCII(name_begin_, name_end_, name)) { | 837 if (base::LowerCaseEqualsASCII(name_begin_, name_end_, name)) { |
836 return true; | 838 return true; |
837 } | 839 } |
838 } | 840 } |
839 | 841 |
840 return false; | 842 return false; |
841 } | 843 } |
842 | 844 |
843 HttpUtil::ValuesIterator::ValuesIterator( | 845 HttpUtil::ValuesIterator::ValuesIterator( |
844 std::string::const_iterator values_begin, | 846 std::string::const_iterator values_begin, |
845 std::string::const_iterator values_end, | 847 std::string::const_iterator values_end, |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
934 value_is_quoted_ = true; | 936 value_is_quoted_ = true; |
935 // Do not store iterators into this. See declaration of unquoted_value_. | 937 // Do not store iterators into this. See declaration of unquoted_value_. |
936 unquoted_value_ = HttpUtil::Unquote(value_begin_, value_end_); | 938 unquoted_value_ = HttpUtil::Unquote(value_begin_, value_end_); |
937 } | 939 } |
938 } | 940 } |
939 | 941 |
940 return true; | 942 return true; |
941 } | 943 } |
942 | 944 |
943 } // namespace net | 945 } // namespace net |
OLD | NEW |