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 |