| 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 #include "net/cookies/cookie_util.h" | 5 #include "net/cookies/cookie_util.h" |
| 6 | 6 |
| 7 #include <cstdio> | 7 #include <cstdio> |
| 8 #include <cstdlib> | 8 #include <cstdlib> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/strings/string_tokenizer.h" | 11 #include "base/strings/string_tokenizer.h" |
| 12 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
| 13 #include "build/build_config.h" | 13 #include "build/build_config.h" |
| 14 #include "net/base/net_util.h" | 14 #include "net/base/net_util.h" |
| 15 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | 15 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
| 16 #include "url/gurl.h" | 16 #include "url/gurl.h" |
| 17 | 17 |
| 18 namespace net { | 18 namespace net { |
| 19 namespace cookie_util { | 19 namespace cookie_util { |
| 20 | 20 |
| 21 bool DomainIsHostOnly(const std::string& domain_string) { | 21 bool DomainIsHostOnly(const std::string& domain_string) { |
| 22 return (domain_string.empty() || domain_string[0] != '.'); | 22 return (domain_string.empty() || domain_string[0] != '.'); |
| 23 } | 23 } |
| 24 | 24 |
| 25 std::string GetEffectiveDomain(const std::string& scheme, | 25 std::string GetEffectiveDomain(const std::string& scheme, |
| 26 const std::string& host) { | 26 const std::string& host) { |
| 27 if (scheme == "http" || scheme == "https") { | 27 if (scheme == "http" || scheme == "https") { |
| 28 return registry_controlled_domains::GetDomainAndRegistry( | 28 return registry_controlled_domains::GetDomainAndRegistry( |
| 29 host, | 29 host, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); |
| 30 registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); | |
| 31 } | 30 } |
| 32 | 31 |
| 33 if (!DomainIsHostOnly(host)) | 32 if (!DomainIsHostOnly(host)) |
| 34 return host.substr(1); | 33 return host.substr(1); |
| 35 return host; | 34 return host; |
| 36 } | 35 } |
| 37 | 36 |
| 38 bool GetCookieDomainWithString(const GURL& url, | 37 bool GetCookieDomainWithString(const GURL& url, |
| 39 const std::string& domain_string, | 38 const std::string& domain_string, |
| 40 std::string* result) { | 39 std::string* result) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 65 if (url_domain_and_registry.empty()) | 64 if (url_domain_and_registry.empty()) |
| 66 return false; // IP addresses/intranet hosts can't set domain cookies. | 65 return false; // IP addresses/intranet hosts can't set domain cookies. |
| 67 const std::string cookie_domain_and_registry( | 66 const std::string cookie_domain_and_registry( |
| 68 GetEffectiveDomain(url_scheme, cookie_domain)); | 67 GetEffectiveDomain(url_scheme, cookie_domain)); |
| 69 if (url_domain_and_registry != cookie_domain_and_registry) | 68 if (url_domain_and_registry != cookie_domain_and_registry) |
| 70 return false; // Can't set a cookie on a different domain + registry. | 69 return false; // Can't set a cookie on a different domain + registry. |
| 71 | 70 |
| 72 // Ensure |url_host| is |cookie_domain| or one of its subdomains. Given that | 71 // Ensure |url_host| is |cookie_domain| or one of its subdomains. Given that |
| 73 // we know the domain+registry are the same from the above checks, this is | 72 // we know the domain+registry are the same from the above checks, this is |
| 74 // basically a simple string suffix check. | 73 // basically a simple string suffix check. |
| 75 const bool is_suffix = (url_host.length() < cookie_domain.length()) ? | 74 const bool is_suffix = |
| 76 (cookie_domain != ("." + url_host)) : | 75 (url_host.length() < cookie_domain.length()) |
| 77 (url_host.compare(url_host.length() - cookie_domain.length(), | 76 ? (cookie_domain != ("." + url_host)) |
| 78 cookie_domain.length(), cookie_domain) != 0); | 77 : (url_host.compare(url_host.length() - cookie_domain.length(), |
| 78 cookie_domain.length(), |
| 79 cookie_domain) != 0); |
| 79 if (is_suffix) | 80 if (is_suffix) |
| 80 return false; | 81 return false; |
| 81 | 82 |
| 82 *result = cookie_domain; | 83 *result = cookie_domain; |
| 83 return true; | 84 return true; |
| 84 } | 85 } |
| 85 | 86 |
| 86 // Parse a cookie expiration time. We try to be lenient, but we need to | 87 // Parse a cookie expiration time. We try to be lenient, but we need to |
| 87 // assume some order to distinguish the fields. The basic rules: | 88 // assume some order to distinguish the fields. The basic rules: |
| 88 // - The month name must be present and prefix the first 3 letters of the | 89 // - The month name must be present and prefix the first 3 letters of the |
| 89 // full month name (jan for January, jun for June). | 90 // full month name (jan for January, jun for June). |
| 90 // - If the year is <= 2 digits, it must occur after the day of month. | 91 // - If the year is <= 2 digits, it must occur after the day of month. |
| 91 // - The time must be of the format hh:mm:ss. | 92 // - The time must be of the format hh:mm:ss. |
| 92 // An average cookie expiration will look something like this: | 93 // An average cookie expiration will look something like this: |
| 93 // Sat, 15-Apr-17 21:01:22 GMT | 94 // Sat, 15-Apr-17 21:01:22 GMT |
| 94 base::Time ParseCookieTime(const std::string& time_string) { | 95 base::Time ParseCookieTime(const std::string& time_string) { |
| 95 static const char* kMonths[] = { "jan", "feb", "mar", "apr", "may", "jun", | 96 static const char* kMonths[] = {"jan", "feb", "mar", "apr", "may", "jun", |
| 96 "jul", "aug", "sep", "oct", "nov", "dec" }; | 97 "jul", "aug", "sep", "oct", "nov", "dec"}; |
| 97 static const int kMonthsLen = arraysize(kMonths); | 98 static const int kMonthsLen = arraysize(kMonths); |
| 98 // We want to be pretty liberal, and support most non-ascii and non-digit | 99 // We want to be pretty liberal, and support most non-ascii and non-digit |
| 99 // characters as a delimiter. We can't treat : as a delimiter, because it | 100 // characters as a delimiter. We can't treat : as a delimiter, because it |
| 100 // is the delimiter for hh:mm:ss, and we want to keep this field together. | 101 // is the delimiter for hh:mm:ss, and we want to keep this field together. |
| 101 // We make sure to include - and +, since they could prefix numbers. | 102 // We make sure to include - and +, since they could prefix numbers. |
| 102 // If the cookie attribute came in in quotes (ex expires="XXX"), the quotes | 103 // If the cookie attribute came in in quotes (ex expires="XXX"), the quotes |
| 103 // will be preserved, and we will get them here. So we make sure to include | 104 // will be preserved, and we will get them here. So we make sure to include |
| 104 // quote characters, and also \ for anything that was internally escaped. | 105 // quote characters, and also \ for anything that was internally escaped. |
| 105 static const char* kDelimiters = "\t !\"#$%&'()*+,-./;<=>?@[\\]^_`{|}~"; | 106 static const char* kDelimiters = "\t !\"#$%&'()*+,-./;<=>?@[\\]^_`{|}~"; |
| 106 | 107 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 131 } | 132 } |
| 132 } else { | 133 } else { |
| 133 // If we've gotten here, it means we've already found and parsed our | 134 // If we've gotten here, it means we've already found and parsed our |
| 134 // month, and we have another string, which we would expect to be the | 135 // month, and we have another string, which we would expect to be the |
| 135 // the time zone name. According to the RFC and my experiments with | 136 // the time zone name. According to the RFC and my experiments with |
| 136 // how sites format their expirations, we don't have much of a reason | 137 // how sites format their expirations, we don't have much of a reason |
| 137 // to support timezones. We don't want to ever barf on user input, | 138 // to support timezones. We don't want to ever barf on user input, |
| 138 // but this DCHECK should pass for well-formed data. | 139 // but this DCHECK should pass for well-formed data. |
| 139 // DCHECK(token == "GMT"); | 140 // DCHECK(token == "GMT"); |
| 140 } | 141 } |
| 141 // Numeric field w/ a colon | 142 // Numeric field w/ a colon |
| 142 } else if (token.find(':') != std::string::npos) { | 143 } else if (token.find(':') != std::string::npos) { |
| 143 if (!found_time && | 144 if (!found_time && |
| 144 #ifdef COMPILER_MSVC | 145 #ifdef COMPILER_MSVC |
| 145 sscanf_s( | 146 sscanf_s( |
| 146 #else | 147 #else |
| 147 sscanf( | 148 sscanf( |
| 148 #endif | 149 #endif |
| 149 token.c_str(), "%2u:%2u:%2u", &exploded.hour, | 150 token.c_str(), |
| 150 &exploded.minute, &exploded.second) == 3) { | 151 "%2u:%2u:%2u", |
| 152 &exploded.hour, |
| 153 &exploded.minute, |
| 154 &exploded.second) == 3) { |
| 151 found_time = true; | 155 found_time = true; |
| 152 } else { | 156 } else { |
| 153 // We should only ever encounter one time-like thing. If we're here, | 157 // We should only ever encounter one time-like thing. If we're here, |
| 154 // it means we've found a second, which shouldn't happen. We keep | 158 // it means we've found a second, which shouldn't happen. We keep |
| 155 // the first. This check should be ok for well-formed input: | 159 // the first. This check should be ok for well-formed input: |
| 156 // NOTREACHED(); | 160 // NOTREACHED(); |
| 157 } | 161 } |
| 158 // Numeric field | 162 // Numeric field |
| 159 } else { | 163 } else { |
| 160 // Overflow with atoi() is unspecified, so we enforce a max length. | 164 // Overflow with atoi() is unspecified, so we enforce a max length. |
| 161 if (!found_day_of_month && token.length() <= 2) { | 165 if (!found_day_of_month && token.length() <= 2) { |
| 162 exploded.day_of_month = atoi(token.c_str()); | 166 exploded.day_of_month = atoi(token.c_str()); |
| 163 found_day_of_month = true; | 167 found_day_of_month = true; |
| 164 } else if (!found_year && token.length() <= 5) { | 168 } else if (!found_year && token.length() <= 5) { |
| 165 exploded.year = atoi(token.c_str()); | 169 exploded.year = atoi(token.c_str()); |
| 166 found_year = true; | 170 found_year = true; |
| 167 } else { | 171 } else { |
| 168 // If we're here, it means we've either found an extra numeric field, | 172 // If we're here, it means we've either found an extra numeric field, |
| (...skipping 12 matching lines...) Expand all Loading... |
| 181 } | 185 } |
| 182 | 186 |
| 183 // Normalize the year to expand abbreviated years to the full year. | 187 // Normalize the year to expand abbreviated years to the full year. |
| 184 if (exploded.year >= 69 && exploded.year <= 99) | 188 if (exploded.year >= 69 && exploded.year <= 99) |
| 185 exploded.year += 1900; | 189 exploded.year += 1900; |
| 186 if (exploded.year >= 0 && exploded.year <= 68) | 190 if (exploded.year >= 0 && exploded.year <= 68) |
| 187 exploded.year += 2000; | 191 exploded.year += 2000; |
| 188 | 192 |
| 189 // If our values are within their correct ranges, we got our time. | 193 // If our values are within their correct ranges, we got our time. |
| 190 if (exploded.day_of_month >= 1 && exploded.day_of_month <= 31 && | 194 if (exploded.day_of_month >= 1 && exploded.day_of_month <= 31 && |
| 191 exploded.month >= 1 && exploded.month <= 12 && | 195 exploded.month >= 1 && exploded.month <= 12 && exploded.year >= 1601 && |
| 192 exploded.year >= 1601 && exploded.year <= 30827 && | 196 exploded.year <= 30827 && exploded.hour <= 23 && exploded.minute <= 59 && |
| 193 exploded.hour <= 23 && exploded.minute <= 59 && exploded.second <= 59) { | 197 exploded.second <= 59) { |
| 194 return base::Time::FromUTCExploded(exploded); | 198 return base::Time::FromUTCExploded(exploded); |
| 195 } | 199 } |
| 196 | 200 |
| 197 // One of our values was out of expected range. For well-formed input, | 201 // One of our values was out of expected range. For well-formed input, |
| 198 // the following check would be reasonable: | 202 // the following check would be reasonable: |
| 199 // NOTREACHED() << "Cookie exploded expiration failed: " << time_string; | 203 // NOTREACHED() << "Cookie exploded expiration failed: " << time_string; |
| 200 | 204 |
| 201 return base::Time(); | 205 return base::Time(); |
| 202 } | 206 } |
| 203 | 207 |
| 204 GURL CookieOriginToURL(const std::string& domain, bool is_https) { | 208 GURL CookieOriginToURL(const std::string& domain, bool is_https) { |
| 205 if (domain.empty()) | 209 if (domain.empty()) |
| 206 return GURL(); | 210 return GURL(); |
| 207 | 211 |
| 208 const std::string scheme = is_https ? "https" : "http"; | 212 const std::string scheme = is_https ? "https" : "http"; |
| 209 const std::string host = domain[0] == '.' ? domain.substr(1) : domain; | 213 const std::string host = domain[0] == '.' ? domain.substr(1) : domain; |
| 210 return GURL(scheme + "://" + host); | 214 return GURL(scheme + "://" + host); |
| 211 } | 215 } |
| 212 | 216 |
| 213 } // namespace cookie_utils | 217 } // namespace cookie_utils |
| 214 } // namespace net | 218 } // namespace net |
| 215 | |
| OLD | NEW |