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