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 483 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
494 } | 494 } |
495 return unescaped; | 495 return unescaped; |
496 } | 496 } |
497 | 497 |
498 // static | 498 // static |
499 std::string HttpUtil::Unquote(const std::string& str) { | 499 std::string HttpUtil::Unquote(const std::string& str) { |
500 return Unquote(str.begin(), str.end()); | 500 return Unquote(str.begin(), str.end()); |
501 } | 501 } |
502 | 502 |
503 // static | 503 // static |
504 bool HttpUtil::StrictUnquote(std::string::const_iterator begin, | |
mmenke
2016/04/26 18:05:57
Hrm...Should this and Unquote share an implementat
Marijn Kruisselbrink
2016/04/27 01:49:49
Good idea. Done.
| |
505 std::string::const_iterator end, | |
506 std::string* out) { | |
507 // Empty string | |
508 if (begin == end) | |
509 return false; | |
510 | |
511 // Nothing to unquote. | |
512 if (!IsQuote(*begin)) | |
513 return false; | |
514 | |
515 // No terminal quote mark. | |
516 if (end - begin < 2 || *begin != *(end - 1)) | |
517 return false; | |
518 | |
519 char quote = *begin; | |
520 | |
521 // Strip quotemarks | |
522 ++begin; | |
523 --end; | |
524 | |
525 // Terminal quote is escaped. | |
526 if (begin != end && *(end - 1) == '\\') | |
mmenke
2016/04/26 18:05:57
BUG: "\\" is valid. Instead, should have a "prev
Marijn Kruisselbrink
2016/04/27 01:49:49
Yeah, just caught that myself too. Added a test an
| |
527 return false; | |
528 | |
529 // Unescape quoted-pair (defined in RFC 2616 section 2.2) | |
530 bool prev_escape = false; | |
531 std::string unescaped; | |
532 for (; begin != end; ++begin) { | |
533 char c = *begin; | |
534 if (c == '\\' && !prev_escape) { | |
535 prev_escape = true; | |
536 continue; | |
537 } | |
538 if (!prev_escape && c == quote) | |
539 return false; | |
540 prev_escape = false; | |
541 unescaped.push_back(c); | |
542 } | |
543 *out = std::move(unescaped); | |
544 return true; | |
545 } | |
546 | |
547 // static | |
548 bool HttpUtil::StrictUnquote(const std::string& str, std::string* out) { | |
549 return StrictUnquote(str.begin(), str.end(), out); | |
550 } | |
551 | |
552 // static | |
504 std::string HttpUtil::Quote(const std::string& str) { | 553 std::string HttpUtil::Quote(const std::string& str) { |
505 std::string escaped; | 554 std::string escaped; |
506 escaped.reserve(2 + str.size()); | 555 escaped.reserve(2 + str.size()); |
507 | 556 |
508 std::string::const_iterator begin = str.begin(); | 557 std::string::const_iterator begin = str.begin(); |
509 std::string::const_iterator end = str.end(); | 558 std::string::const_iterator end = str.end(); |
510 | 559 |
511 // Esape any backslashes or quotemarks within the string, and | 560 // Esape any backslashes or quotemarks within the string, and |
512 // then surround with quotes. | 561 // then surround with quotes. |
513 escaped.push_back('"'); | 562 escaped.push_back('"'); |
(...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
903 if (value_begin_ != value_end_) | 952 if (value_begin_ != value_end_) |
904 return true; | 953 return true; |
905 } | 954 } |
906 return false; | 955 return false; |
907 } | 956 } |
908 | 957 |
909 HttpUtil::NameValuePairsIterator::NameValuePairsIterator( | 958 HttpUtil::NameValuePairsIterator::NameValuePairsIterator( |
910 std::string::const_iterator begin, | 959 std::string::const_iterator begin, |
911 std::string::const_iterator end, | 960 std::string::const_iterator end, |
912 char delimiter, | 961 char delimiter, |
913 OptionalValues optional_values) | 962 Values optional_values, |
963 Quotes strict_quotes) | |
914 : props_(begin, end, delimiter), | 964 : props_(begin, end, delimiter), |
915 valid_(true), | 965 valid_(true), |
916 name_begin_(end), | 966 name_begin_(end), |
917 name_end_(end), | 967 name_end_(end), |
918 value_begin_(end), | 968 value_begin_(end), |
919 value_end_(end), | 969 value_end_(end), |
920 value_is_quoted_(false), | 970 value_is_quoted_(false), |
921 values_optional_(optional_values == VALUES_OPTIONAL) {} | 971 values_optional_(optional_values == Values::OPTIONAL), |
972 strict_quotes_(strict_quotes == Quotes::STRICT) {} | |
922 | 973 |
923 HttpUtil::NameValuePairsIterator::NameValuePairsIterator( | 974 HttpUtil::NameValuePairsIterator::NameValuePairsIterator( |
924 std::string::const_iterator begin, | 975 std::string::const_iterator begin, |
925 std::string::const_iterator end, | 976 std::string::const_iterator end, |
926 char delimiter) | 977 char delimiter) |
927 : NameValuePairsIterator(begin, end, delimiter, VALUES_NOT_OPTIONAL) {} | 978 : NameValuePairsIterator(begin, |
979 end, | |
980 delimiter, | |
981 Values::NOT_OPTIONAL, | |
982 Quotes::NOT_STRICT) {} | |
928 | 983 |
929 HttpUtil::NameValuePairsIterator::NameValuePairsIterator( | 984 HttpUtil::NameValuePairsIterator::NameValuePairsIterator( |
930 const NameValuePairsIterator& other) = default; | 985 const NameValuePairsIterator& other) = default; |
931 | 986 |
932 HttpUtil::NameValuePairsIterator::~NameValuePairsIterator() {} | 987 HttpUtil::NameValuePairsIterator::~NameValuePairsIterator() {} |
933 | 988 |
934 // We expect properties to be formatted as one of: | 989 // We expect properties to be formatted as one of: |
935 // name="value" | 990 // name="value" |
936 // name='value' | 991 // name='value' |
937 // name='\'value\'' | 992 // name='\'value\'' |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
972 TrimLWS(&name_begin_, &name_end_); | 1027 TrimLWS(&name_begin_, &name_end_); |
973 TrimLWS(&value_begin_, &value_end_); | 1028 TrimLWS(&value_begin_, &value_end_); |
974 value_is_quoted_ = false; | 1029 value_is_quoted_ = false; |
975 unquoted_value_.clear(); | 1030 unquoted_value_.clear(); |
976 | 1031 |
977 if (equals != value_end_ && value_begin_ == value_end_) { | 1032 if (equals != value_end_ && value_begin_ == value_end_) { |
978 // Malformed; value is empty | 1033 // Malformed; value is empty |
979 return valid_ = false; | 1034 return valid_ = false; |
980 } | 1035 } |
981 | 1036 |
982 if (value_begin_ != value_end_ && HttpUtil::IsQuote(*value_begin_)) { | 1037 if (value_begin_ != value_end_ && HttpUtil::IsQuote(*value_begin_)) { |
mmenke
2016/04/26 18:05:57
So strict mode fails on foo='bar but succeeds on f
Marijn Kruisselbrink
2016/04/27 01:49:49
Argh, excellent question... And not really somethi
| |
1038 value_is_quoted_ = true; | |
1039 | |
1040 if (strict_quotes_) { | |
1041 if (!HttpUtil::StrictUnquote(value_begin_, value_end_, &unquoted_value_)) | |
1042 return valid_ = false; | |
1043 return true; | |
1044 } | |
1045 | |
983 // Trim surrounding quotemarks off the value | 1046 // Trim surrounding quotemarks off the value |
984 if (*value_begin_ != *(value_end_ - 1) || value_begin_ + 1 == value_end_) { | 1047 if (*value_begin_ != *(value_end_ - 1) || value_begin_ + 1 == value_end_) { |
985 // NOTE: This is not as graceful as it sounds: | 1048 // NOTE: This is not as graceful as it sounds: |
986 // * quoted-pairs will no longer be unquoted | 1049 // * quoted-pairs will no longer be unquoted |
987 // (["\"hello] should give ["hello]). | 1050 // (["\"hello] should give ["hello]). |
988 // * Does not detect when the final quote is escaped | 1051 // * Does not detect when the final quote is escaped |
989 // (["value\"] should give [value"]) | 1052 // (["value\"] should give [value"]) |
1053 value_is_quoted_ = false; | |
990 ++value_begin_; // Gracefully recover from mismatching quotes. | 1054 ++value_begin_; // Gracefully recover from mismatching quotes. |
991 } else { | 1055 } else { |
992 value_is_quoted_ = true; | |
993 // Do not store iterators into this. See declaration of unquoted_value_. | 1056 // Do not store iterators into this. See declaration of unquoted_value_. |
994 unquoted_value_ = HttpUtil::Unquote(value_begin_, value_end_); | 1057 unquoted_value_ = HttpUtil::Unquote(value_begin_, value_end_); |
995 } | 1058 } |
996 } | 1059 } |
997 | 1060 |
998 return true; | 1061 return true; |
999 } | 1062 } |
1000 | 1063 |
1001 } // namespace net | 1064 } // namespace net |
OLD | NEW |