Chromium Code Reviews| 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 |