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 |
46 void HttpUtil::ParseContentType(const std::string& content_type_str, | 80 void HttpUtil::ParseContentType(const std::string& content_type_str, |
47 std::string* mime_type, | 81 std::string* mime_type, |
48 std::string* charset, | 82 std::string* charset, |
49 bool* had_charset, | 83 bool* had_charset, |
50 std::string* boundary) { | 84 std::string* boundary) { |
51 const std::string::const_iterator begin = content_type_str.begin(); | 85 const std::string::const_iterator begin = content_type_str.begin(); |
52 | 86 |
53 // Trim leading and trailing whitespace from type. We include '(' in | 87 // Trim leading and trailing whitespace from type. We include '(' in |
54 // the trailing trim set to catch media-type comments, which are not at all | 88 // the trailing trim set to catch media-type comments, which are not at all |
55 // standard, but may occur in rare cases. | 89 // standard, but may occur in rare cases. |
(...skipping 792 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
848 // bypass empty values. | 882 // bypass empty values. |
849 if (value_begin_ != value_end_) | 883 if (value_begin_ != value_end_) |
850 return true; | 884 return true; |
851 } | 885 } |
852 return false; | 886 return false; |
853 } | 887 } |
854 | 888 |
855 HttpUtil::NameValuePairsIterator::NameValuePairsIterator( | 889 HttpUtil::NameValuePairsIterator::NameValuePairsIterator( |
856 std::string::const_iterator begin, | 890 std::string::const_iterator begin, |
857 std::string::const_iterator end, | 891 std::string::const_iterator end, |
858 char delimiter, | 892 char delimiter) |
859 OptionalValues optional_values) | |
860 : props_(begin, end, delimiter), | 893 : props_(begin, end, delimiter), |
861 valid_(true), | 894 valid_(true), |
862 name_begin_(end), | 895 name_begin_(end), |
863 name_end_(end), | 896 name_end_(end), |
864 value_begin_(end), | 897 value_begin_(end), |
865 value_end_(end), | 898 value_end_(end), |
866 value_is_quoted_(false), | 899 value_is_quoted_(false) { |
867 values_optional_(optional_values == VALUES_OPTIONAL) {} | 900 } |
868 | |
869 HttpUtil::NameValuePairsIterator::NameValuePairsIterator( | |
870 std::string::const_iterator begin, | |
871 std::string::const_iterator end, | |
872 char delimiter) | |
873 : NameValuePairsIterator(begin, end, delimiter, VALUES_NOT_OPTIONAL) {} | |
874 | 901 |
875 HttpUtil::NameValuePairsIterator::~NameValuePairsIterator() {} | 902 HttpUtil::NameValuePairsIterator::~NameValuePairsIterator() {} |
876 | 903 |
877 // We expect properties to be formatted as one of: | 904 // We expect properties to be formatted as one of: |
878 // name="value" | 905 // name="value" |
879 // name='value' | 906 // name='value' |
880 // name='\'value\'' | 907 // name='\'value\'' |
881 // name=value | 908 // name=value |
882 // name = value | 909 // name = value |
883 // name (if values_optional_ is true) | 910 // name= |
884 // Due to buggy implementations found in some embedded devices, we also | 911 // Due to buggy implementations found in some embedded devices, we also |
885 // accept values with missing close quotemark (http://crbug.com/39836): | 912 // accept values with missing close quotemark (http://crbug.com/39836): |
886 // name="value | 913 // name="value |
887 bool HttpUtil::NameValuePairsIterator::GetNext() { | 914 bool HttpUtil::NameValuePairsIterator::GetNext() { |
888 if (!props_.GetNext()) | 915 if (!props_.GetNext()) |
889 return false; | 916 return false; |
890 | 917 |
891 // Set the value as everything. Next we will split out the name. | 918 // Set the value as everything. Next we will split out the name. |
892 value_begin_ = props_.value_begin(); | 919 value_begin_ = props_.value_begin(); |
893 value_end_ = props_.value_end(); | 920 value_end_ = props_.value_end(); |
894 name_begin_ = name_end_ = value_end_; | 921 name_begin_ = name_end_ = value_end_; |
895 | 922 |
896 // Scan for the equals sign. | 923 // Scan for the equals sign. |
897 std::string::const_iterator equals = std::find(value_begin_, value_end_, '='); | 924 std::string::const_iterator equals = std::find(value_begin_, value_end_, '='); |
898 if (equals == value_begin_) | 925 if (equals == value_end_ || equals == value_begin_) |
899 return valid_ = false; // Malformed, no name | 926 return valid_ = false; // Malformed, no equals sign |
900 if (equals == value_end_ && !values_optional_) | |
901 return valid_ = false; // Malformed, no equals sign and values are required | |
902 | 927 |
903 // If an equals sign was found, verify that it wasn't inside of quote marks. | 928 // Verify that the equals sign we found wasn't inside of quote marks. |
904 if (equals != value_end_) { | 929 for (std::string::const_iterator it = value_begin_; it != equals; ++it) { |
905 for (std::string::const_iterator it = value_begin_; it != equals; ++it) { | 930 if (HttpUtil::IsQuote(*it)) |
906 if (HttpUtil::IsQuote(*it)) | 931 return valid_ = false; // Malformed, quote appears before equals sign |
907 return valid_ = false; // Malformed, quote appears before equals sign | |
908 } | |
909 } | 932 } |
910 | 933 |
911 name_begin_ = value_begin_; | 934 name_begin_ = value_begin_; |
912 name_end_ = equals; | 935 name_end_ = equals; |
913 value_begin_ = (equals == value_end_) ? value_end_ : equals + 1; | 936 value_begin_ = equals + 1; |
914 | 937 |
915 TrimLWS(&name_begin_, &name_end_); | 938 TrimLWS(&name_begin_, &name_end_); |
916 TrimLWS(&value_begin_, &value_end_); | 939 TrimLWS(&value_begin_, &value_end_); |
917 value_is_quoted_ = false; | 940 value_is_quoted_ = false; |
918 unquoted_value_.clear(); | 941 unquoted_value_.clear(); |
919 | 942 |
920 if (equals != value_end_ && value_begin_ == value_end_) { | 943 if (value_begin_ == value_end_) |
921 // Malformed; value is empty | 944 return valid_ = false; // Malformed, value is empty |
922 return valid_ = false; | |
923 } | |
924 | 945 |
925 if (HttpUtil::IsQuote(*value_begin_)) { | 946 if (HttpUtil::IsQuote(*value_begin_)) { |
926 // Trim surrounding quotemarks off the value | 947 // Trim surrounding quotemarks off the value |
927 if (*value_begin_ != *(value_end_ - 1) || value_begin_ + 1 == value_end_) { | 948 if (*value_begin_ != *(value_end_ - 1) || value_begin_ + 1 == value_end_) { |
928 // NOTE: This is not as graceful as it sounds: | 949 // NOTE: This is not as graceful as it sounds: |
929 // * quoted-pairs will no longer be unquoted | 950 // * quoted-pairs will no longer be unquoted |
930 // (["\"hello] should give ["hello]). | 951 // (["\"hello] should give ["hello]). |
931 // * Does not detect when the final quote is escaped | 952 // * Does not detect when the final quote is escaped |
932 // (["value\"] should give [value"]) | 953 // (["value\"] should give [value"]) |
933 ++value_begin_; // Gracefully recover from mismatching quotes. | 954 ++value_begin_; // Gracefully recover from mismatching quotes. |
934 } else { | 955 } else { |
935 value_is_quoted_ = true; | 956 value_is_quoted_ = true; |
936 // Do not store iterators into this. See declaration of unquoted_value_. | 957 // Do not store iterators into this. See declaration of unquoted_value_. |
937 unquoted_value_ = HttpUtil::Unquote(value_begin_, value_end_); | 958 unquoted_value_ = HttpUtil::Unquote(value_begin_, value_end_); |
938 } | 959 } |
939 } | 960 } |
940 | 961 |
941 return true; | 962 return true; |
942 } | 963 } |
943 | 964 |
944 } // namespace net | 965 } // namespace net |
OLD | NEW |