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/base/sdch_manager.h" | 5 #include "net/base/sdch_manager.h" |
6 | 6 |
7 #include "base/base64.h" | 7 #include "base/base64.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
10 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
(...skipping 21 matching lines...) Expand all Loading... |
32 GURL::Replacements replacements; | 32 GURL::Replacements replacements; |
33 replacements.SetHostStr(host); | 33 replacements.SetHostStr(host); |
34 *gurl = gurl->ReplaceComponents(replacements); | 34 *gurl = gurl->ReplaceComponents(replacements); |
35 return; | 35 return; |
36 } | 36 } |
37 | 37 |
38 } // namespace | 38 } // namespace |
39 | 39 |
40 namespace net { | 40 namespace net { |
41 | 41 |
42 // Adjust SDCH limits downwards for mobile. | |
43 #if defined(OS_ANDROID) || defined(OS_IOS) | |
44 // static | |
45 const size_t SdchManager::kMaxDictionaryCount = 1; | |
46 const size_t SdchManager::kMaxDictionarySize = 500 * 1000; | |
47 #else | |
48 // static | |
49 const size_t SdchManager::kMaxDictionaryCount = 20; | |
50 const size_t SdchManager::kMaxDictionarySize = 1000 * 1000; | |
51 #endif | |
52 | |
53 // Workaround for http://crbug.com/437794; remove when fixed. | 42 // Workaround for http://crbug.com/437794; remove when fixed. |
54 #if defined(OS_IOS) | 43 #if defined(OS_IOS) |
55 // static | 44 // static |
56 bool SdchManager::g_sdch_enabled_ = false; | 45 bool SdchManager::g_sdch_enabled_ = false; |
57 #else | 46 #else |
58 // static | 47 // static |
59 bool SdchManager::g_sdch_enabled_ = true; | 48 bool SdchManager::g_sdch_enabled_ = true; |
60 #endif | 49 #endif |
61 | 50 |
62 // static | 51 // static |
63 bool SdchManager::g_secure_scheme_supported_ = true; | 52 bool SdchManager::g_secure_scheme_supported_ = true; |
64 | 53 |
65 SdchManager::Dictionary::Dictionary(const std::string& dictionary_text, | 54 SdchManager::Dictionary::Dictionary(const std::string& dictionary_text, |
66 size_t offset, | 55 size_t offset, |
67 const std::string& client_hash, | 56 const std::string& client_hash, |
| 57 const std::string& server_hash, |
68 const GURL& gurl, | 58 const GURL& gurl, |
69 const std::string& domain, | 59 const std::string& domain, |
70 const std::string& path, | 60 const std::string& path, |
71 const base::Time& expiration, | 61 const base::Time& expiration, |
72 const std::set<int>& ports) | 62 const std::set<int>& ports) |
73 : text_(dictionary_text, offset), | 63 : text_(dictionary_text, offset), |
74 client_hash_(client_hash), | 64 client_hash_(client_hash), |
| 65 server_hash_(server_hash), |
75 url_(gurl), | 66 url_(gurl), |
76 domain_(domain), | 67 domain_(domain), |
77 path_(path), | 68 path_(path), |
78 expiration_(expiration), | 69 expiration_(expiration), |
79 ports_(ports), | 70 ports_(ports), |
80 clock_(new base::DefaultClock) { | 71 clock_(new base::DefaultClock) { |
81 } | 72 } |
82 | 73 |
83 SdchManager::Dictionary::Dictionary(const SdchManager::Dictionary& rhs) | 74 SdchManager::Dictionary::Dictionary(const SdchManager::Dictionary& rhs) |
84 : text_(rhs.text_), | 75 : text_(rhs.text_), |
85 client_hash_(rhs.client_hash_), | 76 client_hash_(rhs.client_hash_), |
| 77 server_hash_(rhs.server_hash_), |
86 url_(rhs.url_), | 78 url_(rhs.url_), |
87 domain_(rhs.domain_), | 79 domain_(rhs.domain_), |
88 path_(rhs.path_), | 80 path_(rhs.path_), |
89 expiration_(rhs.expiration_), | 81 expiration_(rhs.expiration_), |
90 ports_(rhs.ports_), | 82 ports_(rhs.ports_), |
91 clock_(new base::DefaultClock) {} | 83 clock_(new base::DefaultClock) { |
| 84 } |
92 | 85 |
93 SdchManager::Dictionary::~Dictionary() {} | 86 SdchManager::Dictionary::~Dictionary() {} |
94 | 87 |
95 // Security functions restricting loads and use of dictionaries. | 88 // Security functions restricting loads and use of dictionaries. |
96 | 89 |
97 // static | 90 // static |
98 SdchProblemCode SdchManager::Dictionary::CanSet(const std::string& domain, | 91 SdchProblemCode SdchManager::Dictionary::CanSet(const std::string& domain, |
99 const std::string& path, | 92 const std::string& path, |
100 const std::set<int>& ports, | 93 const std::set<int>& ports, |
101 const GURL& dictionary_url) { | 94 const GURL& dictionary_url) { |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 DCHECK(thread_checker_.CalledOnValidThread()); | 257 DCHECK(thread_checker_.CalledOnValidThread()); |
265 while (!dictionaries_.empty()) { | 258 while (!dictionaries_.empty()) { |
266 auto it = dictionaries_.begin(); | 259 auto it = dictionaries_.begin(); |
267 dictionaries_.erase(it->first); | 260 dictionaries_.erase(it->first); |
268 } | 261 } |
269 } | 262 } |
270 | 263 |
271 void SdchManager::ClearData() { | 264 void SdchManager::ClearData() { |
272 blacklisted_domains_.clear(); | 265 blacklisted_domains_.clear(); |
273 allow_latency_experiment_.clear(); | 266 allow_latency_experiment_.clear(); |
274 | |
275 // Note that this may result in not having dictionaries we've advertised | |
276 // for incoming responses. The window is relatively small (as ClearData() | |
277 // is not expected to be called frequently), so we rely on meta-refresh | |
278 // to handle this case. | |
279 dictionaries_.clear(); | 267 dictionaries_.clear(); |
280 | |
281 FOR_EACH_OBSERVER(SdchObserver, observers_, OnClearDictionaries(this)); | 268 FOR_EACH_OBSERVER(SdchObserver, observers_, OnClearDictionaries(this)); |
282 } | 269 } |
283 | 270 |
284 // static | 271 // static |
285 void SdchManager::SdchErrorRecovery(SdchProblemCode problem) { | 272 void SdchManager::SdchErrorRecovery(SdchProblemCode problem) { |
286 UMA_HISTOGRAM_ENUMERATION("Sdch3.ProblemCodes_5", problem, | 273 UMA_HISTOGRAM_ENUMERATION("Sdch3.ProblemCodes_5", problem, |
287 SDCH_MAX_PROBLEM_CODE); | 274 SDCH_MAX_PROBLEM_CODE); |
288 } | 275 } |
289 | 276 |
290 // static | 277 // static |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
393 if (rv != SDCH_OK) | 380 if (rv != SDCH_OK) |
394 return rv; | 381 return rv; |
395 | 382 |
396 FOR_EACH_OBSERVER(SdchObserver, | 383 FOR_EACH_OBSERVER(SdchObserver, |
397 observers_, | 384 observers_, |
398 OnGetDictionary(this, request_url, dictionary_url)); | 385 OnGetDictionary(this, request_url, dictionary_url)); |
399 | 386 |
400 return SDCH_OK; | 387 return SDCH_OK; |
401 } | 388 } |
402 | 389 |
| 390 void SdchManager::OnDictionaryUsed(const std::string& server_hash) { |
| 391 FOR_EACH_OBSERVER(SdchObserver, observers_, |
| 392 OnDictionaryUsed(this, server_hash)); |
| 393 } |
| 394 |
403 SdchProblemCode SdchManager::CanFetchDictionary( | 395 SdchProblemCode SdchManager::CanFetchDictionary( |
404 const GURL& referring_url, | 396 const GURL& referring_url, |
405 const GURL& dictionary_url) const { | 397 const GURL& dictionary_url) const { |
406 DCHECK(thread_checker_.CalledOnValidThread()); | 398 DCHECK(thread_checker_.CalledOnValidThread()); |
407 /* The user agent may retrieve a dictionary from the dictionary URL if all of | 399 /* The user agent may retrieve a dictionary from the dictionary URL if all of |
408 the following are true: | 400 the following are true: |
409 1 The dictionary URL host name matches the referrer URL host name and | 401 1 The dictionary URL host name matches the referrer URL host name and |
410 scheme. | 402 scheme. |
411 2 The dictionary URL host name domain matches the parent domain of the | 403 2 The dictionary URL host name domain matches the parent domain of the |
412 referrer URL host name | 404 referrer URL host name |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
514 void SdchManager::AddObserver(SdchObserver* observer) { | 506 void SdchManager::AddObserver(SdchObserver* observer) { |
515 observers_.AddObserver(observer); | 507 observers_.AddObserver(observer); |
516 } | 508 } |
517 | 509 |
518 void SdchManager::RemoveObserver(SdchObserver* observer) { | 510 void SdchManager::RemoveObserver(SdchObserver* observer) { |
519 observers_.RemoveObserver(observer); | 511 observers_.RemoveObserver(observer); |
520 } | 512 } |
521 | 513 |
522 SdchProblemCode SdchManager::AddSdchDictionary( | 514 SdchProblemCode SdchManager::AddSdchDictionary( |
523 const std::string& dictionary_text, | 515 const std::string& dictionary_text, |
524 const GURL& dictionary_url) { | 516 const GURL& dictionary_url, |
| 517 std::string* server_hash_p) { |
525 DCHECK(thread_checker_.CalledOnValidThread()); | 518 DCHECK(thread_checker_.CalledOnValidThread()); |
526 std::string client_hash; | 519 std::string client_hash; |
527 std::string server_hash; | 520 std::string server_hash; |
528 GenerateHash(dictionary_text, &client_hash, &server_hash); | 521 GenerateHash(dictionary_text, &client_hash, &server_hash); |
529 if (dictionaries_.find(server_hash) != dictionaries_.end()) | 522 if (dictionaries_.find(server_hash) != dictionaries_.end()) |
530 return SDCH_DICTIONARY_ALREADY_LOADED; // Already loaded. | 523 return SDCH_DICTIONARY_ALREADY_LOADED; // Already loaded. |
531 | 524 |
532 std::string domain, path; | 525 std::string domain, path; |
533 std::set<int> ports; | 526 std::set<int> ports; |
534 base::Time expiration(base::Time::Now() + base::TimeDelta::FromDays(30)); | 527 base::Time expiration(base::Time::Now() + base::TimeDelta::FromDays(30)); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
591 StripTrailingDot(&dictionary_url_normalized); | 584 StripTrailingDot(&dictionary_url_normalized); |
592 | 585 |
593 SdchProblemCode rv = IsInSupportedDomain(dictionary_url_normalized); | 586 SdchProblemCode rv = IsInSupportedDomain(dictionary_url_normalized); |
594 if (rv != SDCH_OK) | 587 if (rv != SDCH_OK) |
595 return rv; | 588 return rv; |
596 | 589 |
597 rv = Dictionary::CanSet(domain, path, ports, dictionary_url_normalized); | 590 rv = Dictionary::CanSet(domain, path, ports, dictionary_url_normalized); |
598 if (rv != SDCH_OK) | 591 if (rv != SDCH_OK) |
599 return rv; | 592 return rv; |
600 | 593 |
601 // TODO(jar): Remove these hacks to preclude a DOS attack involving piles of | |
602 // useless dictionaries. We should probably have a cache eviction plan, | |
603 // instead of just blocking additions. For now, with the spec in flux, it | |
604 // is probably not worth doing eviction handling. | |
605 if (kMaxDictionarySize < dictionary_text.size()) | |
606 return SDCH_DICTIONARY_IS_TOO_LARGE; | |
607 | |
608 if (kMaxDictionaryCount <= dictionaries_.size()) | |
609 return SDCH_DICTIONARY_COUNT_EXCEEDED; | |
610 | |
611 UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size()); | 594 UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size()); |
612 DVLOG(1) << "Loaded dictionary with client hash " << client_hash | 595 DVLOG(1) << "Loaded dictionary with client hash " << client_hash |
613 << " and server hash " << server_hash; | 596 << " and server hash " << server_hash; |
614 Dictionary dictionary(dictionary_text, header_end + 2, client_hash, | 597 Dictionary dictionary(dictionary_text, header_end + 2, client_hash, |
615 dictionary_url_normalized, domain, path, expiration, | 598 server_hash, dictionary_url_normalized, domain, path, |
616 ports); | 599 expiration, ports); |
617 dictionaries_[server_hash] = | 600 dictionaries_[server_hash] = |
618 new base::RefCountedData<Dictionary>(dictionary); | 601 new base::RefCountedData<Dictionary>(dictionary); |
| 602 if (server_hash_p) |
| 603 *server_hash_p = server_hash; |
619 | 604 |
620 return SDCH_OK; | 605 return SDCH_OK; |
621 } | 606 } |
622 | 607 |
| 608 SdchProblemCode SdchManager::RemoveSdchDictionary( |
| 609 const std::string& server_hash) { |
| 610 if (dictionaries_.find(server_hash) == dictionaries_.end()) |
| 611 return SDCH_DICTIONARY_HASH_NOT_FOUND; |
| 612 |
| 613 dictionaries_.erase(server_hash); |
| 614 return SDCH_OK; |
| 615 } |
| 616 |
623 // static | 617 // static |
624 scoped_ptr<SdchManager::DictionarySet> | 618 scoped_ptr<SdchManager::DictionarySet> |
625 SdchManager::CreateEmptyDictionarySetForTesting() { | 619 SdchManager::CreateEmptyDictionarySetForTesting() { |
626 return scoped_ptr<DictionarySet>(new DictionarySet).Pass(); | 620 return scoped_ptr<DictionarySet>(new DictionarySet).Pass(); |
627 } | 621 } |
628 | 622 |
629 // static | 623 // static |
630 void SdchManager::UrlSafeBase64Encode(const std::string& input, | 624 void SdchManager::UrlSafeBase64Encode(const std::string& input, |
631 std::string* output) { | 625 std::string* output) { |
632 // Since this is only done during a dictionary load, and hashes are only 8 | 626 // Since this is only done during a dictionary load, and hashes are only 8 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
672 entry_dict->SetInteger("tries", it->second.count); | 666 entry_dict->SetInteger("tries", it->second.count); |
673 entry_dict->SetInteger("reason", it->second.reason); | 667 entry_dict->SetInteger("reason", it->second.reason); |
674 entry_list->Append(entry_dict); | 668 entry_list->Append(entry_dict); |
675 } | 669 } |
676 value->Set("blacklisted", entry_list); | 670 value->Set("blacklisted", entry_list); |
677 | 671 |
678 return value; | 672 return value; |
679 } | 673 } |
680 | 674 |
681 } // namespace net | 675 } // namespace net |
OLD | NEW |