alternative_service.cc 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  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
  3. // found in the LICENSE file.
  4. #include "net/http/alternative_service.h"
  5. #include "base/check_op.h"
  6. #include "base/metrics/histogram_macros.h"
  7. #include "base/metrics/histogram_macros_local.h"
  8. #include "base/notreached.h"
  9. #include "base/strings/stringprintf.h"
  10. #include "net/base/port_util.h"
  11. #include "net/third_party/quiche/src/quiche/quic/core/http/spdy_utils.h"
  12. namespace net {
  13. void HistogramAlternateProtocolUsage(AlternateProtocolUsage usage,
  14. bool is_google_host) {
  15. UMA_HISTOGRAM_ENUMERATION("Net.AlternateProtocolUsage", usage,
  16. ALTERNATE_PROTOCOL_USAGE_MAX);
  17. if (is_google_host) {
  18. UMA_HISTOGRAM_ENUMERATION("Net.AlternateProtocolUsageGoogle", usage,
  19. ALTERNATE_PROTOCOL_USAGE_MAX);
  20. }
  21. }
  22. void HistogramBrokenAlternateProtocolLocation(
  23. BrokenAlternateProtocolLocation location) {
  24. UMA_HISTOGRAM_ENUMERATION("Net.AlternateProtocolBrokenLocation", location,
  25. BROKEN_ALTERNATE_PROTOCOL_LOCATION_MAX);
  26. }
  27. bool IsAlternateProtocolValid(NextProto protocol) {
  28. switch (protocol) {
  29. case kProtoUnknown:
  30. return false;
  31. case kProtoHTTP11:
  32. return false;
  33. case kProtoHTTP2:
  34. return true;
  35. case kProtoQUIC:
  36. return true;
  37. }
  38. NOTREACHED();
  39. return false;
  40. }
  41. bool IsProtocolEnabled(NextProto protocol,
  42. bool is_http2_enabled,
  43. bool is_quic_enabled) {
  44. switch (protocol) {
  45. case kProtoUnknown:
  46. NOTREACHED();
  47. return false;
  48. case kProtoHTTP11:
  49. return true;
  50. case kProtoHTTP2:
  51. return is_http2_enabled;
  52. case kProtoQUIC:
  53. return is_quic_enabled;
  54. }
  55. NOTREACHED();
  56. return false;
  57. }
  58. // static
  59. AlternativeServiceInfo
  60. AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo(
  61. const AlternativeService& alternative_service,
  62. base::Time expiration) {
  63. DCHECK_EQ(alternative_service.protocol, kProtoHTTP2);
  64. return AlternativeServiceInfo(alternative_service, expiration,
  65. quic::ParsedQuicVersionVector());
  66. }
  67. // static
  68. AlternativeServiceInfo AlternativeServiceInfo::CreateQuicAlternativeServiceInfo(
  69. const AlternativeService& alternative_service,
  70. base::Time expiration,
  71. const quic::ParsedQuicVersionVector& advertised_versions) {
  72. DCHECK_EQ(alternative_service.protocol, kProtoQUIC);
  73. return AlternativeServiceInfo(alternative_service, expiration,
  74. advertised_versions);
  75. }
  76. AlternativeServiceInfo::AlternativeServiceInfo() : alternative_service_() {}
  77. AlternativeServiceInfo::~AlternativeServiceInfo() = default;
  78. AlternativeServiceInfo::AlternativeServiceInfo(
  79. const AlternativeService& alternative_service,
  80. base::Time expiration,
  81. const quic::ParsedQuicVersionVector& advertised_versions)
  82. : alternative_service_(alternative_service), expiration_(expiration) {
  83. if (alternative_service_.protocol == kProtoQUIC) {
  84. advertised_versions_ = advertised_versions;
  85. }
  86. }
  87. AlternativeServiceInfo::AlternativeServiceInfo(
  88. const AlternativeServiceInfo& alternative_service_info) = default;
  89. AlternativeServiceInfo& AlternativeServiceInfo::operator=(
  90. const AlternativeServiceInfo& alternative_service_info) = default;
  91. std::string AlternativeService::ToString() const {
  92. return base::StringPrintf("%s %s:%d", NextProtoToString(protocol),
  93. host.c_str(), port);
  94. }
  95. std::string AlternativeServiceInfo::ToString() const {
  96. base::Time::Exploded exploded;
  97. expiration_.LocalExplode(&exploded);
  98. return base::StringPrintf(
  99. "%s, expires %04d-%02d-%02d %02d:%02d:%02d",
  100. alternative_service_.ToString().c_str(), exploded.year, exploded.month,
  101. exploded.day_of_month, exploded.hour, exploded.minute, exploded.second);
  102. }
  103. // static
  104. bool AlternativeServiceInfo::TransportVersionLessThan(
  105. const quic::ParsedQuicVersion& lhs,
  106. const quic::ParsedQuicVersion& rhs) {
  107. return lhs.transport_version < rhs.transport_version;
  108. }
  109. std::ostream& operator<<(std::ostream& os,
  110. const AlternativeService& alternative_service) {
  111. os << alternative_service.ToString();
  112. return os;
  113. }
  114. AlternativeServiceInfoVector ProcessAlternativeServices(
  115. const spdy::SpdyAltSvcWireFormat::AlternativeServiceVector&
  116. alternative_service_vector,
  117. bool is_http2_enabled,
  118. bool is_quic_enabled,
  119. const quic::ParsedQuicVersionVector& supported_quic_versions) {
  120. // Convert spdy::SpdyAltSvcWireFormat::AlternativeService entries
  121. // to net::AlternativeServiceInfo.
  122. AlternativeServiceInfoVector alternative_service_info_vector;
  123. for (const spdy::SpdyAltSvcWireFormat::AlternativeService&
  124. alternative_service_entry : alternative_service_vector) {
  125. if (!IsPortValid(alternative_service_entry.port))
  126. continue;
  127. NextProto protocol =
  128. NextProtoFromString(alternative_service_entry.protocol_id);
  129. quic::ParsedQuicVersionVector advertised_versions;
  130. if (protocol == kProtoQUIC) {
  131. continue; // Ignore legacy QUIC alt-svc advertisements.
  132. } else if (!IsAlternateProtocolValid(protocol)) {
  133. quic::ParsedQuicVersion version =
  134. quic::SpdyUtils::ExtractQuicVersionFromAltSvcEntry(
  135. alternative_service_entry, supported_quic_versions);
  136. if (version == quic::ParsedQuicVersion::Unsupported()) {
  137. continue;
  138. }
  139. protocol = kProtoQUIC;
  140. advertised_versions = {version};
  141. }
  142. if (!IsAlternateProtocolValid(protocol) ||
  143. !IsProtocolEnabled(protocol, is_http2_enabled, is_quic_enabled)) {
  144. continue;
  145. }
  146. AlternativeService alternative_service(protocol,
  147. alternative_service_entry.host,
  148. alternative_service_entry.port);
  149. base::Time expiration =
  150. base::Time::Now() +
  151. base::Seconds(alternative_service_entry.max_age_seconds);
  152. AlternativeServiceInfo alternative_service_info;
  153. if (protocol == kProtoQUIC) {
  154. alternative_service_info =
  155. AlternativeServiceInfo::CreateQuicAlternativeServiceInfo(
  156. alternative_service, expiration, advertised_versions);
  157. } else {
  158. alternative_service_info =
  159. AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo(
  160. alternative_service, expiration);
  161. }
  162. alternative_service_info_vector.push_back(alternative_service_info);
  163. }
  164. return alternative_service_info_vector;
  165. }
  166. } // namespace net