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

Side by Side 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // A binary wrapper for QuicClient. 5 // A binary wrapper for QuicClient.
6 // Connects to a host using QUIC, and sends requests to the provided URLS. 6 // Connects to a host using QUIC, sends a request to the provided URL, and
7 // displays the response.
7 // 8 //
8 // Example usage: 9 // Some usage examples:
9 // quic_client --address=127.0.0.1 --port=6122 --hostname=www.google.com 10 //
10 // http://www.google.com/index.html http://www.google.com/favicon.ico 11 // TODO(rtenneti): make --host optional by getting IP Address of URL's host.
12 //
13 // Get IP address of the www.google.com
14 // IP=`dig www.google.com +short | head -1`
15 //
16 // Standard request/response:
17 // quic_client http://www.google.com --host=${IP}
18 // quic_client http://www.google.com --quiet --host=${IP}
19 // quic_client https://www.google.com --port=443 --host=${IP}
20 //
21 // Use a specific version:
22 // quic_client http://www.google.com --version=23 --host=${IP}
23 //
24 // Send a POST instead of a GET:
25 // quic_client http://www.google.com --body="this is a POST body" --host=${IP}
26 //
27 // Append additional headers to the request:
28 // quic_client http://www.google.com --host=${IP}
29 // --headers="Header-A: 1234; Header-B: 5678"
30 //
31 // Connect to a host different to the URL being requested:
32 // Get IP address of the www.google.com
33 // IP=`dig www.google.com +short | head -1`
34 // quic_client mail.google.com --host=${IP}
35 //
36 // Try to connect to a host which does not speak QUIC:
37 // Get IP address of the www.example.com
38 // IP=`dig www.example.com +short | head -1`
39 // quic_client http://www.example.com --host=${IP}
11 40
12 #include <iostream> 41 #include <iostream>
13 42
14 #include "base/at_exit.h" 43 #include "base/at_exit.h"
15 #include "base/command_line.h" 44 #include "base/command_line.h"
16 #include "base/logging.h" 45 #include "base/logging.h"
17 #include "base/strings/string_number_conversions.h" 46 #include "base/strings/string_number_conversions.h"
47 #include "base/strings/string_split.h"
48 #include "base/strings/string_util.h"
18 #include "net/base/ip_endpoint.h" 49 #include "net/base/ip_endpoint.h"
19 #include "net/base/privacy_mode.h" 50 #include "net/base/privacy_mode.h"
20 #include "net/quic/quic_protocol.h" 51 #include "net/quic/quic_protocol.h"
21 #include "net/quic/quic_server_id.h" 52 #include "net/quic/quic_server_id.h"
53 #include "net/quic/quic_utils.h"
22 #include "net/tools/epoll_server/epoll_server.h" 54 #include "net/tools/epoll_server/epoll_server.h"
23 #include "net/tools/quic/quic_client.h" 55 #include "net/tools/quic/quic_client.h"
56 #include "net/tools/quic/spdy_utils.h"
57 #include "url/gurl.h"
24 58
25 std::string FLAGS_address = "127.0.0.1"; 59 using base::StringPiece;
60 using std::cout;
61 using std::cerr;
62 using std::map;
63 using std::string;
64 using std::vector;
65 using std::endl;
66
26 // The IP or hostname the quic client will connect to. 67 // The IP or hostname the quic client will connect to.
27 std::string FLAGS_hostname = "localhost"; 68 string FLAGS_host = "";
28 // The port the quic client will connect to. 69 // The port to connect to.
29 int32 FLAGS_port = 6121; 70 int32 FLAGS_port = 80;
30 // Check the certificates using proof verifier. 71 // If set, send a POST with this body.
31 bool FLAGS_secure = false; 72 string FLAGS_body = "";
32 // QUIC version to speak, e.g. 21. Default value of 0 means 'use the latest 73 // A semicolon separated list of key:value pairs to add to request headers.
33 // version'. 74 string FLAGS_headers = "";
34 int32 FLAGS_quic_version = 0; 75 // Set to true for a quieter output experience.
35 // Size of flow control receive window to advertize to the peer. 76 bool FLAGS_quiet = false;
36 int32 FLAGS_flow_control_window_bytes = 10 * 1024 * 1024; // 10 Mb 77 // QUIC version to speak, e.g. 21. If not set, then all available versions are
78 // offered in the handshake.
79 int32 FLAGS_quic_version = -1;
80 // If true, a version mismatch in the handshake is not considered a failure.
81 // Useful for probing a server to determine if it speaks any version of QUIC.
82 bool FLAGS_version_mismatch_ok = false;
83 // If true, an HTTP response code of 3xx is considered to be a successful
84 // response, otherwise a failure.
85 bool FLAGS_redirect_is_success = true;
37 86
38 int main(int argc, char *argv[]) { 87 int main(int argc, char *argv[]) {
39 base::CommandLine::Init(argc, argv); 88 base::CommandLine::Init(argc, argv);
40 base::CommandLine* line = base::CommandLine::ForCurrentProcess(); 89 base::CommandLine* line = base::CommandLine::ForCurrentProcess();
41 const base::CommandLine::StringVector& urls = line->GetArgs(); 90 const base::CommandLine::StringVector& urls = line->GetArgs();
42 91
43 logging::LoggingSettings settings; 92 logging::LoggingSettings settings;
44 settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; 93 settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
45 CHECK(logging::InitLogging(settings)); 94 CHECK(logging::InitLogging(settings));
46 95
47 if (line->HasSwitch("h") || line->HasSwitch("help") || urls.empty()) { 96 if (line->HasSwitch("h") || line->HasSwitch("help") || urls.empty()) {
48 const char* help_str = 97 const char* help_str =
49 "Usage: quic_client [options] <url> ...\n" 98 "Usage: quic_client [options] <url>\n"
50 "\n" 99 "\n"
51 "At least one <url> with scheme must be provided " 100 "<url> with scheme must be provided (e.g. http://www.google.com)\n\n"
52 "(e.g. http://www.google.com/)\n\n"
53 "Options:\n" 101 "Options:\n"
54 "-h, --help show this help message and exit\n" 102 "-h, --help show this help message and exit\n"
103 "--host=<host> specify the IP address of the hostname to "
104 "connect to\n"
55 "--port=<port> specify the port to connect to\n" 105 "--port=<port> specify the port to connect to\n"
56 "--address=<address> specify the IP address to connect to\n" 106 "--body=<body> specify the body to post\n"
57 "--host=<host> specify the SNI hostname to use\n" 107 "--headers=<headers> specify a semicolon separated list of "
58 "--secure check certificates\n" 108 "key:value pairs to add to request headers\n"
109 "--quiet specify for a quieter output experience\n"
59 "--quic-version=<quic version> specify QUIC version to speak\n" 110 "--quic-version=<quic version> specify QUIC version to speak\n"
60 "--flow-control-window-bytes=<bytes> specify size of flow control " 111 "--version_mismatch_ok if specified a version mismatch in the "
61 "receive window to advertize to the peer\n"; 112 "handshake is not considered a failure\n"
62 std::cout << help_str; 113 "--redirect_is_success if specified an HTTP response code of 3xx "
114 "is considered to be a successful response, otherwise a failure\n";
115 cout << help_str;
63 exit(0); 116 exit(0);
64 } 117 }
118 if (line->HasSwitch("host")) {
119 FLAGS_host = line->GetSwitchValueASCII("host");
120 }
65 if (line->HasSwitch("port")) { 121 if (line->HasSwitch("port")) {
66 int port; 122 int port;
67 if (base::StringToInt(line->GetSwitchValueASCII("port"), &port)) { 123 if (base::StringToInt(line->GetSwitchValueASCII("port"), &port)) {
68 FLAGS_port = port; 124 FLAGS_port = port;
69 } 125 }
70 } 126 }
71 if (line->HasSwitch("address")) { 127 if (line->HasSwitch("body")) {
72 FLAGS_address = line->GetSwitchValueASCII("address"); 128 FLAGS_body = line->GetSwitchValueASCII("body");
73 } 129 }
74 if (line->HasSwitch("hostname")) { 130 if (line->HasSwitch("headers")) {
75 FLAGS_hostname = line->GetSwitchValueASCII("hostname"); 131 FLAGS_headers = line->GetSwitchValueASCII("headers");
76 } 132 }
77 if (line->HasSwitch("secure")) { 133 if (line->HasSwitch("quiet")) {
78 FLAGS_secure = true; 134 FLAGS_quiet = true;
79 } 135 }
80 if (line->HasSwitch("quic-version")) { 136 if (line->HasSwitch("quic-version")) {
81 int quic_version; 137 int quic_version;
82 if (base::StringToInt(line->GetSwitchValueASCII("quic-version"), 138 if (base::StringToInt(line->GetSwitchValueASCII("quic-version"),
83 &quic_version)) { 139 &quic_version)) {
84 FLAGS_quic_version = quic_version; 140 FLAGS_quic_version = quic_version;
85 } 141 }
86 } 142 }
87 if (line->HasSwitch("flow-control-window-bytes")) { 143 if (line->HasSwitch("version_mismatch_ok")) {
88 int flow_control_window_bytes; 144 FLAGS_version_mismatch_ok = true;
89 if (base::StringToInt(
90 line->GetSwitchValueASCII("flow-control-window-bytes"),
91 &flow_control_window_bytes)) {
92 FLAGS_flow_control_window_bytes = flow_control_window_bytes;
93 }
94 } 145 }
95 VLOG(1) << "server port: " << FLAGS_port 146 if (line->HasSwitch("redirect_is_success")) {
96 << " address: " << FLAGS_address 147 FLAGS_redirect_is_success = true;
97 << " hostname: " << FLAGS_hostname 148 }
98 << " secure: " << FLAGS_secure 149
99 << " quic-version: " << FLAGS_quic_version; 150 VLOG(1) << "server host: " << FLAGS_host << " port: " << FLAGS_port
151 << " body: " << FLAGS_body << " headers: " << FLAGS_headers
152 << " quiet: " << FLAGS_quiet
153 << " quic-version: " << FLAGS_quic_version
154 << " version_mismatch_ok: " << FLAGS_version_mismatch_ok
155 << " redirect_is_success: " << FLAGS_redirect_is_success;
100 156
101 base::AtExitManager exit_manager; 157 base::AtExitManager exit_manager;
102 158
103 // Determine IP address to connect to from supplied hostname. 159 // Determine IP address to connect to from supplied hostname.
104 net::IPAddressNumber addr; 160 net::IPAddressNumber ip_addr;
105 CHECK(net::ParseIPLiteralToNumber(FLAGS_address, &addr));
106 161
107 // Populate version vector with all versions if none specified. 162 // TODO(rtenneti): GURL's doesn't support default_protocol argument, thus
108 net::QuicVersionVector versions; 163 // protocol is required in the URL.
109 if (FLAGS_quic_version == 0) { 164 GURL url(urls[0]);
110 versions = net::QuicSupportedVersions(); 165 string host = FLAGS_host;
111 } else { 166 // TODO(rtenneti): get ip_addr from hostname by doing host resolution.
167 CHECK(!host.empty());
168 net::ParseIPLiteralToNumber(host, &ip_addr);
169
170 string host_port = net::IPAddressToStringWithPort(ip_addr, FLAGS_port);
171 VLOG(1) << "Resolved " << host << " to " << host_port << endl;
172
173 // Build the client, and try to connect.
174 net::EpollServer epoll_server;
175 net::QuicServerId server_id(host, FLAGS_port, /*is_https=*/false,
176 net::PRIVACY_MODE_DISABLED);
177 net::QuicVersionVector versions = net::QuicSupportedVersions();
178 if (FLAGS_quic_version != -1) {
179 versions.clear();
112 versions.push_back(static_cast<net::QuicVersion>(FLAGS_quic_version)); 180 versions.push_back(static_cast<net::QuicVersion>(FLAGS_quic_version));
113 } 181 }
114 182 net::tools::QuicClient client(net::IPEndPoint(ip_addr, FLAGS_port), server_id,
115 // Build the client, and try to connect. 183 versions, &epoll_server);
116 VLOG(1) << "Conecting to " << FLAGS_hostname << ":" << FLAGS_port 184 if (!client.Initialize()) {
117 << " with supported versions " 185 cerr << "Failed to initialize client." << endl;
118 << QuicVersionVectorToString(versions);
119 net::EpollServer epoll_server;
120
121 net::tools::QuicClient client(
122 net::IPEndPoint(addr, FLAGS_port),
123 net::QuicServerId(FLAGS_hostname, FLAGS_port, FLAGS_secure,
124 net::PRIVACY_MODE_DISABLED),
125 versions, true, &epoll_server);
126
127 client.Initialize();
128
129 if (!client.Connect()) {
130 LOG(ERROR) << "Client failed to connect to host: "
131 << FLAGS_hostname << ":" << FLAGS_port;
132 return 1; 186 return 1;
133 } 187 }
188 if (!client.Connect()) {
189 net::QuicErrorCode error = client.session()->error();
190 if (FLAGS_version_mismatch_ok && error == net::QUIC_INVALID_VERSION) {
191 cout << "Server talks QUIC, but none of the versions supoorted by "
192 << "this client: " << QuicVersionVectorToString(versions) << endl;
193 // Version mismatch is not deemed a failure.
194 return 0;
195 }
196 cerr << "Failed to connect to " << host_port
197 << ". Error: " << net::QuicUtils::ErrorToString(error) << endl;
198 return 1;
199 }
200 cout << "Connected to " << host_port << endl;
134 201
135 // Send a GET request for each supplied url. 202 // Construct a GET or POST request for supplied URL.
136 client.SendRequestsAndWaitForResponse(urls); 203 net::BalsaHeaders headers;
137 return 0; 204 headers.SetRequestFirstlineFromStringPieces(
205 FLAGS_body.empty() ? "GET" : "POST", url.spec(), "HTTP/1.1");
206
207 // Append any additional headers supplied on the command line.
208 vector<string> headers_tokenized;
209 Tokenize(FLAGS_headers, ";", &headers_tokenized);
210 for (size_t i = 0; i < headers_tokenized.size(); ++i) {
211 string sp;
212 base::TrimWhitespaceASCII(headers_tokenized[i], base::TRIM_ALL, &sp);
213 if (sp.empty()) {
214 continue;
215 }
216 vector<string> kv;
217 base::SplitString(sp, ':', &kv);
218 CHECK_EQ(2u, kv.size());
219 string key;
220 base::TrimWhitespaceASCII(kv[0], base::TRIM_ALL, &key);
221 string value;
222 base::TrimWhitespaceASCII(kv[1], base::TRIM_ALL, &value);
223 headers.AppendHeader(key, value);
224 }
225
226 // Make sure to store the response, for later output.
227 client.set_store_response(true);
228
229 // Send the request.
230 map<string, string> header_block =
231 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
232 client.SendRequestAndWaitForResponse(headers, FLAGS_body, /*fin=*/true);
233
234 // Print request and response details.
235 if (!FLAGS_quiet) {
236 cout << "Request:" << endl;
237 cout << "headers:" << endl;
238 for (const std::pair<string, string>& kv : header_block) {
239 cout << " " << kv.first << ": " << kv.second << endl;
240 }
241 cout << "body: " << FLAGS_body << endl;
242 cout << endl << "Response:";
243 cout << "headers: " << client.latest_response_headers() << endl;
244 cout << "body: " << client.latest_response_body() << endl;
245 }
246
247 size_t response_code = client.latest_response_code();
248 if (response_code >= 200 && response_code < 300) {
249 cout << "Request succeeded (" << response_code << ")." << endl;
250 return 0;
251 } else if (response_code >= 300 && response_code < 400) {
252 if (FLAGS_redirect_is_success) {
253 cout << "Request succeeded (redirect " << response_code << ")." << endl;
254 return 0;
255 } else {
256 cout << "Request failed (redirect " << response_code << ")." << endl;
257 return 1;
258 }
259 } else {
260 cerr << "Request failed (" << response_code << ")." << endl;
261 return 1;
262 }
138 } 263 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698