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

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: Added checks for contents of expired_alt_svcs_ in BrokenAlternativeServicesTest 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 391 matching lines...) Expand 10 before | Expand all | Expand 10 after
443 url::SchemeHostPort canonical_server(kCanonicalScheme, *canonical_suffix, 435 url::SchemeHostPort canonical_server(kCanonicalScheme, *canonical_suffix,
444 origin.port()); 436 origin.port());
445 canonical_host_to_origin_map_[canonical_server] = origin; 437 canonical_host_to_origin_map_[canonical_server] = origin;
446 } 438 }
447 } 439 }
448 return changed; 440 return changed;
449 } 441 }
450 442
451 void HttpServerPropertiesImpl::MarkAlternativeServiceBroken( 443 void HttpServerPropertiesImpl::MarkAlternativeServiceBroken(
452 const AlternativeService& alternative_service) { 444 const AlternativeService& alternative_service) {
453 // Empty host means use host of origin, callers are supposed to substitute. 445 broken_alternative_services_.MarkAlternativeServiceBroken(
454 DCHECK(!alternative_service.host.empty()); 446 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 } 447 }
484 448
485 void HttpServerPropertiesImpl::MarkAlternativeServiceRecentlyBroken( 449 void HttpServerPropertiesImpl::MarkAlternativeServiceRecentlyBroken(
486 const AlternativeService& alternative_service) { 450 const AlternativeService& alternative_service) {
487 if (recently_broken_alternative_services_.Get(alternative_service) == 451 broken_alternative_services_.MarkAlternativeServiceRecentlyBroken(
488 recently_broken_alternative_services_.end()) { 452 alternative_service);
489 recently_broken_alternative_services_.Put(alternative_service, 1);
490 }
491 } 453 }
492 454
493 bool HttpServerPropertiesImpl::IsAlternativeServiceBroken( 455 bool HttpServerPropertiesImpl::IsAlternativeServiceBroken(
494 const AlternativeService& alternative_service) const { 456 const AlternativeService& alternative_service) const {
495 // Empty host means use host of origin, callers are supposed to substitute. 457 return broken_alternative_services_.IsAlternativeServiceBroken(
496 DCHECK(!alternative_service.host.empty()); 458 alternative_service);
497 return base::ContainsKey(broken_alternative_services_, alternative_service);
498 } 459 }
499 460
500 bool HttpServerPropertiesImpl::WasAlternativeServiceRecentlyBroken( 461 bool HttpServerPropertiesImpl::WasAlternativeServiceRecentlyBroken(
501 const AlternativeService& alternative_service) { 462 const AlternativeService& alternative_service) {
502 if (alternative_service.protocol == kProtoUnknown) 463 return broken_alternative_services_.WasAlternativeServiceRecentlyBroken(
503 return false; 464 alternative_service);
504
505 return recently_broken_alternative_services_.Get(alternative_service) !=
506 recently_broken_alternative_services_.end();
507 } 465 }
508 466
509 void HttpServerPropertiesImpl::ConfirmAlternativeService( 467 void HttpServerPropertiesImpl::ConfirmAlternativeService(
510 const AlternativeService& alternative_service) { 468 const AlternativeService& alternative_service) {
511 if (alternative_service.protocol == kProtoUnknown) 469 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 } 470 }
519 471
520 const AlternativeServiceMap& HttpServerPropertiesImpl::alternative_service_map() 472 const AlternativeServiceMap& HttpServerPropertiesImpl::alternative_service_map()
521 const { 473 const {
522 return alternative_service_map_; 474 return alternative_service_map_;
523 } 475 }
524 476
525 std::unique_ptr<base::Value> 477 std::unique_ptr<base::Value>
526 HttpServerPropertiesImpl::GetAlternativeServiceInfoAsValue() const { 478 HttpServerPropertiesImpl::GetAlternativeServiceInfoAsValue() const {
527 std::unique_ptr<base::ListValue> dict_list(new base::ListValue); 479 std::unique_ptr<base::ListValue> dict_list(new base::ListValue);
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
701 653
702 void HttpServerPropertiesImpl::RemoveCanonicalHost( 654 void HttpServerPropertiesImpl::RemoveCanonicalHost(
703 const url::SchemeHostPort& server) { 655 const url::SchemeHostPort& server) {
704 CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server); 656 CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server);
705 if (canonical == canonical_host_to_origin_map_.end()) 657 if (canonical == canonical_host_to_origin_map_.end())
706 return; 658 return;
707 659
708 canonical_host_to_origin_map_.erase(canonical->first); 660 canonical_host_to_origin_map_.erase(canonical->first);
709 } 661 }
710 662
711 void HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings() { 663 void HttpServerPropertiesImpl::OnExpireBrokenAlternativeService(
712 base::TimeTicks now = base::TimeTicks::Now(); 664 const AlternativeService& expired_alternative_service) {
713 while (!broken_alternative_services_.empty()) { 665 // Remove every occurrence of |expired_alternative_service| from
714 BrokenAlternativeServices::iterator it = 666 // |alternative_service_map_|.
715 broken_alternative_services_.begin(); 667 for (AlternativeServiceMap::iterator map_it =
716 if (now < it->second) { 668 alternative_service_map_.begin();
717 break; 669 map_it != alternative_service_map_.end();) {
718 } 670 for (AlternativeServiceInfoVector::iterator it = map_it->second.begin();
719 671 it != map_it->second.end();) {
720 const AlternativeService expired_alternative_service = it->first; 672 AlternativeService alternative_service(it->alternative_service);
721 broken_alternative_services_.erase(it); 673 // Empty hostname in map means hostname of key: substitute before
722 674 // comparing to |expired_alternative_service|.
723 // Remove every occurrence of |expired_alternative_service| from 675 if (alternative_service.host.empty()) {
724 // |alternative_service_map_|. 676 alternative_service.host = map_it->first.host();
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 } 677 }
742 // If an origin has an empty list of alternative services, then remove it 678 if (alternative_service == expired_alternative_service) {
743 // from both |canonical_host_to_origin_map_| and 679 it = map_it->second.erase(it);
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; 680 continue;
749 } 681 }
750 ++map_it; 682 ++it;
751 } 683 }
684 // If an origin has an empty list of alternative services, then remove it
685 // from both |canonical_host_to_origin_map_| and
686 // |alternative_service_map_|.
687 if (map_it->second.empty()) {
688 RemoveCanonicalHost(map_it->first);
689 map_it = alternative_service_map_.Erase(map_it);
690 continue;
691 }
692 ++map_it;
752 } 693 }
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 } 694 }
771 695
772 } // namespace net 696 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698