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 |