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" |
11 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
| 12 #include "base/time/default_clock.h" |
12 #include "base/values.h" | 13 #include "base/values.h" |
13 #include "crypto/sha2.h" | 14 #include "crypto/sha2.h" |
14 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | 15 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
15 #include "net/base/sdch_observer.h" | 16 #include "net/base/sdch_observer.h" |
16 #include "net/url_request/url_request_http_job.h" | 17 #include "net/url_request/url_request_http_job.h" |
17 | 18 |
18 namespace { | 19 namespace { |
19 | 20 |
20 void StripTrailingDot(GURL* gurl) { | 21 void StripTrailingDot(GURL* gurl) { |
21 std::string host(gurl->host()); | 22 std::string host(gurl->host()); |
22 | 23 |
23 if (host.empty()) | 24 if (host.empty()) |
24 return; | 25 return; |
25 | 26 |
26 if (*host.rbegin() != '.') | 27 if (*host.rbegin() != '.') |
27 return; | 28 return; |
28 | 29 |
29 host.resize(host.size() - 1); | 30 host.resize(host.size() - 1); |
30 | 31 |
31 GURL::Replacements replacements; | 32 GURL::Replacements replacements; |
32 replacements.SetHostStr(host); | 33 replacements.SetHostStr(host); |
33 *gurl = gurl->ReplaceComponents(replacements); | 34 *gurl = gurl->ReplaceComponents(replacements); |
34 return; | 35 return; |
35 } | 36 } |
36 | 37 |
37 } // namespace | 38 } // namespace |
38 | 39 |
39 namespace net { | 40 namespace net { |
40 | 41 |
41 //------------------------------------------------------------------------------ | |
42 // static | |
43 | |
44 // Adjust SDCH limits downwards for mobile. | 42 // Adjust SDCH limits downwards for mobile. |
45 #if defined(OS_ANDROID) || defined(OS_IOS) | 43 #if defined(OS_ANDROID) || defined(OS_IOS) |
46 // static | 44 // static |
47 const size_t SdchManager::kMaxDictionaryCount = 1; | 45 const size_t SdchManager::kMaxDictionaryCount = 1; |
48 const size_t SdchManager::kMaxDictionarySize = 500 * 1000; | 46 const size_t SdchManager::kMaxDictionarySize = 500 * 1000; |
49 #else | 47 #else |
50 // static | 48 // static |
51 const size_t SdchManager::kMaxDictionaryCount = 20; | 49 const size_t SdchManager::kMaxDictionaryCount = 20; |
52 const size_t SdchManager::kMaxDictionarySize = 1000 * 1000; | 50 const size_t SdchManager::kMaxDictionarySize = 1000 * 1000; |
53 #endif | 51 #endif |
54 | 52 |
55 // static | 53 // static |
56 bool SdchManager::g_sdch_enabled_ = true; | 54 bool SdchManager::g_sdch_enabled_ = true; |
57 | 55 |
58 // static | 56 // static |
59 bool SdchManager::g_secure_scheme_supported_ = true; | 57 bool SdchManager::g_secure_scheme_supported_ = true; |
60 | 58 |
61 //------------------------------------------------------------------------------ | |
62 SdchManager::Dictionary::Dictionary(const std::string& dictionary_text, | 59 SdchManager::Dictionary::Dictionary(const std::string& dictionary_text, |
63 size_t offset, | 60 size_t offset, |
64 const std::string& client_hash, | 61 const std::string& client_hash, |
65 const GURL& gurl, | 62 const GURL& gurl, |
66 const std::string& domain, | 63 const std::string& domain, |
67 const std::string& path, | 64 const std::string& path, |
68 const base::Time& expiration, | 65 const base::Time& expiration, |
69 const std::set<int>& ports) | 66 const std::set<int>& ports) |
70 : text_(dictionary_text, offset), | 67 : text_(dictionary_text, offset), |
71 client_hash_(client_hash), | 68 client_hash_(client_hash), |
72 url_(gurl), | 69 url_(gurl), |
73 domain_(domain), | 70 domain_(domain), |
74 path_(path), | 71 path_(path), |
75 expiration_(expiration), | 72 expiration_(expiration), |
76 ports_(ports) { | 73 ports_(ports), |
| 74 clock_(new base::DefaultClock) { |
77 } | 75 } |
78 | 76 |
79 SdchManager::Dictionary::~Dictionary() { | 77 SdchManager::Dictionary::Dictionary(const SdchManager::Dictionary& rhs) |
80 } | 78 : text_(rhs.text_), |
| 79 client_hash_(rhs.client_hash_), |
| 80 url_(rhs.url_), |
| 81 domain_(rhs.domain_), |
| 82 path_(rhs.path_), |
| 83 expiration_(rhs.expiration_), |
| 84 ports_(rhs.ports_), |
| 85 clock_(new base::DefaultClock) {} |
81 | 86 |
82 SdchProblemCode SdchManager::Dictionary::CanAdvertise( | 87 SdchManager::Dictionary::~Dictionary() {} |
83 const GURL& target_url) const { | |
84 /* The specific rules of when a dictionary should be advertised in an | |
85 Avail-Dictionary header are modeled after the rules for cookie scoping. The | |
86 terms "domain-match" and "pathmatch" are defined in RFC 2965 [6]. A | |
87 dictionary may be advertised in the Avail-Dictionaries header exactly when | |
88 all of the following are true: | |
89 1. The server's effective host name domain-matches the Domain attribute of | |
90 the dictionary. | |
91 2. If the dictionary has a Port attribute, the request port is one of the | |
92 ports listed in the Port attribute. | |
93 3. The request URI path-matches the path header of the dictionary. | |
94 4. The request is not an HTTPS request. | |
95 We can override (ignore) item (4) only when we have explicitly enabled | |
96 HTTPS support AND the dictionary acquisition scheme matches the target | |
97 url scheme. | |
98 */ | |
99 if (!DomainMatch(target_url, domain_)) | |
100 return SDCH_DICTIONARY_FOUND_HAS_WRONG_DOMAIN; | |
101 if (!ports_.empty() && 0 == ports_.count(target_url.EffectiveIntPort())) | |
102 return SDCH_DICTIONARY_FOUND_HAS_WRONG_PORT_LIST; | |
103 if (path_.size() && !PathMatch(target_url.path(), path_)) | |
104 return SDCH_DICTIONARY_FOUND_HAS_WRONG_PATH; | |
105 if (!SdchManager::secure_scheme_supported() && target_url.SchemeIsSecure()) | |
106 return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME; | |
107 if (target_url.SchemeIsSecure() != url_.SchemeIsSecure()) | |
108 return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME; | |
109 if (base::Time::Now() > expiration_) | |
110 return SDCH_DICTIONARY_FOUND_EXPIRED; | |
111 return SDCH_OK; | |
112 } | |
113 | 88 |
114 //------------------------------------------------------------------------------ | |
115 // Security functions restricting loads and use of dictionaries. | 89 // Security functions restricting loads and use of dictionaries. |
116 | 90 |
117 // static | 91 // static |
118 SdchProblemCode SdchManager::Dictionary::CanSet(const std::string& domain, | 92 SdchProblemCode SdchManager::Dictionary::CanSet(const std::string& domain, |
119 const std::string& path, | 93 const std::string& path, |
120 const std::set<int>& ports, | 94 const std::set<int>& ports, |
121 const GURL& dictionary_url) { | 95 const GURL& dictionary_url) { |
122 /* | 96 /* |
123 A dictionary is invalid and must not be stored if any of the following are | 97 A dictionary is invalid and must not be stored if any of the following are |
124 true: | 98 true: |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 } | 135 } |
162 } | 136 } |
163 | 137 |
164 if (!ports.empty() && 0 == ports.count(dictionary_url.EffectiveIntPort())) | 138 if (!ports.empty() && 0 == ports.count(dictionary_url.EffectiveIntPort())) |
165 return SDCH_DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL; | 139 return SDCH_DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL; |
166 | 140 |
167 return SDCH_OK; | 141 return SDCH_OK; |
168 } | 142 } |
169 | 143 |
170 SdchProblemCode SdchManager::Dictionary::CanUse( | 144 SdchProblemCode SdchManager::Dictionary::CanUse( |
171 const GURL& referring_url) const { | 145 const GURL& target_url) const { |
172 /* | 146 /* |
173 1. The request URL's host name domain-matches the Domain attribute of the | 147 1. The request URL's host name domain-matches the Domain attribute of the |
174 dictionary. | 148 dictionary. |
175 2. If the dictionary has a Port attribute, the request port is one of the | 149 2. If the dictionary has a Port attribute, the request port is one of the |
176 ports listed in the Port attribute. | 150 ports listed in the Port attribute. |
177 3. The request URL path-matches the path attribute of the dictionary. | 151 3. The request URL path-matches the path attribute of the dictionary. |
178 4. The request is not an HTTPS request. | 152 4. The request is not an HTTPS request. |
179 We can override (ignore) item (4) only when we have explicitly enabled | 153 We can override (ignore) item (4) only when we have explicitly enabled |
180 HTTPS support AND the dictionary acquisition scheme matches the target | 154 HTTPS support AND the dictionary acquisition scheme matches the target |
181 url scheme. | 155 url scheme. |
182 */ | 156 */ |
183 if (!DomainMatch(referring_url, domain_)) | 157 if (!DomainMatch(target_url, domain_)) |
184 return SDCH_DICTIONARY_FOUND_HAS_WRONG_DOMAIN; | 158 return SDCH_DICTIONARY_FOUND_HAS_WRONG_DOMAIN; |
185 | 159 |
186 if (!ports_.empty() && 0 == ports_.count(referring_url.EffectiveIntPort())) | 160 if (!ports_.empty() && 0 == ports_.count(target_url.EffectiveIntPort())) |
187 return SDCH_DICTIONARY_FOUND_HAS_WRONG_PORT_LIST; | 161 return SDCH_DICTIONARY_FOUND_HAS_WRONG_PORT_LIST; |
188 | 162 |
189 if (path_.size() && !PathMatch(referring_url.path(), path_)) | 163 if (path_.size() && !PathMatch(target_url.path(), path_)) |
190 return SDCH_DICTIONARY_FOUND_HAS_WRONG_PATH; | 164 return SDCH_DICTIONARY_FOUND_HAS_WRONG_PATH; |
191 | 165 |
192 if (!SdchManager::secure_scheme_supported() && referring_url.SchemeIsSecure()) | 166 if (!SdchManager::secure_scheme_supported() && target_url.SchemeIsSecure()) |
193 return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME; | 167 return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME; |
194 | 168 |
195 if (referring_url.SchemeIsSecure() != url_.SchemeIsSecure()) | 169 if (target_url.SchemeIsSecure() != url_.SchemeIsSecure()) |
196 return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME; | 170 return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME; |
197 | 171 |
198 // TODO(jar): Remove overly restrictive failsafe test (added per security | 172 // TODO(jar): Remove overly restrictive failsafe test (added per security |
199 // review) when we have a need to be more general. | 173 // review) when we have a need to be more general. |
200 if (!referring_url.SchemeIsHTTPOrHTTPS()) | 174 if (!target_url.SchemeIsHTTPOrHTTPS()) |
201 return SDCH_ATTEMPT_TO_DECODE_NON_HTTP_DATA; | 175 return SDCH_ATTEMPT_TO_DECODE_NON_HTTP_DATA; |
202 | 176 |
203 return SDCH_OK; | 177 return SDCH_OK; |
204 } | 178 } |
205 | 179 |
206 // static | 180 // static |
207 bool SdchManager::Dictionary::PathMatch(const std::string& path, | 181 bool SdchManager::Dictionary::PathMatch(const std::string& path, |
208 const std::string& restriction) { | 182 const std::string& restriction) { |
209 /* Must be either: | 183 /* Must be either: |
210 1. P2 is equal to P1 | 184 1. P2 is equal to P1 |
(...skipping 10 matching lines...) Expand all Loading... |
221 return restriction[prefix_length - 1] == '/' || path[prefix_length] == '/'; | 195 return restriction[prefix_length - 1] == '/' || path[prefix_length] == '/'; |
222 } | 196 } |
223 | 197 |
224 // static | 198 // static |
225 bool SdchManager::Dictionary::DomainMatch(const GURL& gurl, | 199 bool SdchManager::Dictionary::DomainMatch(const GURL& gurl, |
226 const std::string& restriction) { | 200 const std::string& restriction) { |
227 // TODO(jar): This is not precisely a domain match definition. | 201 // TODO(jar): This is not precisely a domain match definition. |
228 return gurl.DomainIs(restriction.data(), restriction.size()); | 202 return gurl.DomainIs(restriction.data(), restriction.size()); |
229 } | 203 } |
230 | 204 |
231 //------------------------------------------------------------------------------ | 205 bool SdchManager::Dictionary::Expired() const { |
| 206 return clock_->Now() > expiration_; |
| 207 } |
| 208 |
| 209 void SdchManager::Dictionary::SetClockForTesting( |
| 210 scoped_ptr<base::Clock> clock) { |
| 211 clock_ = clock.Pass(); |
| 212 } |
| 213 |
| 214 SdchManager::DictionarySet::DictionarySet() {} |
| 215 |
| 216 SdchManager::DictionarySet::~DictionarySet() {} |
| 217 |
| 218 std::string SdchManager::DictionarySet::GetDictionaryClientHashList() const { |
| 219 std::string result; |
| 220 bool first = true; |
| 221 for (const auto& entry: dictionaries_) { |
| 222 if (!first) |
| 223 result.append(","); |
| 224 |
| 225 result.append(entry.second->data.client_hash()); |
| 226 first = false; |
| 227 } |
| 228 return result; |
| 229 } |
| 230 |
| 231 const SdchManager::Dictionary* SdchManager::DictionarySet::GetDictionary( |
| 232 const std::string& hash) const { |
| 233 auto it = dictionaries_.find(hash); |
| 234 if (it == dictionaries_.end()) |
| 235 return NULL; |
| 236 |
| 237 return &it->second->data; |
| 238 } |
| 239 |
| 240 bool SdchManager::DictionarySet::Empty() const { |
| 241 return dictionaries_.empty(); |
| 242 } |
| 243 |
| 244 void SdchManager::DictionarySet::AddDictionary( |
| 245 const std::string& server_hash, |
| 246 const scoped_refptr<base::RefCountedData<SdchManager::Dictionary>>& |
| 247 dictionary) { |
| 248 DCHECK(dictionaries_.end() == dictionaries_.find(server_hash)); |
| 249 |
| 250 dictionaries_[server_hash] = dictionary; |
| 251 } |
| 252 |
232 SdchManager::SdchManager() { | 253 SdchManager::SdchManager() { |
233 DCHECK(thread_checker_.CalledOnValidThread()); | 254 DCHECK(thread_checker_.CalledOnValidThread()); |
234 } | 255 } |
235 | 256 |
236 SdchManager::~SdchManager() { | 257 SdchManager::~SdchManager() { |
237 DCHECK(thread_checker_.CalledOnValidThread()); | 258 DCHECK(thread_checker_.CalledOnValidThread()); |
238 while (!dictionaries_.empty()) { | 259 while (!dictionaries_.empty()) { |
239 DictionaryMap::iterator it = dictionaries_.begin(); | 260 auto it = dictionaries_.begin(); |
240 dictionaries_.erase(it->first); | 261 dictionaries_.erase(it->first); |
241 } | 262 } |
242 } | 263 } |
243 | 264 |
244 void SdchManager::ClearData() { | 265 void SdchManager::ClearData() { |
245 blacklisted_domains_.clear(); | 266 blacklisted_domains_.clear(); |
246 allow_latency_experiment_.clear(); | 267 allow_latency_experiment_.clear(); |
247 | 268 |
248 // Note that this may result in not having dictionaries we've advertised | 269 // Note that this may result in not having dictionaries we've advertised |
249 // for incoming responses. The window is relatively small (as ClearData() | 270 // for incoming responses. The window is relatively small (as ClearData() |
250 // is not expected to be called frequently), so we rely on meta-refresh | 271 // is not expected to be called frequently), so we rely on meta-refresh |
251 // to handle this case. | 272 // to handle this case. |
252 dictionaries_.clear(); | 273 dictionaries_.clear(); |
253 | 274 |
254 FOR_EACH_OBSERVER(SdchObserver, observers_, OnClearDictionaries(this)); | 275 FOR_EACH_OBSERVER(SdchObserver, observers_, OnClearDictionaries(this)); |
255 } | 276 } |
256 | 277 |
257 // static | 278 // static |
258 void SdchManager::SdchErrorRecovery(SdchProblemCode problem) { | 279 void SdchManager::SdchErrorRecovery(SdchProblemCode problem) { |
259 UMA_HISTOGRAM_ENUMERATION("Sdch3.ProblemCodes_5", problem, | 280 UMA_HISTOGRAM_ENUMERATION("Sdch3.ProblemCodes_5", problem, |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
379 DCHECK(thread_checker_.CalledOnValidThread()); | 400 DCHECK(thread_checker_.CalledOnValidThread()); |
380 /* The user agent may retrieve a dictionary from the dictionary URL if all of | 401 /* The user agent may retrieve a dictionary from the dictionary URL if all of |
381 the following are true: | 402 the following are true: |
382 1 The dictionary URL host name matches the referrer URL host name and | 403 1 The dictionary URL host name matches the referrer URL host name and |
383 scheme. | 404 scheme. |
384 2 The dictionary URL host name domain matches the parent domain of the | 405 2 The dictionary URL host name domain matches the parent domain of the |
385 referrer URL host name | 406 referrer URL host name |
386 3 The parent domain of the referrer URL host name is not a top level | 407 3 The parent domain of the referrer URL host name is not a top level |
387 domain | 408 domain |
388 */ | 409 */ |
389 // Item (1) above implies item (2). Spec should be updated. | 410 // Item (1) above implies item (2). Spec should be updated. |
390 // I take "host name match" to be "is identical to" | 411 // I take "host name match" to be "is identical to" |
391 if (referring_url.host() != dictionary_url.host() || | 412 if (referring_url.host() != dictionary_url.host() || |
392 referring_url.scheme() != dictionary_url.scheme()) | 413 referring_url.scheme() != dictionary_url.scheme()) |
393 return SDCH_DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST; | 414 return SDCH_DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST; |
394 | 415 |
395 if (!secure_scheme_supported() && referring_url.SchemeIsSecure()) | 416 if (!secure_scheme_supported() && referring_url.SchemeIsSecure()) |
396 return SDCH_DICTIONARY_SELECTED_FOR_SSL; | 417 return SDCH_DICTIONARY_SELECTED_FOR_SSL; |
397 | 418 |
398 // TODO(jar): Remove this failsafe conservative hack which is more restrictive | 419 // TODO(jar): Remove this failsafe conservative hack which is more restrictive |
399 // than current SDCH spec when needed, and justified by security audit. | 420 // than current SDCH spec when needed, and justified by security audit. |
400 if (!referring_url.SchemeIsHTTPOrHTTPS()) | 421 if (!referring_url.SchemeIsHTTPOrHTTPS()) |
401 return SDCH_DICTIONARY_SELECTED_FROM_NON_HTTP; | 422 return SDCH_DICTIONARY_SELECTED_FROM_NON_HTTP; |
402 | 423 |
403 return SDCH_OK; | 424 return SDCH_OK; |
404 } | 425 } |
405 | 426 |
406 SdchProblemCode SdchManager::GetVcdiffDictionary( | 427 scoped_ptr<SdchManager::DictionarySet> |
407 const std::string& server_hash, | 428 SdchManager::GetDictionarySet(const GURL& target_url) { |
408 const GURL& referring_url, | 429 if (IsInSupportedDomain(target_url) != SDCH_OK) |
409 scoped_refptr<Dictionary>* dictionary) { | 430 return NULL; |
410 DCHECK(thread_checker_.CalledOnValidThread()); | |
411 *dictionary = NULL; | |
412 DictionaryMap::iterator it = dictionaries_.find(server_hash); | |
413 if (it == dictionaries_.end()) | |
414 return SDCH_DICTIONARY_HASH_NOT_FOUND; | |
415 | 431 |
416 scoped_refptr<Dictionary> matching_dictionary = it->second; | 432 int count = 0; |
| 433 scoped_ptr<SdchManager::DictionarySet> result(new DictionarySet); |
| 434 for (const auto& entry: dictionaries_) { |
| 435 if (entry.second->data.CanUse(target_url) != SDCH_OK) |
| 436 continue; |
| 437 if (entry.second->data.Expired()) |
| 438 continue; |
| 439 ++count; |
| 440 result->AddDictionary(entry.first, entry.second); |
| 441 } |
417 | 442 |
418 SdchProblemCode rv = IsInSupportedDomain(referring_url); | 443 if (count == 0) |
419 if (rv != SDCH_OK) | 444 return NULL; |
420 return rv; | |
421 | 445 |
422 rv = matching_dictionary->CanUse(referring_url); | 446 UMA_HISTOGRAM_COUNTS("Sdch3.Advertisement_Count", count); |
423 if (rv == SDCH_OK) | 447 |
424 *dictionary = matching_dictionary; | 448 return result.Pass(); |
425 return rv; | |
426 } | 449 } |
427 | 450 |
428 // TODO(jar): If we have evictions from the dictionaries_, then we need to | 451 scoped_ptr<SdchManager::DictionarySet> |
429 // change this interface to return a list of reference counted Dictionary | 452 SdchManager::GetDictionarySetByHash( |
430 // instances that can be used if/when a server specifies one. | 453 const GURL& target_url, |
431 void SdchManager::GetAvailDictionaryList(const GURL& target_url, | 454 const std::string& server_hash, |
432 std::string* list) { | 455 SdchProblemCode* problem_code) { |
433 DCHECK(thread_checker_.CalledOnValidThread()); | 456 scoped_ptr<SdchManager::DictionarySet> result; |
434 int count = 0; | |
435 for (DictionaryMap::iterator it = dictionaries_.begin(); | |
436 it != dictionaries_.end(); ++it) { | |
437 SdchProblemCode rv = IsInSupportedDomain(target_url); | |
438 if (rv != SDCH_OK) | |
439 continue; | |
440 | 457 |
441 if (it->second->CanAdvertise(target_url) != SDCH_OK) | 458 *problem_code = SDCH_DICTIONARY_HASH_NOT_FOUND; |
442 continue; | 459 const auto& it = dictionaries_.find(server_hash); |
443 ++count; | 460 if (it == dictionaries_.end()) |
444 if (!list->empty()) | 461 return result; |
445 list->append(","); | 462 |
446 list->append(it->second->client_hash()); | 463 *problem_code = it->second->data.CanUse(target_url); |
447 } | 464 if (*problem_code != SDCH_OK) |
448 // Watch to see if we have corrupt or numerous dictionaries. | 465 return result; |
449 if (count > 0) | 466 |
450 UMA_HISTOGRAM_COUNTS("Sdch3.Advertisement_Count", count); | 467 result.reset(new DictionarySet); |
| 468 result->AddDictionary(it->first, it->second); |
| 469 return result; |
451 } | 470 } |
452 | 471 |
453 // static | 472 // static |
454 void SdchManager::GenerateHash(const std::string& dictionary_text, | 473 void SdchManager::GenerateHash(const std::string& dictionary_text, |
455 std::string* client_hash, std::string* server_hash) { | 474 std::string* client_hash, std::string* server_hash) { |
456 char binary_hash[32]; | 475 char binary_hash[32]; |
457 crypto::SHA256HashString(dictionary_text, binary_hash, sizeof(binary_hash)); | 476 crypto::SHA256HashString(dictionary_text, binary_hash, sizeof(binary_hash)); |
458 | 477 |
459 std::string first_48_bits(&binary_hash[0], 6); | 478 std::string first_48_bits(&binary_hash[0], 6); |
460 std::string second_48_bits(&binary_hash[6], 6); | 479 std::string second_48_bits(&binary_hash[6], 6); |
461 UrlSafeBase64Encode(first_48_bits, client_hash); | 480 UrlSafeBase64Encode(first_48_bits, client_hash); |
462 UrlSafeBase64Encode(second_48_bits, server_hash); | 481 UrlSafeBase64Encode(second_48_bits, server_hash); |
463 | 482 |
464 DCHECK_EQ(server_hash->length(), 8u); | 483 DCHECK_EQ(server_hash->length(), 8u); |
465 DCHECK_EQ(client_hash->length(), 8u); | 484 DCHECK_EQ(client_hash->length(), 8u); |
466 } | 485 } |
467 | 486 |
468 //------------------------------------------------------------------------------ | |
469 // Methods for supporting latency experiments. | 487 // Methods for supporting latency experiments. |
470 | 488 |
471 bool SdchManager::AllowLatencyExperiment(const GURL& url) const { | 489 bool SdchManager::AllowLatencyExperiment(const GURL& url) const { |
472 DCHECK(thread_checker_.CalledOnValidThread()); | 490 DCHECK(thread_checker_.CalledOnValidThread()); |
473 return allow_latency_experiment_.end() != | 491 return allow_latency_experiment_.end() != |
474 allow_latency_experiment_.find(url.host()); | 492 allow_latency_experiment_.find(url.host()); |
475 } | 493 } |
476 | 494 |
477 void SdchManager::SetAllowLatencyExperiment(const GURL& url, bool enable) { | 495 void SdchManager::SetAllowLatencyExperiment(const GURL& url, bool enable) { |
478 DCHECK(thread_checker_.CalledOnValidThread()); | 496 DCHECK(thread_checker_.CalledOnValidThread()); |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
568 | 586 |
569 SdchProblemCode rv = IsInSupportedDomain(dictionary_url_normalized); | 587 SdchProblemCode rv = IsInSupportedDomain(dictionary_url_normalized); |
570 if (rv != SDCH_OK) | 588 if (rv != SDCH_OK) |
571 return rv; | 589 return rv; |
572 | 590 |
573 rv = Dictionary::CanSet(domain, path, ports, dictionary_url_normalized); | 591 rv = Dictionary::CanSet(domain, path, ports, dictionary_url_normalized); |
574 if (rv != SDCH_OK) | 592 if (rv != SDCH_OK) |
575 return rv; | 593 return rv; |
576 | 594 |
577 // TODO(jar): Remove these hacks to preclude a DOS attack involving piles of | 595 // TODO(jar): Remove these hacks to preclude a DOS attack involving piles of |
578 // useless dictionaries. We should probably have a cache eviction plan, | 596 // useless dictionaries. We should probably have a cache eviction plan, |
579 // instead of just blocking additions. For now, with the spec in flux, it | 597 // instead of just blocking additions. For now, with the spec in flux, it |
580 // is probably not worth doing eviction handling. | 598 // is probably not worth doing eviction handling. |
581 if (kMaxDictionarySize < dictionary_text.size()) | 599 if (kMaxDictionarySize < dictionary_text.size()) |
582 return SDCH_DICTIONARY_IS_TOO_LARGE; | 600 return SDCH_DICTIONARY_IS_TOO_LARGE; |
583 | 601 |
584 if (kMaxDictionaryCount <= dictionaries_.size()) | 602 if (kMaxDictionaryCount <= dictionaries_.size()) |
585 return SDCH_DICTIONARY_COUNT_EXCEEDED; | 603 return SDCH_DICTIONARY_COUNT_EXCEEDED; |
586 | 604 |
587 UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size()); | 605 UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size()); |
588 DVLOG(1) << "Loaded dictionary with client hash " << client_hash | 606 DVLOG(1) << "Loaded dictionary with client hash " << client_hash |
589 << " and server hash " << server_hash; | 607 << " and server hash " << server_hash; |
590 Dictionary* dictionary = | 608 Dictionary dictionary(dictionary_text, header_end + 2, client_hash, |
591 new Dictionary(dictionary_text, header_end + 2, client_hash, | 609 dictionary_url_normalized, domain, path, expiration, |
592 dictionary_url_normalized, domain, | 610 ports); |
593 path, expiration, ports); | 611 dictionaries_[server_hash] = |
594 dictionaries_[server_hash] = dictionary; | 612 new base::RefCountedData<Dictionary>(dictionary); |
| 613 |
595 return SDCH_OK; | 614 return SDCH_OK; |
596 } | 615 } |
597 | 616 |
598 // static | 617 // static |
| 618 scoped_ptr<SdchManager::DictionarySet> |
| 619 SdchManager::CreateEmptyDictionarySetForTesting() { |
| 620 return scoped_ptr<DictionarySet>(new DictionarySet).Pass(); |
| 621 } |
| 622 |
| 623 // static |
599 void SdchManager::UrlSafeBase64Encode(const std::string& input, | 624 void SdchManager::UrlSafeBase64Encode(const std::string& input, |
600 std::string* output) { | 625 std::string* output) { |
601 // 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 |
602 // characters, we just do the simple fixup, rather than rewriting the encoder. | 627 // characters, we just do the simple fixup, rather than rewriting the encoder. |
603 base::Base64Encode(input, output); | 628 base::Base64Encode(input, output); |
604 std::replace(output->begin(), output->end(), '+', '-'); | 629 std::replace(output->begin(), output->end(), '+', '-'); |
605 std::replace(output->begin(), output->end(), '/', '_'); | 630 std::replace(output->begin(), output->end(), '/', '_'); |
606 } | 631 } |
607 | 632 |
608 base::Value* SdchManager::SdchInfoToValue() const { | 633 base::Value* SdchManager::SdchInfoToValue() const { |
609 base::DictionaryValue* value = new base::DictionaryValue(); | 634 base::DictionaryValue* value = new base::DictionaryValue(); |
610 | 635 |
611 value->SetBoolean("sdch_enabled", sdch_enabled()); | 636 value->SetBoolean("sdch_enabled", sdch_enabled()); |
612 value->SetBoolean("secure_scheme_support", secure_scheme_supported()); | 637 value->SetBoolean("secure_scheme_support", secure_scheme_supported()); |
613 | 638 |
614 base::ListValue* entry_list = new base::ListValue(); | 639 base::ListValue* entry_list = new base::ListValue(); |
615 for (DictionaryMap::const_iterator it = dictionaries_.begin(); | 640 for (const auto& entry: dictionaries_) { |
616 it != dictionaries_.end(); ++it) { | |
617 base::DictionaryValue* entry_dict = new base::DictionaryValue(); | 641 base::DictionaryValue* entry_dict = new base::DictionaryValue(); |
618 entry_dict->SetString("url", it->second->url().spec()); | 642 entry_dict->SetString("url", entry.second->data.url().spec()); |
619 entry_dict->SetString("client_hash", it->second->client_hash()); | 643 entry_dict->SetString("client_hash", entry.second->data.client_hash()); |
620 entry_dict->SetString("domain", it->second->domain()); | 644 entry_dict->SetString("domain", entry.second->data.domain()); |
621 entry_dict->SetString("path", it->second->path()); | 645 entry_dict->SetString("path", entry.second->data.path()); |
622 base::ListValue* port_list = new base::ListValue(); | 646 base::ListValue* port_list = new base::ListValue(); |
623 for (std::set<int>::const_iterator port_it = it->second->ports().begin(); | 647 for (std::set<int>::const_iterator port_it = |
624 port_it != it->second->ports().end(); ++port_it) { | 648 entry.second->data.ports().begin(); |
| 649 port_it != entry.second->data.ports().end(); ++port_it) { |
625 port_list->AppendInteger(*port_it); | 650 port_list->AppendInteger(*port_it); |
626 } | 651 } |
627 entry_dict->Set("ports", port_list); | 652 entry_dict->Set("ports", port_list); |
628 entry_dict->SetString("server_hash", it->first); | 653 entry_dict->SetString("server_hash", entry.first); |
629 entry_list->Append(entry_dict); | 654 entry_list->Append(entry_dict); |
630 } | 655 } |
631 value->Set("dictionaries", entry_list); | 656 value->Set("dictionaries", entry_list); |
632 | 657 |
633 entry_list = new base::ListValue(); | 658 entry_list = new base::ListValue(); |
634 for (DomainBlacklistInfo::const_iterator it = blacklisted_domains_.begin(); | 659 for (DomainBlacklistInfo::const_iterator it = blacklisted_domains_.begin(); |
635 it != blacklisted_domains_.end(); ++it) { | 660 it != blacklisted_domains_.end(); ++it) { |
636 if (it->second.count == 0) | 661 if (it->second.count == 0) |
637 continue; | 662 continue; |
638 base::DictionaryValue* entry_dict = new base::DictionaryValue(); | 663 base::DictionaryValue* entry_dict = new base::DictionaryValue(); |
639 entry_dict->SetString("domain", it->first); | 664 entry_dict->SetString("domain", it->first); |
640 if (it->second.count != INT_MAX) | 665 if (it->second.count != INT_MAX) |
641 entry_dict->SetInteger("tries", it->second.count); | 666 entry_dict->SetInteger("tries", it->second.count); |
642 entry_dict->SetInteger("reason", it->second.reason); | 667 entry_dict->SetInteger("reason", it->second.reason); |
643 entry_list->Append(entry_dict); | 668 entry_list->Append(entry_dict); |
644 } | 669 } |
645 value->Set("blacklisted", entry_list); | 670 value->Set("blacklisted", entry_list); |
646 | 671 |
647 return value; | 672 return value; |
648 } | 673 } |
649 | 674 |
650 } // namespace net | 675 } // namespace net |
OLD | NEW |