| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 83 // string, so just go back to the top of the loop and look for | 83 // string, so just go back to the top of the loop and look for |
| 84 // |delimiter| again. | 84 // |delimiter| again. |
| 85 } while (true); | 85 } while (true); |
| 86 | 86 |
| 87 NOTREACHED(); | 87 NOTREACHED(); |
| 88 return line.length(); | 88 return line.length(); |
| 89 } | 89 } |
| 90 | 90 |
| 91 // static | 91 // static |
| 92 void HttpUtil::ParseContentType(const string& content_type_str, | 92 void HttpUtil::ParseContentType(const string& content_type_str, |
| 93 string* mime_type, string* charset, | 93 string* mime_type, |
| 94 bool *had_charset) { | 94 string* charset, |
| 95 bool* had_charset, |
| 96 string* boundary) { |
| 97 const string::const_iterator begin = content_type_str.begin(); |
| 98 |
| 95 // Trim leading and trailing whitespace from type. We include '(' in | 99 // Trim leading and trailing whitespace from type. We include '(' in |
| 96 // the trailing trim set to catch media-type comments, which are not at all | 100 // the trailing trim set to catch media-type comments, which are not at all |
| 97 // standard, but may occur in rare cases. | 101 // standard, but may occur in rare cases. |
| 98 size_t type_val = content_type_str.find_first_not_of(HTTP_LWS); | 102 size_t type_val = content_type_str.find_first_not_of(HTTP_LWS); |
| 99 type_val = std::min(type_val, content_type_str.length()); | 103 type_val = std::min(type_val, content_type_str.length()); |
| 100 size_t type_end = content_type_str.find_first_of(HTTP_LWS ";(", type_val); | 104 size_t type_end = content_type_str.find_first_of(HTTP_LWS ";(", type_val); |
| 101 if (string::npos == type_end) | 105 if (string::npos == type_end) |
| 102 type_end = content_type_str.length(); | 106 type_end = content_type_str.length(); |
| 103 | 107 |
| 104 size_t charset_val = 0; | 108 size_t charset_val = 0; |
| 105 size_t charset_end = 0; | 109 size_t charset_end = 0; |
| 110 bool type_has_charset = false; |
| 106 | 111 |
| 107 // Iterate over parameters | 112 // Iterate over parameters |
| 108 bool type_has_charset = false; | |
| 109 size_t param_start = content_type_str.find_first_of(';', type_end); | 113 size_t param_start = content_type_str.find_first_of(';', type_end); |
| 110 if (param_start != string::npos) { | 114 if (param_start != string::npos) { |
| 111 // We have parameters. Iterate over them. | 115 StringTokenizer tokenizer(begin + param_start, content_type_str.end(), |
| 112 size_t cur_param_start = param_start + 1; | 116 ";"); |
| 113 do { | 117 tokenizer.set_quote_chars("\""); |
| 114 size_t cur_param_end = | 118 while (tokenizer.GetNext()) { |
| 115 FindDelimiter(content_type_str, cur_param_start, ';'); | 119 string::const_iterator equals_sign = |
| 120 std::find(tokenizer.token_begin(), tokenizer.token_end(), '='); |
| 121 if (equals_sign == tokenizer.token_end()) |
| 122 continue; |
| 116 | 123 |
| 117 size_t param_name_start = content_type_str.find_first_not_of( | 124 string::const_iterator param_name_begin = tokenizer.token_begin(); |
| 118 HTTP_LWS, cur_param_start); | 125 string::const_iterator param_name_end = equals_sign; |
| 119 param_name_start = std::min(param_name_start, cur_param_end); | 126 TrimLWS(¶m_name_begin, ¶m_name_end); |
| 120 | 127 |
| 121 static const char charset_str[] = "charset="; | 128 string::const_iterator param_value_begin = equals_sign + 1; |
| 122 size_t charset_end_offset = std::min( | 129 string::const_iterator param_value_end = tokenizer.token_end(); |
| 123 param_name_start + sizeof(charset_str) - 1, cur_param_end); | 130 DCHECK(param_value_begin <= tokenizer.token_end()); |
| 124 if (LowerCaseEqualsASCII( | 131 TrimLWS(¶m_value_begin, ¶m_value_end); |
| 125 content_type_str.begin() + param_name_start, | 132 |
| 126 content_type_str.begin() + charset_end_offset, charset_str)) { | 133 if (LowerCaseEqualsASCII(param_name_begin, param_name_end, "charset")) { |
| 127 charset_val = param_name_start + sizeof(charset_str) - 1; | 134 // TODO(abarth): Refactor this function to consistently use iterators. |
| 128 charset_end = cur_param_end; | 135 charset_val = param_value_begin - begin; |
| 136 charset_end = param_value_end - begin; |
| 129 type_has_charset = true; | 137 type_has_charset = true; |
| 138 } else if (LowerCaseEqualsASCII(param_name_begin, param_name_end, |
| 139 "boundary")) { |
| 140 if (boundary) |
| 141 boundary->assign(param_value_begin, param_value_end); |
| 130 } | 142 } |
| 131 | 143 } |
| 132 cur_param_start = cur_param_end + 1; | |
| 133 } while (cur_param_start < content_type_str.length()); | |
| 134 } | 144 } |
| 135 | 145 |
| 136 if (type_has_charset) { | 146 if (type_has_charset) { |
| 137 // Trim leading and trailing whitespace from charset_val. We include | 147 // Trim leading and trailing whitespace from charset_val. We include |
| 138 // '(' in the trailing trim set to catch media-type comments, which are | 148 // '(' in the trailing trim set to catch media-type comments, which are |
| 139 // not at all standard, but may occur in rare cases. | 149 // not at all standard, but may occur in rare cases. |
| 140 charset_val = content_type_str.find_first_not_of(HTTP_LWS, charset_val); | 150 charset_val = content_type_str.find_first_not_of(HTTP_LWS, charset_val); |
| 141 charset_val = std::min(charset_val, charset_end); | 151 charset_val = std::min(charset_val, charset_end); |
| 142 char first_char = content_type_str[charset_val]; | 152 char first_char = content_type_str[charset_val]; |
| 143 if (first_char == '"' || first_char == '\'') { | 153 if (first_char == '"' || first_char == '\'') { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 155 // also, if type_val is the same as mime_type, then just update the | 165 // also, if type_val is the same as mime_type, then just update the |
| 156 // charset. however, if charset is empty and mime_type hasn't | 166 // charset. however, if charset is empty and mime_type hasn't |
| 157 // changed, then don't wipe-out an existing charset. We | 167 // changed, then don't wipe-out an existing charset. We |
| 158 // also want to reject a mime-type if it does not include a slash. | 168 // also want to reject a mime-type if it does not include a slash. |
| 159 // some servers give junk after the charset parameter, which may | 169 // some servers give junk after the charset parameter, which may |
| 160 // include a comma, so this check makes us a bit more tolerant. | 170 // include a comma, so this check makes us a bit more tolerant. |
| 161 if (content_type_str.length() != 0 && | 171 if (content_type_str.length() != 0 && |
| 162 content_type_str != "*/*" && | 172 content_type_str != "*/*" && |
| 163 content_type_str.find_first_of('/') != string::npos) { | 173 content_type_str.find_first_of('/') != string::npos) { |
| 164 // Common case here is that mime_type is empty | 174 // Common case here is that mime_type is empty |
| 165 bool eq = !mime_type->empty() && | 175 bool eq = !mime_type->empty() && LowerCaseEqualsASCII(begin + type_val, |
| 166 LowerCaseEqualsASCII(content_type_str.begin() + type_val, | 176 begin + type_end, |
| 167 content_type_str.begin() + type_end, | 177 mime_type->data()); |
| 168 mime_type->data()); | |
| 169 if (!eq) { | 178 if (!eq) { |
| 170 mime_type->assign(content_type_str.begin() + type_val, | 179 mime_type->assign(begin + type_val, begin + type_end); |
| 171 content_type_str.begin() + type_end); | |
| 172 StringToLowerASCII(mime_type); | 180 StringToLowerASCII(mime_type); |
| 173 } | 181 } |
| 174 if ((!eq && *had_charset) || type_has_charset) { | 182 if ((!eq && *had_charset) || type_has_charset) { |
| 175 *had_charset = true; | 183 *had_charset = true; |
| 176 charset->assign(content_type_str.begin() + charset_val, | 184 charset->assign(begin + charset_val, begin + charset_end); |
| 177 content_type_str.begin() + charset_end); | |
| 178 StringToLowerASCII(charset); | 185 StringToLowerASCII(charset); |
| 179 } | 186 } |
| 180 } | 187 } |
| 181 } | 188 } |
| 182 | 189 |
| 183 // static | 190 // static |
| 184 // Parse the Range header according to RFC 2616 14.35.1 | 191 // Parse the Range header according to RFC 2616 14.35.1 |
| 185 // ranges-specifier = byte-ranges-specifier | 192 // ranges-specifier = byte-ranges-specifier |
| 186 // byte-ranges-specifier = bytes-unit "=" byte-range-set | 193 // byte-ranges-specifier = bytes-unit "=" byte-range-set |
| 187 // byte-range-set = 1#( byte-range-spec | suffix-byte-range-spec ) | 194 // byte-range-set = 1#( byte-range-spec | suffix-byte-range-spec ) |
| (...skipping 646 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 834 value_is_quoted_ = true; | 841 value_is_quoted_ = true; |
| 835 // Do not store iterators into this. See declaration of unquoted_value_. | 842 // Do not store iterators into this. See declaration of unquoted_value_. |
| 836 unquoted_value_ = HttpUtil::Unquote(value_begin_, value_end_); | 843 unquoted_value_ = HttpUtil::Unquote(value_begin_, value_end_); |
| 837 } | 844 } |
| 838 } | 845 } |
| 839 | 846 |
| 840 return true; | 847 return true; |
| 841 } | 848 } |
| 842 | 849 |
| 843 } // namespace net | 850 } // namespace net |
| OLD | NEW |