Add --quic_versions to QuicToyServer and improve version parsing
This CL improves our version parsing code to allow using ALPN and parse a list, and uses that in a new --quic_versions flag on QuicToyServer. Note that ParseQuicVersionString is only used in tests and toy code.
gfe-relnote: n/a, test-only
PiperOrigin-RevId: 299245199
Change-Id: I33c0f73b6a094de0dba86b69bd598a24ee162872
diff --git a/quic/core/quic_versions.cc b/quic/core/quic_versions.cc
index a7450aa..b5fc585 100644
--- a/quic/core/quic_versions.cc
+++ b/quic/core/quic_versions.cc
@@ -263,7 +263,8 @@
return UnsupportedQuicVersion();
}
-ParsedQuicVersion ParseQuicVersionString(std::string version_string) {
+ParsedQuicVersion ParseQuicVersionString(
+ quiche::QuicheStringPiece version_string) {
if (version_string.empty()) {
return UnsupportedQuicVersion();
}
@@ -271,12 +272,26 @@
if (quiche::QuicheTextUtils::StringToInt(version_string,
&quic_version_number) &&
quic_version_number > 0) {
- return ParsedQuicVersion(
- PROTOCOL_QUIC_CRYPTO,
- static_cast<QuicTransportVersion>(quic_version_number));
+ QuicTransportVersion transport_version =
+ static_cast<QuicTransportVersion>(quic_version_number);
+ bool transport_version_is_supported = false;
+ for (QuicTransportVersion transport_vers : SupportedTransportVersions()) {
+ if (transport_vers == transport_version) {
+ transport_version_is_supported = true;
+ break;
+ }
+ }
+ if (!transport_version_is_supported ||
+ !ParsedQuicVersionIsValid(PROTOCOL_QUIC_CRYPTO, transport_version)) {
+ return UnsupportedQuicVersion();
+ }
+ return ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, transport_version);
}
for (const ParsedQuicVersion& version : AllSupportedVersions()) {
- if (version_string == ParsedQuicVersionToString(version)) {
+ if (version_string == ParsedQuicVersionToString(version) ||
+ version_string == AlpnForVersion(version) ||
+ (version.handshake_protocol == PROTOCOL_QUIC_CRYPTO &&
+ version_string == QuicVersionToString(version.transport_version))) {
return version;
}
}
@@ -286,6 +301,25 @@
return UnsupportedQuicVersion();
}
+ParsedQuicVersionVector ParseQuicVersionVectorString(
+ quiche::QuicheStringPiece versions_string) {
+ ParsedQuicVersionVector versions;
+ std::vector<quiche::QuicheStringPiece> version_strings =
+ quiche::QuicheTextUtils::Split(versions_string, ',');
+ for (quiche::QuicheStringPiece version_string : version_strings) {
+ quiche::QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(
+ &version_string);
+ ParsedQuicVersion version = ParseQuicVersionString(version_string);
+ if (version.transport_version == QUIC_VERSION_UNSUPPORTED ||
+ std::find(versions.begin(), versions.end(), version) !=
+ versions.end()) {
+ continue;
+ }
+ versions.push_back(version);
+ }
+ return versions;
+}
+
QuicTransportVersionVector AllSupportedTransportVersions() {
constexpr auto supported_transport_versions = SupportedTransportVersions();
QuicTransportVersionVector supported_versions(
diff --git a/quic/core/quic_versions.h b/quic/core/quic_versions.h
index bb539b1..e07e24a 100644
--- a/quic/core/quic_versions.h
+++ b/quic/core/quic_versions.h
@@ -21,6 +21,7 @@
#include "net/third_party/quiche/src/quic/core/quic_tag.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
namespace quic {
@@ -399,10 +400,17 @@
QUIC_EXPORT_PRIVATE ParsedQuicVersion
ParseQuicVersionLabel(QuicVersionLabel version_label);
-// Parses a QUIC version string such as "Q043" or "T099".
-// Also supports parsing numbers such as "44".
+// Parses a QUIC version string such as "Q043" or "T050". Also supports parsing
+// ALPN such as "h3-25" or "h3-Q050". For PROTOCOL_QUIC_CRYPTO versions, also
+// supports parsing numbers such as "46".
QUIC_EXPORT_PRIVATE ParsedQuicVersion
-ParseQuicVersionString(std::string version_string);
+ParseQuicVersionString(quiche::QuicheStringPiece version_string);
+
+// Parses a comma-separated list of QUIC version strings. Supports parsing by
+// label, ALPN and numbers for PROTOCOL_QUIC_CRYPTO. Skips unknown versions.
+// For example: "h3-25,Q050,46".
+QUIC_EXPORT_PRIVATE ParsedQuicVersionVector
+ParseQuicVersionVectorString(quiche::QuicheStringPiece versions_string);
// Constructs a QuicVersionLabel from the provided ParsedQuicVersion.
QUIC_EXPORT_PRIVATE QuicVersionLabel
diff --git a/quic/core/quic_versions_test.cc b/quic/core/quic_versions_test.cc
index 59d7b09..851619f 100644
--- a/quic/core/quic_versions_test.cc
+++ b/quic/core/quic_versions_test.cc
@@ -15,7 +15,9 @@
namespace test {
namespace {
-using testing::_;
+using ::testing::_;
+using ::testing::ElementsAre;
+using ::testing::IsEmpty;
class QuicVersionsTest : public QuicTest {
protected:
@@ -152,19 +154,110 @@
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43),
ParseQuicVersionString("Q043"));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46),
+ ParseQuicVersionString("QUIC_VERSION_46"));
+ EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46),
+ ParseQuicVersionString("46"));
+ EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46),
ParseQuicVersionString("Q046"));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_48),
ParseQuicVersionString("Q048"));
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50),
ParseQuicVersionString("Q050"));
+ EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50),
+ ParseQuicVersionString("50"));
+ EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50),
+ ParseQuicVersionString("h3-Q050"));
EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString(""));
EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("Q 46"));
EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("Q046 "));
+ EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("99"));
+ EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("70"));
- // Test a TLS version:
EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50),
ParseQuicVersionString("T050"));
+ EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_50),
+ ParseQuicVersionString("h3-T050"));
+ EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27),
+ ParseQuicVersionString("ff00001b"));
+ EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_27),
+ ParseQuicVersionString("h3-27"));
+ EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25),
+ ParseQuicVersionString("ff000019"));
+ EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_IETF_DRAFT_25),
+ ParseQuicVersionString("h3-25"));
+}
+
+TEST_F(QuicVersionsTest, ParseQuicVersionVectorString) {
+ ParsedQuicVersion version_q046(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46);
+ ParsedQuicVersion version_q050(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_50);
+ ParsedQuicVersion version_t050(PROTOCOL_TLS1_3, QUIC_VERSION_50);
+ ParsedQuicVersion version_draft_25(PROTOCOL_TLS1_3,
+ QUIC_VERSION_IETF_DRAFT_25);
+ ParsedQuicVersion version_draft_27(PROTOCOL_TLS1_3,
+ QUIC_VERSION_IETF_DRAFT_27);
+
+ EXPECT_THAT(ParseQuicVersionVectorString(""), IsEmpty());
+
+ EXPECT_THAT(ParseQuicVersionVectorString("QUIC_VERSION_50"),
+ ElementsAre(version_q050));
+ EXPECT_THAT(ParseQuicVersionVectorString("h3-Q050"),
+ ElementsAre(version_q050));
+ EXPECT_THAT(ParseQuicVersionVectorString("h3-T050"),
+ ElementsAre(version_t050));
+
+ EXPECT_THAT(ParseQuicVersionVectorString("h3-25, h3-27"),
+ ElementsAre(version_draft_25, version_draft_27));
+ EXPECT_THAT(ParseQuicVersionVectorString("h3-25,h3-27"),
+ ElementsAre(version_draft_25, version_draft_27));
+ EXPECT_THAT(ParseQuicVersionVectorString("h3-25,h3-27,h3-25"),
+ ElementsAre(version_draft_25, version_draft_27));
+ EXPECT_THAT(ParseQuicVersionVectorString("h3-25,h3-27, h3-25"),
+ ElementsAre(version_draft_25, version_draft_27));
+ EXPECT_THAT(ParseQuicVersionVectorString("h3-27,h3-25"),
+ ElementsAre(version_draft_27, version_draft_25));
+
+ EXPECT_THAT(ParseQuicVersionVectorString("h3-27,50"),
+ ElementsAre(version_draft_27, version_q050));
+
+ EXPECT_THAT(ParseQuicVersionVectorString("h3-Q050, h3-T050"),
+ ElementsAre(version_q050, version_t050));
+ EXPECT_THAT(ParseQuicVersionVectorString("h3-T050, h3-Q050"),
+ ElementsAre(version_t050, version_q050));
+ EXPECT_THAT(ParseQuicVersionVectorString("QUIC_VERSION_50,h3-T050"),
+ ElementsAre(version_q050, version_t050));
+ EXPECT_THAT(ParseQuicVersionVectorString("h3-T050,QUIC_VERSION_50"),
+ ElementsAre(version_t050, version_q050));
+ EXPECT_THAT(ParseQuicVersionVectorString("QUIC_VERSION_50, h3-T050"),
+ ElementsAre(version_q050, version_t050));
+ EXPECT_THAT(ParseQuicVersionVectorString("h3-T050, QUIC_VERSION_50"),
+ ElementsAre(version_t050, version_q050));
+
+ EXPECT_THAT(ParseQuicVersionVectorString("QUIC_VERSION_50,QUIC_VERSION_46"),
+ ElementsAre(version_q050, version_q046));
+ EXPECT_THAT(ParseQuicVersionVectorString("QUIC_VERSION_46,QUIC_VERSION_50"),
+ ElementsAre(version_q046, version_q050));
+
+ // Regression test for https://crbug.com/1044952.
+ EXPECT_THAT(ParseQuicVersionVectorString("QUIC_VERSION_50, QUIC_VERSION_50"),
+ ElementsAre(version_q050));
+ EXPECT_THAT(ParseQuicVersionVectorString("h3-Q050, h3-Q050"),
+ ElementsAre(version_q050));
+ EXPECT_THAT(ParseQuicVersionVectorString("h3-T050, h3-T050"),
+ ElementsAre(version_t050));
+ EXPECT_THAT(ParseQuicVersionVectorString("h3-Q050, QUIC_VERSION_50"),
+ ElementsAre(version_q050));
+ EXPECT_THAT(ParseQuicVersionVectorString(
+ "QUIC_VERSION_50, h3-Q050, QUIC_VERSION_50, h3-Q050"),
+ ElementsAre(version_q050));
+ EXPECT_THAT(ParseQuicVersionVectorString("QUIC_VERSION_50, h3-T050, h3-Q050"),
+ ElementsAre(version_q050, version_t050));
+
+ EXPECT_THAT(ParseQuicVersionVectorString("99"), IsEmpty());
+ EXPECT_THAT(ParseQuicVersionVectorString("70"), IsEmpty());
+ EXPECT_THAT(ParseQuicVersionVectorString("h3-01"), IsEmpty());
+ EXPECT_THAT(ParseQuicVersionVectorString("h3-01,h3-25"),
+ ElementsAre(version_draft_25));
}
TEST_F(QuicVersionsTest, CreateQuicVersionLabel) {
diff --git a/quic/tools/quic_toy_client.cc b/quic/tools/quic_toy_client.cc
index 8a9532d..63a0671 100644
--- a/quic/tools/quic_toy_client.cc
+++ b/quic/tools/quic_toy_client.cc
@@ -184,30 +184,29 @@
quic::ParsedQuicVersionVector versions = quic::CurrentSupportedVersions();
- std::string quic_version_string = GetQuicFlag(FLAGS_quic_version);
if (GetQuicFlag(FLAGS_quic_ietf_draft)) {
quic::QuicVersionInitializeSupportForIetfDraft();
versions = {};
for (const ParsedQuicVersion& version : AllSupportedVersions()) {
- // Find the first version that supports IETF QUIC.
if (version.HasIetfQuicFrames() &&
version.handshake_protocol == quic::PROTOCOL_TLS1_3) {
- versions = {version};
- break;
+ versions.push_back(version);
}
}
- CHECK_EQ(versions.size(), 1u);
- quic::QuicEnableVersion(versions[0]);
+ }
- } else if (!quic_version_string.empty()) {
- quic::ParsedQuicVersion parsed_quic_version =
- quic::ParseQuicVersionString(quic_version_string);
- if (parsed_quic_version.transport_version ==
- quic::QUIC_VERSION_UNSUPPORTED) {
- return 1;
- }
- versions = {parsed_quic_version};
- quic::QuicEnableVersion(parsed_quic_version);
+ std::string quic_version_string = GetQuicFlag(FLAGS_quic_version);
+ if (!quic_version_string.empty()) {
+ versions = quic::ParseQuicVersionVectorString(quic_version_string);
+ }
+
+ if (versions.empty()) {
+ std::cerr << "No known version selected." << std::endl;
+ return 1;
+ }
+
+ for (const quic::ParsedQuicVersion& version : versions) {
+ quic::QuicEnableVersion(version);
}
if (GetQuicFlag(FLAGS_force_version_negotiation)) {
diff --git a/quic/tools/quic_toy_server.cc b/quic/tools/quic_toy_server.cc
index a23e7d9..20ee151 100644
--- a/quic/tools/quic_toy_server.cc
+++ b/quic/tools/quic_toy_server.cc
@@ -36,8 +36,15 @@
DEFINE_QUIC_COMMAND_LINE_FLAG(bool,
quic_ietf_draft,
false,
- "Use the IETF draft version. This also enables "
- "required internal QUIC flags.");
+ "Only enable IETF draft versions. This also "
+ "enables required internal QUIC flags.");
+
+DEFINE_QUIC_COMMAND_LINE_FLAG(
+ std::string,
+ quic_versions,
+ "",
+ "QUIC versions to enable, e.g. \"h3-25,h3-27\". If not set, then all "
+ "available versions are enabled.");
namespace quic {
@@ -73,6 +80,13 @@
} else {
supported_versions = AllSupportedVersions();
}
+ std::string versions_string = GetQuicFlag(FLAGS_quic_versions);
+ if (!versions_string.empty()) {
+ supported_versions = ParseQuicVersionVectorString(versions_string);
+ }
+ if (supported_versions.empty()) {
+ return 1;
+ }
for (const auto& version : supported_versions) {
QuicEnableVersion(version);
}