Chromium Code Reviews| 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 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 132 | 132 |
| 133 // TODO(jar): Redirects in dictionary fetches might plausibly be problematic, | 133 // TODO(jar): Redirects in dictionary fetches might plausibly be problematic, |
| 134 // and hence the conservative approach is to not allow any redirects (if there | 134 // and hence the conservative approach is to not allow any redirects (if there |
| 135 // were any... then don't allow the dictionary to be set). | 135 // were any... then don't allow the dictionary to be set). |
| 136 | 136 |
| 137 if (domain.empty()) { | 137 if (domain.empty()) { |
| 138 SdchErrorRecovery(DICTIONARY_MISSING_DOMAIN_SPECIFIER); | 138 SdchErrorRecovery(DICTIONARY_MISSING_DOMAIN_SPECIFIER); |
| 139 return false; // Domain is required. | 139 return false; // Domain is required. |
| 140 } | 140 } |
| 141 if (registry_controlled_domains::GetDomainAndRegistry( | 141 if (registry_controlled_domains::GetDomainAndRegistry( |
| 142 domain, | 142 domain, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES) |
| 143 registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES).empty()) { | 143 .empty()) { |
|
Ryan Sleevi
2014/10/11 02:04:47
Bug in clang-format
It prioritized keeping a para
jkarlin
2014/10/16 00:19:32
Is that in the style guide anywhere? I can't seem
mmenke
2014/10/16 00:25:54
Technically no, but preferring not to split an arg
Peter Kasting
2014/10/30 20:20:59
I would phrase this as "breaking at whitespace is
jkarlin
2014/10/30 23:44:47
Filed https://code.google.com/p/chromium/issues/de
jkarlin
2014/11/11 19:01:44
Still waiting on this one.
| |
| 144 SdchErrorRecovery(DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN); | 144 SdchErrorRecovery(DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN); |
| 145 return false; // domain was a TLD. | 145 return false; // domain was a TLD. |
| 146 } | 146 } |
| 147 if (!Dictionary::DomainMatch(dictionary_url, domain)) { | 147 if (!Dictionary::DomainMatch(dictionary_url, domain)) { |
| 148 SdchErrorRecovery(DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL); | 148 SdchErrorRecovery(DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL); |
| 149 return false; | 149 return false; |
| 150 } | 150 } |
| 151 | 151 |
| 152 std::string referrer_url_host = dictionary_url.host(); | 152 std::string referrer_url_host = dictionary_url.host(); |
| 153 size_t postfix_domain_index = referrer_url_host.rfind(domain); | 153 size_t postfix_domain_index = referrer_url_host.rfind(domain); |
| 154 // See if it is indeed a postfix, or just an internal string. | 154 // See if it is indeed a postfix, or just an internal string. |
| 155 if (referrer_url_host.size() == postfix_domain_index + domain.size()) { | 155 if (referrer_url_host.size() == postfix_domain_index + domain.size()) { |
| 156 // It is a postfix... so check to see if there's a dot in the prefix. | 156 // It is a postfix... so check to see if there's a dot in the prefix. |
| 157 size_t end_of_host_index = referrer_url_host.find_first_of('.'); | 157 size_t end_of_host_index = referrer_url_host.find_first_of('.'); |
| 158 if (referrer_url_host.npos != end_of_host_index && | 158 if (referrer_url_host.npos != end_of_host_index && |
| 159 end_of_host_index < postfix_domain_index) { | 159 end_of_host_index < postfix_domain_index) { |
| 160 SdchErrorRecovery(DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX); | 160 SdchErrorRecovery(DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX); |
| 161 return false; | 161 return false; |
| 162 } | 162 } |
| 163 } | 163 } |
| 164 | 164 |
| 165 if (!ports.empty() | 165 if (!ports.empty() && 0 == ports.count(dictionary_url.EffectiveIntPort())) { |
| 166 && 0 == ports.count(dictionary_url.EffectiveIntPort())) { | |
| 167 SdchErrorRecovery(DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL); | 166 SdchErrorRecovery(DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL); |
| 168 return false; | 167 return false; |
| 169 } | 168 } |
| 170 return true; | 169 return true; |
| 171 } | 170 } |
| 172 | 171 |
| 173 // static | 172 // static |
| 174 bool SdchManager::Dictionary::CanUse(const GURL& referring_url) { | 173 bool SdchManager::Dictionary::CanUse(const GURL& referring_url) { |
| 175 /* | 174 /* |
| 176 1. The request URL's host name domain-matches the Domain attribute of the | 175 1. The request URL's host name domain-matches the Domain attribute of the |
| 177 dictionary. | 176 dictionary. |
| 178 2. If the dictionary has a Port attribute, the request port is one of the | 177 2. If the dictionary has a Port attribute, the request port is one of the |
| 179 ports listed in the Port attribute. | 178 ports listed in the Port attribute. |
| 180 3. The request URL path-matches the path attribute of the dictionary. | 179 3. The request URL path-matches the path attribute of the dictionary. |
| 181 4. The request is not an HTTPS request. | 180 4. The request is not an HTTPS request. |
| 182 We can override (ignore) item (4) only when we have explicitly enabled | 181 We can override (ignore) item (4) only when we have explicitly enabled |
| 183 HTTPS support AND the dictionary acquisition scheme matches the target | 182 HTTPS support AND the dictionary acquisition scheme matches the target |
| 184 url scheme. | 183 url scheme. |
| 185 */ | 184 */ |
| 186 if (!DomainMatch(referring_url, domain_)) { | 185 if (!DomainMatch(referring_url, domain_)) { |
| 187 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_DOMAIN); | 186 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_DOMAIN); |
| 188 return false; | 187 return false; |
| 189 } | 188 } |
| 190 if (!ports_.empty() | 189 if (!ports_.empty() && 0 == ports_.count(referring_url.EffectiveIntPort())) { |
| 191 && 0 == ports_.count(referring_url.EffectiveIntPort())) { | |
| 192 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_PORT_LIST); | 190 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_PORT_LIST); |
| 193 return false; | 191 return false; |
| 194 } | 192 } |
| 195 if (path_.size() && !PathMatch(referring_url.path(), path_)) { | 193 if (path_.size() && !PathMatch(referring_url.path(), path_)) { |
| 196 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_PATH); | 194 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_PATH); |
| 197 return false; | 195 return false; |
| 198 } | 196 } |
| 199 if (!SdchManager::secure_scheme_supported() && | 197 if (!SdchManager::secure_scheme_supported() && |
| 200 referring_url.SchemeIsSecure()) { | 198 referring_url.SchemeIsSecure()) { |
| 201 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_SCHEME); | 199 SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_SCHEME); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 234 } | 232 } |
| 235 | 233 |
| 236 // static | 234 // static |
| 237 bool SdchManager::Dictionary::DomainMatch(const GURL& gurl, | 235 bool SdchManager::Dictionary::DomainMatch(const GURL& gurl, |
| 238 const std::string& restriction) { | 236 const std::string& restriction) { |
| 239 // TODO(jar): This is not precisely a domain match definition. | 237 // TODO(jar): This is not precisely a domain match definition. |
| 240 return gurl.DomainIs(restriction.data(), restriction.size()); | 238 return gurl.DomainIs(restriction.data(), restriction.size()); |
| 241 } | 239 } |
| 242 | 240 |
| 243 //------------------------------------------------------------------------------ | 241 //------------------------------------------------------------------------------ |
| 244 SdchManager::SdchManager() | 242 SdchManager::SdchManager() : fetches_count_for_testing_(0) { |
| 245 : fetches_count_for_testing_(0) { | |
| 246 DCHECK(CalledOnValidThread()); | 243 DCHECK(CalledOnValidThread()); |
| 247 } | 244 } |
| 248 | 245 |
| 249 SdchManager::~SdchManager() { | 246 SdchManager::~SdchManager() { |
| 250 DCHECK(CalledOnValidThread()); | 247 DCHECK(CalledOnValidThread()); |
| 251 while (!dictionaries_.empty()) { | 248 while (!dictionaries_.empty()) { |
| 252 DictionaryMap::iterator it = dictionaries_.begin(); | 249 DictionaryMap::iterator it = dictionaries_.begin(); |
| 253 dictionaries_.erase(it->first); | 250 dictionaries_.erase(it->first); |
| 254 } | 251 } |
| 255 } | 252 } |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 317 blacklist_info->count = INT_MAX; | 314 blacklist_info->count = INT_MAX; |
| 318 blacklist_info->exponential_count = INT_MAX; | 315 blacklist_info->exponential_count = INT_MAX; |
| 319 blacklist_info->reason = blacklist_reason; | 316 blacklist_info->reason = blacklist_reason; |
| 320 } | 317 } |
| 321 | 318 |
| 322 void SdchManager::ClearBlacklistings() { | 319 void SdchManager::ClearBlacklistings() { |
| 323 blacklisted_domains_.clear(); | 320 blacklisted_domains_.clear(); |
| 324 } | 321 } |
| 325 | 322 |
| 326 void SdchManager::ClearDomainBlacklisting(const std::string& domain) { | 323 void SdchManager::ClearDomainBlacklisting(const std::string& domain) { |
| 327 BlacklistInfo* blacklist_info = &blacklisted_domains_[ | 324 BlacklistInfo* blacklist_info = |
| 328 base::StringToLowerASCII(domain)]; | 325 &blacklisted_domains_[base::StringToLowerASCII(domain)]; |
| 329 blacklist_info->count = 0; | 326 blacklist_info->count = 0; |
| 330 blacklist_info->reason = MIN_PROBLEM_CODE; | 327 blacklist_info->reason = MIN_PROBLEM_CODE; |
| 331 } | 328 } |
| 332 | 329 |
| 333 int SdchManager::BlackListDomainCount(const std::string& domain) { | 330 int SdchManager::BlackListDomainCount(const std::string& domain) { |
| 334 std::string domain_lower(base::StringToLowerASCII(domain)); | 331 std::string domain_lower(base::StringToLowerASCII(domain)); |
| 335 | 332 |
| 336 if (blacklisted_domains_.end() == blacklisted_domains_.find(domain_lower)) | 333 if (blacklisted_domains_.end() == blacklisted_domains_.find(domain_lower)) |
| 337 return 0; | 334 return 0; |
| 338 return blacklisted_domains_[domain_lower].count; | 335 return blacklisted_domains_[domain_lower].count; |
| 339 } | 336 } |
| 340 | 337 |
| 341 int SdchManager::BlacklistDomainExponential(const std::string& domain) { | 338 int SdchManager::BlacklistDomainExponential(const std::string& domain) { |
| 342 std::string domain_lower(base::StringToLowerASCII(domain)); | 339 std::string domain_lower(base::StringToLowerASCII(domain)); |
| 343 | 340 |
| 344 if (blacklisted_domains_.end() == blacklisted_domains_.find(domain_lower)) | 341 if (blacklisted_domains_.end() == blacklisted_domains_.find(domain_lower)) |
| 345 return 0; | 342 return 0; |
| 346 return blacklisted_domains_[domain_lower].exponential_count; | 343 return blacklisted_domains_[domain_lower].exponential_count; |
| 347 } | 344 } |
| 348 | 345 |
| 349 bool SdchManager::IsInSupportedDomain(const GURL& url) { | 346 bool SdchManager::IsInSupportedDomain(const GURL& url) { |
| 350 DCHECK(CalledOnValidThread()); | 347 DCHECK(CalledOnValidThread()); |
| 351 if (!g_sdch_enabled_ ) | 348 if (!g_sdch_enabled_) |
| 352 return false; | 349 return false; |
| 353 | 350 |
| 354 if (!secure_scheme_supported() && url.SchemeIsSecure()) | 351 if (!secure_scheme_supported() && url.SchemeIsSecure()) |
| 355 return false; | 352 return false; |
| 356 | 353 |
| 357 if (blacklisted_domains_.empty()) | 354 if (blacklisted_domains_.empty()) |
| 358 return true; | 355 return true; |
| 359 | 356 |
| 360 DomainBlacklistInfo::iterator it = | 357 DomainBlacklistInfo::iterator it = |
| 361 blacklisted_domains_.find(base::StringToLowerASCII(url.host())); | 358 blacklisted_domains_.find(base::StringToLowerASCII(url.host())); |
| 362 if (blacklisted_domains_.end() == it || it->second.count == 0) | 359 if (blacklisted_domains_.end() == it || it->second.count == 0) |
| 363 return true; | 360 return true; |
| 364 | 361 |
| 365 UMA_HISTOGRAM_ENUMERATION("Sdch3.BlacklistReason", it->second.reason, | 362 UMA_HISTOGRAM_ENUMERATION( |
| 366 MAX_PROBLEM_CODE); | 363 "Sdch3.BlacklistReason", it->second.reason, MAX_PROBLEM_CODE); |
| 367 SdchErrorRecovery(DOMAIN_BLACKLIST_INCLUDES_TARGET); | 364 SdchErrorRecovery(DOMAIN_BLACKLIST_INCLUDES_TARGET); |
| 368 | 365 |
| 369 int count = it->second.count - 1; | 366 int count = it->second.count - 1; |
| 370 if (count > 0) { | 367 if (count > 0) { |
| 371 it->second.count = count; | 368 it->second.count = count; |
| 372 } else { | 369 } else { |
| 373 it->second.count = 0; | 370 it->second.count = 0; |
| 374 it->second.reason = MIN_PROBLEM_CODE; | 371 it->second.reason = MIN_PROBLEM_CODE; |
| 375 } | 372 } |
| 376 | 373 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 414 // TODO(jar): Remove this failsafe conservative hack which is more restrictive | 411 // TODO(jar): Remove this failsafe conservative hack which is more restrictive |
| 415 // than current SDCH spec when needed, and justified by security audit. | 412 // than current SDCH spec when needed, and justified by security audit. |
| 416 if (!referring_url.SchemeIsHTTPOrHTTPS()) { | 413 if (!referring_url.SchemeIsHTTPOrHTTPS()) { |
| 417 SdchErrorRecovery(DICTIONARY_SELECTED_FROM_NON_HTTP); | 414 SdchErrorRecovery(DICTIONARY_SELECTED_FROM_NON_HTTP); |
| 418 return false; | 415 return false; |
| 419 } | 416 } |
| 420 | 417 |
| 421 return true; | 418 return true; |
| 422 } | 419 } |
| 423 | 420 |
| 424 void SdchManager::GetVcdiffDictionary( | 421 void SdchManager::GetVcdiffDictionary(const std::string& server_hash, |
| 425 const std::string& server_hash, | 422 const GURL& referring_url, |
| 426 const GURL& referring_url, | 423 scoped_refptr<Dictionary>* dictionary) { |
| 427 scoped_refptr<Dictionary>* dictionary) { | |
| 428 DCHECK(CalledOnValidThread()); | 424 DCHECK(CalledOnValidThread()); |
| 429 *dictionary = NULL; | 425 *dictionary = NULL; |
| 430 DictionaryMap::iterator it = dictionaries_.find(server_hash); | 426 DictionaryMap::iterator it = dictionaries_.find(server_hash); |
| 431 if (it == dictionaries_.end()) { | 427 if (it == dictionaries_.end()) { |
| 432 return; | 428 return; |
| 433 } | 429 } |
| 434 scoped_refptr<Dictionary> matching_dictionary = it->second; | 430 scoped_refptr<Dictionary> matching_dictionary = it->second; |
| 435 if (!IsInSupportedDomain(referring_url)) | 431 if (!IsInSupportedDomain(referring_url)) |
| 436 return; | 432 return; |
| 437 if (!matching_dictionary->CanUse(referring_url)) | 433 if (!matching_dictionary->CanUse(referring_url)) |
| 438 return; | 434 return; |
| 439 *dictionary = matching_dictionary; | 435 *dictionary = matching_dictionary; |
| 440 } | 436 } |
| 441 | 437 |
| 442 // TODO(jar): If we have evictions from the dictionaries_, then we need to | 438 // TODO(jar): If we have evictions from the dictionaries_, then we need to |
| 443 // change this interface to return a list of reference counted Dictionary | 439 // change this interface to return a list of reference counted Dictionary |
| 444 // instances that can be used if/when a server specifies one. | 440 // instances that can be used if/when a server specifies one. |
| 445 void SdchManager::GetAvailDictionaryList(const GURL& target_url, | 441 void SdchManager::GetAvailDictionaryList(const GURL& target_url, |
| 446 std::string* list) { | 442 std::string* list) { |
| 447 DCHECK(CalledOnValidThread()); | 443 DCHECK(CalledOnValidThread()); |
| 448 int count = 0; | 444 int count = 0; |
| 449 for (DictionaryMap::iterator it = dictionaries_.begin(); | 445 for (DictionaryMap::iterator it = dictionaries_.begin(); |
| 450 it != dictionaries_.end(); ++it) { | 446 it != dictionaries_.end(); |
| 447 ++it) { | |
| 451 if (!IsInSupportedDomain(target_url)) | 448 if (!IsInSupportedDomain(target_url)) |
| 452 continue; | 449 continue; |
| 453 if (!it->second->CanAdvertise(target_url)) | 450 if (!it->second->CanAdvertise(target_url)) |
| 454 continue; | 451 continue; |
| 455 ++count; | 452 ++count; |
| 456 if (!list->empty()) | 453 if (!list->empty()) |
| 457 list->append(","); | 454 list->append(","); |
| 458 list->append(it->second->client_hash()); | 455 list->append(it->second->client_hash()); |
| 459 } | 456 } |
| 460 // Watch to see if we have corrupt or numerous dictionaries. | 457 // Watch to see if we have corrupt or numerous dictionaries. |
| 461 if (count > 0) | 458 if (count > 0) |
| 462 UMA_HISTOGRAM_COUNTS("Sdch3.Advertisement_Count", count); | 459 UMA_HISTOGRAM_COUNTS("Sdch3.Advertisement_Count", count); |
| 463 } | 460 } |
| 464 | 461 |
| 465 // static | 462 // static |
| 466 void SdchManager::GenerateHash(const std::string& dictionary_text, | 463 void SdchManager::GenerateHash(const std::string& dictionary_text, |
| 467 std::string* client_hash, std::string* server_hash) { | 464 std::string* client_hash, |
| 465 std::string* server_hash) { | |
| 468 char binary_hash[32]; | 466 char binary_hash[32]; |
| 469 crypto::SHA256HashString(dictionary_text, binary_hash, sizeof(binary_hash)); | 467 crypto::SHA256HashString(dictionary_text, binary_hash, sizeof(binary_hash)); |
| 470 | 468 |
| 471 std::string first_48_bits(&binary_hash[0], 6); | 469 std::string first_48_bits(&binary_hash[0], 6); |
| 472 std::string second_48_bits(&binary_hash[6], 6); | 470 std::string second_48_bits(&binary_hash[6], 6); |
| 473 UrlSafeBase64Encode(first_48_bits, client_hash); | 471 UrlSafeBase64Encode(first_48_bits, client_hash); |
| 474 UrlSafeBase64Encode(second_48_bits, server_hash); | 472 UrlSafeBase64Encode(second_48_bits, server_hash); |
| 475 | 473 |
| 476 DCHECK_EQ(server_hash->length(), 8u); | 474 DCHECK_EQ(server_hash->length(), 8u); |
| 477 DCHECK_EQ(client_hash->length(), 8u); | 475 DCHECK_EQ(client_hash->length(), 8u); |
| 478 } | 476 } |
| 479 | 477 |
| 480 //------------------------------------------------------------------------------ | 478 //------------------------------------------------------------------------------ |
| 481 // Methods for supporting latency experiments. | 479 // Methods for supporting latency experiments. |
| 482 | 480 |
| 483 bool SdchManager::AllowLatencyExperiment(const GURL& url) const { | 481 bool SdchManager::AllowLatencyExperiment(const GURL& url) const { |
| 484 DCHECK(CalledOnValidThread()); | 482 DCHECK(CalledOnValidThread()); |
| 485 return allow_latency_experiment_.end() != | 483 return allow_latency_experiment_.end() != |
| 486 allow_latency_experiment_.find(url.host()); | 484 allow_latency_experiment_.find(url.host()); |
| 487 } | 485 } |
| 488 | 486 |
| 489 void SdchManager::SetAllowLatencyExperiment(const GURL& url, bool enable) { | 487 void SdchManager::SetAllowLatencyExperiment(const GURL& url, bool enable) { |
| 490 DCHECK(CalledOnValidThread()); | 488 DCHECK(CalledOnValidThread()); |
| 491 if (enable) { | 489 if (enable) { |
| 492 allow_latency_experiment_.insert(url.host()); | 490 allow_latency_experiment_.insert(url.host()); |
| 493 return; | 491 return; |
| 494 } | 492 } |
| 495 ExperimentSet::iterator it = allow_latency_experiment_.find(url.host()); | 493 ExperimentSet::iterator it = allow_latency_experiment_.find(url.host()); |
| 496 if (allow_latency_experiment_.end() == it) | 494 if (allow_latency_experiment_.end() == it) |
| 497 return; // It was already erased, or never allowed. | 495 return; // It was already erased, or never allowed. |
| 498 SdchErrorRecovery(LATENCY_TEST_DISALLOWED); | 496 SdchErrorRecovery(LATENCY_TEST_DISALLOWED); |
| 499 allow_latency_experiment_.erase(it); | 497 allow_latency_experiment_.erase(it); |
| 500 } | 498 } |
| 501 | 499 |
| 502 void SdchManager::AddSdchDictionary(const std::string& dictionary_text, | 500 void SdchManager::AddSdchDictionary(const std::string& dictionary_text, |
| 503 const GURL& dictionary_url) { | 501 const GURL& dictionary_url) { |
| 504 DCHECK(CalledOnValidThread()); | 502 DCHECK(CalledOnValidThread()); |
| 505 std::string client_hash; | 503 std::string client_hash; |
| 506 std::string server_hash; | 504 std::string server_hash; |
| 507 GenerateHash(dictionary_text, &client_hash, &server_hash); | 505 GenerateHash(dictionary_text, &client_hash, &server_hash); |
| 508 if (dictionaries_.find(server_hash) != dictionaries_.end()) { | 506 if (dictionaries_.find(server_hash) != dictionaries_.end()) { |
| 509 SdchErrorRecovery(DICTIONARY_ALREADY_LOADED); | 507 SdchErrorRecovery(DICTIONARY_ALREADY_LOADED); |
| 510 return; // Already loaded. | 508 return; // Already loaded. |
| 511 } | 509 } |
| 512 | 510 |
| 513 std::string domain, path; | 511 std::string domain, path; |
| 514 std::set<int> ports; | 512 std::set<int> ports; |
| 515 base::Time expiration(base::Time::Now() + base::TimeDelta::FromDays(30)); | 513 base::Time expiration(base::Time::Now() + base::TimeDelta::FromDays(30)); |
| 516 | 514 |
| 517 if (dictionary_text.empty()) { | 515 if (dictionary_text.empty()) { |
| 518 SdchErrorRecovery(DICTIONARY_HAS_NO_TEXT); | 516 SdchErrorRecovery(DICTIONARY_HAS_NO_TEXT); |
| 519 return; // Missing header. | 517 return; // Missing header. |
| 520 } | 518 } |
| 521 | 519 |
| 522 size_t header_end = dictionary_text.find("\n\n"); | 520 size_t header_end = dictionary_text.find("\n\n"); |
| 523 if (std::string::npos == header_end) { | 521 if (std::string::npos == header_end) { |
| 524 SdchErrorRecovery(DICTIONARY_HAS_NO_HEADER); | 522 SdchErrorRecovery(DICTIONARY_HAS_NO_HEADER); |
| 525 return; // Missing header. | 523 return; // Missing header. |
| 526 } | 524 } |
| 527 size_t line_start = 0; // Start of line being parsed. | 525 size_t line_start = 0; // Start of line being parsed. |
| 528 while (1) { | 526 while (1) { |
| 529 size_t line_end = dictionary_text.find('\n', line_start); | 527 size_t line_end = dictionary_text.find('\n', line_start); |
| 530 DCHECK(std::string::npos != line_end); | 528 DCHECK(std::string::npos != line_end); |
| 531 DCHECK_LE(line_end, header_end); | 529 DCHECK_LE(line_end, header_end); |
| 532 | 530 |
| 533 size_t colon_index = dictionary_text.find(':', line_start); | 531 size_t colon_index = dictionary_text.find(':', line_start); |
| 534 if (std::string::npos == colon_index) { | 532 if (std::string::npos == colon_index) { |
| 535 SdchErrorRecovery(DICTIONARY_HEADER_LINE_MISSING_COLON); | 533 SdchErrorRecovery(DICTIONARY_HEADER_LINE_MISSING_COLON); |
| 536 return; // Illegal line missing a colon. | 534 return; // Illegal line missing a colon. |
| 537 } | 535 } |
| 538 | 536 |
| 539 if (colon_index > line_end) | 537 if (colon_index > line_end) |
| 540 break; | 538 break; |
| 541 | 539 |
| 542 size_t value_start = dictionary_text.find_first_not_of(" \t", | 540 size_t value_start = |
| 543 colon_index + 1); | 541 dictionary_text.find_first_not_of(" \t", colon_index + 1); |
| 544 if (std::string::npos != value_start) { | 542 if (std::string::npos != value_start) { |
| 545 if (value_start >= line_end) | 543 if (value_start >= line_end) |
| 546 break; | 544 break; |
| 547 std::string name(dictionary_text, line_start, colon_index - line_start); | 545 std::string name(dictionary_text, line_start, colon_index - line_start); |
| 548 std::string value(dictionary_text, value_start, line_end - value_start); | 546 std::string value(dictionary_text, value_start, line_end - value_start); |
| 549 name = base::StringToLowerASCII(name); | 547 name = base::StringToLowerASCII(name); |
| 550 if (name == "domain") { | 548 if (name == "domain") { |
| 551 domain = value; | 549 domain = value; |
| 552 } else if (name == "path") { | 550 } else if (name == "path") { |
| 553 path = value; | 551 path = value; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 590 return; | 588 return; |
| 591 } | 589 } |
| 592 if (kMaxDictionaryCount <= dictionaries_.size()) { | 590 if (kMaxDictionaryCount <= dictionaries_.size()) { |
| 593 SdchErrorRecovery(DICTIONARY_COUNT_EXCEEDED); | 591 SdchErrorRecovery(DICTIONARY_COUNT_EXCEEDED); |
| 594 return; | 592 return; |
| 595 } | 593 } |
| 596 | 594 |
| 597 UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size()); | 595 UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size()); |
| 598 DVLOG(1) << "Loaded dictionary with client hash " << client_hash | 596 DVLOG(1) << "Loaded dictionary with client hash " << client_hash |
| 599 << " and server hash " << server_hash; | 597 << " and server hash " << server_hash; |
| 600 Dictionary* dictionary = | 598 Dictionary* dictionary = new Dictionary(dictionary_text, |
| 601 new Dictionary(dictionary_text, header_end + 2, client_hash, | 599 header_end + 2, |
| 602 dictionary_url_normalized, domain, | 600 client_hash, |
| 603 path, expiration, ports); | 601 dictionary_url_normalized, |
| 602 domain, | |
| 603 path, | |
| 604 expiration, | |
| 605 ports); | |
| 604 dictionaries_[server_hash] = dictionary; | 606 dictionaries_[server_hash] = dictionary; |
| 605 return; | 607 return; |
| 606 } | 608 } |
| 607 | 609 |
| 608 // static | 610 // static |
| 609 void SdchManager::UrlSafeBase64Encode(const std::string& input, | 611 void SdchManager::UrlSafeBase64Encode(const std::string& input, |
| 610 std::string* output) { | 612 std::string* output) { |
| 611 // Since this is only done during a dictionary load, and hashes are only 8 | 613 // Since this is only done during a dictionary load, and hashes are only 8 |
| 612 // characters, we just do the simple fixup, rather than rewriting the encoder. | 614 // characters, we just do the simple fixup, rather than rewriting the encoder. |
| 613 base::Base64Encode(input, output); | 615 base::Base64Encode(input, output); |
| 614 std::replace(output->begin(), output->end(), '+', '-'); | 616 std::replace(output->begin(), output->end(), '+', '-'); |
| 615 std::replace(output->begin(), output->end(), '/', '_'); | 617 std::replace(output->begin(), output->end(), '/', '_'); |
| 616 } | 618 } |
| 617 | 619 |
| 618 } // namespace net | 620 } // namespace net |
| OLD | NEW |