| 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 25 matching lines...) Expand all Loading... |
| 36 if (line[end] != '\\') | 36 if (line[end] != '\\') |
| 37 return end; | 37 return end; |
| 38 } | 38 } |
| 39 return line.length(); | 39 return line.length(); |
| 40 } | 40 } |
| 41 | 41 |
| 42 | 42 |
| 43 // HttpUtil ------------------------------------------------------------------- | 43 // HttpUtil ------------------------------------------------------------------- |
| 44 | 44 |
| 45 // static | 45 // static |
| 46 size_t HttpUtil::FindDelimiter(const std::string& line, | |
| 47 size_t search_start, | |
| 48 char delimiter) { | |
| 49 do { | |
| 50 // search_start points to the spot from which we should start looking | |
| 51 // for the delimiter. | |
| 52 const char delim_str[] = { delimiter, '"', '\'', '\0' }; | |
| 53 size_t cur_delim_pos = line.find_first_of(delim_str, search_start); | |
| 54 if (cur_delim_pos == std::string::npos) | |
| 55 return line.length(); | |
| 56 | |
| 57 char ch = line[cur_delim_pos]; | |
| 58 if (ch == delimiter) { | |
| 59 // Found delimiter | |
| 60 return cur_delim_pos; | |
| 61 } | |
| 62 | |
| 63 // We hit the start of a quoted string. Look for its end. | |
| 64 search_start = FindStringEnd(line, cur_delim_pos, ch); | |
| 65 if (search_start == line.length()) | |
| 66 return search_start; | |
| 67 | |
| 68 ++search_start; | |
| 69 | |
| 70 // search_start now points to the first char after the end of the | |
| 71 // string, so just go back to the top of the loop and look for | |
| 72 // |delimiter| again. | |
| 73 } while (true); | |
| 74 | |
| 75 NOTREACHED(); | |
| 76 return line.length(); | |
| 77 } | |
| 78 | |
| 79 // static | |
| 80 void HttpUtil::ParseContentType(const std::string& content_type_str, | 46 void HttpUtil::ParseContentType(const std::string& content_type_str, |
| 81 std::string* mime_type, | 47 std::string* mime_type, |
| 82 std::string* charset, | 48 std::string* charset, |
| 83 bool* had_charset, | 49 bool* had_charset, |
| 84 std::string* boundary) { | 50 std::string* boundary) { |
| 85 const std::string::const_iterator begin = content_type_str.begin(); | 51 const std::string::const_iterator begin = content_type_str.begin(); |
| 86 | 52 |
| 87 // Trim leading and trailing whitespace from type. We include '(' in | 53 // Trim leading and trailing whitespace from type. We include '(' in |
| 88 // the trailing trim set to catch media-type comments, which are not at all | 54 // the trailing trim set to catch media-type comments, which are not at all |
| 89 // standard, but may occur in rare cases. | 55 // standard, but may occur in rare cases. |
| (...skipping 798 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 888 // bypass empty values. | 854 // bypass empty values. |
| 889 if (value_begin_ != value_end_) | 855 if (value_begin_ != value_end_) |
| 890 return true; | 856 return true; |
| 891 } | 857 } |
| 892 return false; | 858 return false; |
| 893 } | 859 } |
| 894 | 860 |
| 895 HttpUtil::NameValuePairsIterator::NameValuePairsIterator( | 861 HttpUtil::NameValuePairsIterator::NameValuePairsIterator( |
| 896 std::string::const_iterator begin, | 862 std::string::const_iterator begin, |
| 897 std::string::const_iterator end, | 863 std::string::const_iterator end, |
| 898 char delimiter) | 864 char delimiter, |
| 865 OptionalValues optional_values) |
| 899 : props_(begin, end, delimiter), | 866 : props_(begin, end, delimiter), |
| 900 valid_(true), | 867 valid_(true), |
| 901 name_begin_(end), | 868 name_begin_(end), |
| 902 name_end_(end), | 869 name_end_(end), |
| 903 value_begin_(end), | 870 value_begin_(end), |
| 904 value_end_(end), | 871 value_end_(end), |
| 905 value_is_quoted_(false) { | 872 value_is_quoted_(false), |
| 906 } | 873 values_optional_(optional_values == VALUES_OPTIONAL) {} |
| 874 |
| 875 HttpUtil::NameValuePairsIterator::NameValuePairsIterator( |
| 876 std::string::const_iterator begin, |
| 877 std::string::const_iterator end, |
| 878 char delimiter) |
| 879 : NameValuePairsIterator(begin, end, delimiter, VALUES_NOT_OPTIONAL) {} |
| 907 | 880 |
| 908 HttpUtil::NameValuePairsIterator::~NameValuePairsIterator() {} | 881 HttpUtil::NameValuePairsIterator::~NameValuePairsIterator() {} |
| 909 | 882 |
| 910 // We expect properties to be formatted as one of: | 883 // We expect properties to be formatted as one of: |
| 911 // name="value" | 884 // name="value" |
| 912 // name='value' | 885 // name='value' |
| 913 // name='\'value\'' | 886 // name='\'value\'' |
| 914 // name=value | 887 // name=value |
| 915 // name = value | 888 // name = value |
| 916 // name= | 889 // name (if values_optional_ is true) |
| 917 // Due to buggy implementations found in some embedded devices, we also | 890 // Due to buggy implementations found in some embedded devices, we also |
| 918 // accept values with missing close quotemark (http://crbug.com/39836): | 891 // accept values with missing close quotemark (http://crbug.com/39836): |
| 919 // name="value | 892 // name="value |
| 920 bool HttpUtil::NameValuePairsIterator::GetNext() { | 893 bool HttpUtil::NameValuePairsIterator::GetNext() { |
| 921 if (!props_.GetNext()) | 894 if (!props_.GetNext()) |
| 922 return false; | 895 return false; |
| 923 | 896 |
| 924 // Set the value as everything. Next we will split out the name. | 897 // Set the value as everything. Next we will split out the name. |
| 925 value_begin_ = props_.value_begin(); | 898 value_begin_ = props_.value_begin(); |
| 926 value_end_ = props_.value_end(); | 899 value_end_ = props_.value_end(); |
| 927 name_begin_ = name_end_ = value_end_; | 900 name_begin_ = name_end_ = value_end_; |
| 928 | 901 |
| 929 // Scan for the equals sign. | 902 // Scan for the equals sign. |
| 930 std::string::const_iterator equals = std::find(value_begin_, value_end_, '='); | 903 std::string::const_iterator equals = std::find(value_begin_, value_end_, '='); |
| 931 if (equals == value_end_ || equals == value_begin_) | 904 if (equals == value_begin_) |
| 932 return valid_ = false; // Malformed, no equals sign | 905 return valid_ = false; // Malformed, no name |
| 906 if (equals == value_end_ && !values_optional_) |
| 907 return valid_ = false; // Malformed, no equals sign and values are required |
| 933 | 908 |
| 934 // Verify that the equals sign we found wasn't inside of quote marks. | 909 // If an equals sign was found, verify that it wasn't inside of quote marks. |
| 935 for (std::string::const_iterator it = value_begin_; it != equals; ++it) { | 910 if (equals != value_end_) { |
| 936 if (HttpUtil::IsQuote(*it)) | 911 for (std::string::const_iterator it = value_begin_; it != equals; ++it) { |
| 937 return valid_ = false; // Malformed, quote appears before equals sign | 912 if (HttpUtil::IsQuote(*it)) |
| 913 return valid_ = false; // Malformed, quote appears before equals sign |
| 914 } |
| 938 } | 915 } |
| 939 | 916 |
| 940 name_begin_ = value_begin_; | 917 name_begin_ = value_begin_; |
| 941 name_end_ = equals; | 918 name_end_ = equals; |
| 942 value_begin_ = equals + 1; | 919 value_begin_ = (equals == value_end_) ? value_end_ : equals + 1; |
| 943 | 920 |
| 944 TrimLWS(&name_begin_, &name_end_); | 921 TrimLWS(&name_begin_, &name_end_); |
| 945 TrimLWS(&value_begin_, &value_end_); | 922 TrimLWS(&value_begin_, &value_end_); |
| 946 value_is_quoted_ = false; | 923 value_is_quoted_ = false; |
| 947 unquoted_value_.clear(); | 924 unquoted_value_.clear(); |
| 948 | 925 |
| 949 if (value_begin_ == value_end_) | 926 if (equals != value_end_ && value_begin_ == value_end_) { |
| 950 return valid_ = false; // Malformed, value is empty | 927 // Malformed; value is empty |
| 928 return valid_ = false; |
| 929 } |
| 951 | 930 |
| 952 if (HttpUtil::IsQuote(*value_begin_)) { | 931 if (value_begin_ != value_end_ && HttpUtil::IsQuote(*value_begin_)) { |
| 953 // Trim surrounding quotemarks off the value | 932 // Trim surrounding quotemarks off the value |
| 954 if (*value_begin_ != *(value_end_ - 1) || value_begin_ + 1 == value_end_) { | 933 if (*value_begin_ != *(value_end_ - 1) || value_begin_ + 1 == value_end_) { |
| 955 // NOTE: This is not as graceful as it sounds: | 934 // NOTE: This is not as graceful as it sounds: |
| 956 // * quoted-pairs will no longer be unquoted | 935 // * quoted-pairs will no longer be unquoted |
| 957 // (["\"hello] should give ["hello]). | 936 // (["\"hello] should give ["hello]). |
| 958 // * Does not detect when the final quote is escaped | 937 // * Does not detect when the final quote is escaped |
| 959 // (["value\"] should give [value"]) | 938 // (["value\"] should give [value"]) |
| 960 ++value_begin_; // Gracefully recover from mismatching quotes. | 939 ++value_begin_; // Gracefully recover from mismatching quotes. |
| 961 } else { | 940 } else { |
| 962 value_is_quoted_ = true; | 941 value_is_quoted_ = true; |
| 963 // Do not store iterators into this. See declaration of unquoted_value_. | 942 // Do not store iterators into this. See declaration of unquoted_value_. |
| 964 unquoted_value_ = HttpUtil::Unquote(value_begin_, value_end_); | 943 unquoted_value_ = HttpUtil::Unquote(value_begin_, value_end_); |
| 965 } | 944 } |
| 966 } | 945 } |
| 967 | 946 |
| 968 return true; | 947 return true; |
| 969 } | 948 } |
| 970 | 949 |
| 971 } // namespace net | 950 } // namespace net |
| OLD | NEW |