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

Unified Diff: net/cookies/parsed_cookie.cc

Issue 10697035: Add a mutable version of CookieMonster::ParsedCookie (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Merged with ToT Created 8 years, 5 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 side-by-side diff with in-line comments
Download patch
Index: net/cookies/parsed_cookie.cc
diff --git a/net/cookies/parsed_cookie.cc b/net/cookies/parsed_cookie.cc
index f9af3c9fa94046bc9c6f6e4d8b27209a2508c38a..08c8c9462da26f5de19429eeb453e61810f3b7d7 100644
--- a/net/cookies/parsed_cookie.cc
+++ b/net/cookies/parsed_cookie.cc
@@ -47,6 +47,25 @@
#include "base/logging.h"
#include "base/string_util.h"
+namespace {
+
+const char kPathTokenName[] = "path";
+const char kDomainTokenName[] = "domain";
+const char kMACKeyTokenName[] = "mac-key";
+const char kMACAlgorithmTokenName[] = "mac-algorithm";
+const char kExpiresTokenName[] = "expires";
+const char kMaxAgeTokenName[] = "max-age";
+const char kSecureTokenName[] = "secure";
+const char kHttpOnlyTokenName[] = "httponly";
+
+const char kTerminator[] = "\n\r\0";
+const int kTerminatorLen = sizeof(kTerminator) - 1;
+const char kWhitespace[] = " \t";
+const char kValueSeparator[] = ";";
+const char kTokenSeparator[] = ";=";
+
+} // namespace
+
namespace net {
ParsedCookie::ParsedCookie(const std::string& cookie_line)
@@ -103,23 +122,140 @@ static inline bool SeekBackPast(std::string::const_iterator* it,
return *it == end;
}
-const char ParsedCookie::kTerminator[] = "\n\r\0";
-const int ParsedCookie::kTerminatorLen = sizeof(kTerminator) - 1;
-const char ParsedCookie::kWhitespace[] = " \t";
-const char ParsedCookie::kValueSeparator[] = ";";
-const char ParsedCookie::kTokenSeparator[] = ";=";
+// Validate whether |value| is a valid token according to [RFC2616],
+// Section 2.2.
+static bool IsValidToken(const std::string& value) {
+ if (value.empty())
+ return false;
+
+ // Check that |value| has no separators.
+ std::string separators = "()<>@,;:\\\"/[]?={} \t";
+ if (value.find_first_of(separators) != std::string::npos)
+ return false;
+
+ // Check that |value| has no CTLs.
+ for (std::string::const_iterator i = value.begin(); i != value.end(); ++i) {
+ if ((*i >= 0 && *i <= 31) || *i >= 127)
+ return false;
+ }
+
+ return true;
+}
+
+bool ParsedCookie::SetName(const std::string& name) {
+ if (!IsValidToken(name))
+ return false;
+ if (pairs_.empty())
+ pairs_.push_back(std::make_pair("", ""));
+ pairs_[0].first = name;
+ is_valid_ = true;
+ return true;
+}
+
+// Validate value, which may be according to RFC 6265
+// cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
+// cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
+// ; US-ASCII characters excluding CTLs,
+// ; whitespace DQUOTE, comma, semicolon,
+// ; and backslash
+static bool IsValidCookieValue(const std::string& value) {
+ // Number of characters to skip in validation at beginning and end of string.
+ size_t skip = 0;
+ if (value.size() >= 2 && *value.begin() == '"' && *(value.end()-1) == '"')
+ skip = 1;
+ for (std::string::const_iterator i = value.begin() + skip;
+ i != value.end() - skip; ++i) {
+ bool valid_octet =
+ (*i == 0x21 ||
+ (*i >= 0x23 && *i <= 0x2B) ||
+ (*i >= 0x2D && *i <= 0x3A) ||
+ (*i >= 0x3C && *i <= 0x5B) ||
+ (*i >= 0x5D && *i <= 0x7E));
+ if (!valid_octet)
+ return false;
+ }
+ return true;
+}
+
+bool ParsedCookie::SetValue(const std::string& value) {
+ if (!IsValidCookieValue(value))
+ return false;
+ if (pairs_.empty())
+ pairs_.push_back(std::make_pair("", ""));
+ pairs_[0].second = value;
+ is_valid_ = true;
+ return true;
+}
+
+bool ParsedCookie::SetPath(const std::string& path) {
+ if (path.empty())
+ return ClearAttributePair(path_index_);
+ else
+ return SetAttributePair(&path_index_, kPathTokenName, path);
+}
+
+bool ParsedCookie::SetDomain(const std::string& domain) {
+ if (domain.empty())
+ return ClearAttributePair(domain_index_);
+ else
+ return SetAttributePair(&domain_index_, kDomainTokenName, domain);
+}
+
+bool ParsedCookie::SetMACKey(const std::string& mac_key) {
+ if (mac_key.empty())
+ return ClearAttributePair(mac_key_index_);
+ else
+ return SetAttributePair(&mac_key_index_, kMACKeyTokenName, mac_key);
+}
+
+bool ParsedCookie::SetMACAlgorithm(const std::string& mac_algorithm) {
+ if (mac_algorithm.empty()) {
+ return ClearAttributePair(mac_algorithm_index_);
+ } else {
+ return SetAttributePair(&mac_algorithm_index_, kMACAlgorithmTokenName,
+ mac_algorithm);
+ }
+}
+
+bool ParsedCookie::SetExpires(const std::string& expires) {
+ if (expires.empty())
+ return ClearAttributePair(expires_index_);
+ else
+ return SetAttributePair(&expires_index_, kExpiresTokenName, expires);
+}
+
+bool ParsedCookie::SetMaxAge(const std::string& maxage) {
+ if (maxage.empty())
+ return ClearAttributePair(maxage_index_);
+ else
+ return SetAttributePair(&maxage_index_, kMaxAgeTokenName, maxage);
+}
-// Create a cookie-line for the cookie. For debugging only!
-// If we want to use this for something more than debugging, we
-// should rewrite it better...
-std::string ParsedCookie::DebugString() const {
+bool ParsedCookie::SetIsSecure(bool is_secure) {
+ if (is_secure)
+ return SetAttributePair(&secure_index_, kSecureTokenName, "");
+ else
+ return ClearAttributePair(secure_index_);
+}
+
+bool ParsedCookie::SetIsHttpOnly(bool is_http_only) {
+ if (is_http_only)
+ return SetAttributePair(&httponly_index_, kHttpOnlyTokenName, "");
+ else
+ return ClearAttributePair(httponly_index_);
+}
+
+std::string ParsedCookie::ToCookieLine() const {
std::string out;
for (PairList::const_iterator it = pairs_.begin();
it != pairs_.end(); ++it) {
+ if (!out.empty())
+ out.append("; ");
out.append(it->first);
- out.append("=");
- out.append(it->second);
- out.append("; ");
+ if (it->first != kSecureTokenName && it->first != kHttpOnlyTokenName) {
+ out.append("=");
+ out.append(it->second);
+ }
}
return out;
}
@@ -279,15 +415,6 @@ void ParsedCookie::ParseTokenValuePairs(const std::string& cookie_line) {
}
void ParsedCookie::SetupAttributes() {
- static const char kPathTokenName[] = "path";
- static const char kDomainTokenName[] = "domain";
- static const char kMACKeyTokenName[] = "mac-key";
- static const char kMACAlgorithmTokenName[] = "mac-algorithm";
- static const char kExpiresTokenName[] = "expires";
- static const char kMaxAgeTokenName[] = "max-age";
- static const char kSecureTokenName[] = "secure";
- static const char kHttpOnlyTokenName[] = "httponly";
-
// We skip over the first token/value, the user supplied one.
for (size_t i = 1; i < pairs_.size(); ++i) {
if (pairs_[i].first == kPathTokenName) {
@@ -312,4 +439,53 @@ void ParsedCookie::SetupAttributes() {
}
}
+static bool IsValidCookieAttributeValue(const std::string& value) {
+ // The greatest common denominator of cookie attribute values is
+ // <any CHAR except CTLs or ";"> according to RFC 6265.
+ for (std::string::const_iterator i = value.begin(); i != value.end(); ++i) {
+ if ((*i >= 0 && *i <= 31) || *i == ';')
+ return false;
+ }
+ return true;
+}
+
+bool ParsedCookie::SetAttributePair(size_t* index,
+ const std::string& key,
+ const std::string& value) {
+ if (!IsValidToken(key) || !IsValidCookieAttributeValue(value))
+ return false;
+ if (*index) {
+ pairs_[*index].second = value;
+ } else {
+ // Reserve first spot for cooie name and value.
erikwright (departed) 2012/07/12 15:50:57 Seems to me it would be better to fail if there is
battre 2012/07/12 18:03:10 Done.
+ if (pairs_.empty())
+ pairs_.push_back(std::make_pair("", ""));
+ pairs_.push_back(std::make_pair(key, value));
+ *index = pairs_.size() - 1;
+ }
+ is_valid_ = true;
+ return true;
+}
+
+bool ParsedCookie::ClearAttributePair(size_t index) {
+ // The first pair (name/value of cookie at pairs_[0]) cannot be cleared.
+ // Cookie attributes that don't have a value at the moment, are represented
+ // with an index being equal to 0.
+ if (index == 0)
+ return true;
+
+ size_t* indexes[] = {&path_index_, &domain_index_, &mac_key_index_,
+ &mac_algorithm_index_, &expires_index_, &maxage_index_, &secure_index_,
+ &httponly_index_};
+ for (size_t i = 0; i < arraysize(indexes); ++i) {
+ if (*indexes[i] == index)
+ *indexes[i] = 0;
+ else if (*indexes[i] > index)
+ --*indexes[i];
+ }
+ pairs_.erase(pairs_.begin() + index);
+ is_valid_ = pairs_.empty();
erikwright (departed) 2012/07/12 15:50:57 It seems that is_valid_ can never be mutated by th
battre 2012/07/12 18:03:10 I have redefined IsValid() as you have suggested.
+ return true;
erikwright (departed) 2012/07/12 15:50:57 If you won't ever return false, change return type
battre 2012/07/12 18:03:10 Done, even thought this comes at the cost of makin
+}
+
} // namespace

Powered by Google App Engine
This is Rietveld 408576698