| 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 "crypto/sha2.h" | 12 #include "crypto/sha2.h" |
| 13 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | 13 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
| 14 #include "net/url_request/url_request_http_job.h" | 14 #include "net/url_request/url_request_http_job.h" |
| 15 | 15 |
| 16 namespace net { | 16 namespace net { |
| 17 | 17 |
| 18 //------------------------------------------------------------------------------ | 18 //------------------------------------------------------------------------------ |
| 19 // static | 19 // static |
| 20 const size_t SdchManager::kMaxDictionarySize = 1000000; | 20 const size_t SdchManager::kMaxDictionarySize = 1000000; |
| 21 | 21 |
| 22 // static | 22 // static |
| 23 const size_t SdchManager::kMaxDictionaryCount = 20; | 23 const size_t SdchManager::kMaxDictionaryCount = 20; |
| 24 | 24 |
| 25 // static | 25 // static |
| 26 SdchManager* SdchManager::global_ = NULL; | |
| 27 | |
| 28 // static | |
| 29 bool SdchManager::g_sdch_enabled_ = true; | 26 bool SdchManager::g_sdch_enabled_ = true; |
| 30 | 27 |
| 31 // static | 28 // static |
| 32 bool SdchManager::g_secure_scheme_supported_ = false; | 29 bool SdchManager::g_secure_scheme_supported_ = false; |
| 33 | 30 |
| 34 //------------------------------------------------------------------------------ | 31 //------------------------------------------------------------------------------ |
| 35 SdchManager::Dictionary::Dictionary(const std::string& dictionary_text, | 32 SdchManager::Dictionary::Dictionary(const std::string& dictionary_text, |
| 36 size_t offset, | 33 size_t offset, |
| 37 const std::string& client_hash, | 34 const std::string& client_hash, |
| 38 const GURL& gurl, | 35 const GURL& gurl, |
| 39 const std::string& domain, | 36 const std::string& domain, |
| 40 const std::string& path, | 37 const std::string& path, |
| 41 const base::Time& expiration, | 38 const base::Time& expiration, |
| 42 const std::set<int>& ports) | 39 const std::set<int>& ports) |
| 43 : text_(dictionary_text, offset), | 40 : text_(dictionary_text, offset), |
| 44 client_hash_(client_hash), | 41 client_hash_(client_hash), |
| 45 url_(gurl), | 42 url_(gurl), |
| 46 domain_(domain), | 43 domain_(domain), |
| 47 path_(path), | 44 path_(path), |
| 48 expiration_(expiration), | 45 expiration_(expiration), |
| 49 ports_(ports) { | 46 ports_(ports) { |
| 50 } | 47 } |
| 51 | 48 |
| 52 SdchManager::Dictionary::~Dictionary() { | 49 SdchManager::Dictionary::~Dictionary() { |
| 53 } | 50 } |
| 54 | 51 |
| 55 bool SdchManager::Dictionary::CanAdvertise(const GURL& target_url) { | 52 bool SdchManager::Dictionary::CanAdvertise(const GURL& target_url) { |
| 56 if (!SdchManager::Global()->IsInSupportedDomain(target_url)) | |
| 57 return false; | |
| 58 /* The specific rules of when a dictionary should be advertised in an | 53 /* The specific rules of when a dictionary should be advertised in an |
| 59 Avail-Dictionary header are modeled after the rules for cookie scoping. The | 54 Avail-Dictionary header are modeled after the rules for cookie scoping. The |
| 60 terms "domain-match" and "pathmatch" are defined in RFC 2965 [6]. A | 55 terms "domain-match" and "pathmatch" are defined in RFC 2965 [6]. A |
| 61 dictionary may be advertised in the Avail-Dictionaries header exactly when | 56 dictionary may be advertised in the Avail-Dictionaries header exactly when |
| 62 all of the following are true: | 57 all of the following are true: |
| 63 1. The server's effective host name domain-matches the Domain attribute of | 58 1. The server's effective host name domain-matches the Domain attribute of |
| 64 the dictionary. | 59 the dictionary. |
| 65 2. If the dictionary has a Port attribute, the request port is one of the | 60 2. If the dictionary has a Port attribute, the request port is one of the |
| 66 ports listed in the Port attribute. | 61 ports listed in the Port attribute. |
| 67 3. The request URI path-matches the path header of the dictionary. | 62 3. The request URI path-matches the path header of the dictionary. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 85 } | 80 } |
| 86 | 81 |
| 87 //------------------------------------------------------------------------------ | 82 //------------------------------------------------------------------------------ |
| 88 // Security functions restricting loads and use of dictionaries. | 83 // Security functions restricting loads and use of dictionaries. |
| 89 | 84 |
| 90 // static | 85 // static |
| 91 bool SdchManager::Dictionary::CanSet(const std::string& domain, | 86 bool SdchManager::Dictionary::CanSet(const std::string& domain, |
| 92 const std::string& path, | 87 const std::string& path, |
| 93 const std::set<int>& ports, | 88 const std::set<int>& ports, |
| 94 const GURL& dictionary_url) { | 89 const GURL& dictionary_url) { |
| 95 if (!SdchManager::Global()->IsInSupportedDomain(dictionary_url)) | |
| 96 return false; | |
| 97 /* | 90 /* |
| 98 A dictionary is invalid and must not be stored if any of the following are | 91 A dictionary is invalid and must not be stored if any of the following are |
| 99 true: | 92 true: |
| 100 1. The dictionary has no Domain attribute. | 93 1. The dictionary has no Domain attribute. |
| 101 2. The effective host name that derives from the referer URL host name does | 94 2. The effective host name that derives from the referer URL host name does |
| 102 not domain-match the Domain attribute. | 95 not domain-match the Domain attribute. |
| 103 3. The Domain attribute is a top level domain. | 96 3. The Domain attribute is a top level domain. |
| 104 4. The referer URL host is a host domain name (not IP address) and has the | 97 4. The referer URL host is a host domain name (not IP address) and has the |
| 105 form HD, where D is the value of the Domain attribute, and H is a string | 98 form HD, where D is the value of the Domain attribute, and H is a string |
| 106 that contains one or more dots. | 99 that contains one or more dots. |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 if (!ports.empty() | 136 if (!ports.empty() |
| 144 && 0 == ports.count(dictionary_url.EffectiveIntPort())) { | 137 && 0 == ports.count(dictionary_url.EffectiveIntPort())) { |
| 145 SdchErrorRecovery(DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL); | 138 SdchErrorRecovery(DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL); |
| 146 return false; | 139 return false; |
| 147 } | 140 } |
| 148 return true; | 141 return true; |
| 149 } | 142 } |
| 150 | 143 |
| 151 // static | 144 // static |
| 152 bool SdchManager::Dictionary::CanUse(const GURL& referring_url) { | 145 bool SdchManager::Dictionary::CanUse(const GURL& referring_url) { |
| 153 if (!SdchManager::Global()->IsInSupportedDomain(referring_url)) | |
| 154 return false; | |
| 155 /* | 146 /* |
| 156 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 |
| 157 dictionary. | 148 dictionary. |
| 158 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 |
| 159 ports listed in the Port attribute. | 150 ports listed in the Port attribute. |
| 160 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. |
| 161 4. The request is not an HTTPS request. | 152 4. The request is not an HTTPS request. |
| 162 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 |
| 163 HTTPS support AND dictionary has been acquired over HTTPS. | 154 HTTPS support AND dictionary has been acquired over HTTPS. |
| 164 */ | 155 */ |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 214 | 205 |
| 215 // static | 206 // static |
| 216 bool SdchManager::Dictionary::DomainMatch(const GURL& gurl, | 207 bool SdchManager::Dictionary::DomainMatch(const GURL& gurl, |
| 217 const std::string& restriction) { | 208 const std::string& restriction) { |
| 218 // TODO(jar): This is not precisely a domain match definition. | 209 // TODO(jar): This is not precisely a domain match definition. |
| 219 return gurl.DomainIs(restriction.data(), restriction.size()); | 210 return gurl.DomainIs(restriction.data(), restriction.size()); |
| 220 } | 211 } |
| 221 | 212 |
| 222 //------------------------------------------------------------------------------ | 213 //------------------------------------------------------------------------------ |
| 223 SdchManager::SdchManager() { | 214 SdchManager::SdchManager() { |
| 224 DCHECK(!global_); | |
| 225 DCHECK(CalledOnValidThread()); | 215 DCHECK(CalledOnValidThread()); |
| 226 global_ = this; | |
| 227 } | 216 } |
| 228 | 217 |
| 229 SdchManager::~SdchManager() { | 218 SdchManager::~SdchManager() { |
| 230 DCHECK_EQ(this, global_); | |
| 231 DCHECK(CalledOnValidThread()); | 219 DCHECK(CalledOnValidThread()); |
| 232 while (!dictionaries_.empty()) { | 220 while (!dictionaries_.empty()) { |
| 233 DictionaryMap::iterator it = dictionaries_.begin(); | 221 DictionaryMap::iterator it = dictionaries_.begin(); |
| 234 it->second->Release(); | 222 it->second->Release(); |
| 235 dictionaries_.erase(it->first); | 223 dictionaries_.erase(it->first); |
| 236 } | 224 } |
| 237 global_ = NULL; | |
| 238 } | 225 } |
| 239 | 226 |
| 240 // static | 227 // static |
| 241 void SdchManager::Shutdown() { | |
| 242 EnableSdchSupport(false); | |
| 243 if (!global_ ) | |
| 244 return; | |
| 245 global_->set_sdch_fetcher(NULL); | |
| 246 } | |
| 247 | |
| 248 // static | |
| 249 SdchManager* SdchManager::Global() { | |
| 250 return global_; | |
| 251 } | |
| 252 | |
| 253 // static | |
| 254 void SdchManager::SdchErrorRecovery(ProblemCodes problem) { | 228 void SdchManager::SdchErrorRecovery(ProblemCodes problem) { |
| 255 UMA_HISTOGRAM_ENUMERATION("Sdch3.ProblemCodes_4", problem, MAX_PROBLEM_CODE); | 229 UMA_HISTOGRAM_ENUMERATION("Sdch3.ProblemCodes_4", problem, MAX_PROBLEM_CODE); |
| 256 } | 230 } |
| 257 | 231 |
| 258 void SdchManager::set_sdch_fetcher(SdchFetcher* fetcher) { | 232 void SdchManager::set_sdch_fetcher(SdchFetcher* fetcher) { |
| 259 DCHECK(CalledOnValidThread()); | 233 DCHECK(CalledOnValidThread()); |
| 260 fetcher_.reset(fetcher); | 234 fetcher_.reset(fetcher); |
| 261 } | 235 } |
| 262 | 236 |
| 263 // static | 237 // static |
| 264 void SdchManager::EnableSdchSupport(bool enabled) { | 238 void SdchManager::EnableSdchSupport(bool enabled) { |
| 265 g_sdch_enabled_ = enabled; | 239 g_sdch_enabled_ = enabled; |
| 266 } | 240 } |
| 267 | 241 |
| 268 // static | 242 // static |
| 269 void SdchManager::EnableSecureSchemeSupport(bool enabled) { | 243 void SdchManager::EnableSecureSchemeSupport(bool enabled) { |
| 270 g_secure_scheme_supported_ = enabled; | 244 g_secure_scheme_supported_ = enabled; |
| 271 } | 245 } |
| 272 | 246 |
| 273 // static | |
| 274 void SdchManager::BlacklistDomain(const GURL& url) { | 247 void SdchManager::BlacklistDomain(const GURL& url) { |
| 275 if (!global_ ) | 248 SetAllowLatencyExperiment(url, false); |
| 276 return; | |
| 277 global_->SetAllowLatencyExperiment(url, false); | |
| 278 | 249 |
| 279 std::string domain(StringToLowerASCII(url.host())); | 250 std::string domain(StringToLowerASCII(url.host())); |
| 280 int count = global_->blacklisted_domains_[domain]; | 251 int count = blacklisted_domains_[domain]; |
| 281 if (count > 0) | 252 if (count > 0) |
| 282 return; // Domain is already blacklisted. | 253 return; // Domain is already blacklisted. |
| 283 | 254 |
| 284 count = 1 + 2 * global_->exponential_blacklist_count[domain]; | 255 count = 1 + 2 * exponential_blacklist_count[domain]; |
| 285 if (count > 0) | 256 if (count > 0) |
| 286 global_->exponential_blacklist_count[domain] = count; | 257 exponential_blacklist_count[domain] = count; |
| 287 else | 258 else |
| 288 count = INT_MAX; | 259 count = INT_MAX; |
| 289 | 260 |
| 290 global_->blacklisted_domains_[domain] = count; | 261 blacklisted_domains_[domain] = count; |
| 291 } | 262 } |
| 292 | 263 |
| 293 // static | |
| 294 void SdchManager::BlacklistDomainForever(const GURL& url) { | 264 void SdchManager::BlacklistDomainForever(const GURL& url) { |
| 295 if (!global_ ) | 265 SetAllowLatencyExperiment(url, false); |
| 296 return; | |
| 297 global_->SetAllowLatencyExperiment(url, false); | |
| 298 | 266 |
| 299 std::string domain(StringToLowerASCII(url.host())); | 267 std::string domain(StringToLowerASCII(url.host())); |
| 300 global_->exponential_blacklist_count[domain] = INT_MAX; | 268 exponential_blacklist_count[domain] = INT_MAX; |
| 301 global_->blacklisted_domains_[domain] = INT_MAX; | 269 blacklisted_domains_[domain] = INT_MAX; |
| 302 } | 270 } |
| 303 | 271 |
| 304 // static | |
| 305 void SdchManager::ClearBlacklistings() { | 272 void SdchManager::ClearBlacklistings() { |
| 306 Global()->blacklisted_domains_.clear(); | 273 blacklisted_domains_.clear(); |
| 307 Global()->exponential_blacklist_count.clear(); | 274 exponential_blacklist_count.clear(); |
| 308 } | 275 } |
| 309 | 276 |
| 310 // static | |
| 311 void SdchManager::ClearDomainBlacklisting(const std::string& domain) { | 277 void SdchManager::ClearDomainBlacklisting(const std::string& domain) { |
| 312 Global()->blacklisted_domains_.erase(StringToLowerASCII(domain)); | 278 blacklisted_domains_.erase(StringToLowerASCII(domain)); |
| 313 } | 279 } |
| 314 | 280 |
| 315 // static | |
| 316 int SdchManager::BlackListDomainCount(const std::string& domain) { | 281 int SdchManager::BlackListDomainCount(const std::string& domain) { |
| 317 if (Global()->blacklisted_domains_.end() == | 282 if (blacklisted_domains_.end() == blacklisted_domains_.find(domain)) |
| 318 Global()->blacklisted_domains_.find(domain)) | |
| 319 return 0; | 283 return 0; |
| 320 return Global()->blacklisted_domains_[StringToLowerASCII(domain)]; | 284 return blacklisted_domains_[StringToLowerASCII(domain)]; |
| 321 } | 285 } |
| 322 | 286 |
| 323 // static | |
| 324 int SdchManager::BlacklistDomainExponential(const std::string& domain) { | 287 int SdchManager::BlacklistDomainExponential(const std::string& domain) { |
| 325 if (Global()->exponential_blacklist_count.end() == | 288 if (exponential_blacklist_count.end() == |
| 326 Global()->exponential_blacklist_count.find(domain)) | 289 exponential_blacklist_count.find(domain)) |
| 327 return 0; | 290 return 0; |
| 328 return Global()->exponential_blacklist_count[StringToLowerASCII(domain)]; | 291 return exponential_blacklist_count[StringToLowerASCII(domain)]; |
| 329 } | 292 } |
| 330 | 293 |
| 331 bool SdchManager::IsInSupportedDomain(const GURL& url) { | 294 bool SdchManager::IsInSupportedDomain(const GURL& url) { |
| 332 DCHECK(CalledOnValidThread()); | 295 DCHECK(CalledOnValidThread()); |
| 333 if (!g_sdch_enabled_ ) | 296 if (!g_sdch_enabled_ ) |
| 334 return false; | 297 return false; |
| 335 | 298 |
| 336 if (blacklisted_domains_.empty()) | 299 if (blacklisted_domains_.empty()) |
| 337 return true; | 300 return true; |
| 338 | 301 |
| 339 std::string domain(StringToLowerASCII(url.host())); | 302 std::string domain(StringToLowerASCII(url.host())); |
| 340 DomainCounter::iterator it = blacklisted_domains_.find(domain); | 303 DomainCounter::iterator it = blacklisted_domains_.find(domain); |
| 341 if (blacklisted_domains_.end() == it) | 304 if (blacklisted_domains_.end() == it) |
| 342 return true; | 305 return true; |
| 343 | 306 |
| 344 int count = it->second - 1; | 307 int count = it->second - 1; |
| 345 if (count > 0) | 308 if (count > 0) |
| 346 blacklisted_domains_[domain] = count; | 309 blacklisted_domains_[domain] = count; |
| 347 else | 310 else |
| 348 blacklisted_domains_.erase(domain); | 311 blacklisted_domains_.erase(domain); |
| 349 SdchErrorRecovery(DOMAIN_BLACKLIST_INCLUDES_TARGET); | 312 SdchErrorRecovery(DOMAIN_BLACKLIST_INCLUDES_TARGET); |
| 350 return false; | 313 return false; |
| 351 } | 314 } |
| 352 | 315 |
| 353 void SdchManager::FetchDictionary(const GURL& request_url, | 316 void SdchManager::FetchDictionary(const GURL& request_url, |
| 354 const GURL& dictionary_url) { | 317 const GURL& dictionary_url) { |
| 355 DCHECK(CalledOnValidThread()); | 318 DCHECK(CalledOnValidThread()); |
| 356 if (SdchManager::Global()->CanFetchDictionary(request_url, dictionary_url) && | 319 if (CanFetchDictionary(request_url, dictionary_url) && fetcher_.get()) |
| 357 fetcher_.get()) | |
| 358 fetcher_->Schedule(dictionary_url); | 320 fetcher_->Schedule(dictionary_url); |
| 359 } | 321 } |
| 360 | 322 |
| 361 bool SdchManager::CanFetchDictionary(const GURL& referring_url, | 323 bool SdchManager::CanFetchDictionary(const GURL& referring_url, |
| 362 const GURL& dictionary_url) const { | 324 const GURL& dictionary_url) const { |
| 363 DCHECK(CalledOnValidThread()); | 325 DCHECK(CalledOnValidThread()); |
| 364 /* The user agent may retrieve a dictionary from the dictionary URL if all of | 326 /* The user agent may retrieve a dictionary from the dictionary URL if all of |
| 365 the following are true: | 327 the following are true: |
| 366 1 The dictionary URL host name matches the referrer URL host name and | 328 1 The dictionary URL host name matches the referrer URL host name and |
| 367 scheme. | 329 scheme. |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 458 if (port >= 0) | 420 if (port >= 0) |
| 459 ports.insert(port); | 421 ports.insert(port); |
| 460 } | 422 } |
| 461 } | 423 } |
| 462 | 424 |
| 463 if (line_end >= header_end) | 425 if (line_end >= header_end) |
| 464 break; | 426 break; |
| 465 line_start = line_end + 1; | 427 line_start = line_end + 1; |
| 466 } | 428 } |
| 467 | 429 |
| 430 if (!IsInSupportedDomain(dictionary_url)) |
| 431 return false; |
| 432 |
| 468 if (!Dictionary::CanSet(domain, path, ports, dictionary_url)) | 433 if (!Dictionary::CanSet(domain, path, ports, dictionary_url)) |
| 469 return false; | 434 return false; |
| 470 | 435 |
| 471 // TODO(jar): Remove these hacks to preclude a DOS attack involving piles of | 436 // TODO(jar): Remove these hacks to preclude a DOS attack involving piles of |
| 472 // useless dictionaries. We should probably have a cache eviction plan, | 437 // useless dictionaries. We should probably have a cache eviction plan, |
| 473 // instead of just blocking additions. For now, with the spec in flux, it | 438 // instead of just blocking additions. For now, with the spec in flux, it |
| 474 // is probably not worth doing eviction handling. | 439 // is probably not worth doing eviction handling. |
| 475 if (kMaxDictionarySize < dictionary_text.size()) { | 440 if (kMaxDictionarySize < dictionary_text.size()) { |
| 476 SdchErrorRecovery(DICTIONARY_IS_TOO_LARGE); | 441 SdchErrorRecovery(DICTIONARY_IS_TOO_LARGE); |
| 477 return false; | 442 return false; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 494 | 459 |
| 495 void SdchManager::GetVcdiffDictionary(const std::string& server_hash, | 460 void SdchManager::GetVcdiffDictionary(const std::string& server_hash, |
| 496 const GURL& referring_url, Dictionary** dictionary) { | 461 const GURL& referring_url, Dictionary** dictionary) { |
| 497 DCHECK(CalledOnValidThread()); | 462 DCHECK(CalledOnValidThread()); |
| 498 *dictionary = NULL; | 463 *dictionary = NULL; |
| 499 DictionaryMap::iterator it = dictionaries_.find(server_hash); | 464 DictionaryMap::iterator it = dictionaries_.find(server_hash); |
| 500 if (it == dictionaries_.end()) { | 465 if (it == dictionaries_.end()) { |
| 501 return; | 466 return; |
| 502 } | 467 } |
| 503 Dictionary* matching_dictionary = it->second; | 468 Dictionary* matching_dictionary = it->second; |
| 469 if (!IsInSupportedDomain(referring_url)) |
| 470 return; |
| 504 if (!matching_dictionary->CanUse(referring_url)) | 471 if (!matching_dictionary->CanUse(referring_url)) |
| 505 return; | 472 return; |
| 506 *dictionary = matching_dictionary; | 473 *dictionary = matching_dictionary; |
| 507 } | 474 } |
| 508 | 475 |
| 509 // TODO(jar): If we have evictions from the dictionaries_, then we need to | 476 // TODO(jar): If we have evictions from the dictionaries_, then we need to |
| 510 // change this interface to return a list of reference counted Dictionary | 477 // change this interface to return a list of reference counted Dictionary |
| 511 // instances that can be used if/when a server specifies one. | 478 // instances that can be used if/when a server specifies one. |
| 512 void SdchManager::GetAvailDictionaryList(const GURL& target_url, | 479 void SdchManager::GetAvailDictionaryList(const GURL& target_url, |
| 513 std::string* list) { | 480 std::string* list) { |
| 514 DCHECK(CalledOnValidThread()); | 481 DCHECK(CalledOnValidThread()); |
| 515 int count = 0; | 482 int count = 0; |
| 516 for (DictionaryMap::iterator it = dictionaries_.begin(); | 483 for (DictionaryMap::iterator it = dictionaries_.begin(); |
| 517 it != dictionaries_.end(); ++it) { | 484 it != dictionaries_.end(); ++it) { |
| 485 if (!IsInSupportedDomain(target_url)) |
| 486 continue; |
| 518 if (!it->second->CanAdvertise(target_url)) | 487 if (!it->second->CanAdvertise(target_url)) |
| 519 continue; | 488 continue; |
| 520 ++count; | 489 ++count; |
| 521 if (!list->empty()) | 490 if (!list->empty()) |
| 522 list->append(","); | 491 list->append(","); |
| 523 list->append(it->second->client_hash()); | 492 list->append(it->second->client_hash()); |
| 524 } | 493 } |
| 525 // Watch to see if we have corrupt or numerous dictionaries. | 494 // Watch to see if we have corrupt or numerous dictionaries. |
| 526 if (count > 0) | 495 if (count > 0) |
| 527 UMA_HISTOGRAM_COUNTS("Sdch3.Advertisement_Count", count); | 496 UMA_HISTOGRAM_COUNTS("Sdch3.Advertisement_Count", count); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 578 case '/': | 547 case '/': |
| 579 (*output)[i] = '_'; | 548 (*output)[i] = '_'; |
| 580 continue; | 549 continue; |
| 581 default: | 550 default: |
| 582 continue; | 551 continue; |
| 583 } | 552 } |
| 584 } | 553 } |
| 585 } | 554 } |
| 586 | 555 |
| 587 } // namespace net | 556 } // namespace net |
| OLD | NEW |