Allow setting connection options from command line in QuicToyClient This CL also adds a convenience method that can parse a comma-separated list of QuicTags, with corresponding test. The additions in the shared code are only used in QuicToyClient, so this CL does not impact existing behavior in prod. Test-tool-only change PiperOrigin-RevId: 317685170 Change-Id: I83e7737a3e4e40446e6051bd3ec07dfbf81559e2
diff --git a/quic/core/quic_tag.cc b/quic/core/quic_tag.cc index 270383d..b25c5b7 100644 --- a/quic/core/quic_tag.cc +++ b/quic/core/quic_tag.cc
@@ -74,4 +74,32 @@ tag_vector.end(); } +QuicTag ParseQuicTag(quiche::QuicheStringPiece tag_string) { + quiche::QuicheTextUtils::RemoveLeadingAndTrailingWhitespace(&tag_string); + std::string tag_bytes; + if (tag_string.length() == 8) { + tag_bytes = quiche::QuicheTextUtils::HexDecode(tag_string); + tag_string = tag_bytes; + } + QuicTag tag = 0; + // Iterate over every character from right to left. + for (auto it = tag_string.crbegin(); it != tag_string.crend(); ++it) { + // The cast here is required on platforms where char is signed. + unsigned char token_char = static_cast<unsigned char>(*it); + tag <<= 8; + tag |= token_char; + } + return tag; +} + +QuicTagVector ParseQuicTagVector(quiche::QuicheStringPiece tags_string) { + QuicTagVector tag_vector; + std::vector<quiche::QuicheStringPiece> tag_strings = + quiche::QuicheTextUtils::Split(tags_string, ','); + for (quiche::QuicheStringPiece tag_string : tag_strings) { + tag_vector.push_back(ParseQuicTag(tag_string)); + } + return tag_vector; +} + } // namespace quic
diff --git a/quic/core/quic_tag.h b/quic/core/quic_tag.h index 71fcdd5..7ba6cfc 100644 --- a/quic/core/quic_tag.h +++ b/quic/core/quic_tag.h
@@ -10,6 +10,7 @@ #include <vector> #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 { @@ -48,6 +49,17 @@ // treat it as a number if not. QUIC_EXPORT_PRIVATE std::string QuicTagToString(QuicTag tag); +// Utility function that converts a string of the form "ABCD" to its +// corresponding QuicTag. Note that tags that are less than four characters +// long are right-padded with zeroes. Tags that contain non-ASCII characters +// are represented as 8-character-long hexadecimal strings. +QUIC_EXPORT_PRIVATE QuicTag ParseQuicTag(quiche::QuicheStringPiece tag_string); + +// Utility function that converts a string of the form "ABCD,EFGH" to a vector +// of the form {kABCD,kEFGH}. Note the caveats on ParseQuicTag. +QUIC_EXPORT_PRIVATE QuicTagVector +ParseQuicTagVector(quiche::QuicheStringPiece tags_string); + } // namespace quic #endif // QUICHE_QUIC_CORE_QUIC_TAG_H_
diff --git a/quic/core/quic_tag_test.cc b/quic/core/quic_tag_test.cc index 3d58133..3dc93ad 100644 --- a/quic/core/quic_tag_test.cc +++ b/quic/core/quic_tag_test.cc
@@ -33,6 +33,35 @@ EXPECT_EQ('D', bytes[3]); } +TEST_F(QuicTagTest, ParseQuicTag) { + QuicTag tag_abcd = MakeQuicTag('A', 'B', 'C', 'D'); + EXPECT_EQ(ParseQuicTag("ABCD"), tag_abcd); + QuicTag tag_efgh = MakeQuicTag('E', 'F', 'G', 'H'); + EXPECT_EQ(ParseQuicTag("EFGH"), tag_efgh); + QuicTag tag_ijk = MakeQuicTag('I', 'J', 'K', 0); + EXPECT_EQ(ParseQuicTag("IJK"), tag_ijk); + QuicTag tag_l = MakeQuicTag('L', 0, 0, 0); + EXPECT_EQ(ParseQuicTag("L"), tag_l); + QuicTag tag_hex = MakeQuicTag('M', 'N', 'O', 255); + EXPECT_EQ(ParseQuicTag("4d4e4fff"), tag_hex); + EXPECT_EQ(ParseQuicTag("4D4E4FFF"), tag_hex); + QuicTag tag_zero = 0; + EXPECT_EQ(ParseQuicTag(""), tag_zero); + QuicTagVector tag_vector; + tag_vector.push_back(tag_abcd); + EXPECT_EQ(ParseQuicTagVector("ABCD"), tag_vector); + tag_vector.push_back(tag_efgh); + EXPECT_EQ(ParseQuicTagVector("ABCD,EFGH"), tag_vector); + tag_vector.push_back(tag_ijk); + EXPECT_EQ(ParseQuicTagVector("ABCD,EFGH,IJK"), tag_vector); + tag_vector.push_back(tag_l); + EXPECT_EQ(ParseQuicTagVector("ABCD,EFGH,IJK,L"), tag_vector); + tag_vector.push_back(tag_hex); + EXPECT_EQ(ParseQuicTagVector("ABCD,EFGH,IJK,L,4d4e4fff"), tag_vector); + tag_vector.push_back(tag_zero); + EXPECT_EQ(ParseQuicTagVector("ABCD,EFGH,IJK,L,4d4e4fff,"), tag_vector); +} + } // namespace } // namespace test } // namespace quic
diff --git a/quic/tools/quic_epoll_client_factory.cc b/quic/tools/quic_epoll_client_factory.cc index 1751f41..38dc582 100644 --- a/quic/tools/quic_epoll_client_factory.cc +++ b/quic/tools/quic_epoll_client_factory.cc
@@ -22,6 +22,7 @@ std::string host_for_lookup, uint16_t port, ParsedQuicVersionVector versions, + const QuicConfig& config, std::unique_ptr<ProofVerifier> verifier) { QuicSocketAddress addr = tools::LookupAddress(host_for_lookup, quiche::QuicheStrCat(port)); @@ -30,8 +31,9 @@ return nullptr; } QuicServerId server_id(host_for_handshake, port, false); - return std::make_unique<QuicClient>(addr, server_id, versions, &epoll_server_, - std::move(verifier)); + return std::make_unique<QuicClient>(addr, server_id, versions, config, + &epoll_server_, std::move(verifier), + nullptr); } } // namespace quic
diff --git a/quic/tools/quic_epoll_client_factory.h b/quic/tools/quic_epoll_client_factory.h index 2ee26d9..392bd6c 100644 --- a/quic/tools/quic_epoll_client_factory.h +++ b/quic/tools/quic_epoll_client_factory.h
@@ -18,6 +18,7 @@ std::string host_for_lookup, uint16_t port, ParsedQuicVersionVector versions, + const QuicConfig& config, std::unique_ptr<ProofVerifier> verifier) override; private:
diff --git a/quic/tools/quic_toy_client.cc b/quic/tools/quic_toy_client.cc index 0018f05..b42f967 100644 --- a/quic/tools/quic_toy_client.cc +++ b/quic/tools/quic_toy_client.cc
@@ -109,6 +109,20 @@ "versions are offered in the handshake. Also supports wire versions " "such as Q043 or T099."); +DEFINE_QUIC_COMMAND_LINE_FLAG( + std::string, + connection_options, + "", + "Connection options as ASCII tags separated by commas, " + "e.g. \"ABCD,EFGH\""); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + std::string, + client_connection_options, + "", + "Client connection options as ASCII tags separated by commas, " + "e.g. \"ABCD,EFGH\""); + DEFINE_QUIC_COMMAND_LINE_FLAG(bool, quic_ietf_draft, false, @@ -232,9 +246,22 @@ proof_verifier = quic::CreateDefaultProofVerifier(url.host()); } + QuicConfig config; + std::string connection_options_string = GetQuicFlag(FLAGS_connection_options); + if (!connection_options_string.empty()) { + config.SetConnectionOptionsToSend( + ParseQuicTagVector(connection_options_string)); + } + std::string client_connection_options_string = + GetQuicFlag(FLAGS_client_connection_options); + if (!client_connection_options_string.empty()) { + config.SetClientConnectionOptions( + ParseQuicTagVector(client_connection_options_string)); + } + // Build the client, and try to connect. std::unique_ptr<QuicSpdyClientBase> client = client_factory_->CreateClient( - url.host(), host, port, versions, std::move(proof_verifier)); + url.host(), host, port, versions, config, std::move(proof_verifier)); if (client == nullptr) { std::cerr << "Failed to create client." << std::endl;
diff --git a/quic/tools/quic_toy_client.h b/quic/tools/quic_toy_client.h index 1a20122..d9d8eca 100644 --- a/quic/tools/quic_toy_client.h +++ b/quic/tools/quic_toy_client.h
@@ -26,6 +26,7 @@ std::string host_for_lookup, uint16_t port, ParsedQuicVersionVector versions, + const QuicConfig& config, std::unique_ptr<ProofVerifier> verifier) = 0; };