| 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 // Portions of this code based on Mozilla: | 5 // Portions of this code based on Mozilla: |
| 6 // (netwerk/cookie/src/nsCookieService.cpp) | 6 // (netwerk/cookie/src/nsCookieService.cpp) |
| 7 /* ***** BEGIN LICENSE BLOCK ***** | 7 /* ***** BEGIN LICENSE BLOCK ***** |
| 8 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 | 8 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
| 9 * | 9 * |
| 10 * The contents of this file are subject to the Mozilla Public License Version | 10 * The contents of this file are subject to the Mozilla Public License Version |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 67 // Determine the cookie domain to use for setting the specified cookie. | 67 // Determine the cookie domain to use for setting the specified cookie. |
| 68 bool GetCookieDomain(const GURL& url, | 68 bool GetCookieDomain(const GURL& url, |
| 69 const ParsedCookie& pc, | 69 const ParsedCookie& pc, |
| 70 std::string* result) { | 70 std::string* result) { |
| 71 std::string domain_string; | 71 std::string domain_string; |
| 72 if (pc.HasDomain()) | 72 if (pc.HasDomain()) |
| 73 domain_string = pc.Domain(); | 73 domain_string = pc.Domain(); |
| 74 return cookie_util::GetCookieDomainWithString(url, domain_string, result); | 74 return cookie_util::GetCookieDomainWithString(url, domain_string, result); |
| 75 } | 75 } |
| 76 | 76 |
| 77 std::string CanonPathWithString(const GURL& url, | |
| 78 const std::string& path_string) { | |
| 79 // The RFC says the path should be a prefix of the current URL path. | |
| 80 // However, Mozilla allows you to set any path for compatibility with | |
| 81 // broken websites. We unfortunately will mimic this behavior. We try | |
| 82 // to be generous and accept cookies with an invalid path attribute, and | |
| 83 // default the path to something reasonable. | |
| 84 | |
| 85 // The path was supplied in the cookie, we'll take it. | |
| 86 if (!path_string.empty() && path_string[0] == '/') | |
| 87 return path_string; | |
| 88 | |
| 89 // The path was not supplied in the cookie or invalid, we will default | |
| 90 // to the current URL path. | |
| 91 // """Defaults to the path of the request URL that generated the | |
| 92 // Set-Cookie response, up to, but not including, the | |
| 93 // right-most /.""" | |
| 94 // How would this work for a cookie on /? We will include it then. | |
| 95 const std::string& url_path = url.path(); | |
| 96 | |
| 97 size_t idx = url_path.find_last_of('/'); | |
| 98 | |
| 99 // The cookie path was invalid or a single '/'. | |
| 100 if (idx == 0 || idx == std::string::npos) | |
| 101 return std::string("/"); | |
| 102 | |
| 103 // Return up to the rightmost '/'. | |
| 104 return url_path.substr(0, idx); | |
| 105 } | |
| 106 | |
| 107 // Compares cookies using name, domain and path, so that "equivalent" cookies | 77 // Compares cookies using name, domain and path, so that "equivalent" cookies |
| 108 // (per RFC 2965) are equal to each other. | 78 // (per RFC 2965) are equal to each other. |
| 109 int PartialCookieOrdering(const CanonicalCookie& a, const CanonicalCookie& b) { | 79 int PartialCookieOrdering(const CanonicalCookie& a, const CanonicalCookie& b) { |
| 110 int diff = a.Name().compare(b.Name()); | 80 int diff = a.Name().compare(b.Name()); |
| 111 if (diff != 0) | 81 if (diff != 0) |
| 112 return diff; | 82 return diff; |
| 113 | 83 |
| 114 diff = a.Domain().compare(b.Domain()); | 84 diff = a.Domain().compare(b.Domain()); |
| 115 if (diff != 0) | 85 if (diff != 0) |
| 116 return diff; | 86 return diff; |
| 117 | 87 |
| 118 return a.Path().compare(b.Path()); | 88 return a.Path().compare(b.Path()); |
| 119 } | 89 } |
| 120 | 90 |
| 121 } // namespace | 91 } // namespace |
| 122 | 92 |
| 123 CanonicalCookie::CanonicalCookie() | 93 CanonicalCookie::CanonicalCookie() |
| 124 : secure_(false), | 94 : secure_(false), |
| 125 httponly_(false) { | 95 httponly_(false) { |
| 126 } | 96 } |
| 127 | 97 |
| 128 CanonicalCookie::CanonicalCookie(const CanonicalCookie& other) = default; | 98 CanonicalCookie::CanonicalCookie(const CanonicalCookie& other) = default; |
| 129 | 99 |
| 130 CanonicalCookie::~CanonicalCookie() {} | 100 CanonicalCookie::~CanonicalCookie() {} |
| 131 | 101 |
| 132 // static | 102 // static |
| 133 std::string CanonicalCookie::CanonPath(const GURL& url, | 103 std::string CanonicalCookie::CanonPathWithString( |
| 134 const ParsedCookie& pc) { | 104 const GURL& url, |
| 135 std::string path_string; | 105 const std::string& path_string) { |
| 136 if (pc.HasPath()) | 106 // The RFC says the path should be a prefix of the current URL path. |
| 137 path_string = pc.Path(); | 107 // However, Mozilla allows you to set any path for compatibility with |
| 138 return CanonPathWithString(url, path_string); | 108 // broken websites. We unfortunately will mimic this behavior. We try |
| 109 // to be generous and accept cookies with an invalid path attribute, and |
| 110 // default the path to something reasonable. |
| 111 |
| 112 // The path was supplied in the cookie, we'll take it. |
| 113 if (!path_string.empty() && path_string[0] == '/') |
| 114 return path_string; |
| 115 |
| 116 // The path was not supplied in the cookie or invalid, we will default |
| 117 // to the current URL path. |
| 118 // """Defaults to the path of the request URL that generated the |
| 119 // Set-Cookie response, up to, but not including, the |
| 120 // right-most /.""" |
| 121 // How would this work for a cookie on /? We will include it then. |
| 122 const std::string& url_path = url.path(); |
| 123 |
| 124 size_t idx = url_path.find_last_of('/'); |
| 125 |
| 126 // The cookie path was invalid or a single '/'. |
| 127 if (idx == 0 || idx == std::string::npos) |
| 128 return std::string("/"); |
| 129 |
| 130 // Return up to the rightmost '/'. |
| 131 return url_path.substr(0, idx); |
| 139 } | 132 } |
| 140 | 133 |
| 141 // static | 134 // static |
| 142 Time CanonicalCookie::CanonExpiration(const ParsedCookie& pc, | 135 Time CanonicalCookie::CanonExpiration(const ParsedCookie& pc, |
| 143 const Time& current, | 136 const Time& current, |
| 144 const Time& server_time) { | 137 const Time& server_time) { |
| 145 // First, try the Max-Age attribute. | 138 // First, try the Max-Age attribute. |
| 146 uint64_t max_age = 0; | 139 uint64_t max_age = 0; |
| 147 if (pc.HasMaxAge() && | 140 if (pc.HasMaxAge() && |
| 148 #ifdef COMPILER_MSVC | 141 #ifdef COMPILER_MSVC |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 // Per 3.2.1 of "Deprecate modification of 'secure' cookies from non-secure | 187 // Per 3.2.1 of "Deprecate modification of 'secure' cookies from non-secure |
| 195 // origins", if the cookie's "secure-only-flag" is "true" and the requesting | 188 // origins", if the cookie's "secure-only-flag" is "true" and the requesting |
| 196 // URL does not have a secure scheme, the cookie should be thrown away. | 189 // URL does not have a secure scheme, the cookie should be thrown away. |
| 197 // https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone | 190 // https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone |
| 198 if (parsed_cookie.IsSecure() && !url.SchemeIsCryptographic()) { | 191 if (parsed_cookie.IsSecure() && !url.SchemeIsCryptographic()) { |
| 199 VLOG(kVlogSetCookies) | 192 VLOG(kVlogSetCookies) |
| 200 << "Create() is trying to create a secure cookie from an insecure URL"; | 193 << "Create() is trying to create a secure cookie from an insecure URL"; |
| 201 return nullptr; | 194 return nullptr; |
| 202 } | 195 } |
| 203 | 196 |
| 204 std::string cookie_path = CanonicalCookie::CanonPath(url, parsed_cookie); | 197 std::string cookie_path = CanonPathWithString( |
| 198 url, parsed_cookie.HasPath() ? parsed_cookie.Path() : std::string()); |
| 199 |
| 205 Time server_time(creation_time); | 200 Time server_time(creation_time); |
| 206 if (options.has_server_time()) | 201 if (options.has_server_time()) |
| 207 server_time = options.server_time(); | 202 server_time = options.server_time(); |
| 208 | 203 |
| 209 Time cookie_expires = CanonicalCookie::CanonExpiration(parsed_cookie, | 204 Time cookie_expires = CanonicalCookie::CanonExpiration(parsed_cookie, |
| 210 creation_time, | 205 creation_time, |
| 211 server_time); | 206 server_time); |
| 212 | 207 |
| 213 CookiePrefix prefix = CanonicalCookie::GetCookiePrefix(parsed_cookie.Name()); | 208 CookiePrefix prefix = CanonicalCookie::GetCookiePrefix(parsed_cookie.Name()); |
| 214 bool is_cookie_valid = | 209 bool is_cookie_valid = |
| 215 CanonicalCookie::IsCookiePrefixValid(prefix, url, parsed_cookie); | 210 CanonicalCookie::IsCookiePrefixValid(prefix, url, parsed_cookie); |
| 216 CanonicalCookie::RecordCookiePrefixMetrics(prefix, is_cookie_valid); | 211 CanonicalCookie::RecordCookiePrefixMetrics(prefix, is_cookie_valid); |
| 217 if (!is_cookie_valid) { | 212 if (!is_cookie_valid) { |
| 218 VLOG(kVlogSetCookies) | 213 VLOG(kVlogSetCookies) |
| 219 << "Create() failed because the cookie violated prefix rules."; | 214 << "Create() failed because the cookie violated prefix rules."; |
| 220 return nullptr; | 215 return nullptr; |
| 221 } | 216 } |
| 222 | 217 |
| 223 return base::WrapUnique(new CanonicalCookie( | 218 return base::WrapUnique(new CanonicalCookie( |
| 224 parsed_cookie.Name(), parsed_cookie.Value(), cookie_domain, cookie_path, | 219 parsed_cookie.Name(), parsed_cookie.Value(), cookie_domain, cookie_path, |
| 225 creation_time, cookie_expires, creation_time, parsed_cookie.IsSecure(), | 220 creation_time, cookie_expires, creation_time, parsed_cookie.IsSecure(), |
| 226 parsed_cookie.IsHttpOnly(), parsed_cookie.SameSite(), | 221 parsed_cookie.IsHttpOnly(), parsed_cookie.SameSite(), |
| 227 parsed_cookie.Priority())); | 222 parsed_cookie.Priority())); |
| 228 } | 223 } |
| 229 | 224 |
| 230 // static | 225 // static |
| 231 std::unique_ptr<CanonicalCookie> CanonicalCookie::Create( | 226 std::unique_ptr<CanonicalCookie> CanonicalCookie::Create( |
| 232 const GURL& url, | |
| 233 const std::string& name, | |
| 234 const std::string& value, | |
| 235 const std::string& domain, | |
| 236 const std::string& path, | |
| 237 const base::Time& creation, | |
| 238 const base::Time& expiration, | |
| 239 bool secure, | |
| 240 bool http_only, | |
| 241 CookieSameSite same_site, | |
| 242 CookiePriority priority) { | |
| 243 // Expect valid attribute tokens and values, as defined by the ParsedCookie | |
| 244 // logic, otherwise don't create the cookie. | |
| 245 std::string parsed_name = ParsedCookie::ParseTokenString(name); | |
| 246 if (parsed_name != name) | |
| 247 return nullptr; | |
| 248 std::string parsed_value = ParsedCookie::ParseValueString(value); | |
| 249 if (parsed_value != value) | |
| 250 return nullptr; | |
| 251 | |
| 252 std::string parsed_domain = ParsedCookie::ParseValueString(domain); | |
| 253 if (parsed_domain != domain) | |
| 254 return nullptr; | |
| 255 std::string cookie_domain; | |
| 256 if (!cookie_util::GetCookieDomainWithString(url, parsed_domain, | |
| 257 &cookie_domain)) { | |
| 258 return nullptr; | |
| 259 } | |
| 260 | |
| 261 if (secure && !url.SchemeIsCryptographic()) | |
| 262 return nullptr; | |
| 263 | |
| 264 std::string parsed_path = ParsedCookie::ParseValueString(path); | |
| 265 if (parsed_path != path) | |
| 266 return nullptr; | |
| 267 | |
| 268 std::string cookie_path = CanonPathWithString(url, parsed_path); | |
| 269 // Expect that the path was either not specified (empty), or is valid. | |
| 270 if (!parsed_path.empty() && cookie_path != parsed_path) | |
| 271 return nullptr; | |
| 272 // Canonicalize path again to make sure it escapes characters as needed. | |
| 273 url::Component path_component(0, cookie_path.length()); | |
| 274 url::RawCanonOutputT<char> canon_path; | |
| 275 url::Component canon_path_component; | |
| 276 url::CanonicalizePath(cookie_path.data(), path_component, &canon_path, | |
| 277 &canon_path_component); | |
| 278 cookie_path = std::string(canon_path.data() + canon_path_component.begin, | |
| 279 canon_path_component.len); | |
| 280 | |
| 281 return base::WrapUnique(new CanonicalCookie( | |
| 282 parsed_name, parsed_value, cookie_domain, cookie_path, creation, | |
| 283 expiration, creation, secure, http_only, same_site, priority)); | |
| 284 } | |
| 285 | |
| 286 // static | |
| 287 std::unique_ptr<CanonicalCookie> CanonicalCookie::Create( | |
| 288 const std::string& name, | 227 const std::string& name, |
| 289 const std::string& value, | 228 const std::string& value, |
| 290 const std::string& domain, | 229 const std::string& domain, |
| 291 const std::string& path, | 230 const std::string& path, |
| 292 const base::Time& creation, | 231 const base::Time& creation, |
| 293 const base::Time& expiration, | 232 const base::Time& expiration, |
| 294 const base::Time& last_access, | 233 const base::Time& last_access, |
| 295 bool secure, | 234 bool secure, |
| 296 bool http_only, | 235 bool http_only, |
| 297 CookieSameSite same_site, | 236 CookieSameSite same_site, |
| 298 CookiePriority priority) { | 237 CookiePriority priority) { |
| 238 DCHECK(!name.empty()); |
| 239 DCHECK(!path.empty()); |
| 240 |
| 299 return base::WrapUnique( | 241 return base::WrapUnique( |
| 300 new CanonicalCookie(name, value, domain, path, creation, expiration, | 242 new CanonicalCookie(name, value, domain, path, creation, expiration, |
| 301 last_access, secure, http_only, same_site, priority)); | 243 last_access, secure, http_only, same_site, priority)); |
| 302 } | 244 } |
| 303 | 245 |
| 304 bool CanonicalCookie::IsEquivalentForSecureCookieMatching( | 246 bool CanonicalCookie::IsEquivalentForSecureCookieMatching( |
| 305 const CanonicalCookie& ecc) const { | 247 const CanonicalCookie& ecc) const { |
| 306 return (name_ == ecc.Name() && (ecc.IsDomainMatch(DomainWithoutDot()) || | 248 return (name_ == ecc.Name() && (ecc.IsDomainMatch(DomainWithoutDot()) || |
| 307 IsDomainMatch(ecc.DomainWithoutDot())) && | 249 IsDomainMatch(ecc.DomainWithoutDot())) && |
| 308 ecc.IsOnPath(Path())); | 250 ecc.IsOnPath(Path())); |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 521 return true; | 463 return true; |
| 522 } | 464 } |
| 523 | 465 |
| 524 std::string CanonicalCookie::DomainWithoutDot() const { | 466 std::string CanonicalCookie::DomainWithoutDot() const { |
| 525 if (domain_.empty() || domain_[0] != '.') | 467 if (domain_.empty() || domain_[0] != '.') |
| 526 return domain_; | 468 return domain_; |
| 527 return domain_.substr(1); | 469 return domain_.substr(1); |
| 528 } | 470 } |
| 529 | 471 |
| 530 } // namespace net | 472 } // namespace net |
| OLD | NEW |