Allow TLS-based versions in quic_client and quic_server

Also adds functions for overriding the version label for T099, parsing version labels from strings, and easily enabling flags required by particular QUIC versions.

gfe-relnote: protected by disabled flag quic_supports_tls_handshake, or test-only code
PiperOrigin-RevId: 242047771
Change-Id: I00d8948fca5e91021c386944371dc3b92f1f3988
diff --git a/quic/core/quic_versions.cc b/quic/core/quic_versions.cc
index 036fbd0..62f9ce9 100644
--- a/quic/core/quic_versions.cc
+++ b/quic/core/quic_versions.cc
@@ -8,11 +8,13 @@
 
 #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_arraysize.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_endian.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
 
 namespace quic {
 namespace {
@@ -23,6 +25,10 @@
   return MakeQuicTag(d, c, b, a);
 }
 
+// Version label for ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99).
+// Defaults to "T099". Can be overridden for IETF interop events.
+QuicVersionLabel kQuicT099VersionLabel = 0;
+
 }  // namespace
 
 ParsedQuicVersion::ParsedQuicVersion(HandshakeProtocol handshake_protocol,
@@ -66,6 +72,10 @@
     case QUIC_VERSION_47:
       return MakeVersionLabel(proto, '0', '4', '7');
     case QUIC_VERSION_99:
+      if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3 &&
+          kQuicT099VersionLabel != 0) {
+        return kQuicT099VersionLabel;
+      }
       return MakeVersionLabel(proto, '0', '9', '9');
     default:
       // This shold be an ERROR because we should never attempt to convert an
@@ -105,6 +115,41 @@
   return UnsupportedQuicVersion();
 }
 
+ParsedQuicVersion ParseQuicVersionString(std::string version_string) {
+  if (version_string.length() == 0) {
+    return UnsupportedQuicVersion();
+  }
+  int quic_version_number = 0;
+  if (QuicTextUtils::StringToInt(version_string, &quic_version_number) &&
+      quic_version_number > 0) {
+    return ParsedQuicVersion(
+        PROTOCOL_QUIC_CRYPTO,
+        static_cast<QuicTransportVersion>(quic_version_number));
+  }
+
+  std::vector<HandshakeProtocol> protocols = {PROTOCOL_QUIC_CRYPTO};
+  if (FLAGS_quic_supports_tls_handshake) {
+    protocols.push_back(PROTOCOL_TLS1_3);
+  }
+  for (QuicTransportVersion version : kSupportedTransportVersions) {
+    for (HandshakeProtocol handshake : protocols) {
+      const ParsedQuicVersion parsed_version =
+          ParsedQuicVersion(handshake, version);
+      if (version_string == ParsedQuicVersionToString(parsed_version)) {
+        return parsed_version;
+      }
+    }
+  }
+  // Still recognize T099 even if kQuicT099VersionLabel has been changed.
+  if (FLAGS_quic_supports_tls_handshake && version_string == "T099") {
+    return ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99);
+  }
+  // Reading from the client so this should not be considered an ERROR.
+  QUIC_DLOG(INFO) << "Unsupported QUIC version string: \"" << version_string
+                  << "\".";
+  return UnsupportedQuicVersion();
+}
+
 QuicTransportVersionVector AllSupportedTransportVersions() {
   QuicTransportVersionVector supported_versions;
   for (QuicTransportVersion version : kSupportedTransportVersions) {
@@ -333,5 +378,49 @@
   return ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED);
 }
 
+void QuicVersionInitializeSupportForIetfDraft(int32_t draft_version) {
+  if (draft_version == 0) {
+    return;
+  }
+  if (draft_version < 0 || draft_version >= 256) {
+    LOG(FATAL) << "Invalid IETF draft version " << draft_version;
+    return;
+  }
+
+  kQuicT099VersionLabel = 0xff000000 + draft_version;
+
+  // Enable necessary flags.
+  SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true);
+  SetQuicReloadableFlag(quic_deprecate_ack_bundling_mode, true);
+  SetQuicReloadableFlag(quic_rpm_decides_when_to_send_acks, true);
+  SetQuicReloadableFlag(quic_use_uber_loss_algorithm, true);
+  SetQuicReloadableFlag(quic_use_uber_received_packet_manager, true);
+  SetQuicReloadableFlag(quic_validate_packet_number_post_decryption, true);
+  SetQuicRestartFlag(quic_enable_accept_random_ipn, true);
+}
+
+void QuicEnableVersion(ParsedQuicVersion parsed_version) {
+  if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3) {
+    SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true);
+  }
+  static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u,
+                "Supported versions out of sync");
+  if (parsed_version.transport_version >= QUIC_VERSION_99) {
+    SetQuicReloadableFlag(quic_enable_version_99, true);
+  }
+  if (parsed_version.transport_version >= QUIC_VERSION_47) {
+    SetQuicReloadableFlag(quic_enable_version_47, true);
+  }
+  if (parsed_version.transport_version >= QUIC_VERSION_46) {
+    SetQuicReloadableFlag(quic_enable_version_46, true);
+  }
+  if (parsed_version.transport_version >= QUIC_VERSION_44) {
+    SetQuicReloadableFlag(quic_enable_version_44, true);
+  }
+  if (parsed_version.transport_version >= QUIC_VERSION_43) {
+    SetQuicReloadableFlag(quic_enable_version_43, true);
+  }
+}
+
 #undef RETURN_STRING_LITERAL  // undef for jumbo builds
 }  // namespace quic
diff --git a/quic/core/quic_versions.h b/quic/core/quic_versions.h
index b23ae08..2c78760 100644
--- a/quic/core/quic_versions.h
+++ b/quic/core/quic_versions.h
@@ -227,6 +227,11 @@
 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".
+QUIC_EXPORT_PRIVATE ParsedQuicVersion
+ParseQuicVersionString(std::string version_string);
+
 // Constructs a QuicVersionLabel from the provided ParsedQuicVersion.
 QUIC_EXPORT_PRIVATE QuicVersionLabel
 CreateQuicVersionLabel(ParsedQuicVersion parsed_version);
@@ -348,6 +353,14 @@
   return transport_version == QUIC_VERSION_99;
 }
 
+// Initializes support for the provided IETF draft version by setting flags
+// and the version label.
+QUIC_EXPORT_PRIVATE void QuicVersionInitializeSupportForIetfDraft(
+    int32_t draft_version);
+
+// Enables the flags required to support this version of QUIC.
+QUIC_EXPORT_PRIVATE void QuicEnableVersion(ParsedQuicVersion parsed_version);
+
 }  // namespace quic
 
 #endif  // QUICHE_QUIC_CORE_QUIC_VERSIONS_H_
diff --git a/quic/core/quic_versions_test.cc b/quic/core/quic_versions_test.cc
index db7f53a..6139ca8 100644
--- a/quic/core/quic_versions_test.cc
+++ b/quic/core/quic_versions_test.cc
@@ -171,6 +171,45 @@
             ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '7')));
 }
 
+TEST_F(QuicVersionsTest, ParseQuicVersionString) {
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_39),
+            ParseQuicVersionString("Q039"));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43),
+            ParseQuicVersionString("Q043"));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44),
+            ParseQuicVersionString("Q044"));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46),
+            ParseQuicVersionString("Q046"));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47),
+            ParseQuicVersionString("Q047"));
+
+  EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString(""));
+  EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("Q 47"));
+  EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("Q047 "));
+
+  // Test a TLS version:
+  FLAGS_quic_supports_tls_handshake = true;
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_39),
+            ParseQuicVersionString("T039"));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_43),
+            ParseQuicVersionString("T043"));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_44),
+            ParseQuicVersionString("T044"));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_46),
+            ParseQuicVersionString("T046"));
+  EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_47),
+            ParseQuicVersionString("T047"));
+
+  FLAGS_quic_supports_tls_handshake = false;
+  EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("T035"));
+  EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("T039"));
+  EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("T043"));
+  EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("T044"));
+  EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("T045"));
+  EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("T046"));
+  EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("T047"));
+}
+
 TEST_F(QuicVersionsTest, CreateQuicVersionLabel) {
   EXPECT_EQ(MakeVersionLabel('Q', '0', '3', '9'),
             CreateQuicVersionLabel(
@@ -516,6 +555,58 @@
   EXPECT_EQ(QUIC_VERSION_47, 47);
   EXPECT_EQ(QUIC_VERSION_99, 99);
 }
+
+TEST_F(QuicVersionsTest, InitializeSupportForIetfDraft) {
+  FLAGS_quic_supports_tls_handshake = true;
+  ParsedQuicVersion parsed_version_t099 =
+      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99);
+  FLAGS_quic_supports_tls_handshake = false;
+  EXPECT_EQ(MakeVersionLabel('T', '0', '9', '9'),
+            CreateQuicVersionLabel(parsed_version_t099));
+
+  QuicVersionInitializeSupportForIetfDraft(0);
+  EXPECT_EQ(MakeVersionLabel('T', '0', '9', '9'),
+            CreateQuicVersionLabel(parsed_version_t099));
+  EXPECT_FALSE(FLAGS_quic_supports_tls_handshake);
+
+  QuicVersionInitializeSupportForIetfDraft(18);
+  EXPECT_TRUE(FLAGS_quic_supports_tls_handshake);
+  EXPECT_EQ(MakeVersionLabel(0xff, 0, 0, 18),
+            CreateQuicVersionLabel(parsed_version_t099));
+}
+
+TEST_F(QuicVersionsTest, QuicEnableVersion) {
+  FLAGS_quic_supports_tls_handshake = true;
+  ParsedQuicVersion parsed_version_q047 =
+      ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47);
+  ParsedQuicVersion parsed_version_t047 =
+      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_47);
+  ParsedQuicVersion parsed_version_t099 =
+      ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99);
+  FLAGS_quic_supports_tls_handshake = false;
+  SetQuicReloadableFlag(quic_disable_version_39, false);
+  SetQuicReloadableFlag(quic_enable_version_43, true);
+  SetQuicReloadableFlag(quic_enable_version_44, true);
+  SetQuicReloadableFlag(quic_enable_version_46, true);
+  SetQuicReloadableFlag(quic_enable_version_47, false);
+  SetQuicReloadableFlag(quic_enable_version_99, false);
+
+  QuicEnableVersion(parsed_version_q047);
+  EXPECT_FALSE(FLAGS_quic_supports_tls_handshake);
+  EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_47));
+  EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99));
+
+  QuicEnableVersion(parsed_version_t047);
+  EXPECT_TRUE(FLAGS_quic_supports_tls_handshake);
+  EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_47));
+  EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99));
+
+  QuicEnableVersion(parsed_version_t099);
+  EXPECT_TRUE(FLAGS_quic_supports_tls_handshake);
+  EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_47));
+  EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_99));
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/quic/tools/quic_client_bin.cc b/quic/tools/quic_client_bin.cc
index ff81125..ee8262f 100644
--- a/quic/tools/quic_client_bin.cc
+++ b/quic/tools/quic_client_bin.cc
@@ -47,6 +47,7 @@
 #include "net/third_party/quiche/src/quic/core/quic_packets.h"
 #include "net/third_party/quiche/src/quic/core/quic_server_id.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_default_proof_providers.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
@@ -151,11 +152,20 @@
                               "Set to true for a quieter output experience.");
 
 DEFINE_QUIC_COMMAND_LINE_FLAG(
-    int32_t,
+    std::string,
     quic_version,
-    -1,
+    "",
     "QUIC version to speak, e.g. 21. If not set, then all available "
-    "versions are offered in the handshake.");
+    "versions are offered in the handshake. Also supports wire versions "
+    "such as Q043 or T099.");
+
+DEFINE_QUIC_COMMAND_LINE_FLAG(
+    int32_t,
+    quic_ietf_draft,
+    0,
+    "QUIC IETF draft number to use over the wire, e.g. 18. "
+    "By default this sets quic_version to T099. "
+    "This also enables required internal QUIC flags.");
 
 DEFINE_QUIC_COMMAND_LINE_FLAG(
     bool,
@@ -228,12 +238,31 @@
   quic::QuicEpollServer epoll_server;
   quic::QuicServerId server_id(url.host(), port, false);
   quic::ParsedQuicVersionVector versions = quic::CurrentSupportedVersions();
-  if (GetQuicFlag(FLAGS_quic_version) != -1) {
-    versions.clear();
-    versions.push_back(quic::ParsedQuicVersion(
-        quic::PROTOCOL_QUIC_CRYPTO, static_cast<quic::QuicTransportVersion>(
-                                        GetQuicFlag(FLAGS_quic_version))));
+
+  std::string quic_version_string = GetQuicFlag(FLAGS_quic_version);
+  const int32_t quic_ietf_draft = GetQuicFlag(FLAGS_quic_ietf_draft);
+  if (quic_ietf_draft > 0) {
+    quic::QuicVersionInitializeSupportForIetfDraft(quic_ietf_draft);
+    if (quic_version_string.length() == 0) {
+      quic_version_string = "T099";
+    }
   }
+  if (quic_version_string.length() > 0) {
+    if (quic_version_string[0] == 'T') {
+      // ParseQuicVersionString checks quic_supports_tls_handshake.
+      SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true);
+    }
+    quic::ParsedQuicVersion parsed_quic_version =
+        quic::ParseQuicVersionString(quic_version_string);
+    if (parsed_quic_version.transport_version ==
+        quic::QUIC_VERSION_UNSUPPORTED) {
+      return 1;
+    }
+    versions.clear();
+    versions.push_back(parsed_quic_version);
+    quic::QuicEnableVersion(parsed_quic_version);
+  }
+
   const int32_t num_requests(GetQuicFlag(FLAGS_num_requests));
   std::unique_ptr<quic::ProofVerifier> proof_verifier;
   if (GetQuicFlag(FLAGS_disable_certificate_verification)) {
diff --git a/quic/tools/quic_server_bin.cc b/quic/tools/quic_server_bin.cc
index 1029fbd..128c873 100644
--- a/quic/tools/quic_server_bin.cc
+++ b/quic/tools/quic_server_bin.cc
@@ -7,6 +7,7 @@
 
 #include <vector>
 
+#include "net/third_party/quiche/src/quic/core/quic_versions.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_default_proof_providers.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
@@ -26,6 +27,13 @@
     "construction to seed the cache. Cache directory can be "
     "generated using `wget -p --save-headers <url>`");
 
+DEFINE_QUIC_COMMAND_LINE_FLAG(
+    int32_t,
+    quic_ietf_draft,
+    0,
+    "QUIC IETF draft number to use over the wire, e.g. 18. "
+    "This also enables required internal QUIC flags.");
+
 int main(int argc, char* argv[]) {
   const char* usage = "Usage: quic_server [options]";
   std::vector<std::string> non_option_args =
@@ -35,6 +43,13 @@
     exit(0);
   }
 
+  const int32_t quic_ietf_draft = GetQuicFlag(FLAGS_quic_ietf_draft);
+  if (quic_ietf_draft > 0) {
+    quic::QuicVersionInitializeSupportForIetfDraft(quic_ietf_draft);
+    quic::QuicEnableVersion(
+        quic::ParsedQuicVersion(quic::PROTOCOL_TLS1_3, quic::QUIC_VERSION_99));
+  }
+
   quic::QuicMemoryCacheBackend memory_cache_backend;
   if (!GetQuicFlag(FLAGS_quic_response_cache_dir).empty()) {
     memory_cache_backend.InitializeBackend(