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 27 matching lines...) Expand all Loading... | |
38 * decision by deleting the provisions above and replace them with the notice | 38 * decision by deleting the provisions above and replace them with the notice |
39 * and other provisions required by the GPL or the LGPL. If you do not delete | 39 * and other provisions required by the GPL or the LGPL. If you do not delete |
40 * the provisions above, a recipient may use your version of this file under | 40 * the provisions above, a recipient may use your version of this file under |
41 * the terms of any one of the MPL, the GPL or the LGPL. | 41 * the terms of any one of the MPL, the GPL or the LGPL. |
42 * | 42 * |
43 * ***** END LICENSE BLOCK ***** */ | 43 * ***** END LICENSE BLOCK ***** */ |
44 | 44 |
45 #include "net/cookies/parsed_cookie.h" | 45 #include "net/cookies/parsed_cookie.h" |
46 | 46 |
47 #include "base/logging.h" | 47 #include "base/logging.h" |
48 #include "base/metrics/histogram.h" | |
48 #include "base/string_util.h" | 49 #include "base/string_util.h" |
49 | 50 |
51 // We are collecting several UMA statistics in this file, and they relate to | |
erikwright (departed)
2013/05/28 19:59:05
nit: Prefix with 'TODO(jww): Remove metrics code a
jww
2013/05/28 20:45:47
Done.
| |
52 // http://crbug.com/238041. We are measuring stats related to control characters | |
53 // in cookies because, currently, we allow control characters in a variety of | |
54 // scenarios where various RFCs theoretically disallow them. These control | |
55 // characters have the potential to cause problems with certain web servers that | |
56 // reject HTTP requests that contain cookies with control characters. We are | |
57 // measuring whether disallowing such cookies would have a notable impact on our | |
58 // users. We want to collect these stats through 1 stable release, so these UMA | |
59 // stats should remain at least through the M29 branch-point. | |
60 | |
50 namespace { | 61 namespace { |
51 | 62 |
52 const char kPathTokenName[] = "path"; | 63 const char kPathTokenName[] = "path"; |
53 const char kDomainTokenName[] = "domain"; | 64 const char kDomainTokenName[] = "domain"; |
54 const char kExpiresTokenName[] = "expires"; | 65 const char kExpiresTokenName[] = "expires"; |
55 const char kMaxAgeTokenName[] = "max-age"; | 66 const char kMaxAgeTokenName[] = "max-age"; |
56 const char kSecureTokenName[] = "secure"; | 67 const char kSecureTokenName[] = "secure"; |
57 const char kHttpOnlyTokenName[] = "httponly"; | 68 const char kHttpOnlyTokenName[] = "httponly"; |
58 const char kPriorityTokenName[] = "priority"; | 69 const char kPriorityTokenName[] = "priority"; |
59 | 70 |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
175 bool ParsedCookie::IsValid() const { | 186 bool ParsedCookie::IsValid() const { |
176 return !pairs_.empty(); | 187 return !pairs_.empty(); |
177 } | 188 } |
178 | 189 |
179 CookiePriority ParsedCookie::Priority() const { | 190 CookiePriority ParsedCookie::Priority() const { |
180 return (priority_index_ == 0) ? COOKIE_PRIORITY_DEFAULT : | 191 return (priority_index_ == 0) ? COOKIE_PRIORITY_DEFAULT : |
181 StringToCookiePriority(pairs_[priority_index_].second); | 192 StringToCookiePriority(pairs_[priority_index_].second); |
182 } | 193 } |
183 | 194 |
184 bool ParsedCookie::SetName(const std::string& name) { | 195 bool ParsedCookie::SetName(const std::string& name) { |
185 if (!IsValidToken(name)) | 196 if (!IsValidToken(name)) { |
197 UMA_HISTOGRAM_BOOLEAN("Cookies.SetNameInvalidToken", true); | |
186 return false; | 198 return false; |
199 } | |
187 if (pairs_.empty()) | 200 if (pairs_.empty()) |
188 pairs_.push_back(std::make_pair("", "")); | 201 pairs_.push_back(std::make_pair("", "")); |
189 pairs_[0].first = name; | 202 pairs_[0].first = name; |
203 UMA_HISTOGRAM_BOOLEAN("Cookies.SetNameInvalidToken", false); | |
190 return true; | 204 return true; |
191 } | 205 } |
192 | 206 |
193 bool ParsedCookie::SetValue(const std::string& value) { | 207 bool ParsedCookie::SetValue(const std::string& value) { |
194 if (!IsValidCookieValue(value)) | 208 if (!IsValidCookieValue(value)) { |
209 UMA_HISTOGRAM_BOOLEAN("Cookies.SetValueInvalidCookieValue", true); | |
195 return false; | 210 return false; |
211 } | |
196 if (pairs_.empty()) | 212 if (pairs_.empty()) |
197 pairs_.push_back(std::make_pair("", "")); | 213 pairs_.push_back(std::make_pair("", "")); |
198 pairs_[0].second = value; | 214 pairs_[0].second = value; |
215 UMA_HISTOGRAM_BOOLEAN("Cookies.SetValueInvalidCookieValue", false); | |
199 return true; | 216 return true; |
200 } | 217 } |
201 | 218 |
202 bool ParsedCookie::SetPath(const std::string& path) { | 219 bool ParsedCookie::SetPath(const std::string& path) { |
203 return SetString(&path_index_, kPathTokenName, path); | 220 return SetString(&path_index_, kPathTokenName, path); |
204 } | 221 } |
205 | 222 |
206 bool ParsedCookie::SetDomain(const std::string& domain) { | 223 bool ParsedCookie::SetDomain(const std::string& domain) { |
207 return SetString(&domain_index_, kDomainTokenName, domain); | 224 return SetString(&domain_index_, kDomainTokenName, domain); |
208 } | 225 } |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
330 std::string::const_iterator it = value.begin(); | 347 std::string::const_iterator it = value.begin(); |
331 std::string::const_iterator end = FindFirstTerminator(value); | 348 std::string::const_iterator end = FindFirstTerminator(value); |
332 | 349 |
333 std::string::const_iterator value_start, value_end; | 350 std::string::const_iterator value_start, value_end; |
334 ParseValue(&it, end, &value_start, &value_end); | 351 ParseValue(&it, end, &value_start, &value_end); |
335 return std::string(value_start, value_end); | 352 return std::string(value_start, value_end); |
336 } | 353 } |
337 | 354 |
338 // Parse all token/value pairs and populate pairs_. | 355 // Parse all token/value pairs and populate pairs_. |
339 void ParsedCookie::ParseTokenValuePairs(const std::string& cookie_line) { | 356 void ParsedCookie::ParseTokenValuePairs(const std::string& cookie_line) { |
357 bool parsed_invalid_control_char = false; | |
358 bool parsed_invalid_token = false; | |
359 | |
340 pairs_.clear(); | 360 pairs_.clear(); |
341 | 361 |
342 // Ok, here we go. We should be expecting to be starting somewhere | 362 // Ok, here we go. We should be expecting to be starting somewhere |
343 // before the cookie line, not including any header name... | 363 // before the cookie line, not including any header name... |
344 std::string::const_iterator start = cookie_line.begin(); | 364 std::string::const_iterator start = cookie_line.begin(); |
345 std::string::const_iterator it = start; | 365 std::string::const_iterator it = start; |
346 | 366 |
347 // TODO(erikwright): Make sure we're stripping \r\n in the network code. | 367 // TODO(erikwright): Make sure we're stripping \r\n in the network code. |
348 // Then we can log any unexpected terminators. | 368 // Then we can log any unexpected terminators. |
349 std::string::const_iterator end = FindFirstTerminator(cookie_line); | 369 std::string::const_iterator end = FindFirstTerminator(cookie_line); |
(...skipping 27 matching lines...) Expand all Loading... | |
377 pair.first = std::string(token_start, token_end); | 397 pair.first = std::string(token_start, token_end); |
378 ++it; // Skip past the '='. | 398 ++it; // Skip past the '='. |
379 } | 399 } |
380 | 400 |
381 // OK, now try to parse a value. | 401 // OK, now try to parse a value. |
382 std::string::const_iterator value_start, value_end; | 402 std::string::const_iterator value_start, value_end; |
383 ParseValue(&it, end, &value_start, &value_end); | 403 ParseValue(&it, end, &value_start, &value_end); |
384 // OK, we're finished with a Token/Value. | 404 // OK, we're finished with a Token/Value. |
385 pair.second = std::string(value_start, value_end); | 405 pair.second = std::string(value_start, value_end); |
386 | 406 |
407 if (!IsValidCookieAttributeValue(pair.second)) | |
408 parsed_invalid_control_char = true; | |
409 if (!IsValidToken(pair.second)) | |
410 parsed_invalid_token = true; | |
411 | |
387 // From RFC2109: "Attributes (names) (attr) are case-insensitive." | 412 // From RFC2109: "Attributes (names) (attr) are case-insensitive." |
388 if (pair_num != 0) | 413 if (pair_num != 0) |
389 StringToLowerASCII(&pair.first); | 414 StringToLowerASCII(&pair.first); |
390 pairs_.push_back(pair); | 415 pairs_.push_back(pair); |
391 | 416 |
392 // We've processed a token/value pair, we're either at the end of | 417 // We've processed a token/value pair, we're either at the end of |
393 // the string or a ValueSeparator like ';', which we want to skip. | 418 // the string or a ValueSeparator like ';', which we want to skip. |
394 if (it != end) | 419 if (it != end) |
395 ++it; | 420 ++it; |
396 } | 421 } |
422 | |
423 UMA_HISTOGRAM_BOOLEAN("Cookies.ParsedInvalidControlCharacter", | |
424 parsed_invalid_control_char); | |
425 UMA_HISTOGRAM_BOOLEAN("Cookies.ParsedInvalidToken", parsed_invalid_token); | |
397 } | 426 } |
398 | 427 |
399 void ParsedCookie::SetupAttributes() { | 428 void ParsedCookie::SetupAttributes() { |
400 // We skip over the first token/value, the user supplied one. | 429 // We skip over the first token/value, the user supplied one. |
401 for (size_t i = 1; i < pairs_.size(); ++i) { | 430 for (size_t i = 1; i < pairs_.size(); ++i) { |
402 if (pairs_[i].first == kPathTokenName) { | 431 if (pairs_[i].first == kPathTokenName) { |
403 path_index_ = i; | 432 path_index_ = i; |
404 } else if (pairs_[i].first == kDomainTokenName) { | 433 } else if (pairs_[i].first == kDomainTokenName) { |
405 domain_index_ = i; | 434 domain_index_ = i; |
406 } else if (pairs_[i].first == kExpiresTokenName) { | 435 } else if (pairs_[i].first == kExpiresTokenName) { |
(...skipping 30 matching lines...) Expand all Loading... | |
437 ClearAttributePair(*index); | 466 ClearAttributePair(*index); |
438 return true; | 467 return true; |
439 } else { | 468 } else { |
440 return SetAttributePair(index, key, std::string()); | 469 return SetAttributePair(index, key, std::string()); |
441 } | 470 } |
442 } | 471 } |
443 | 472 |
444 bool ParsedCookie::SetAttributePair(size_t* index, | 473 bool ParsedCookie::SetAttributePair(size_t* index, |
445 const std::string& key, | 474 const std::string& key, |
446 const std::string& value) { | 475 const std::string& value) { |
447 if (!IsValidToken(key) || !IsValidCookieAttributeValue(value)) | 476 if (!IsValidToken(key) || !IsValidCookieAttributeValue(value)) { |
477 UMA_HISTOGRAM_BOOLEAN("Cookies.SetAttributePairInvalidChars", true); | |
448 return false; | 478 return false; |
479 } | |
480 UMA_HISTOGRAM_BOOLEAN("Cookies.SetAttributePairInvalidChars", false); | |
449 if (!IsValid()) | 481 if (!IsValid()) |
450 return false; | 482 return false; |
451 if (*index) { | 483 if (*index) { |
452 pairs_[*index].second = value; | 484 pairs_[*index].second = value; |
453 } else { | 485 } else { |
454 pairs_.push_back(std::make_pair(key, value)); | 486 pairs_.push_back(std::make_pair(key, value)); |
455 *index = pairs_.size() - 1; | 487 *index = pairs_.size() - 1; |
456 } | 488 } |
457 return true; | 489 return true; |
458 } | 490 } |
(...skipping 11 matching lines...) Expand all Loading... | |
470 for (size_t i = 0; i < arraysize(indexes); ++i) { | 502 for (size_t i = 0; i < arraysize(indexes); ++i) { |
471 if (*indexes[i] == index) | 503 if (*indexes[i] == index) |
472 *indexes[i] = 0; | 504 *indexes[i] = 0; |
473 else if (*indexes[i] > index) | 505 else if (*indexes[i] > index) |
474 --*indexes[i]; | 506 --*indexes[i]; |
475 } | 507 } |
476 pairs_.erase(pairs_.begin() + index); | 508 pairs_.erase(pairs_.begin() + index); |
477 } | 509 } |
478 | 510 |
479 } // namespace | 511 } // namespace |
OLD | NEW |