Move virtually all the toy client logic out of quic_client_bin.cc and into a new
QuicToyClient class which can be used in chromium.
gfe-relnote: n/a - Tools only
PiperOrigin-RevId: 248451756
Change-Id: I7e9b7e2520ee40adcc692ea4e82e26d0a71760ef
diff --git a/quic/tools/quic_client_bin.cc b/quic/tools/quic_client_bin.cc
index 1ec47a9..e84b7fe 100644
--- a/quic/tools/quic_client_bin.cc
+++ b/quic/tools/quic_client_bin.cc
@@ -51,25 +51,16 @@
#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"
-#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_system_event_loop.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
-#include "net/third_party/quiche/src/quic/tools/fake_proof_verifier.h"
-#include "net/third_party/quiche/src/quic/tools/quic_client.h"
-#include "net/third_party/quiche/src/quic/tools/quic_url.h"
+#include "net/third_party/quiche/src/quic/tools/quic_toy_client.h"
namespace {
using quic::QuicSocketAddress;
using quic::QuicStringPiece;
-using quic::QuicTextUtils;
-using quic::QuicUrl;
QuicSocketAddress LookupAddress(std::string host, std::string port) {
addrinfo hint;
@@ -90,101 +81,29 @@
return QuicSocketAddress(*info_list->ai_addr);
}
+class QuicEpollClientFactory : public quic::QuicToyClientBase::ClientFactory {
+ public:
+ std::unique_ptr<quic::QuicSpdyClientBase> CreateClient(
+ std::string host,
+ uint16_t port,
+ quic::ParsedQuicVersionVector versions,
+ std::unique_ptr<quic::ProofVerifier> verifier) {
+ quic::QuicSocketAddress addr = LookupAddress(host, quic::QuicStrCat(port));
+ if (!addr.IsInitialized()) {
+ QUIC_LOG(ERROR) << "Unable to resolve address: " << host;
+ return nullptr;
+ }
+ quic::QuicServerId server_id(host, port, false);
+ return quic::QuicMakeUnique<quic::QuicClient>(
+ addr, server_id, versions, &epoll_server_, std::move(verifier));
+ }
+
+ private:
+ quic::QuicEpollServer epoll_server_;
+};
+
} // namespace
-DEFINE_QUIC_COMMAND_LINE_FLAG(
- std::string,
- host,
- "",
- "The IP or hostname to connect to. If not provided, the host "
- "will be derived from the provided URL.");
-
-DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, port, 0, "The port to connect to.");
-
-DEFINE_QUIC_COMMAND_LINE_FLAG(std::string,
- body,
- "",
- "If set, send a POST with this body.");
-
-DEFINE_QUIC_COMMAND_LINE_FLAG(
- std::string,
- body_hex,
- "",
- "If set, contents are converted from hex to ascii, before "
- "sending as body of a POST. e.g. --body_hex=\"68656c6c6f\"");
-
-DEFINE_QUIC_COMMAND_LINE_FLAG(
- std::string,
- headers,
- "",
- "A semicolon separated list of key:value pairs to "
- "add to request headers.");
-
-DEFINE_QUIC_COMMAND_LINE_FLAG(bool,
- quiet,
- false,
- "Set to true for a quieter output experience.");
-
-DEFINE_QUIC_COMMAND_LINE_FLAG(
- std::string,
- quic_version,
- "",
- "QUIC version to speak, e.g. 21. If not set, then all available "
- "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,
- version_mismatch_ok,
- false,
- "If true, a version mismatch in the handshake is not considered a "
- "failure. Useful for probing a server to determine if it speaks "
- "any version of QUIC.");
-
-DEFINE_QUIC_COMMAND_LINE_FLAG(
- bool,
- force_version_negotiation,
- false,
- "If true, start by proposing a version that is reserved for version "
- "negotiation.");
-
-DEFINE_QUIC_COMMAND_LINE_FLAG(
- bool,
- redirect_is_success,
- true,
- "If true, an HTTP response code of 3xx is considered to be a "
- "successful response, otherwise a failure.");
-
-DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t,
- initial_mtu,
- 0,
- "Initial MTU of the connection.");
-
-DEFINE_QUIC_COMMAND_LINE_FLAG(
- int32_t,
- num_requests,
- 1,
- "How many sequential requests to make on a single connection.");
-
-DEFINE_QUIC_COMMAND_LINE_FLAG(bool,
- disable_certificate_verification,
- false,
- "If true, don't verify the server certificate.");
-
-DEFINE_QUIC_COMMAND_LINE_FLAG(
- bool,
- drop_response_body,
- false,
- "If true, drop response body immediately after it is received.");
-
int main(int argc, char* argv[]) {
QuicSystemEventLoop event_loop("quic_client");
const char* usage = "Usage: quic_client [options] <url>";
@@ -197,193 +116,7 @@
exit(0);
}
- QuicUrl url(urls[0], "https");
- std::string host = GetQuicFlag(FLAGS_host);
- if (host.empty()) {
- host = url.host();
- }
- int port = GetQuicFlag(FLAGS_port);
- if (port == 0) {
- port = url.port();
- }
-
- // Determine IP address to connect to from supplied hostname.
- QuicSocketAddress addr = LookupAddress(host, quic::QuicStrCat(port));
- if (!addr.IsInitialized()) {
- return 1;
- }
- std::cerr << "Resolved " << url.ToString() << " to " << addr.ToString()
- << std::endl;
-
- // Build the client, and try to connect.
- quic::QuicEpollServer epoll_server;
- quic::QuicServerId server_id(url.host(), port, false);
- quic::ParsedQuicVersionVector versions = quic::CurrentSupportedVersions();
-
- 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);
- }
-
- if (GetQuicFlag(FLAGS_force_version_negotiation)) {
- versions.insert(versions.begin(),
- quic::QuicVersionReservedForNegotiation());
- }
-
- const int32_t num_requests(GetQuicFlag(FLAGS_num_requests));
- std::unique_ptr<quic::ProofVerifier> proof_verifier;
- if (GetQuicFlag(FLAGS_disable_certificate_verification)) {
- proof_verifier = quic::QuicMakeUnique<quic::FakeProofVerifier>();
- } else {
- proof_verifier = quic::CreateDefaultProofVerifier();
- }
- quic::QuicClient client(addr, server_id, versions, &epoll_server,
- std::move(proof_verifier));
- int32_t initial_mtu = GetQuicFlag(FLAGS_initial_mtu);
- client.set_initial_max_packet_length(
- initial_mtu != 0 ? initial_mtu : quic::kDefaultMaxPacketSize);
- client.set_drop_response_body(GetQuicFlag(FLAGS_drop_response_body));
- if (!client.Initialize()) {
- std::cerr << "Failed to initialize client." << std::endl;
- return 1;
- }
- if (!client.Connect()) {
- quic::QuicErrorCode error = client.session()->error();
- if (error == quic::QUIC_INVALID_VERSION) {
- std::cerr << "Server talks QUIC, but none of the versions supported by "
- << "this client: " << ParsedQuicVersionVectorToString(versions)
- << std::endl;
- // 0: No error.
- // 20: Failed to connect due to QUIC_INVALID_VERSION.
- return GetQuicFlag(FLAGS_version_mismatch_ok) ? 0 : 20;
- }
- std::cerr << "Failed to connect to " << addr.ToString()
- << ". Error: " << quic::QuicErrorCodeToString(error) << std::endl;
- return 1;
- }
- std::cerr << "Connected to " << addr.ToString() << std::endl;
-
- // Construct the string body from flags, if provided.
- std::string body = GetQuicFlag(FLAGS_body);
- if (!GetQuicFlag(FLAGS_body_hex).empty()) {
- DCHECK(GetQuicFlag(FLAGS_body).empty())
- << "Only set one of --body and --body_hex.";
- body = QuicTextUtils::HexDecode(GetQuicFlag(FLAGS_body_hex));
- }
-
- // Construct a GET or POST request for supplied URL.
- spdy::SpdyHeaderBlock header_block;
- header_block[":method"] = body.empty() ? "GET" : "POST";
- header_block[":scheme"] = url.scheme();
- header_block[":authority"] = url.HostPort();
- header_block[":path"] = url.PathParamsQuery();
-
- // Append any additional headers supplied on the command line.
- const std::string headers = GetQuicFlag(FLAGS_headers);
- for (QuicStringPiece sp : QuicTextUtils::Split(headers, ';')) {
- QuicTextUtils::RemoveLeadingAndTrailingWhitespace(&sp);
- if (sp.empty()) {
- continue;
- }
- std::vector<QuicStringPiece> kv = QuicTextUtils::Split(sp, ':');
- QuicTextUtils::RemoveLeadingAndTrailingWhitespace(&kv[0]);
- QuicTextUtils::RemoveLeadingAndTrailingWhitespace(&kv[1]);
- header_block[kv[0]] = kv[1];
- }
-
- // Make sure to store the response, for later output.
- client.set_store_response(true);
-
- for (int i = 0; i < num_requests; ++i) {
- // Send the request.
- client.SendRequestAndWaitForResponse(header_block, body, /*fin=*/true);
-
- // Print request and response details.
- if (!GetQuicFlag(FLAGS_quiet)) {
- std::cout << "Request:" << std::endl;
- std::cout << "headers:" << header_block.DebugString();
- if (!GetQuicFlag(FLAGS_body_hex).empty()) {
- // Print the user provided hex, rather than binary body.
- std::cout << "body:\n"
- << QuicTextUtils::HexDump(
- QuicTextUtils::HexDecode(GetQuicFlag(FLAGS_body_hex)))
- << std::endl;
- } else {
- std::cout << "body: " << body << std::endl;
- }
- std::cout << std::endl;
-
- if (!client.preliminary_response_headers().empty()) {
- std::cout << "Preliminary response headers: "
- << client.preliminary_response_headers() << std::endl;
- std::cout << std::endl;
- }
-
- std::cout << "Response:" << std::endl;
- std::cout << "headers: " << client.latest_response_headers() << std::endl;
- std::string response_body = client.latest_response_body();
- if (!GetQuicFlag(FLAGS_body_hex).empty()) {
- // Assume response is binary data.
- std::cout << "body:\n"
- << QuicTextUtils::HexDump(response_body) << std::endl;
- } else {
- std::cout << "body: " << response_body << std::endl;
- }
- std::cout << "trailers: " << client.latest_response_trailers()
- << std::endl;
- }
-
- if (!client.connected()) {
- std::cerr << "Request caused connection failure. Error: "
- << quic::QuicErrorCodeToString(client.session()->error())
- << std::endl;
- return 1;
- }
-
- size_t response_code = client.latest_response_code();
- if (response_code >= 200 && response_code < 300) {
- std::cout << "Request succeeded (" << response_code << ")." << std::endl;
- } else if (response_code >= 300 && response_code < 400) {
- if (GetQuicFlag(FLAGS_redirect_is_success)) {
- std::cout << "Request succeeded (redirect " << response_code << ")."
- << std::endl;
- } else {
- std::cout << "Request failed (redirect " << response_code << ")."
- << std::endl;
- return 1;
- }
- } else {
- std::cout << "Request failed (" << response_code << ")." << std::endl;
- return 1;
- }
-
- // Change the ephemeral port if there are more requests to do.
- if (i + 1 < num_requests) {
- if (!client.ChangeEphemeralPort()) {
- std::cerr << "Failed to change ephemeral port." << std::endl;
- return 1;
- }
- }
- }
-
- return 0;
+ QuicEpollClientFactory factory;
+ quic::QuicToyClientBase client(&factory);
+ return client.SendRequestsAndPrintResponses(urls);
}