| 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 |