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) {