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;
};