diff --git a/cobalt/h5vcc/h5vcc_settings.cc b/cobalt/h5vcc/h5vcc_settings.cc index 3c6062001737..020eec444a6a 100644 --- a/cobalt/h5vcc/h5vcc_settings.cc +++ b/cobalt/h5vcc/h5vcc_settings.cc @@ -118,6 +118,16 @@ bool H5vccSettings::Set(const std::string& name, SetValueType value) const { } } + if (name.compare(network::kProtocolFilterKey) == 0 && + value.IsType() && + value.AsType().size() < 8192) { + std::string rawJson = value.AsType(); + persistent_settings_->Set(network::kProtocolFilterKey, + base::Value(rawJson)); + network_module_->SetProtocolFilterFromPersistentSettings(); + return true; + } + if (name.compare("cpu_usage_tracker_intervals") == 0 && value.IsType() && value.AsType().size() < 512) { absl::optional config = @@ -193,6 +203,13 @@ std::string H5vccSettings::GetPersistentSettingAsString( absl::optional json = base::WriteJson(value); return json.value_or(std::string()); } + + if (key.compare(network::kProtocolFilterKey) == 0) { + base::Value value; + persistent_settings_->Get(network::kProtocolFilterKey, &value); + if (!value.is_string()) return std::string(); + return value.GetString(); + } return std::string(); } diff --git a/cobalt/network/network_module.cc b/cobalt/network/network_module.cc index 8b2ec4558009..781f30b69b77 100644 --- a/cobalt/network/network_module.cc +++ b/cobalt/network/network_module.cc @@ -18,6 +18,7 @@ #include "base/bind.h" #include "base/command_line.h" +#include "base/json/json_reader.h" #include "base/logging.h" #include "base/path_service.h" #include "base/strings/string_number_conversions.h" @@ -160,6 +161,68 @@ void NetworkModule::SetEnableHttp3FromPersistentSettings() { } } +void NetworkModule::SetProtocolFilterFromPersistentSettings() { + if (!options_.persistent_settings) return; + + base::Value value; + options_.persistent_settings->Get(kProtocolFilterKey, &value); + if (!value.is_string()) return; + + if (value.GetString().empty()) { + task_runner()->PostTask(FROM_HERE, + base::Bind( + [](URLRequestContext* url_request_context) { + url_request_context->url_request_context() + ->quic_context() + ->params() + ->protocol_filter = absl::nullopt; + }, + base::Unretained(url_request_context_.get()))); + return; + } + + absl::optional config = + base::JSONReader::Read(value.GetString()); + if (!config.has_value() || !config->is_list()) return; + + net::ProtocolFilter protocol_filter; + for (auto& filter_value : config->GetList()) { + if (!filter_value.is_dict()) return; + const auto& dict = filter_value.GetDict(); + const base::Value* origin = dict.Find("origin"); + const base::Value* alt_svc = dict.Find("altSvc"); + if (!origin || !alt_svc) continue; + if (!origin->is_string() || !alt_svc->is_string()) continue; + net::ProtocolFilterEntry entry; + entry.origin = origin->GetString(); + if (base::StartsWith(alt_svc->GetString(), "h3")) { + entry.alt_svc.protocol = net::kProtoQUIC; + if (base::StartsWith(alt_svc->GetString(), "h3-Q046")) { + entry.alt_svc.quic_version = + net::ProtocolFilterEntry::QuicVersion::Q046; + } else { + entry.alt_svc.quic_version = + net::ProtocolFilterEntry::QuicVersion::RFC_V1; + } + } else { + entry.alt_svc.protocol = net::kProtoUnknown; + } + protocol_filter.push_back(std::move(entry)); + } + + task_runner()->PostTask( + FROM_HERE, base::Bind( + [](URLRequestContext* url_request_context, + net::ProtocolFilter protocol_filter) { + url_request_context->url_request_context() + ->quic_context() + ->params() + ->protocol_filter = std::move(protocol_filter); + }, + base::Unretained(url_request_context_.get()), + std::move(protocol_filter))); +} + void NetworkModule::EnsureStorageManagerStarted() { DCHECK(storage_manager_); storage_manager_->EnsureStarted(); @@ -249,6 +312,7 @@ void NetworkModule::Initialize(const std::string& user_agent_string, SetEnableQuicFromPersistentSettings(); SetEnableHttp2FromPersistentSettings(); SetEnableHttp3FromPersistentSettings(); + SetProtocolFilterFromPersistentSettings(); } void NetworkModule::OnCreate( diff --git a/cobalt/network/network_module.h b/cobalt/network/network_module.h index e0151d690139..9f25673b20a1 100644 --- a/cobalt/network/network_module.h +++ b/cobalt/network/network_module.h @@ -61,6 +61,7 @@ constexpr int32_t kEnabledClientHintHeaders = (kCallTypeLoader | kCallTypeXHR); const char kQuicEnabledPersistentSettingsKey[] = "QUICEnabled"; const char kHttp2EnabledPersistentSettingsKey[] = "HTTP2Enabled"; const char kHttp3EnabledPersistentSettingsKey[] = "HTTP3Enabled"; +const char kProtocolFilterKey[] = "protocolfilter"; class NetworkSystem; // NetworkModule wraps various networking-related components such as @@ -133,6 +134,7 @@ class NetworkModule : public base::CurrentThread::DestructionObserver { void SetEnableQuicFromPersistentSettings(); void SetEnableHttp2FromPersistentSettings(); void SetEnableHttp3FromPersistentSettings(); + void SetProtocolFilterFromPersistentSettings(); // Adds the Client Hint Headers to the provided URLFetcher if enabled. void AddClientHintHeaders(net::URLFetcher& url_fetcher, diff --git a/net/http/http_stream_factory_job_controller.cc b/net/http/http_stream_factory_job_controller.cc index c2d1194a6309..7e8427aa64ca 100644 --- a/net/http/http_stream_factory_job_controller.cc +++ b/net/http/http_stream_factory_job_controller.cc @@ -11,6 +11,9 @@ #include "base/functional/bind.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" +#if defined(STARBOARD) +#include "base/strings/pattern.h" +#endif // defined(STARBOARD) #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/task/single_thread_task_runner.h" @@ -1203,6 +1206,35 @@ HttpStreamFactory::JobController::GetAlternativeServiceInfoInternal( url::SchemeHostPort(original_url), request_info.network_anonymization_key); #if defined(STARBOARD) + if (session_->context().quic_context->params()->protocol_filter.has_value()) { + url::SchemeHostPort origin(original_url); + const ProtocolFilter& protocol_filter = *(session_->context().quic_context->params()->protocol_filter); + for (const ProtocolFilterEntry& entry : protocol_filter) { + if (!base::MatchPattern(origin.host(), entry.origin)) continue; + + if (entry.alt_svc.protocol != kProtoQUIC) { + return AlternativeServiceInfo(); + } + + quic::ParsedQuicVersionVector versions; + if (entry.alt_svc.quic_version == ProtocolFilterEntry::QuicVersion::Q046) { + versions.push_back(quic::ParsedQuicVersion::Q046()); + } else { + versions.push_back(quic::ParsedQuicVersion::RFCv1()); + } + + // If version not supported, skip. + if (SelectQuicVersion(versions) == quic::ParsedQuicVersion::Unsupported()) { + continue; + } + + return AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( + AlternativeService(net::kProtoQUIC, origin.host(), + origin.port()), + base::Time::Max(), versions); + } + } + // This block of code suggests QUIC connection for initial requests to a // new host. This method is proven to provide performance benefit while still // enabling Cobalt network module to fall back on TCP connection when QUIC @@ -1213,7 +1245,7 @@ HttpStreamFactory::JobController::GetAlternativeServiceInfoInternal( // Leave the port restriction only in production builds to simplify testing #if defined(COBALT_BUILD_TYPE_GOLD) if (origin.port() == kDefaultQUICServerPort) { -#endif +#endif // defined(COBALT_BUILD_TYPE_GOLD) quic::ParsedQuicVersionVector versions = quic::AllSupportedVersions(); return AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( AlternativeService(net::kProtoQUIC, origin.host(), @@ -1221,13 +1253,13 @@ HttpStreamFactory::JobController::GetAlternativeServiceInfoInternal( base::Time::Max(), versions); #if defined(COBALT_BUILD_TYPE_GOLD) } -#endif +#endif // defined(COBALT_BUILD_TYPE_GOLD) return AlternativeServiceInfo(); } #else if (alternative_service_info_vector.empty()) return AlternativeServiceInfo(); -#endif +#endif // defined(STARBOARD) bool quic_advertised = false; bool quic_all_broken = true; diff --git a/net/quic/quic_context.h b/net/quic/quic_context.h index a92da726fddd..6faf2508f564 100644 --- a/net/quic/quic_context.h +++ b/net/quic/quic_context.h @@ -12,10 +12,32 @@ #include "base/time/time.h" #include "net/base/features.h" #include "net/base/host_port_pair.h" +#if defined(STARBOARD) +#include "net/socket/next_proto.h" +#endif // defined(STARBOARD) #include "net/third_party/quiche/src/quiche/quic/core/quic_connection.h" namespace net { +#if defined(STARBOARD) +struct ProtocolFilterEntry { + +enum QuicVersion { + Q046, + RFC_V1 +}; + +struct AltSvc { + NextProto protocol; + QuicVersion quic_version; +}; + + std::string origin; + AltSvc alt_svc; +}; +using ProtocolFilter = std::vector; +#endif // defined(STARBOARD) + // Default QUIC supported versions used in absence of any external // configuration. inline NET_EXPORT_PRIVATE quic::ParsedQuicVersionVector @@ -201,6 +223,10 @@ struct NET_EXPORT QuicParams { // If true, delay main job even the request can be sent immediately on an // available SPDY session. bool delay_main_job_with_available_spdy_session = false; +#if defined(STARBOARD) + // Override alternative service for an origin. + absl::optional protocol_filter; +#endif // defined(STARBOARD) }; // QuicContext contains QUIC-related variables that are shared across all of the