Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1512)

Side by Side Diff: net/http/http_util.cc

Issue 1811163002: Share link header parsing code between blink and content. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@base-optional
Patch Set: rebase Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/http/http_util.h ('k') | net/http/http_util_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 427 matching lines...) Expand 10 before | Expand all | Expand 10 after
438 while (*begin < *end && IsLWS((*end)[-1])) 438 while (*begin < *end && IsLWS((*end)[-1]))
439 --(*end); 439 --(*end);
440 } 440 }
441 441
442 bool HttpUtil::IsQuote(char c) { 442 bool HttpUtil::IsQuote(char c) {
443 // Single quote mark isn't actually part of quoted-text production, 443 // Single quote mark isn't actually part of quoted-text production,
444 // but apparently some servers rely on this. 444 // but apparently some servers rely on this.
445 return c == '"' || c == '\''; 445 return c == '"' || c == '\'';
446 } 446 }
447 447
448 namespace {
449 bool IsTokenChar(unsigned char c) {
450 return !(c >= 0x80 || c <= 0x1F || c == 0x7F || c == '(' || c == ')' ||
451 c == '<' || c == '>' || c == '@' || c == ',' || c == ';' ||
452 c == ':' || c == '\\' || c == '"' || c == '/' || c == '[' ||
453 c == ']' || c == '?' || c == '=' || c == '{' || c == '}' ||
454 c == ' ' || c == '\t');
455 }
456 } // anonymous namespace
457
448 // See RFC 2616 Sec 2.2 for the definition of |token|. 458 // See RFC 2616 Sec 2.2 for the definition of |token|.
449 bool HttpUtil::IsToken(std::string::const_iterator begin, 459 bool HttpUtil::IsToken(std::string::const_iterator begin,
450 std::string::const_iterator end) { 460 std::string::const_iterator end) {
451 if (begin == end) 461 if (begin == end)
452 return false; 462 return false;
453 for (std::string::const_iterator iter = begin; iter != end; ++iter) { 463 for (std::string::const_iterator iter = begin; iter != end; ++iter) {
454 unsigned char c = *iter; 464 if (!IsTokenChar(*iter))
455 if (c >= 0x80 || c <= 0x1F || c == 0x7F ||
456 c == '(' || c == ')' || c == '<' || c == '>' || c == '@' ||
457 c == ',' || c == ';' || c == ':' || c == '\\' || c == '"' ||
458 c == '/' || c == '[' || c == ']' || c == '?' || c == '=' ||
459 c == '{' || c == '}' || c == ' ' || c == '\t')
460 return false; 465 return false;
461 } 466 }
462 return true; 467 return true;
463 } 468 }
464 469
465 std::string HttpUtil::Unquote(std::string::const_iterator begin, 470 // See RFC 5987 Sec 3.2.1 for the definition of |parmname|.
466 std::string::const_iterator end) { 471 bool HttpUtil::IsParmName(std::string::const_iterator begin,
472 std::string::const_iterator end) {
473 if (begin == end)
474 return false;
475 for (std::string::const_iterator iter = begin; iter != end; ++iter) {
476 unsigned char c = *iter;
477 if (!IsTokenChar(c) || c == '*' || c == '\'' || c == '%')
478 return false;
479 }
480 return true;
481 }
482
483 namespace {
484 bool UnquoteImpl(std::string::const_iterator begin,
485 std::string::const_iterator end,
486 bool strict_quotes,
487 std::string* out) {
467 // Empty string 488 // Empty string
468 if (begin == end) 489 if (begin == end)
469 return std::string(); 490 return false;
470 491
471 // Nothing to unquote. 492 // Nothing to unquote.
472 if (!IsQuote(*begin)) 493 if (!HttpUtil::IsQuote(*begin))
473 return std::string(begin, end); 494 return false;
495
496 // Anything other than double quotes in strict mode.
497 if (strict_quotes && *begin != '"')
498 return false;
474 499
475 // No terminal quote mark. 500 // No terminal quote mark.
476 if (end - begin < 2 || *begin != *(end - 1)) 501 if (end - begin < 2 || *begin != *(end - 1))
477 return std::string(begin, end); 502 return false;
503
504 char quote = *begin;
478 505
479 // Strip quotemarks 506 // Strip quotemarks
480 ++begin; 507 ++begin;
481 --end; 508 --end;
482 509
483 // Unescape quoted-pair (defined in RFC 2616 section 2.2) 510 // Unescape quoted-pair (defined in RFC 2616 section 2.2)
511 bool prev_escape = false;
484 std::string unescaped; 512 std::string unescaped;
485 bool prev_escape = false;
486 for (; begin != end; ++begin) { 513 for (; begin != end; ++begin) {
487 char c = *begin; 514 char c = *begin;
488 if (c == '\\' && !prev_escape) { 515 if (c == '\\' && !prev_escape) {
489 prev_escape = true; 516 prev_escape = true;
490 continue; 517 continue;
491 } 518 }
519 if (strict_quotes && !prev_escape && c == quote)
520 return false;
492 prev_escape = false; 521 prev_escape = false;
493 unescaped.push_back(c); 522 unescaped.push_back(c);
494 } 523 }
495 return unescaped; 524
525 // Terminal quote is escaped.
526 if (strict_quotes && prev_escape)
527 return false;
528
529 *out = std::move(unescaped);
530 return true;
531 }
532 } // anonymous namespace
533
534 std::string HttpUtil::Unquote(std::string::const_iterator begin,
535 std::string::const_iterator end) {
536 std::string result;
537 if (!UnquoteImpl(begin, end, false, &result))
538 return std::string(begin, end);
539
540 return result;
496 } 541 }
497 542
498 // static 543 // static
499 std::string HttpUtil::Unquote(const std::string& str) { 544 std::string HttpUtil::Unquote(const std::string& str) {
500 return Unquote(str.begin(), str.end()); 545 return Unquote(str.begin(), str.end());
501 } 546 }
502 547
503 // static 548 // static
549 bool HttpUtil::StrictUnquote(std::string::const_iterator begin,
550 std::string::const_iterator end,
551 std::string* out) {
552 return UnquoteImpl(begin, end, true, out);
553 }
554
555 // static
556 bool HttpUtil::StrictUnquote(const std::string& str, std::string* out) {
557 return StrictUnquote(str.begin(), str.end(), out);
558 }
559
560 // static
504 std::string HttpUtil::Quote(const std::string& str) { 561 std::string HttpUtil::Quote(const std::string& str) {
505 std::string escaped; 562 std::string escaped;
506 escaped.reserve(2 + str.size()); 563 escaped.reserve(2 + str.size());
507 564
508 std::string::const_iterator begin = str.begin(); 565 std::string::const_iterator begin = str.begin();
509 std::string::const_iterator end = str.end(); 566 std::string::const_iterator end = str.end();
510 567
511 // Esape any backslashes or quotemarks within the string, and 568 // Esape any backslashes or quotemarks within the string, and
512 // then surround with quotes. 569 // then surround with quotes.
513 escaped.push_back('"'); 570 escaped.push_back('"');
(...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after
903 if (value_begin_ != value_end_) 960 if (value_begin_ != value_end_)
904 return true; 961 return true;
905 } 962 }
906 return false; 963 return false;
907 } 964 }
908 965
909 HttpUtil::NameValuePairsIterator::NameValuePairsIterator( 966 HttpUtil::NameValuePairsIterator::NameValuePairsIterator(
910 std::string::const_iterator begin, 967 std::string::const_iterator begin,
911 std::string::const_iterator end, 968 std::string::const_iterator end,
912 char delimiter, 969 char delimiter,
913 OptionalValues optional_values) 970 Values optional_values,
971 Quotes strict_quotes)
914 : props_(begin, end, delimiter), 972 : props_(begin, end, delimiter),
915 valid_(true), 973 valid_(true),
916 name_begin_(end), 974 name_begin_(end),
917 name_end_(end), 975 name_end_(end),
918 value_begin_(end), 976 value_begin_(end),
919 value_end_(end), 977 value_end_(end),
920 value_is_quoted_(false), 978 value_is_quoted_(false),
921 values_optional_(optional_values == VALUES_OPTIONAL) {} 979 values_optional_(optional_values == Values::NOT_REQUIRED),
980 strict_quotes_(strict_quotes == Quotes::STRICT_QUOTES) {
981 if (strict_quotes_)
982 props_.set_quote_chars("\"");
983 }
922 984
923 HttpUtil::NameValuePairsIterator::NameValuePairsIterator( 985 HttpUtil::NameValuePairsIterator::NameValuePairsIterator(
924 std::string::const_iterator begin, 986 std::string::const_iterator begin,
925 std::string::const_iterator end, 987 std::string::const_iterator end,
926 char delimiter) 988 char delimiter)
927 : NameValuePairsIterator(begin, end, delimiter, VALUES_NOT_OPTIONAL) {} 989 : NameValuePairsIterator(begin,
990 end,
991 delimiter,
992 Values::REQUIRED,
993 Quotes::NOT_STRICT) {}
928 994
929 HttpUtil::NameValuePairsIterator::NameValuePairsIterator( 995 HttpUtil::NameValuePairsIterator::NameValuePairsIterator(
930 const NameValuePairsIterator& other) = default; 996 const NameValuePairsIterator& other) = default;
931 997
932 HttpUtil::NameValuePairsIterator::~NameValuePairsIterator() {} 998 HttpUtil::NameValuePairsIterator::~NameValuePairsIterator() {}
933 999
934 // We expect properties to be formatted as one of: 1000 // We expect properties to be formatted as one of:
935 // name="value" 1001 // name="value"
936 // name='value' 1002 // name='value'
937 // name='\'value\'' 1003 // name='\'value\''
(...skipping 15 matching lines...) Expand all
953 // Scan for the equals sign. 1019 // Scan for the equals sign.
954 std::string::const_iterator equals = std::find(value_begin_, value_end_, '='); 1020 std::string::const_iterator equals = std::find(value_begin_, value_end_, '=');
955 if (equals == value_begin_) 1021 if (equals == value_begin_)
956 return valid_ = false; // Malformed, no name 1022 return valid_ = false; // Malformed, no name
957 if (equals == value_end_ && !values_optional_) 1023 if (equals == value_end_ && !values_optional_)
958 return valid_ = false; // Malformed, no equals sign and values are required 1024 return valid_ = false; // Malformed, no equals sign and values are required
959 1025
960 // If an equals sign was found, verify that it wasn't inside of quote marks. 1026 // If an equals sign was found, verify that it wasn't inside of quote marks.
961 if (equals != value_end_) { 1027 if (equals != value_end_) {
962 for (std::string::const_iterator it = value_begin_; it != equals; ++it) { 1028 for (std::string::const_iterator it = value_begin_; it != equals; ++it) {
963 if (HttpUtil::IsQuote(*it)) 1029 if (IsQuote(*it))
964 return valid_ = false; // Malformed, quote appears before equals sign 1030 return valid_ = false; // Malformed, quote appears before equals sign
965 } 1031 }
966 } 1032 }
967 1033
968 name_begin_ = value_begin_; 1034 name_begin_ = value_begin_;
969 name_end_ = equals; 1035 name_end_ = equals;
970 value_begin_ = (equals == value_end_) ? value_end_ : equals + 1; 1036 value_begin_ = (equals == value_end_) ? value_end_ : equals + 1;
971 1037
972 TrimLWS(&name_begin_, &name_end_); 1038 TrimLWS(&name_begin_, &name_end_);
973 TrimLWS(&value_begin_, &value_end_); 1039 TrimLWS(&value_begin_, &value_end_);
974 value_is_quoted_ = false; 1040 value_is_quoted_ = false;
975 unquoted_value_.clear(); 1041 unquoted_value_.clear();
976 1042
977 if (equals != value_end_ && value_begin_ == value_end_) { 1043 if (equals != value_end_ && value_begin_ == value_end_) {
978 // Malformed; value is empty 1044 // Malformed; value is empty
979 return valid_ = false; 1045 return valid_ = false;
980 } 1046 }
981 1047
982 if (value_begin_ != value_end_ && HttpUtil::IsQuote(*value_begin_)) { 1048 if (value_begin_ != value_end_ && IsQuote(*value_begin_)) {
1049 value_is_quoted_ = true;
1050
1051 if (strict_quotes_) {
1052 if (!HttpUtil::StrictUnquote(value_begin_, value_end_, &unquoted_value_))
1053 return valid_ = false;
1054 return true;
1055 }
1056
983 // Trim surrounding quotemarks off the value 1057 // Trim surrounding quotemarks off the value
984 if (*value_begin_ != *(value_end_ - 1) || value_begin_ + 1 == value_end_) { 1058 if (*value_begin_ != *(value_end_ - 1) || value_begin_ + 1 == value_end_) {
985 // NOTE: This is not as graceful as it sounds: 1059 // NOTE: This is not as graceful as it sounds:
986 // * quoted-pairs will no longer be unquoted 1060 // * quoted-pairs will no longer be unquoted
987 // (["\"hello] should give ["hello]). 1061 // (["\"hello] should give ["hello]).
988 // * Does not detect when the final quote is escaped 1062 // * Does not detect when the final quote is escaped
989 // (["value\"] should give [value"]) 1063 // (["value\"] should give [value"])
1064 value_is_quoted_ = false;
990 ++value_begin_; // Gracefully recover from mismatching quotes. 1065 ++value_begin_; // Gracefully recover from mismatching quotes.
991 } else { 1066 } else {
992 value_is_quoted_ = true;
993 // Do not store iterators into this. See declaration of unquoted_value_. 1067 // Do not store iterators into this. See declaration of unquoted_value_.
994 unquoted_value_ = HttpUtil::Unquote(value_begin_, value_end_); 1068 unquoted_value_ = HttpUtil::Unquote(value_begin_, value_end_);
995 } 1069 }
996 } 1070 }
997 1071
998 return true; 1072 return true;
999 } 1073 }
1000 1074
1075 bool HttpUtil::NameValuePairsIterator::IsQuote(char c) const {
1076 if (strict_quotes_)
1077 return c == '"';
1078 return HttpUtil::IsQuote(c);
1079 }
1080
1001 } // namespace net 1081 } // namespace net
OLDNEW
« no previous file with comments | « net/http/http_util.h ('k') | net/http/http_util_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698