Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(507)

Side by Side Diff: net/base/sdch_manager.cc

Issue 495523003: Change SDCHDictionaryFetcher to use URLRequest instead of URLFetcher. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed try job failures. Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/base/sdch_manager.h ('k') | net/base/sdch_manager_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 382 matching lines...) Expand 10 before | Expand all | Expand 10 after
393 // TODO(jar): Remove this failsafe conservative hack which is more restrictive 393 // TODO(jar): Remove this failsafe conservative hack which is more restrictive
394 // than current SDCH spec when needed, and justified by security audit. 394 // than current SDCH spec when needed, and justified by security audit.
395 if (!referring_url.SchemeIsHTTPOrHTTPS()) { 395 if (!referring_url.SchemeIsHTTPOrHTTPS()) {
396 SdchErrorRecovery(DICTIONARY_SELECTED_FROM_NON_HTTP); 396 SdchErrorRecovery(DICTIONARY_SELECTED_FROM_NON_HTTP);
397 return false; 397 return false;
398 } 398 }
399 399
400 return true; 400 return true;
401 } 401 }
402 402
403 bool SdchManager::AddSdchDictionary(const std::string& dictionary_text, 403 void SdchManager::GetVcdiffDictionary(
404 const std::string& server_hash,
405 const GURL& referring_url,
406 scoped_refptr<Dictionary>* dictionary) {
407 DCHECK(CalledOnValidThread());
408 *dictionary = NULL;
409 DictionaryMap::iterator it = dictionaries_.find(server_hash);
410 if (it == dictionaries_.end()) {
411 return;
412 }
413 scoped_refptr<Dictionary> matching_dictionary = it->second;
414 if (!IsInSupportedDomain(referring_url))
415 return;
416 if (!matching_dictionary->CanUse(referring_url))
417 return;
418 *dictionary = matching_dictionary;
419 }
420
421 // TODO(jar): If we have evictions from the dictionaries_, then we need to
422 // change this interface to return a list of reference counted Dictionary
423 // instances that can be used if/when a server specifies one.
424 void SdchManager::GetAvailDictionaryList(const GURL& target_url,
425 std::string* list) {
426 DCHECK(CalledOnValidThread());
427 int count = 0;
428 for (DictionaryMap::iterator it = dictionaries_.begin();
429 it != dictionaries_.end(); ++it) {
430 if (!IsInSupportedDomain(target_url))
431 continue;
432 if (!it->second->CanAdvertise(target_url))
433 continue;
434 ++count;
435 if (!list->empty())
436 list->append(",");
437 list->append(it->second->client_hash());
438 }
439 // Watch to see if we have corrupt or numerous dictionaries.
440 if (count > 0)
441 UMA_HISTOGRAM_COUNTS("Sdch3.Advertisement_Count", count);
442 }
443
444 // static
445 void SdchManager::GenerateHash(const std::string& dictionary_text,
446 std::string* client_hash, std::string* server_hash) {
447 char binary_hash[32];
448 crypto::SHA256HashString(dictionary_text, binary_hash, sizeof(binary_hash));
449
450 std::string first_48_bits(&binary_hash[0], 6);
451 std::string second_48_bits(&binary_hash[6], 6);
452 UrlSafeBase64Encode(first_48_bits, client_hash);
453 UrlSafeBase64Encode(second_48_bits, server_hash);
454
455 DCHECK_EQ(server_hash->length(), 8u);
456 DCHECK_EQ(client_hash->length(), 8u);
457 }
458
459 //------------------------------------------------------------------------------
460 // Methods for supporting latency experiments.
461
462 bool SdchManager::AllowLatencyExperiment(const GURL& url) const {
463 DCHECK(CalledOnValidThread());
464 return allow_latency_experiment_.end() !=
465 allow_latency_experiment_.find(url.host());
466 }
467
468 void SdchManager::SetAllowLatencyExperiment(const GURL& url, bool enable) {
469 DCHECK(CalledOnValidThread());
470 if (enable) {
471 allow_latency_experiment_.insert(url.host());
472 return;
473 }
474 ExperimentSet::iterator it = allow_latency_experiment_.find(url.host());
475 if (allow_latency_experiment_.end() == it)
476 return; // It was already erased, or never allowed.
477 SdchErrorRecovery(LATENCY_TEST_DISALLOWED);
478 allow_latency_experiment_.erase(it);
479 }
480
481 void SdchManager::AddSdchDictionary(const std::string& dictionary_text,
404 const GURL& dictionary_url) { 482 const GURL& dictionary_url) {
405 DCHECK(CalledOnValidThread()); 483 DCHECK(CalledOnValidThread());
406 std::string client_hash; 484 std::string client_hash;
407 std::string server_hash; 485 std::string server_hash;
408 GenerateHash(dictionary_text, &client_hash, &server_hash); 486 GenerateHash(dictionary_text, &client_hash, &server_hash);
409 if (dictionaries_.find(server_hash) != dictionaries_.end()) { 487 if (dictionaries_.find(server_hash) != dictionaries_.end()) {
410 SdchErrorRecovery(DICTIONARY_ALREADY_LOADED); 488 SdchErrorRecovery(DICTIONARY_ALREADY_LOADED);
411 return false; // Already loaded. 489 return; // Already loaded.
412 } 490 }
413 491
414 std::string domain, path; 492 std::string domain, path;
415 std::set<int> ports; 493 std::set<int> ports;
416 base::Time expiration(base::Time::Now() + base::TimeDelta::FromDays(30)); 494 base::Time expiration(base::Time::Now() + base::TimeDelta::FromDays(30));
417 495
418 if (dictionary_text.empty()) { 496 if (dictionary_text.empty()) {
419 SdchErrorRecovery(DICTIONARY_HAS_NO_TEXT); 497 SdchErrorRecovery(DICTIONARY_HAS_NO_TEXT);
420 return false; // Missing header. 498 return; // Missing header.
421 } 499 }
422 500
423 size_t header_end = dictionary_text.find("\n\n"); 501 size_t header_end = dictionary_text.find("\n\n");
424 if (std::string::npos == header_end) { 502 if (std::string::npos == header_end) {
425 SdchErrorRecovery(DICTIONARY_HAS_NO_HEADER); 503 SdchErrorRecovery(DICTIONARY_HAS_NO_HEADER);
426 return false; // Missing header. 504 return; // Missing header.
427 } 505 }
428 size_t line_start = 0; // Start of line being parsed. 506 size_t line_start = 0; // Start of line being parsed.
429 while (1) { 507 while (1) {
430 size_t line_end = dictionary_text.find('\n', line_start); 508 size_t line_end = dictionary_text.find('\n', line_start);
431 DCHECK(std::string::npos != line_end); 509 DCHECK(std::string::npos != line_end);
432 DCHECK_LE(line_end, header_end); 510 DCHECK_LE(line_end, header_end);
433 511
434 size_t colon_index = dictionary_text.find(':', line_start); 512 size_t colon_index = dictionary_text.find(':', line_start);
435 if (std::string::npos == colon_index) { 513 if (std::string::npos == colon_index) {
436 SdchErrorRecovery(DICTIONARY_HEADER_LINE_MISSING_COLON); 514 SdchErrorRecovery(DICTIONARY_HEADER_LINE_MISSING_COLON);
437 return false; // Illegal line missing a colon. 515 return; // Illegal line missing a colon.
438 } 516 }
439 517
440 if (colon_index > line_end) 518 if (colon_index > line_end)
441 break; 519 break;
442 520
443 size_t value_start = dictionary_text.find_first_not_of(" \t", 521 size_t value_start = dictionary_text.find_first_not_of(" \t",
444 colon_index + 1); 522 colon_index + 1);
445 if (std::string::npos != value_start) { 523 if (std::string::npos != value_start) {
446 if (value_start >= line_end) 524 if (value_start >= line_end)
447 break; 525 break;
448 std::string name(dictionary_text, line_start, colon_index - line_start); 526 std::string name(dictionary_text, line_start, colon_index - line_start);
449 std::string value(dictionary_text, value_start, line_end - value_start); 527 std::string value(dictionary_text, value_start, line_end - value_start);
450 name = base::StringToLowerASCII(name); 528 name = base::StringToLowerASCII(name);
451 if (name == "domain") { 529 if (name == "domain") {
452 domain = value; 530 domain = value;
453 } else if (name == "path") { 531 } else if (name == "path") {
454 path = value; 532 path = value;
455 } else if (name == "format-version") { 533 } else if (name == "format-version") {
456 if (value != "1.0") 534 if (value != "1.0")
457 return false; 535 return;
458 } else if (name == "max-age") { 536 } else if (name == "max-age") {
459 int64 seconds; 537 int64 seconds;
460 base::StringToInt64(value, &seconds); 538 base::StringToInt64(value, &seconds);
461 expiration = base::Time::Now() + base::TimeDelta::FromSeconds(seconds); 539 expiration = base::Time::Now() + base::TimeDelta::FromSeconds(seconds);
462 } else if (name == "port") { 540 } else if (name == "port") {
463 int port; 541 int port;
464 base::StringToInt(value, &port); 542 base::StringToInt(value, &port);
465 if (port >= 0) 543 if (port >= 0)
466 ports.insert(port); 544 ports.insert(port);
467 } 545 }
468 } 546 }
469 547
470 if (line_end >= header_end) 548 if (line_end >= header_end)
471 break; 549 break;
472 line_start = line_end + 1; 550 line_start = line_end + 1;
473 } 551 }
474 552
475 if (!IsInSupportedDomain(dictionary_url)) 553 if (!IsInSupportedDomain(dictionary_url))
476 return false; 554 return;
477 555
478 if (!Dictionary::CanSet(domain, path, ports, dictionary_url)) 556 if (!Dictionary::CanSet(domain, path, ports, dictionary_url))
479 return false; 557 return;
480 558
481 // TODO(jar): Remove these hacks to preclude a DOS attack involving piles of 559 // TODO(jar): Remove these hacks to preclude a DOS attack involving piles of
482 // useless dictionaries. We should probably have a cache eviction plan, 560 // useless dictionaries. We should probably have a cache eviction plan,
483 // instead of just blocking additions. For now, with the spec in flux, it 561 // instead of just blocking additions. For now, with the spec in flux, it
484 // is probably not worth doing eviction handling. 562 // is probably not worth doing eviction handling.
485 if (kMaxDictionarySize < dictionary_text.size()) { 563 if (kMaxDictionarySize < dictionary_text.size()) {
486 SdchErrorRecovery(DICTIONARY_IS_TOO_LARGE); 564 SdchErrorRecovery(DICTIONARY_IS_TOO_LARGE);
487 return false; 565 return;
488 } 566 }
489 if (kMaxDictionaryCount <= dictionaries_.size()) { 567 if (kMaxDictionaryCount <= dictionaries_.size()) {
490 SdchErrorRecovery(DICTIONARY_COUNT_EXCEEDED); 568 SdchErrorRecovery(DICTIONARY_COUNT_EXCEEDED);
491 return false; 569 return;
492 } 570 }
493 571
494 UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size()); 572 UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size());
495 DVLOG(1) << "Loaded dictionary with client hash " << client_hash 573 DVLOG(1) << "Loaded dictionary with client hash " << client_hash
496 << " and server hash " << server_hash; 574 << " and server hash " << server_hash;
497 Dictionary* dictionary = 575 Dictionary* dictionary =
498 new Dictionary(dictionary_text, header_end + 2, client_hash, 576 new Dictionary(dictionary_text, header_end + 2, client_hash,
499 dictionary_url, domain, path, expiration, ports); 577 dictionary_url, domain, path, expiration, ports);
500 dictionaries_[server_hash] = dictionary; 578 dictionaries_[server_hash] = dictionary;
501 return true; 579 return;
502 }
503
504 void SdchManager::GetVcdiffDictionary(
505 const std::string& server_hash,
506 const GURL& referring_url,
507 scoped_refptr<Dictionary>* dictionary) {
508 DCHECK(CalledOnValidThread());
509 *dictionary = NULL;
510 DictionaryMap::iterator it = dictionaries_.find(server_hash);
511 if (it == dictionaries_.end()) {
512 return;
513 }
514 scoped_refptr<Dictionary> matching_dictionary = it->second;
515 if (!IsInSupportedDomain(referring_url))
516 return;
517 if (!matching_dictionary->CanUse(referring_url))
518 return;
519 *dictionary = matching_dictionary;
520 }
521
522 // TODO(jar): If we have evictions from the dictionaries_, then we need to
523 // change this interface to return a list of reference counted Dictionary
524 // instances that can be used if/when a server specifies one.
525 void SdchManager::GetAvailDictionaryList(const GURL& target_url,
526 std::string* list) {
527 DCHECK(CalledOnValidThread());
528 int count = 0;
529 for (DictionaryMap::iterator it = dictionaries_.begin();
530 it != dictionaries_.end(); ++it) {
531 if (!IsInSupportedDomain(target_url))
532 continue;
533 if (!it->second->CanAdvertise(target_url))
534 continue;
535 ++count;
536 if (!list->empty())
537 list->append(",");
538 list->append(it->second->client_hash());
539 }
540 // Watch to see if we have corrupt or numerous dictionaries.
541 if (count > 0)
542 UMA_HISTOGRAM_COUNTS("Sdch3.Advertisement_Count", count);
543 } 580 }
544 581
545 // static 582 // static
546 void SdchManager::GenerateHash(const std::string& dictionary_text,
547 std::string* client_hash, std::string* server_hash) {
548 char binary_hash[32];
549 crypto::SHA256HashString(dictionary_text, binary_hash, sizeof(binary_hash));
550
551 std::string first_48_bits(&binary_hash[0], 6);
552 std::string second_48_bits(&binary_hash[6], 6);
553 UrlSafeBase64Encode(first_48_bits, client_hash);
554 UrlSafeBase64Encode(second_48_bits, server_hash);
555
556 DCHECK_EQ(server_hash->length(), 8u);
557 DCHECK_EQ(client_hash->length(), 8u);
558 }
559
560 //------------------------------------------------------------------------------
561 // Methods for supporting latency experiments.
562
563 bool SdchManager::AllowLatencyExperiment(const GURL& url) const {
564 DCHECK(CalledOnValidThread());
565 return allow_latency_experiment_.end() !=
566 allow_latency_experiment_.find(url.host());
567 }
568
569 void SdchManager::SetAllowLatencyExperiment(const GURL& url, bool enable) {
570 DCHECK(CalledOnValidThread());
571 if (enable) {
572 allow_latency_experiment_.insert(url.host());
573 return;
574 }
575 ExperimentSet::iterator it = allow_latency_experiment_.find(url.host());
576 if (allow_latency_experiment_.end() == it)
577 return; // It was already erased, or never allowed.
578 SdchErrorRecovery(LATENCY_TEST_DISALLOWED);
579 allow_latency_experiment_.erase(it);
580 }
581
582 // static
583 void SdchManager::UrlSafeBase64Encode(const std::string& input, 583 void SdchManager::UrlSafeBase64Encode(const std::string& input,
584 std::string* output) { 584 std::string* output) {
585 // Since this is only done during a dictionary load, and hashes are only 8 585 // Since this is only done during a dictionary load, and hashes are only 8
586 // characters, we just do the simple fixup, rather than rewriting the encoder. 586 // characters, we just do the simple fixup, rather than rewriting the encoder.
587 base::Base64Encode(input, output); 587 base::Base64Encode(input, output);
588 std::replace(output->begin(), output->end(), '+', '-'); 588 std::replace(output->begin(), output->end(), '+', '-');
589 std::replace(output->begin(), output->end(), '/', '_'); 589 std::replace(output->begin(), output->end(), '/', '_');
590 } 590 }
591 591
592 } // namespace net 592 } // namespace net
OLDNEW
« no previous file with comments | « net/base/sdch_manager.h ('k') | net/base/sdch_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698