Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(518)

Unified Diff: net/tools/quic/quic_client_bin.cc

Issue 847813005: Updates quic_client_bin.cc to be more user friendly, and support more (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@Refactoring_code_for_readability_83493327
Patch Set: Added DumpHeadersToString to dump response headers Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/tools/quic/quic_client_bin.cc
diff --git a/net/tools/quic/quic_client_bin.cc b/net/tools/quic/quic_client_bin.cc
index 6fcde96fa6be57c79221bf914dc413853fab46b0..dcebd39a9848a6894bc008384565a5dc936a4340 100644
--- a/net/tools/quic/quic_client_bin.cc
+++ b/net/tools/quic/quic_client_bin.cc
@@ -3,11 +3,40 @@
// found in the LICENSE file.
// A binary wrapper for QuicClient.
-// Connects to a host using QUIC, and sends requests to the provided URLS.
+// Connects to a host using QUIC, sends a request to the provided URL, and
+// displays the response.
//
-// Example usage:
-// quic_client --address=127.0.0.1 --port=6122 --hostname=www.google.com
-// http://www.google.com/index.html http://www.google.com/favicon.ico
+// Some usage examples:
+//
+// TODO(rtenneti): make --host optional by getting IP Address of URL's host.
+//
+// Get IP address of the www.google.com
+// IP=`dig www.google.com +short | head -1`
+//
+// Standard request/response:
+// quic_client http://www.google.com --host=${IP}
+// quic_client http://www.google.com --quiet --host=${IP}
+// quic_client https://www.google.com --port=443 --host=${IP}
+//
+// Use a specific version:
+// quic_client http://www.google.com --version=23 --host=${IP}
+//
+// Send a POST instead of a GET:
+// quic_client http://www.google.com --body="this is a POST body" --host=${IP}
+//
+// Append additional headers to the request:
+// quic_client http://www.google.com --host=${IP}
+// --headers="Header-A: 1234; Header-B: 5678"
+//
+// Connect to a host different to the URL being requested:
+// Get IP address of the www.google.com
+// IP=`dig www.google.com +short | head -1`
+// quic_client mail.google.com --host=${IP}
+//
+// Try to connect to a host which does not speak QUIC:
+// Get IP address of the www.example.com
+// IP=`dig www.example.com +short | head -1`
+// quic_client http://www.example.com --host=${IP}
#include <iostream>
@@ -15,25 +44,45 @@
#include "base/command_line.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
#include "net/base/ip_endpoint.h"
#include "net/base/privacy_mode.h"
#include "net/quic/quic_protocol.h"
#include "net/quic/quic_server_id.h"
+#include "net/quic/quic_utils.h"
#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_client.h"
+#include "net/tools/quic/spdy_utils.h"
+#include "url/gurl.h"
+
+using base::StringPiece;
+using std::cout;
+using std::cerr;
+using std::map;
+using std::string;
+using std::vector;
+using std::endl;
-std::string FLAGS_address = "127.0.0.1";
// The IP or hostname the quic client will connect to.
-std::string FLAGS_hostname = "localhost";
-// The port the quic client will connect to.
-int32 FLAGS_port = 6121;
-// Check the certificates using proof verifier.
-bool FLAGS_secure = false;
-// QUIC version to speak, e.g. 21. Default value of 0 means 'use the latest
-// version'.
-int32 FLAGS_quic_version = 0;
-// Size of flow control receive window to advertize to the peer.
-int32 FLAGS_flow_control_window_bytes = 10 * 1024 * 1024; // 10 Mb
+string FLAGS_host = "";
+// The port to connect to.
+int32 FLAGS_port = 80;
+// If set, send a POST with this body.
+string FLAGS_body = "";
+// A semicolon separated list of key:value pairs to add to request headers.
+string FLAGS_headers = "";
+// Set to true for a quieter output experience.
+bool FLAGS_quiet = false;
+// QUIC version to speak, e.g. 21. If not set, then all available versions are
+// offered in the handshake.
+int32 FLAGS_quic_version = -1;
+// 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.
+bool FLAGS_version_mismatch_ok = false;
+// If true, an HTTP response code of 3xx is considered to be a successful
+// response, otherwise a failure.
+bool FLAGS_redirect_is_success = true;
int main(int argc, char *argv[]) {
base::CommandLine::Init(argc, argv);
@@ -46,36 +95,43 @@ int main(int argc, char *argv[]) {
if (line->HasSwitch("h") || line->HasSwitch("help") || urls.empty()) {
const char* help_str =
- "Usage: quic_client [options] <url> ...\n"
+ "Usage: quic_client [options] <url>\n"
"\n"
- "At least one <url> with scheme must be provided "
- "(e.g. http://www.google.com/)\n\n"
+ "<url> with scheme must be provided (e.g. http://www.google.com)\n\n"
"Options:\n"
"-h, --help show this help message and exit\n"
+ "--host=<host> specify the IP address of the hostname to "
+ "connect to\n"
"--port=<port> specify the port to connect to\n"
- "--address=<address> specify the IP address to connect to\n"
- "--host=<host> specify the SNI hostname to use\n"
- "--secure check certificates\n"
+ "--body=<body> specify the body to post\n"
+ "--headers=<headers> specify a semicolon separated list of "
+ "key:value pairs to add to request headers\n"
+ "--quiet specify for a quieter output experience\n"
"--quic-version=<quic version> specify QUIC version to speak\n"
- "--flow-control-window-bytes=<bytes> specify size of flow control "
- "receive window to advertize to the peer\n";
- std::cout << help_str;
+ "--version_mismatch_ok if specified a version mismatch in the "
+ "handshake is not considered a failure\n"
+ "--redirect_is_success if specified an HTTP response code of 3xx "
+ "is considered to be a successful response, otherwise a failure\n";
+ cout << help_str;
exit(0);
}
+ if (line->HasSwitch("host")) {
+ FLAGS_host = line->GetSwitchValueASCII("host");
+ }
if (line->HasSwitch("port")) {
int port;
if (base::StringToInt(line->GetSwitchValueASCII("port"), &port)) {
FLAGS_port = port;
}
}
- if (line->HasSwitch("address")) {
- FLAGS_address = line->GetSwitchValueASCII("address");
+ if (line->HasSwitch("body")) {
+ FLAGS_body = line->GetSwitchValueASCII("body");
}
- if (line->HasSwitch("hostname")) {
- FLAGS_hostname = line->GetSwitchValueASCII("hostname");
+ if (line->HasSwitch("headers")) {
+ FLAGS_headers = line->GetSwitchValueASCII("headers");
}
- if (line->HasSwitch("secure")) {
- FLAGS_secure = true;
+ if (line->HasSwitch("quiet")) {
+ FLAGS_quiet = true;
}
if (line->HasSwitch("quic-version")) {
int quic_version;
@@ -84,55 +140,124 @@ int main(int argc, char *argv[]) {
FLAGS_quic_version = quic_version;
}
}
- if (line->HasSwitch("flow-control-window-bytes")) {
- int flow_control_window_bytes;
- if (base::StringToInt(
- line->GetSwitchValueASCII("flow-control-window-bytes"),
- &flow_control_window_bytes)) {
- FLAGS_flow_control_window_bytes = flow_control_window_bytes;
- }
+ if (line->HasSwitch("version_mismatch_ok")) {
+ FLAGS_version_mismatch_ok = true;
+ }
+ if (line->HasSwitch("redirect_is_success")) {
+ FLAGS_redirect_is_success = true;
}
- VLOG(1) << "server port: " << FLAGS_port
- << " address: " << FLAGS_address
- << " hostname: " << FLAGS_hostname
- << " secure: " << FLAGS_secure
- << " quic-version: " << FLAGS_quic_version;
+
+ VLOG(1) << "server host: " << FLAGS_host << " port: " << FLAGS_port
+ << " body: " << FLAGS_body << " headers: " << FLAGS_headers
+ << " quiet: " << FLAGS_quiet
+ << " quic-version: " << FLAGS_quic_version
+ << " version_mismatch_ok: " << FLAGS_version_mismatch_ok
+ << " redirect_is_success: " << FLAGS_redirect_is_success;
base::AtExitManager exit_manager;
// Determine IP address to connect to from supplied hostname.
- net::IPAddressNumber addr;
- CHECK(net::ParseIPLiteralToNumber(FLAGS_address, &addr));
+ net::IPAddressNumber ip_addr;
- // Populate version vector with all versions if none specified.
- net::QuicVersionVector versions;
- if (FLAGS_quic_version == 0) {
- versions = net::QuicSupportedVersions();
- } else {
- versions.push_back(static_cast<net::QuicVersion>(FLAGS_quic_version));
- }
+ // TODO(rtenneti): GURL's doesn't support default_protocol argument, thus
+ // protocol is required in the URL.
+ GURL url(urls[0]);
+ string host = FLAGS_host;
+ // TODO(rtenneti): get ip_addr from hostname by doing host resolution.
+ CHECK(!host.empty());
+ net::ParseIPLiteralToNumber(host, &ip_addr);
+
+ string host_port = net::IPAddressToStringWithPort(ip_addr, FLAGS_port);
+ VLOG(1) << "Resolved " << host << " to " << host_port << endl;
// Build the client, and try to connect.
- VLOG(1) << "Conecting to " << FLAGS_hostname << ":" << FLAGS_port
- << " with supported versions "
- << QuicVersionVectorToString(versions);
net::EpollServer epoll_server;
+ net::QuicServerId server_id(host, FLAGS_port, /*is_https=*/false,
+ net::PRIVACY_MODE_DISABLED);
+ net::QuicVersionVector versions = net::QuicSupportedVersions();
+ if (FLAGS_quic_version != -1) {
+ versions.clear();
+ versions.push_back(static_cast<net::QuicVersion>(FLAGS_quic_version));
+ }
+ net::tools::QuicClient client(net::IPEndPoint(ip_addr, FLAGS_port), server_id,
+ versions, &epoll_server);
+ if (!client.Initialize()) {
+ cerr << "Failed to initialize client." << endl;
+ return 1;
+ }
+ if (!client.Connect()) {
+ net::QuicErrorCode error = client.session()->error();
+ if (FLAGS_version_mismatch_ok && error == net::QUIC_INVALID_VERSION) {
+ cout << "Server talks QUIC, but none of the versions supoorted by "
+ << "this client: " << QuicVersionVectorToString(versions) << endl;
+ // Version mismatch is not deemed a failure.
+ return 0;
+ }
+ cerr << "Failed to connect to " << host_port
+ << ". Error: " << net::QuicUtils::ErrorToString(error) << endl;
+ return 1;
+ }
+ cout << "Connected to " << host_port << endl;
+
+ // Construct a GET or POST request for supplied URL.
+ net::BalsaHeaders headers;
+ headers.SetRequestFirstlineFromStringPieces(
+ FLAGS_body.empty() ? "GET" : "POST", url.spec(), "HTTP/1.1");
+
+ // Append any additional headers supplied on the command line.
+ vector<string> headers_tokenized;
+ Tokenize(FLAGS_headers, ";", &headers_tokenized);
+ for (size_t i = 0; i < headers_tokenized.size(); ++i) {
+ string sp;
+ base::TrimWhitespaceASCII(headers_tokenized[i], base::TRIM_ALL, &sp);
+ if (sp.empty()) {
+ continue;
+ }
+ vector<string> kv;
+ base::SplitString(sp, ':', &kv);
+ CHECK_EQ(2u, kv.size());
+ string key;
+ base::TrimWhitespaceASCII(kv[0], base::TRIM_ALL, &key);
+ string value;
+ base::TrimWhitespaceASCII(kv[1], base::TRIM_ALL, &value);
+ headers.AppendHeader(key, value);
+ }
- net::tools::QuicClient client(
- net::IPEndPoint(addr, FLAGS_port),
- net::QuicServerId(FLAGS_hostname, FLAGS_port, FLAGS_secure,
- net::PRIVACY_MODE_DISABLED),
- versions, true, &epoll_server);
+ // Make sure to store the response, for later output.
+ client.set_store_response(true);
- client.Initialize();
+ // Send the request.
+ map<string, string> header_block =
+ net::tools::SpdyUtils::RequestHeadersToSpdy4Headers(headers);
ramant (doing other things) 2015/01/13 01:35:47 rjshade: rch pointed out an issue with RequestHead
rjshade 2015/01/13 15:22:36 This call to RequestHeadersToSpdy4Headers is just
+ client.SendRequestAndWaitForResponse(headers, FLAGS_body, /*fin=*/true);
- if (!client.Connect()) {
- LOG(ERROR) << "Client failed to connect to host: "
- << FLAGS_hostname << ":" << FLAGS_port;
- return 1;
+ // Print request and response details.
+ if (!FLAGS_quiet) {
+ cout << "Request:" << endl;
+ cout << "headers:" << endl;
+ for (const std::pair<string, string>& kv : header_block) {
+ cout << " " << kv.first << ": " << kv.second << endl;
+ }
+ cout << "body: " << FLAGS_body << endl;
+ cout << endl << "Response:";
+ cout << "headers: " << client.latest_response_headers() << endl;
+ cout << "body: " << client.latest_response_body() << endl;
}
- // Send a GET request for each supplied url.
- client.SendRequestsAndWaitForResponse(urls);
- return 0;
+ size_t response_code = client.latest_response_code();
+ if (response_code >= 200 && response_code < 300) {
+ cout << "Request succeeded (" << response_code << ")." << endl;
+ return 0;
+ } else if (response_code >= 300 && response_code < 400) {
+ if (FLAGS_redirect_is_success) {
+ cout << "Request succeeded (redirect " << response_code << ")." << endl;
+ return 0;
+ } else {
+ cout << "Request failed (redirect " << response_code << ")." << endl;
+ return 1;
+ }
+ } else {
+ cerr << "Request failed (" << response_code << ")." << endl;
+ return 1;
+ }
}

Powered by Google App Engine
This is Rietveld 408576698