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

Side by Side Diff: net/http/http_server_properties_impl.cc

Issue 2898983006: Fix and refactor HttpServerPropertiesImpl's alternative services brokenness expiration behavior (Closed)
Patch Set: Fixed cherie's comments from ps9; added BrokenAlternativeServicesTest.ScheduleExpireTaskAfterExpire Created 3 years, 6 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
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/http/http_server_properties_impl.h" 5 #include "net/http/http_server_properties_impl.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <memory> 8 #include <memory>
9 #include <utility> 9 #include <utility>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/location.h" 12 #include "base/location.h"
13 #include "base/logging.h" 13 #include "base/logging.h"
14 #include "base/metrics/histogram_macros.h" 14 #include "base/metrics/histogram_macros.h"
15 #include "base/single_thread_task_runner.h" 15 #include "base/single_thread_task_runner.h"
16 #include "base/stl_util.h" 16 #include "base/stl_util.h"
17 #include "base/strings/string_util.h" 17 #include "base/strings/string_util.h"
18 #include "base/threading/thread_task_runner_handle.h" 18 #include "base/threading/thread_task_runner_handle.h"
19 #include "base/values.h" 19 #include "base/values.h"
20 20
21 namespace net { 21 namespace net {
22 22
23 namespace { 23 HttpServerPropertiesImpl::HttpServerPropertiesImpl()
24 : HttpServerPropertiesImpl(&broken_alternative_services_clock_) {}
24 25
25 // Initial delay for broken alternative services. 26 HttpServerPropertiesImpl::HttpServerPropertiesImpl(
26 const uint64_t kBrokenAlternativeProtocolDelaySecs = 300; 27 base::TickClock* broken_alternative_services_clock)
27 // Subsequent failures result in exponential (base 2) backoff. 28 : broken_alternative_services_(this, broken_alternative_services_clock),
28 // Limit binary shift to limit delay to approximately 2 days. 29 spdy_servers_map_(SpdyServersMap::NO_AUTO_EVICT),
29 const int kBrokenDelayMaxShift = 9;
30
31 } // namespace
32
33 HttpServerPropertiesImpl::HttpServerPropertiesImpl()
34 : spdy_servers_map_(SpdyServersMap::NO_AUTO_EVICT),
35 alternative_service_map_(AlternativeServiceMap::NO_AUTO_EVICT), 30 alternative_service_map_(AlternativeServiceMap::NO_AUTO_EVICT),
36 recently_broken_alternative_services_(
37 RecentlyBrokenAlternativeServices::NO_AUTO_EVICT),
38 server_network_stats_map_(ServerNetworkStatsMap::NO_AUTO_EVICT), 31 server_network_stats_map_(ServerNetworkStatsMap::NO_AUTO_EVICT),
39 quic_server_info_map_(QuicServerInfoMap::NO_AUTO_EVICT), 32 quic_server_info_map_(QuicServerInfoMap::NO_AUTO_EVICT),
40 max_server_configs_stored_in_properties_(kMaxQuicServersToPersist), 33 max_server_configs_stored_in_properties_(kMaxQuicServersToPersist) {
41 weak_ptr_factory_(this) {
42 canonical_suffixes_.push_back(".ggpht.com"); 34 canonical_suffixes_.push_back(".ggpht.com");
43 canonical_suffixes_.push_back(".c.youtube.com"); 35 canonical_suffixes_.push_back(".c.youtube.com");
44 canonical_suffixes_.push_back(".googlevideo.com"); 36 canonical_suffixes_.push_back(".googlevideo.com");
45 canonical_suffixes_.push_back(".googleusercontent.com"); 37 canonical_suffixes_.push_back(".googleusercontent.com");
46 } 38 }
47 39
48 HttpServerPropertiesImpl::~HttpServerPropertiesImpl() { 40 HttpServerPropertiesImpl::~HttpServerPropertiesImpl() {
49 } 41 }
50 42
51 void HttpServerPropertiesImpl::SetSpdyServers( 43 void HttpServerPropertiesImpl::SetSpdyServers(
(...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after
447 url::SchemeHostPort canonical_server(kCanonicalScheme, *canonical_suffix, 439 url::SchemeHostPort canonical_server(kCanonicalScheme, *canonical_suffix,
448 origin.port()); 440 origin.port());
449 canonical_host_to_origin_map_[canonical_server] = origin; 441 canonical_host_to_origin_map_[canonical_server] = origin;
450 } 442 }
451 } 443 }
452 return changed; 444 return changed;
453 } 445 }
454 446
455 void HttpServerPropertiesImpl::MarkAlternativeServiceBroken( 447 void HttpServerPropertiesImpl::MarkAlternativeServiceBroken(
456 const AlternativeService& alternative_service) { 448 const AlternativeService& alternative_service) {
457 // Empty host means use host of origin, callers are supposed to substitute. 449 broken_alternative_services_.MarkAlternativeServiceBroken(
458 DCHECK(!alternative_service.host.empty()); 450 alternative_service);
459 if (alternative_service.protocol == kProtoUnknown) {
460 LOG(DFATAL) << "Trying to mark unknown alternate protocol broken.";
461 return;
462 }
463 auto it = recently_broken_alternative_services_.Get(alternative_service);
464 int shift = 0;
465 if (it == recently_broken_alternative_services_.end()) {
466 recently_broken_alternative_services_.Put(alternative_service, 1);
467 } else {
468 shift = it->second++;
469 }
470 if (shift > kBrokenDelayMaxShift)
471 shift = kBrokenDelayMaxShift;
472 base::TimeDelta delay =
473 base::TimeDelta::FromSeconds(kBrokenAlternativeProtocolDelaySecs);
474 base::TimeTicks when = base::TimeTicks::Now() + delay * (1 << shift);
475 auto result = broken_alternative_services_.insert(
476 std::make_pair(alternative_service, when));
477 // Return if alternative service is already in expiration queue.
478 if (!result.second) {
479 return;
480 }
481
482 // If this is the only entry in the list, schedule an expiration task.
483 // Otherwise it will be rescheduled automatically when the pending task runs.
484 if (broken_alternative_services_.size() == 1) {
485 ScheduleBrokenAlternateProtocolMappingsExpiration();
486 }
487 } 451 }
488 452
489 void HttpServerPropertiesImpl::MarkAlternativeServiceRecentlyBroken( 453 void HttpServerPropertiesImpl::MarkAlternativeServiceRecentlyBroken(
490 const AlternativeService& alternative_service) { 454 const AlternativeService& alternative_service) {
491 if (recently_broken_alternative_services_.Get(alternative_service) == 455 broken_alternative_services_.MarkAlternativeServiceRecentlyBroken(
492 recently_broken_alternative_services_.end()) { 456 alternative_service);
493 recently_broken_alternative_services_.Put(alternative_service, 1);
494 }
495 } 457 }
496 458
497 bool HttpServerPropertiesImpl::IsAlternativeServiceBroken( 459 bool HttpServerPropertiesImpl::IsAlternativeServiceBroken(
498 const AlternativeService& alternative_service) const { 460 const AlternativeService& alternative_service) const {
499 // Empty host means use host of origin, callers are supposed to substitute. 461 return broken_alternative_services_.IsAlternativeServiceBroken(
500 DCHECK(!alternative_service.host.empty()); 462 alternative_service);
501 return base::ContainsKey(broken_alternative_services_, alternative_service);
502 } 463 }
503 464
504 bool HttpServerPropertiesImpl::WasAlternativeServiceRecentlyBroken( 465 bool HttpServerPropertiesImpl::WasAlternativeServiceRecentlyBroken(
505 const AlternativeService& alternative_service) { 466 const AlternativeService& alternative_service) {
506 if (alternative_service.protocol == kProtoUnknown) 467 return broken_alternative_services_.WasAlternativeServiceRecentlyBroken(
507 return false; 468 alternative_service);
508
509 return recently_broken_alternative_services_.Get(alternative_service) !=
510 recently_broken_alternative_services_.end();
511 } 469 }
512 470
513 void HttpServerPropertiesImpl::ConfirmAlternativeService( 471 void HttpServerPropertiesImpl::ConfirmAlternativeService(
514 const AlternativeService& alternative_service) { 472 const AlternativeService& alternative_service) {
515 if (alternative_service.protocol == kProtoUnknown) 473 broken_alternative_services_.ConfirmAlternativeService(alternative_service);
516 return;
517 broken_alternative_services_.erase(alternative_service);
518 auto it = recently_broken_alternative_services_.Get(alternative_service);
519 if (it != recently_broken_alternative_services_.end()) {
520 recently_broken_alternative_services_.Erase(it);
521 }
522 } 474 }
523 475
524 const AlternativeServiceMap& HttpServerPropertiesImpl::alternative_service_map() 476 const AlternativeServiceMap& HttpServerPropertiesImpl::alternative_service_map()
525 const { 477 const {
526 return alternative_service_map_; 478 return alternative_service_map_;
527 } 479 }
528 480
529 std::unique_ptr<base::Value> 481 std::unique_ptr<base::Value>
530 HttpServerPropertiesImpl::GetAlternativeServiceInfoAsValue() const { 482 HttpServerPropertiesImpl::GetAlternativeServiceInfoAsValue() const {
531 std::unique_ptr<base::ListValue> dict_list(new base::ListValue); 483 std::unique_ptr<base::ListValue> dict_list(new base::ListValue);
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
705 657
706 void HttpServerPropertiesImpl::RemoveCanonicalHost( 658 void HttpServerPropertiesImpl::RemoveCanonicalHost(
707 const url::SchemeHostPort& server) { 659 const url::SchemeHostPort& server) {
708 CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server); 660 CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server);
709 if (canonical == canonical_host_to_origin_map_.end()) 661 if (canonical == canonical_host_to_origin_map_.end())
710 return; 662 return;
711 663
712 canonical_host_to_origin_map_.erase(canonical->first); 664 canonical_host_to_origin_map_.erase(canonical->first);
713 } 665 }
714 666
715 void HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings() { 667 void HttpServerPropertiesImpl::OnExpireBrokenAlternativeService(
716 base::TimeTicks now = base::TimeTicks::Now(); 668 const AlternativeService& expired_alternative_service) {
717 while (!broken_alternative_services_.empty()) { 669 // Remove every occurrence of |expired_alternative_service| from
718 BrokenAlternativeServices::iterator it = 670 // |alternative_service_map_|.
719 broken_alternative_services_.begin(); 671 for (AlternativeServiceMap::iterator map_it =
720 if (now < it->second) { 672 alternative_service_map_.begin();
721 break; 673 map_it != alternative_service_map_.end();) {
722 } 674 for (AlternativeServiceInfoVector::iterator it = map_it->second.begin();
723 675 it != map_it->second.end();) {
724 const AlternativeService expired_alternative_service = it->first; 676 AlternativeService alternative_service(it->alternative_service);
725 broken_alternative_services_.erase(it); 677 // Empty hostname in map means hostname of key: substitute before
726 678 // comparing to |expired_alternative_service|.
727 // Remove every occurrence of |expired_alternative_service| from 679 if (alternative_service.host.empty()) {
728 // |alternative_service_map_|. 680 alternative_service.host = map_it->first.host();
729 for (AlternativeServiceMap::iterator map_it =
730 alternative_service_map_.begin();
731 map_it != alternative_service_map_.end();) {
732 for (AlternativeServiceInfoVector::iterator it = map_it->second.begin();
733 it != map_it->second.end();) {
734 AlternativeService alternative_service(it->alternative_service);
735 // Empty hostname in map means hostname of key: substitute before
736 // comparing to |expired_alternative_service|.
737 if (alternative_service.host.empty()) {
738 alternative_service.host = map_it->first.host();
739 }
740 if (alternative_service == expired_alternative_service) {
741 it = map_it->second.erase(it);
742 continue;
743 }
744 ++it;
745 } 681 }
746 // If an origin has an empty list of alternative services, then remove it 682 if (alternative_service == expired_alternative_service) {
747 // from both |canonical_host_to_origin_map_| and 683 it = map_it->second.erase(it);
748 // |alternative_service_map_|.
749 if (map_it->second.empty()) {
750 RemoveCanonicalHost(map_it->first);
751 map_it = alternative_service_map_.Erase(map_it);
752 continue; 684 continue;
753 } 685 }
754 ++map_it; 686 ++it;
755 } 687 }
688 // If an origin has an empty list of alternative services, then remove it
689 // from both |canonical_host_to_origin_map_| and
690 // |alternative_service_map_|.
691 if (map_it->second.empty()) {
692 RemoveCanonicalHost(map_it->first);
693 map_it = alternative_service_map_.Erase(map_it);
694 continue;
695 }
696 ++map_it;
756 } 697 }
757 ScheduleBrokenAlternateProtocolMappingsExpiration();
758 }
759
760 void
761 HttpServerPropertiesImpl::ScheduleBrokenAlternateProtocolMappingsExpiration() {
762 if (broken_alternative_services_.empty()) {
763 return;
764 }
765 base::TimeTicks now = base::TimeTicks::Now();
766 base::TimeTicks when = broken_alternative_services_.front().second;
767 base::TimeDelta delay = when > now ? when - now : base::TimeDelta();
768 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
769 FROM_HERE,
770 base::Bind(
771 &HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings,
772 weak_ptr_factory_.GetWeakPtr()),
773 delay);
774 } 698 }
775 699
776 } // namespace net 700 } // namespace net
OLDNEW
« no previous file with comments | « net/http/http_server_properties_impl.h ('k') | net/http/http_server_properties_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698