Chromium Code Reviews| 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 "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/string_tokenizer.h" | |
| 9 #include "base/string_util.h" | |
| 8 #include "googleurl/src/gurl.h" | 10 #include "googleurl/src/gurl.h" |
| 9 #include "net/base/net_util.h" | 11 #include "net/base/net_util.h" |
| 10 #include "net/base/registry_controlled_domain.h" | 12 #include "net/base/registry_controlled_domain.h" |
| 11 | 13 |
| 12 namespace net { | 14 namespace net { |
| 13 namespace cookie_util { | 15 namespace cookie_util { |
| 14 | 16 |
| 15 bool DomainIsHostOnly(const std::string& domain_string) { | 17 bool DomainIsHostOnly(const std::string& domain_string) { |
| 16 return (domain_string.empty() || domain_string[0] != '.'); | 18 return (domain_string.empty() || domain_string[0] != '.'); |
| 17 } | 19 } |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 67 (cookie_domain != ("." + url_host)) : | 69 (cookie_domain != ("." + url_host)) : |
| 68 (url_host.compare(url_host.length() - cookie_domain.length(), | 70 (url_host.compare(url_host.length() - cookie_domain.length(), |
| 69 cookie_domain.length(), cookie_domain) != 0); | 71 cookie_domain.length(), cookie_domain) != 0); |
| 70 if (is_suffix) | 72 if (is_suffix) |
| 71 return false; | 73 return false; |
| 72 | 74 |
| 73 *result = cookie_domain; | 75 *result = cookie_domain; |
| 74 return true; | 76 return true; |
| 75 } | 77 } |
| 76 | 78 |
| 79 // Parse a cookie expiration time. We try to be lenient, but we need to | |
| 80 // assume some order to distinguish the fields. The basic rules: | |
| 81 // - The month name must be present and prefix the first 3 letters of the | |
| 82 // full month name (jan for January, jun for June). | |
| 83 // - If the year is <= 2 digits, it must occur after the day of month. | |
| 84 // - The time must be of the format hh:mm:ss. | |
| 85 // An average cookie expiration will look something like this: | |
| 86 // Sat, 15-Apr-17 21:01:22 GMT | |
| 87 base::Time ParseCookieTime(const std::string& time_string) { | |
| 88 static const char* kMonths[] = { "jan", "feb", "mar", "apr", "may", "jun", | |
| 89 "jul", "aug", "sep", "oct", "nov", "dec" }; | |
| 90 static const int kMonthsLen = arraysize(kMonths); | |
| 91 // We want to be pretty liberal, and support most non-ascii and non-digit | |
| 92 // characters as a delimiter. We can't treat : as a delimiter, because it | |
| 93 // is the delimiter for hh:mm:ss, and we want to keep this field together. | |
| 94 // We make sure to include - and +, since they could prefix numbers. | |
| 95 // If the cookie attribute came in in quotes (ex expires="XXX"), the quotes | |
| 96 // will be preserved, and we will get them here. So we make sure to include | |
| 97 // quote characters, and also \ for anything that was internally escaped. | |
| 98 static const char* kDelimiters = "\t !\"#$%&'()*+,-./;<=>?@[\\]^_`{|}~"; | |
| 99 | |
| 100 base::Time::Exploded exploded = {0}; | |
| 101 | |
| 102 StringTokenizer tokenizer(time_string, kDelimiters); | |
| 103 | |
| 104 bool found_day_of_month = false; | |
| 105 bool found_month = false; | |
| 106 bool found_time = false; | |
| 107 bool found_year = false; | |
| 108 | |
| 109 while (tokenizer.GetNext()) { | |
| 110 const std::string token = tokenizer.token(); | |
| 111 DCHECK(!token.empty()); | |
| 112 bool numerical = IsAsciiDigit(token[0]); | |
| 113 | |
| 114 // String field | |
| 115 if (!numerical) { | |
| 116 if (!found_month) { | |
| 117 for (int i = 0; i < kMonthsLen; ++i) { | |
| 118 // Match prefix, so we could match January, etc | |
| 119 if (base::strncasecmp(token.c_str(), kMonths[i], 3) == 0) { | |
| 120 exploded.month = i + 1; | |
| 121 found_month = true; | |
| 122 break; | |
| 123 } | |
| 124 } | |
| 125 } else { | |
| 126 // If we've gotten here, it means we've already found and parsed our | |
| 127 // month, and we have another string, which we would expect to be the | |
| 128 // the time zone name. According to the RFC and my experiments with | |
| 129 // how sites format their expirations, we don't have much of a reason | |
| 130 // to support timezones. We don't want to ever barf on user input, | |
| 131 // but this DCHECK should pass for well-formed data. | |
| 132 // DCHECK(token == "GMT"); | |
| 133 } | |
| 134 // Numeric field w/ a colon | |
| 135 } else if (token.find(':') != std::string::npos) { | |
| 136 if (!found_time && | |
| 137 #ifdef COMPILER_MSVC | |
|
erikwright (departed)
2012/07/17 15:59:20
#include "build/build_config.h"
battre
2012/07/18 08:48:43
Done.
| |
| 138 sscanf_s( | |
| 139 #else | |
| 140 sscanf( | |
|
erikwright (departed)
2012/07/17 15:59:20
#include <cstdio>
battre
2012/07/18 08:48:43
Done.
| |
| 141 #endif | |
| 142 token.c_str(), "%2u:%2u:%2u", &exploded.hour, | |
| 143 &exploded.minute, &exploded.second) == 3) { | |
| 144 found_time = true; | |
| 145 } else { | |
| 146 // We should only ever encounter one time-like thing. If we're here, | |
| 147 // it means we've found a second, which shouldn't happen. We keep | |
| 148 // the first. This check should be ok for well-formed input: | |
| 149 // NOTREACHED(); | |
| 150 } | |
| 151 // Numeric field | |
| 152 } else { | |
| 153 // Overflow with atoi() is unspecified, so we enforce a max length. | |
| 154 if (!found_day_of_month && token.length() <= 2) { | |
| 155 exploded.day_of_month = atoi(token.c_str()); | |
| 156 found_day_of_month = true; | |
| 157 } else if (!found_year && token.length() <= 5) { | |
| 158 exploded.year = atoi(token.c_str()); | |
|
erikwright (departed)
2012/07/17 15:59:20
<cstdlib>
battre
2012/07/18 08:48:43
Done.
| |
| 159 found_year = true; | |
| 160 } else { | |
| 161 // If we're here, it means we've either found an extra numeric field, | |
| 162 // or a numeric field which was too long. For well-formed input, the | |
| 163 // following check would be reasonable: | |
| 164 // NOTREACHED(); | |
| 165 } | |
| 166 } | |
| 167 } | |
| 168 | |
| 169 if (!found_day_of_month || !found_month || !found_time || !found_year) { | |
| 170 // We didn't find all of the fields we need. For well-formed input, the | |
| 171 // following check would be reasonable: | |
| 172 // NOTREACHED() << "Cookie parse expiration failed: " << time_string; | |
| 173 return base::Time(); | |
| 174 } | |
| 175 | |
| 176 // Normalize the year to expand abbreviated years to the full year. | |
| 177 if (exploded.year >= 69 && exploded.year <= 99) | |
| 178 exploded.year += 1900; | |
| 179 if (exploded.year >= 0 && exploded.year <= 68) | |
| 180 exploded.year += 2000; | |
| 181 | |
| 182 // If our values are within their correct ranges, we got our time. | |
| 183 if (exploded.day_of_month >= 1 && exploded.day_of_month <= 31 && | |
| 184 exploded.month >= 1 && exploded.month <= 12 && | |
| 185 exploded.year >= 1601 && exploded.year <= 30827 && | |
| 186 exploded.hour <= 23 && exploded.minute <= 59 && exploded.second <= 59) { | |
| 187 return base::Time::FromUTCExploded(exploded); | |
| 188 } | |
| 189 | |
| 190 // One of our values was out of expected range. For well-formed input, | |
| 191 // the following check would be reasonable: | |
| 192 // NOTREACHED() << "Cookie exploded expiration failed: " << time_string; | |
| 193 | |
| 194 return base::Time(); | |
| 195 } | |
| 196 | |
| 77 } // namespace cookie_utils | 197 } // namespace cookie_utils |
| 78 } // namespace net | 198 } // namespace net |
| 79 | 199 |
| OLD | NEW |