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

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: 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(
25 HttpBrokenAlternativeServicesManager::DefaultClock::GetInstance()) {}
24 26
25 // Initial delay for broken alternative services. 27 HttpServerPropertiesImpl::HttpServerPropertiesImpl(
26 const uint64_t kBrokenAlternativeProtocolDelaySecs = 300; 28 HttpBrokenAlternativeServicesManager::Clock* clock)
27 // Subsequent failures result in exponential (base 2) backoff. 29 : broken_alternative_services_(this, clock),
28 // Limit binary shift to limit delay to approximately 2 days. 30 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), 31 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), 32 server_network_stats_map_(ServerNetworkStatsMap::NO_AUTO_EVICT),
39 quic_server_info_map_(QuicServerInfoMap::NO_AUTO_EVICT), 33 quic_server_info_map_(QuicServerInfoMap::NO_AUTO_EVICT),
40 max_server_configs_stored_in_properties_(kMaxQuicServersToPersist), 34 max_server_configs_stored_in_properties_(kMaxQuicServersToPersist) {
41 weak_ptr_factory_(this) {
42 canonical_suffixes_.push_back(".ggpht.com"); 35 canonical_suffixes_.push_back(".ggpht.com");
43 canonical_suffixes_.push_back(".c.youtube.com"); 36 canonical_suffixes_.push_back(".c.youtube.com");
44 canonical_suffixes_.push_back(".googlevideo.com"); 37 canonical_suffixes_.push_back(".googlevideo.com");
45 canonical_suffixes_.push_back(".googleusercontent.com"); 38 canonical_suffixes_.push_back(".googleusercontent.com");
46 } 39 }
47 40
48 HttpServerPropertiesImpl::~HttpServerPropertiesImpl() { 41 HttpServerPropertiesImpl::~HttpServerPropertiesImpl() {
49 } 42 }
50 43
51 void HttpServerPropertiesImpl::SetSpdyServers( 44 void HttpServerPropertiesImpl::SetSpdyServers(
(...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after
443 url::SchemeHostPort canonical_server(kCanonicalScheme, *canonical_suffix, 436 url::SchemeHostPort canonical_server(kCanonicalScheme, *canonical_suffix,
444 origin.port()); 437 origin.port());
445 canonical_host_to_origin_map_[canonical_server] = origin; 438 canonical_host_to_origin_map_[canonical_server] = origin;
446 } 439 }
447 } 440 }
448 return changed; 441 return changed;
449 } 442 }
450 443
451 void HttpServerPropertiesImpl::MarkAlternativeServiceBroken( 444 void HttpServerPropertiesImpl::MarkAlternativeServiceBroken(
452 const AlternativeService& alternative_service) { 445 const AlternativeService& alternative_service) {
453 // Empty host means use host of origin, callers are supposed to substitute. 446 broken_alternative_services_.MarkAlternativeServiceBroken(
454 DCHECK(!alternative_service.host.empty()); 447 alternative_service);
455 if (alternative_service.protocol == kProtoUnknown) {
456 LOG(DFATAL) << "Trying to mark unknown alternate protocol broken.";
457 return;
458 }
459 auto it = recently_broken_alternative_services_.Get(alternative_service);
460 int shift = 0;
461 if (it == recently_broken_alternative_services_.end()) {
462 recently_broken_alternative_services_.Put(alternative_service, 1);
463 } else {
464 shift = it->second++;
465 }
466 if (shift > kBrokenDelayMaxShift)
467 shift = kBrokenDelayMaxShift;
468 base::TimeDelta delay =
469 base::TimeDelta::FromSeconds(kBrokenAlternativeProtocolDelaySecs);
470 base::TimeTicks when = base::TimeTicks::Now() + delay * (1 << shift);
471 auto result = broken_alternative_services_.insert(
472 std::make_pair(alternative_service, when));
473 // Return if alternative service is already in expiration queue.
474 if (!result.second) {
475 return;
476 }
477
478 // If this is the only entry in the list, schedule an expiration task.
479 // Otherwise it will be rescheduled automatically when the pending task runs.
480 if (broken_alternative_services_.size() == 1) {
481 ScheduleBrokenAlternateProtocolMappingsExpiration();
482 }
483 } 448 }
484 449
485 void HttpServerPropertiesImpl::MarkAlternativeServiceRecentlyBroken( 450 void HttpServerPropertiesImpl::MarkAlternativeServiceRecentlyBroken(
486 const AlternativeService& alternative_service) { 451 const AlternativeService& alternative_service) {
487 if (recently_broken_alternative_services_.Get(alternative_service) == 452 broken_alternative_services_.MarkAlternativeServiceRecentlyBroken(
488 recently_broken_alternative_services_.end()) { 453 alternative_service);
489 recently_broken_alternative_services_.Put(alternative_service, 1);
490 }
491 } 454 }
492 455
493 bool HttpServerPropertiesImpl::IsAlternativeServiceBroken( 456 bool HttpServerPropertiesImpl::IsAlternativeServiceBroken(
494 const AlternativeService& alternative_service) const { 457 const AlternativeService& alternative_service) const {
495 // Empty host means use host of origin, callers are supposed to substitute. 458 return broken_alternative_services_.IsAlternativeServiceBroken(
496 DCHECK(!alternative_service.host.empty()); 459 alternative_service);
497 return base::ContainsKey(broken_alternative_services_, alternative_service);
498 } 460 }
499 461
500 bool HttpServerPropertiesImpl::WasAlternativeServiceRecentlyBroken( 462 bool HttpServerPropertiesImpl::WasAlternativeServiceRecentlyBroken(
501 const AlternativeService& alternative_service) { 463 const AlternativeService& alternative_service) {
502 if (alternative_service.protocol == kProtoUnknown) 464 return broken_alternative_services_.WasAlternativeServiceRecentlyBroken(
503 return false; 465 alternative_service);
504
505 return recently_broken_alternative_services_.Get(alternative_service) !=
506 recently_broken_alternative_services_.end();
507 } 466 }
508 467
509 void HttpServerPropertiesImpl::ConfirmAlternativeService( 468 void HttpServerPropertiesImpl::ConfirmAlternativeService(
510 const AlternativeService& alternative_service) { 469 const AlternativeService& alternative_service) {
511 if (alternative_service.protocol == kProtoUnknown) 470 broken_alternative_services_.ConfirmAlternativeService(alternative_service);
512 return;
513 broken_alternative_services_.erase(alternative_service);
514 auto it = recently_broken_alternative_services_.Get(alternative_service);
515 if (it != recently_broken_alternative_services_.end()) {
516 recently_broken_alternative_services_.Erase(it);
517 }
518 } 471 }
519 472
520 const AlternativeServiceMap& HttpServerPropertiesImpl::alternative_service_map() 473 const AlternativeServiceMap& HttpServerPropertiesImpl::alternative_service_map()
521 const { 474 const {
522 return alternative_service_map_; 475 return alternative_service_map_;
523 } 476 }
524 477
525 std::unique_ptr<base::Value> 478 std::unique_ptr<base::Value>
526 HttpServerPropertiesImpl::GetAlternativeServiceInfoAsValue() const { 479 HttpServerPropertiesImpl::GetAlternativeServiceInfoAsValue() const {
527 std::unique_ptr<base::ListValue> dict_list(new base::ListValue); 480 std::unique_ptr<base::ListValue> dict_list(new base::ListValue);
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
642 } 595 }
643 596
644 quic_server_info_map_.Swap(temp_map); 597 quic_server_info_map_.Swap(temp_map);
645 } 598 }
646 599
647 bool HttpServerPropertiesImpl::IsInitialized() const { 600 bool HttpServerPropertiesImpl::IsInitialized() const {
648 // No initialization is needed. 601 // No initialization is needed.
649 return true; 602 return true;
650 } 603 }
651 604
605 void HttpServerPropertiesImpl::OnExpireBrokenAlternativeService(
606 const AlternativeService& expired_alternative_service) {
607 // Remove every occurrence of |expired_alternative_service| from
608 // |alternative_service_map_|.
609 for (AlternativeServiceMap::iterator map_it =
610 alternative_service_map_.begin();
611 map_it != alternative_service_map_.end();) {
612 for (AlternativeServiceInfoVector::iterator it = map_it->second.begin();
613 it != map_it->second.end();) {
614 AlternativeService alternative_service(it->alternative_service);
615 // Empty hostname in map means hostname of key: substitute before
616 // comparing to |expired_alternative_service|.
617 if (alternative_service.host.empty()) {
618 alternative_service.host = map_it->first.host();
619 }
620 if (alternative_service == expired_alternative_service) {
621 it = map_it->second.erase(it);
622 continue;
623 }
624 ++it;
625 }
626 // If an origin has an empty list of alternative services, then remove it
627 // from both |canonical_host_to_origin_map_| and
628 // |alternative_service_map_|.
629 if (map_it->second.empty()) {
630 RemoveCanonicalHost(map_it->first);
631 map_it = alternative_service_map_.Erase(map_it);
632 continue;
633 }
634 ++map_it;
635 }
636 }
Ryan Hamilton 2017/05/25 03:03:50 nit: would you mind moving this back to where the
wangyix1 2017/05/26 01:14:25 Done.
637
652 AlternativeServiceMap::const_iterator 638 AlternativeServiceMap::const_iterator
653 HttpServerPropertiesImpl::GetAlternateProtocolIterator( 639 HttpServerPropertiesImpl::GetAlternateProtocolIterator(
654 const url::SchemeHostPort& server) { 640 const url::SchemeHostPort& server) {
655 AlternativeServiceMap::const_iterator it = 641 AlternativeServiceMap::const_iterator it =
656 alternative_service_map_.Get(server); 642 alternative_service_map_.Get(server);
657 if (it != alternative_service_map_.end()) 643 if (it != alternative_service_map_.end())
658 return it; 644 return it;
659 645
660 CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server); 646 CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server);
661 if (canonical == canonical_host_to_origin_map_.end()) { 647 if (canonical == canonical_host_to_origin_map_.end()) {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
701 687
702 void HttpServerPropertiesImpl::RemoveCanonicalHost( 688 void HttpServerPropertiesImpl::RemoveCanonicalHost(
703 const url::SchemeHostPort& server) { 689 const url::SchemeHostPort& server) {
704 CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server); 690 CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server);
705 if (canonical == canonical_host_to_origin_map_.end()) 691 if (canonical == canonical_host_to_origin_map_.end())
706 return; 692 return;
707 693
708 canonical_host_to_origin_map_.erase(canonical->first); 694 canonical_host_to_origin_map_.erase(canonical->first);
709 } 695 }
710 696
711 void HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings() {
712 base::TimeTicks now = base::TimeTicks::Now();
713 while (!broken_alternative_services_.empty()) {
714 BrokenAlternativeServices::iterator it =
715 broken_alternative_services_.begin();
716 if (now < it->second) {
717 break;
718 }
719
720 const AlternativeService expired_alternative_service = it->first;
721 broken_alternative_services_.erase(it);
722
723 // Remove every occurrence of |expired_alternative_service| from
724 // |alternative_service_map_|.
725 for (AlternativeServiceMap::iterator map_it =
726 alternative_service_map_.begin();
727 map_it != alternative_service_map_.end();) {
728 for (AlternativeServiceInfoVector::iterator it = map_it->second.begin();
729 it != map_it->second.end();) {
730 AlternativeService alternative_service(it->alternative_service);
731 // Empty hostname in map means hostname of key: substitute before
732 // comparing to |expired_alternative_service|.
733 if (alternative_service.host.empty()) {
734 alternative_service.host = map_it->first.host();
735 }
736 if (alternative_service == expired_alternative_service) {
737 it = map_it->second.erase(it);
738 continue;
739 }
740 ++it;
741 }
742 // If an origin has an empty list of alternative services, then remove it
743 // from both |canonical_host_to_origin_map_| and
744 // |alternative_service_map_|.
745 if (map_it->second.empty()) {
746 RemoveCanonicalHost(map_it->first);
747 map_it = alternative_service_map_.Erase(map_it);
748 continue;
749 }
750 ++map_it;
751 }
752 }
753 ScheduleBrokenAlternateProtocolMappingsExpiration();
754 }
755
756 void
757 HttpServerPropertiesImpl::ScheduleBrokenAlternateProtocolMappingsExpiration() {
758 if (broken_alternative_services_.empty()) {
759 return;
760 }
761 base::TimeTicks now = base::TimeTicks::Now();
762 base::TimeTicks when = broken_alternative_services_.front().second;
763 base::TimeDelta delay = when > now ? when - now : base::TimeDelta();
764 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
765 FROM_HERE,
766 base::Bind(
767 &HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings,
768 weak_ptr_factory_.GetWeakPtr()),
769 delay);
770 }
771
772 } // namespace net 697 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698