| 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> |
| 11 | 11 |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/strings/string_number_conversions.h" | 13 #include "base/strings/string_number_conversions.h" |
| 14 #include "base/strings/string_piece.h" | 14 #include "base/strings/string_piece.h" |
| 15 #include "base/strings/string_tokenizer.h" | 15 #include "base/strings/string_tokenizer.h" |
| 16 #include "base/strings/string_util.h" | 16 #include "base/strings/string_util.h" |
| 17 #include "base/strings/stringprintf.h" | 17 #include "base/strings/stringprintf.h" |
| 18 #include "base/time/time.h" | 18 #include "base/time/time.h" |
| 19 #include "net/base/url_util.h" | 19 #include "net/base/url_util.h" |
| 20 | 20 |
| 21 namespace net { | 21 namespace net { |
| 22 | 22 |
| 23 namespace { |
| 24 template <typename ConstIterator> |
| 25 void TrimLWSImplementation(ConstIterator* begin, ConstIterator* end) { |
| 26 // leading whitespace |
| 27 while (*begin < *end && HttpUtil::IsLWS((*begin)[0])) |
| 28 ++(*begin); |
| 29 |
| 30 // trailing whitespace |
| 31 while (*begin < *end && HttpUtil::IsLWS((*end)[-1])) |
| 32 --(*end); |
| 33 } |
| 34 } // namespace |
| 35 |
| 23 // Helpers -------------------------------------------------------------------- | 36 // Helpers -------------------------------------------------------------------- |
| 24 | 37 |
| 25 // Returns the index of the closing quote of the string, if any. |start| points | 38 // Returns the index of the closing quote of the string, if any. |start| points |
| 26 // at the opening quote. | 39 // at the opening quote. |
| 27 static size_t FindStringEnd(const std::string& line, size_t start, char delim) { | 40 static size_t FindStringEnd(const std::string& line, size_t start, char delim) { |
| 28 DCHECK_LT(start, line.length()); | 41 DCHECK_LT(start, line.length()); |
| 29 DCHECK_EQ(line[start], delim); | 42 DCHECK_EQ(line[start], delim); |
| 30 DCHECK((delim == '"') || (delim == '\'')); | 43 DCHECK((delim == '"') || (delim == '\'')); |
| 31 | 44 |
| 32 const char set[] = { delim, '\\', '\0' }; | 45 const char set[] = { delim, '\\', '\0' }; |
| (...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 base::StartsWith(lower_name, "sec-", base::CompareCase::SENSITIVE)) | 346 base::StartsWith(lower_name, "sec-", base::CompareCase::SENSITIVE)) |
| 334 return false; | 347 return false; |
| 335 for (size_t i = 0; i < arraysize(kForbiddenHeaderFields); ++i) { | 348 for (size_t i = 0; i < arraysize(kForbiddenHeaderFields); ++i) { |
| 336 if (lower_name == kForbiddenHeaderFields[i]) | 349 if (lower_name == kForbiddenHeaderFields[i]) |
| 337 return false; | 350 return false; |
| 338 } | 351 } |
| 339 return true; | 352 return true; |
| 340 } | 353 } |
| 341 | 354 |
| 342 // static | 355 // static |
| 343 bool HttpUtil::IsValidHeaderName(const std::string& name) { | 356 bool HttpUtil::IsValidHeaderName(const base::StringPiece& name) { |
| 344 // Check whether the header name is RFC 2616-compliant. | 357 // Check whether the header name is RFC 2616-compliant. |
| 345 return HttpUtil::IsToken(name); | 358 return HttpUtil::IsToken(name); |
| 346 } | 359 } |
| 347 | 360 |
| 348 // static | 361 // static |
| 349 bool HttpUtil::IsValidHeaderValue(const std::string& value) { | 362 bool HttpUtil::IsValidHeaderValue(const base::StringPiece& value) { |
| 350 // Just a sanity check: disallow NUL, CR and LF. | 363 // Just a sanity check: disallow NUL, CR and LF. |
| 351 return value.find_first_of("\0\r\n", 0, 3) == std::string::npos; | 364 for (char c : value) { |
| 365 if (c == '\0' || c == '\r' || c == '\n') |
| 366 return false; |
| 367 } |
| 368 return true; |
| 352 } | 369 } |
| 353 | 370 |
| 354 // static | 371 // static |
| 355 std::string HttpUtil::StripHeaders(const std::string& headers, | 372 std::string HttpUtil::StripHeaders(const std::string& headers, |
| 356 const char* const headers_to_remove[], | 373 const char* const headers_to_remove[], |
| 357 size_t headers_to_remove_len) { | 374 size_t headers_to_remove_len) { |
| 358 std::string stripped_headers; | 375 std::string stripped_headers; |
| 359 HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n"); | 376 HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n"); |
| 360 | 377 |
| 361 while (it.GetNext()) { | 378 while (it.GetNext()) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 402 kNonCoalescingHeaders[i])) | 419 kNonCoalescingHeaders[i])) |
| 403 return true; | 420 return true; |
| 404 } | 421 } |
| 405 return false; | 422 return false; |
| 406 } | 423 } |
| 407 | 424 |
| 408 bool HttpUtil::IsLWS(char c) { | 425 bool HttpUtil::IsLWS(char c) { |
| 409 return strchr(HTTP_LWS, c) != NULL; | 426 return strchr(HTTP_LWS, c) != NULL; |
| 410 } | 427 } |
| 411 | 428 |
| 429 // static |
| 412 void HttpUtil::TrimLWS(std::string::const_iterator* begin, | 430 void HttpUtil::TrimLWS(std::string::const_iterator* begin, |
| 413 std::string::const_iterator* end) { | 431 std::string::const_iterator* end) { |
| 414 // leading whitespace | 432 TrimLWSImplementation(begin, end); |
| 415 while (*begin < *end && IsLWS((*begin)[0])) | 433 } |
| 416 ++(*begin); | |
| 417 | 434 |
| 418 // trailing whitespace | 435 // static |
| 419 while (*begin < *end && IsLWS((*end)[-1])) | 436 base::StringPiece HttpUtil::TrimLWS(const base::StringPiece& string) { |
| 420 --(*end); | 437 const char* begin = string.data(); |
| 438 const char* end = string.data() + string.size(); |
| 439 TrimLWSImplementation(&begin, &end); |
| 440 return base::StringPiece(begin, end - begin); |
| 421 } | 441 } |
| 422 | 442 |
| 423 bool HttpUtil::IsQuote(char c) { | 443 bool HttpUtil::IsQuote(char c) { |
| 424 // Single quote mark isn't actually part of quoted-text production, | 444 // Single quote mark isn't actually part of quoted-text production, |
| 425 // but apparently some servers rely on this. | 445 // but apparently some servers rely on this. |
| 426 return c == '"' || c == '\''; | 446 return c == '"' || c == '\''; |
| 427 } | 447 } |
| 428 | 448 |
| 429 namespace { | 449 namespace { |
| 430 bool IsTokenChar(unsigned char c) { | 450 bool IsTokenChar(unsigned char c) { |
| 431 return !(c >= 0x80 || c <= 0x1F || c == 0x7F || c == '(' || c == ')' || | 451 return !(c >= 0x80 || c <= 0x1F || c == 0x7F || c == '(' || c == ')' || |
| 432 c == '<' || c == '>' || c == '@' || c == ',' || c == ';' || | 452 c == '<' || c == '>' || c == '@' || c == ',' || c == ';' || |
| 433 c == ':' || c == '\\' || c == '"' || c == '/' || c == '[' || | 453 c == ':' || c == '\\' || c == '"' || c == '/' || c == '[' || |
| 434 c == ']' || c == '?' || c == '=' || c == '{' || c == '}' || | 454 c == ']' || c == '?' || c == '=' || c == '{' || c == '}' || |
| 435 c == ' ' || c == '\t'); | 455 c == ' ' || c == '\t'); |
| 436 } | 456 } |
| 437 } // anonymous namespace | 457 } // anonymous namespace |
| 438 | 458 |
| 439 // See RFC 2616 Sec 2.2 for the definition of |token|. | 459 // See RFC 2616 Sec 2.2 for the definition of |token|. |
| 440 bool HttpUtil::IsToken(std::string::const_iterator begin, | 460 bool HttpUtil::IsToken(const base::StringPiece& string) { |
| 441 std::string::const_iterator end) { | 461 if (string.empty()) |
| 442 if (begin == end) | |
| 443 return false; | 462 return false; |
| 444 for (std::string::const_iterator iter = begin; iter != end; ++iter) { | 463 for (char c : string) { |
| 445 if (!IsTokenChar(*iter)) | 464 if (!IsTokenChar(c)) |
| 446 return false; | 465 return false; |
| 447 } | 466 } |
| 448 return true; | 467 return true; |
| 449 } | 468 } |
| 450 | 469 |
| 451 // See RFC 5987 Sec 3.2.1 for the definition of |parmname|. | 470 // See RFC 5987 Sec 3.2.1 for the definition of |parmname|. |
| 452 bool HttpUtil::IsParmName(std::string::const_iterator begin, | 471 bool HttpUtil::IsParmName(std::string::const_iterator begin, |
| 453 std::string::const_iterator end) { | 472 std::string::const_iterator end) { |
| 454 if (begin == end) | 473 if (begin == end) |
| 455 return false; | 474 return false; |
| (...skipping 428 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 884 | 903 |
| 885 name_end_ = colon; | 904 name_end_ = colon; |
| 886 | 905 |
| 887 // If the name starts with LWS, it is an invalid line. | 906 // If the name starts with LWS, it is an invalid line. |
| 888 // Leading LWS implies a line continuation, and these should have | 907 // Leading LWS implies a line continuation, and these should have |
| 889 // already been joined by AssembleRawHeaders(). | 908 // already been joined by AssembleRawHeaders(). |
| 890 if (name_begin_ == name_end_ || IsLWS(*name_begin_)) | 909 if (name_begin_ == name_end_ || IsLWS(*name_begin_)) |
| 891 continue; | 910 continue; |
| 892 | 911 |
| 893 TrimLWS(&name_begin_, &name_end_); | 912 TrimLWS(&name_begin_, &name_end_); |
| 894 if (!IsToken(name_begin_, name_end_)) | 913 DCHECK(name_begin_ < name_end_); |
| 914 if (!IsToken(base::StringPiece(name_begin_, name_end_))) |
| 895 continue; // skip malformed header | 915 continue; // skip malformed header |
| 896 | 916 |
| 897 values_begin_ = colon + 1; | 917 values_begin_ = colon + 1; |
| 898 TrimLWS(&values_begin_, &values_end_); | 918 TrimLWS(&values_begin_, &values_end_); |
| 899 | 919 |
| 900 // if we got a header name, then we are done. | 920 // if we got a header name, then we are done. |
| 901 return true; | 921 return true; |
| 902 } | 922 } |
| 903 return false; | 923 return false; |
| 904 } | 924 } |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1053 return true; | 1073 return true; |
| 1054 } | 1074 } |
| 1055 | 1075 |
| 1056 bool HttpUtil::NameValuePairsIterator::IsQuote(char c) const { | 1076 bool HttpUtil::NameValuePairsIterator::IsQuote(char c) const { |
| 1057 if (strict_quotes_) | 1077 if (strict_quotes_) |
| 1058 return c == '"'; | 1078 return c == '"'; |
| 1059 return HttpUtil::IsQuote(c); | 1079 return HttpUtil::IsQuote(c); |
| 1060 } | 1080 } |
| 1061 | 1081 |
| 1062 } // namespace net | 1082 } // namespace net |
| OLD | NEW |