Skip to content

Commit

Permalink
Support IETF QUIC in serialized HTTP server properties
Browse files Browse the repository at this point in the history
Servers can indicate QUIC support by using the Alt-Svc header.
When they do, they use ALPN to communicate which version of QUIC
they support. However, before this CL, we only supported versions
Q043 and Q046 when saving those properties to disk. This was not
an issue when we only supported one version, as we would pick
that one when no server versions were saved. However, we now
regularly support both Q050 and h3-29, so this CL ensures we
correctly remember what version the server advertised. Since
the JSON format is not backwards compatible, this CL changes
the dictionary key used for these versions. That will ensure
that alternating between old and new versions of the code does
not cause any parse failures.

R=renjietang@chromium.org

Change-Id: I432f4e9510252c5cc6cbbcb324fdd3ebf75ce662
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2704643
Reviewed-by: Renjie Tang <renjietang@chromium.org>
Commit-Queue: Renjie Tang <renjietang@chromium.org>
Commit-Queue: David Schinazi <dschinazi@chromium.org>
Auto-Submit: David Schinazi <dschinazi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#855385}
  • Loading branch information
David Schinazi authored and Chromium LUCI CQ committed Feb 18, 2021
1 parent 1f65245 commit ef381b5
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 27 deletions.
27 changes: 11 additions & 16 deletions net/http/http_server_properties_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const char kProtocolKey[] = "protocol_str";
const char kHostKey[] = "host";
const char kPortKey[] = "port";
const char kExpirationKey[] = "expiration";
const char kAdvertisedVersionsKey[] = "advertised_versions";
const char kAdvertisedAlpnsKey[] = "advertised_alpns";
const char kNetworkStatsKey[] = "network_stats";
const char kSrttKey[] = "srtt";
const char kBrokenAlternativeServicesKey[] = "broken_alternative_services";
Expand Down Expand Up @@ -532,30 +532,25 @@ bool HttpServerPropertiesManager::ParseAlternativeServiceInfoDictOfServer(
}

// Advertised versions list is optional.
// It is only used for versions that use the legacy Google AltSvc format.
if (dict.FindKey(kAdvertisedVersionsKey)) {
const base::Value* versions_list = dict.FindListKey(kAdvertisedVersionsKey);
if (dict.FindKey(kAdvertisedAlpnsKey)) {
const base::Value* versions_list = dict.FindListKey(kAdvertisedAlpnsKey);
if (!versions_list) {
DVLOG(1) << "Malformed alternative service advertised versions list for "
<< "server: " << server_str;
return false;
}
quic::ParsedQuicVersionVector advertised_versions;
for (const auto& value : versions_list->GetList()) {
int version;
if (!value.GetAsInteger(&version)) {
std::string version_string;
if (!value.GetAsString(&version_string)) {
DVLOG(1) << "Malformed alternative service version for server: "
<< server_str;
return false;
}
for (const quic::ParsedQuicVersion& supported :
quic::AllSupportedVersions()) {
if (supported.UsesQuicCrypto() &&
supported.SupportsGoogleAltSvcFormat() &&
static_cast<int>(supported.transport_version) == version) {
advertised_versions.push_back(supported);
break;
}
quic::ParsedQuicVersion version =
quic::ParseQuicVersionString(version_string);
if (version != quic::ParsedQuicVersion::Unsupported()) {
advertised_versions.push_back(version);
}
}
alternative_service_info->set_advertised_versions(advertised_versions);
Expand Down Expand Up @@ -806,9 +801,9 @@ void HttpServerPropertiesManager::SaveAlternativeServiceToServerPrefs(
alternative_service_info.expiration().ToInternalValue()));
base::Value advertised_versions_list(base::Value::Type::LIST);
for (const auto& version : alternative_service_info.advertised_versions()) {
advertised_versions_list.Append(version.transport_version);
advertised_versions_list.Append(quic::AlpnForVersion(version));
}
alternative_service_dict.SetKey(kAdvertisedVersionsKey,
alternative_service_dict.SetKey(kAdvertisedAlpnsKey,
std::move(advertised_versions_list));
alternative_service_list.Append(std::move(alternative_service_dict));
}
Expand Down
2 changes: 2 additions & 0 deletions net/http/http_server_properties_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ class NET_EXPORT_PRIVATE HttpServerPropertiesManager {
DoNotLoadAltSvcForInsecureOrigins);
FRIEND_TEST_ALL_PREFIXES(HttpServerPropertiesManagerTest,
DoNotLoadExpiredAlternativeService);
FRIEND_TEST_ALL_PREFIXES(HttpServerPropertiesManagerTest,
AdvertisedVersionsRoundTrip);

void AddServerData(const base::Value& server_dict,
HttpServerProperties::ServerInfoMap* server_info_map,
Expand Down
84 changes: 73 additions & 11 deletions net/http/http_server_properties_manager_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1216,14 +1216,14 @@ TEST_F(HttpServerPropertiesManagerTest, UpdatePrefsWithCache) {
"\"server_id\":\"https://mail.google.com:80\","
"\"server_info\":\"quic_server_info1\"}],"
"\"servers\":["
"{\"alternative_service\":[{\"advertised_versions\":[],"
"{\"alternative_service\":[{\"advertised_alpns\":[],"
"\"expiration\":\"13756212000000000\",\"port\":443,"
"\"protocol_str\":\"h2\"},"
"{\"advertised_versions\":[],\"expiration\":\"13758804000000000\","
"{\"advertised_alpns\":[],\"expiration\":\"13758804000000000\","
"\"host\":\"www.google.com\",\"port\":1234,\"protocol_str\":\"h2\"}],"
"\"isolation\":[],"
"\"server\":\"https://www.google.com:80\"},"
"{\"alternative_service\":[{\"advertised_versions\":[],"
"{\"alternative_service\":[{\"advertised_alpns\":[],"
"\"expiration\":\"9223372036854775807\",\"host\":\"foo.google.com\","
"\"port\":444,\"protocol_str\":\"h2\"}],"
"\"isolation\":[],"
Expand Down Expand Up @@ -1520,14 +1520,16 @@ TEST_F(HttpServerPropertiesManagerTest, PersistAdvertisedVersionsToPref) {
"\"server_info\":\"quic_server_info1\"}],"
"\"servers\":["
"{\"alternative_service\":[{"
"\"advertised_versions\":[46,43],\"expiration\":\"13756212000000000\","
"\"port\":443,\"protocol_str\":\"quic\"},{\"advertised_versions\":[],"
"\"advertised_alpns\":[\"h3-Q046\",\"h3-Q043\"],\"expiration\":"
"\"13756212000000000\","
"\"port\":443,\"protocol_str\":\"quic\"},{\"advertised_alpns\":[],"
"\"expiration\":\"13758804000000000\",\"host\":\"www.google.com\","
"\"port\":1234,\"protocol_str\":\"h2\"}],"
"\"isolation\":[],"
"\"server\":\"https://www.google.com:80\"},"
"{\"alternative_service\":[{"
"\"advertised_versions\":[50,73],\"expiration\":\"9223372036854775807\","
"\"advertised_alpns\":[\"h3-Q050\",\"h3-29\"],\"expiration\":"
"\"9223372036854775807\","
"\"host\":\"foo.google.com\",\"port\":444,\"protocol_str\":\"quic\"}],"
"\"isolation\":[],"
"\"network_stats\":{\"srtt\":42},"
Expand All @@ -1553,7 +1555,7 @@ TEST_F(HttpServerPropertiesManagerTest, ReadAdvertisedVersionsFromPref) {
"\"expiration\":\"9223372036854775807\","
// Add 33 which we know is not supported, as regression test for
// https://crbug.com/1061509
"\"advertised_versions\":[33,46,43]}]}");
"\"advertised_alpns\":[\"h3-Q033\",\"h3-Q046\",\"h3-Q043\"]}]}");
ASSERT_TRUE(server_dict);
ASSERT_TRUE(server_dict->is_dict());

Expand Down Expand Up @@ -1588,7 +1590,7 @@ TEST_F(HttpServerPropertiesManagerTest, ReadAdvertisedVersionsFromPref) {
// Verify advertised versions.
const quic::ParsedQuicVersionVector loaded_advertised_versions =
alternative_service_info_vector[1].advertised_versions();
EXPECT_EQ(2u, loaded_advertised_versions.size());
ASSERT_EQ(2u, loaded_advertised_versions.size());
EXPECT_EQ(quic::ParsedQuicVersion::Q043(), loaded_advertised_versions[0]);
EXPECT_EQ(quic::ParsedQuicVersion::Q046(), loaded_advertised_versions[1]);

Expand Down Expand Up @@ -1638,7 +1640,7 @@ TEST_F(HttpServerPropertiesManagerTest,
"\"server_id\":\"https://mail.google.com:80\","
"\"server_info\":\"quic_server_info1\"}],"
"\"servers\":["
"{\"alternative_service\":[{\"advertised_versions\":[50,73],"
"{\"alternative_service\":[{\"advertised_alpns\":[\"h3-Q050\",\"h3-29\"],"
"\"expiration\":\"13756212000000000\",\"port\":443,"
"\"protocol_str\":\"quic\"}],"
"\"isolation\":[],"
Expand Down Expand Up @@ -1678,7 +1680,8 @@ TEST_F(HttpServerPropertiesManagerTest,
"\"server_id\":\"https://mail.google.com:80\","
"\"server_info\":\"quic_server_info1\"}],"
"\"servers\":["
"{\"alternative_service\":[{\"advertised_versions\":[46,43],"
"{\"alternative_service\":"
"[{\"advertised_alpns\":[\"h3-Q046\",\"h3-Q043\"],"
"\"expiration\":\"13756212000000000\",\"port\":443,"
"\"protocol_str\":\"quic\"}],"
"\"isolation\":[],"
Expand Down Expand Up @@ -1713,7 +1716,8 @@ TEST_F(HttpServerPropertiesManagerTest,
"\"server_id\":\"https://mail.google.com:80\","
"\"server_info\":\"quic_server_info1\"}],"
"\"servers\":["
"{\"alternative_service\":[{\"advertised_versions\":[43,46],"
"{\"alternative_service\":"
"[{\"advertised_alpns\":[\"h3-Q043\",\"h3-Q046\"],"
"\"expiration\":\"13756212000000000\",\"port\":443,"
"\"protocol_str\":\"quic\"}],"
"\"isolation\":[],"
Expand Down Expand Up @@ -2998,4 +3002,62 @@ TEST_F(HttpServerPropertiesManagerTest,
preferences_json);
}

TEST_F(HttpServerPropertiesManagerTest, AdvertisedVersionsRoundTrip) {
for (const quic::ParsedQuicVersion& version : quic::AllSupportedVersions()) {
// Reset test infrastructure.
TearDown();
SetUp();
InitializePrefs();
// Create alternate version information.
const url::SchemeHostPort server("https", "quic.example.org", 443);
AlternativeServiceInfoVector alternative_service_info_vector_in;
AlternativeService quic_alternative_service(kProtoQUIC, "", 443);
base::Time expiration;
ASSERT_TRUE(base::Time::FromUTCString("2036-12-01 10:00:00", &expiration));
quic::ParsedQuicVersionVector advertised_versions = {version};
alternative_service_info_vector_in.push_back(
AlternativeServiceInfo::CreateQuicAlternativeServiceInfo(
quic_alternative_service, expiration, advertised_versions));
http_server_props_->SetAlternativeServices(
server, NetworkIsolationKey(), alternative_service_info_vector_in);
// Save to JSON.
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_NE(0u, GetPendingMainThreadTaskCount());
FastForwardUntilNoTasksRemain();
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
const base::Value* http_server_properties =
pref_delegate_->GetServerProperties();
std::string preferences_json;
EXPECT_TRUE(
base::JSONWriter::Write(*http_server_properties, &preferences_json));
// Reset test infrastructure.
TearDown();
SetUp();
InitializePrefs();
// Read from JSON.
std::unique_ptr<base::Value> preferences_dict =
base::JSONReader::ReadDeprecated(preferences_json);
ASSERT_TRUE(preferences_dict);
ASSERT_TRUE(preferences_dict->is_dict());
const base::Value* servers_list = preferences_dict->FindListKey("servers");
ASSERT_TRUE(servers_list);
ASSERT_TRUE(servers_list->is_list());
ASSERT_EQ(servers_list->GetList().size(), 1u);
const base::Value& server_dict = servers_list->GetList()[0];
HttpServerProperties::ServerInfo server_info;
EXPECT_TRUE(HttpServerPropertiesManager::ParseAlternativeServiceInfo(
server, server_dict, &server_info));
ASSERT_TRUE(server_info.alternative_services.has_value());
AlternativeServiceInfoVector alternative_service_info_vector_out =
server_info.alternative_services.value();
ASSERT_EQ(1u, alternative_service_info_vector_out.size());
EXPECT_EQ(
kProtoQUIC,
alternative_service_info_vector_out[0].alternative_service().protocol);
// Ensure we correctly parsed the version.
EXPECT_EQ(advertised_versions,
alternative_service_info_vector_out[0].advertised_versions());
}
}

} // namespace net

0 comments on commit ef381b5

Please sign in to comment.