| OLD | NEW |
| 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, sends a request to the provided URL, and | 6 // Connects to a host using QUIC, sends a request to the provided URL, and |
| 7 // displays the response. | 7 // displays the response. |
| 8 // | 8 // |
| 9 // Some usage examples: | 9 // Some usage examples: |
| 10 // | 10 // |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 using std::string; | 77 using std::string; |
| 78 using std::vector; | 78 using std::vector; |
| 79 using std::endl; | 79 using std::endl; |
| 80 | 80 |
| 81 // The IP or hostname the quic client will connect to. | 81 // The IP or hostname the quic client will connect to. |
| 82 string FLAGS_host = ""; | 82 string FLAGS_host = ""; |
| 83 // The port to connect to. | 83 // The port to connect to. |
| 84 int32 FLAGS_port = 0; | 84 int32 FLAGS_port = 0; |
| 85 // If set, send a POST with this body. | 85 // If set, send a POST with this body. |
| 86 string FLAGS_body = ""; | 86 string FLAGS_body = ""; |
| 87 // If set, contents are converted from hex to ascii, before sending as body of |
| 88 // a POST. e.g. --body_hex=\"68656c6c6f\" |
| 89 string FLAGS_body_hex = ""; |
| 87 // A semicolon separated list of key:value pairs to add to request headers. | 90 // A semicolon separated list of key:value pairs to add to request headers. |
| 88 string FLAGS_headers = ""; | 91 string FLAGS_headers = ""; |
| 89 // Set to true for a quieter output experience. | 92 // Set to true for a quieter output experience. |
| 90 bool FLAGS_quiet = false; | 93 bool FLAGS_quiet = false; |
| 91 // QUIC version to speak, e.g. 21. If not set, then all available versions are | 94 // QUIC version to speak, e.g. 21. If not set, then all available versions are |
| 92 // offered in the handshake. | 95 // offered in the handshake. |
| 93 int32 FLAGS_quic_version = -1; | 96 int32 FLAGS_quic_version = -1; |
| 94 // If true, a version mismatch in the handshake is not considered a failure. | 97 // If true, a version mismatch in the handshake is not considered a failure. |
| 95 // Useful for probing a server to determine if it speaks any version of QUIC. | 98 // Useful for probing a server to determine if it speaks any version of QUIC. |
| 96 bool FLAGS_version_mismatch_ok = false; | 99 bool FLAGS_version_mismatch_ok = false; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 111 const net::CompletionCallback& callback, | 114 const net::CompletionCallback& callback, |
| 112 scoped_ptr<net::CertVerifier::Request>* out_req, | 115 scoped_ptr<net::CertVerifier::Request>* out_req, |
| 113 const net::BoundNetLog& net_log) override { | 116 const net::BoundNetLog& net_log) override { |
| 114 return net::OK; | 117 return net::OK; |
| 115 } | 118 } |
| 116 | 119 |
| 117 // Returns true if this CertVerifier supports stapled OCSP responses. | 120 // Returns true if this CertVerifier supports stapled OCSP responses. |
| 118 bool SupportsOCSPStapling() override { return false; } | 121 bool SupportsOCSPStapling() override { return false; } |
| 119 }; | 122 }; |
| 120 | 123 |
| 124 static bool DecodeHexString(const base::StringPiece& hex, std::string* bytes) { |
| 125 bytes->clear(); |
| 126 if (hex.empty()) |
| 127 return true; |
| 128 std::vector<uint8> v; |
| 129 if (!base::HexStringToBytes(hex.as_string(), &v)) |
| 130 return false; |
| 131 if (!v.empty()) |
| 132 bytes->assign(reinterpret_cast<const char*>(&v[0]), v.size()); |
| 133 return true; |
| 134 }; |
| 135 |
| 121 int main(int argc, char *argv[]) { | 136 int main(int argc, char *argv[]) { |
| 122 base::CommandLine::Init(argc, argv); | 137 base::CommandLine::Init(argc, argv); |
| 123 base::CommandLine* line = base::CommandLine::ForCurrentProcess(); | 138 base::CommandLine* line = base::CommandLine::ForCurrentProcess(); |
| 124 const base::CommandLine::StringVector& urls = line->GetArgs(); | 139 const base::CommandLine::StringVector& urls = line->GetArgs(); |
| 125 | 140 |
| 126 logging::LoggingSettings settings; | 141 logging::LoggingSettings settings; |
| 127 settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; | 142 settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; |
| 128 CHECK(logging::InitLogging(settings)); | 143 CHECK(logging::InitLogging(settings)); |
| 129 | 144 |
| 130 FLAGS_quic_supports_trailers = true; | 145 FLAGS_quic_supports_trailers = true; |
| 131 | 146 |
| 132 if (line->HasSwitch("h") || line->HasSwitch("help") || urls.empty()) { | 147 if (line->HasSwitch("h") || line->HasSwitch("help") || urls.empty()) { |
| 133 const char* help_str = | 148 const char* help_str = |
| 134 "Usage: quic_client [options] <url>\n" | 149 "Usage: quic_client [options] <url>\n" |
| 135 "\n" | 150 "\n" |
| 136 "<url> with scheme must be provided (e.g. http://www.google.com)\n\n" | 151 "<url> with scheme must be provided (e.g. http://www.google.com)\n\n" |
| 137 "Options:\n" | 152 "Options:\n" |
| 138 "-h, --help show this help message and exit\n" | 153 "-h, --help show this help message and exit\n" |
| 139 "--host=<host> specify the IP address of the hostname to " | 154 "--host=<host> specify the IP address of the hostname to " |
| 140 "connect to\n" | 155 "connect to\n" |
| 141 "--port=<port> specify the port to connect to\n" | 156 "--port=<port> specify the port to connect to\n" |
| 142 "--body=<body> specify the body to post\n" | 157 "--body=<body> specify the body to post\n" |
| 158 "--body_hex=<body_hex> specify the body_hex to be printed out\n" |
| 143 "--headers=<headers> specify a semicolon separated list of " | 159 "--headers=<headers> specify a semicolon separated list of " |
| 144 "key:value pairs to add to request headers\n" | 160 "key:value pairs to add to request headers\n" |
| 145 "--quiet specify for a quieter output experience\n" | 161 "--quiet specify for a quieter output experience\n" |
| 146 "--quic-version=<quic version> specify QUIC version to speak\n" | 162 "--quic-version=<quic version> specify QUIC version to speak\n" |
| 147 "--version_mismatch_ok if specified a version mismatch in the " | 163 "--version_mismatch_ok if specified a version mismatch in the " |
| 148 "handshake is not considered a failure\n" | 164 "handshake is not considered a failure\n" |
| 149 "--redirect_is_success if specified an HTTP response code of 3xx " | 165 "--redirect_is_success if specified an HTTP response code of 3xx " |
| 150 "is considered to be a successful response, otherwise a failure\n" | 166 "is considered to be a successful response, otherwise a failure\n" |
| 151 "--initial_mtu=<initial_mtu> specify the initial MTU of the connection" | 167 "--initial_mtu=<initial_mtu> specify the initial MTU of the connection" |
| 152 "\n" | 168 "\n" |
| 153 "--disable-certificate-verification do not verify certificates\n"; | 169 "--disable-certificate-verification do not verify certificates\n"; |
| 154 cout << help_str; | 170 cout << help_str; |
| 155 exit(0); | 171 exit(0); |
| 156 } | 172 } |
| 157 if (line->HasSwitch("host")) { | 173 if (line->HasSwitch("host")) { |
| 158 FLAGS_host = line->GetSwitchValueASCII("host"); | 174 FLAGS_host = line->GetSwitchValueASCII("host"); |
| 159 } | 175 } |
| 160 if (line->HasSwitch("port")) { | 176 if (line->HasSwitch("port")) { |
| 161 if (!base::StringToInt(line->GetSwitchValueASCII("port"), &FLAGS_port)) { | 177 if (!base::StringToInt(line->GetSwitchValueASCII("port"), &FLAGS_port)) { |
| 162 std::cerr << "--port must be an integer\n"; | 178 std::cerr << "--port must be an integer\n"; |
| 163 return 1; | 179 return 1; |
| 164 } | 180 } |
| 165 } | 181 } |
| 166 if (line->HasSwitch("body")) { | 182 if (line->HasSwitch("body")) { |
| 167 FLAGS_body = line->GetSwitchValueASCII("body"); | 183 FLAGS_body = line->GetSwitchValueASCII("body"); |
| 168 } | 184 } |
| 185 if (line->HasSwitch("body_hex")) { |
| 186 FLAGS_body_hex = line->GetSwitchValueASCII("body_hex"); |
| 187 } |
| 169 if (line->HasSwitch("headers")) { | 188 if (line->HasSwitch("headers")) { |
| 170 FLAGS_headers = line->GetSwitchValueASCII("headers"); | 189 FLAGS_headers = line->GetSwitchValueASCII("headers"); |
| 171 } | 190 } |
| 172 if (line->HasSwitch("quiet")) { | 191 if (line->HasSwitch("quiet")) { |
| 173 FLAGS_quiet = true; | 192 FLAGS_quiet = true; |
| 174 } | 193 } |
| 175 if (line->HasSwitch("quic-version")) { | 194 if (line->HasSwitch("quic-version")) { |
| 176 int quic_version; | 195 int quic_version; |
| 177 if (base::StringToInt(line->GetSwitchValueASCII("quic-version"), | 196 if (base::StringToInt(line->GetSwitchValueASCII("quic-version"), |
| 178 &quic_version)) { | 197 &quic_version)) { |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 266 << "this client: " << QuicVersionVectorToString(versions) << endl; | 285 << "this client: " << QuicVersionVectorToString(versions) << endl; |
| 267 // Version mismatch is not deemed a failure. | 286 // Version mismatch is not deemed a failure. |
| 268 return 0; | 287 return 0; |
| 269 } | 288 } |
| 270 cerr << "Failed to connect to " << host_port | 289 cerr << "Failed to connect to " << host_port |
| 271 << ". Error: " << net::QuicUtils::ErrorToString(error) << endl; | 290 << ". Error: " << net::QuicUtils::ErrorToString(error) << endl; |
| 272 return 1; | 291 return 1; |
| 273 } | 292 } |
| 274 cout << "Connected to " << host_port << endl; | 293 cout << "Connected to " << host_port << endl; |
| 275 | 294 |
| 295 // Construct the string body from flags, if provided. |
| 296 string body = FLAGS_body; |
| 297 if (!FLAGS_body_hex.empty()) { |
| 298 DCHECK(FLAGS_body.empty()) << "Only set one of --body and --body_hex."; |
| 299 DecodeHexString(FLAGS_body_hex, &body); |
| 300 } |
| 301 |
| 276 // Construct a GET or POST request for supplied URL. | 302 // Construct a GET or POST request for supplied URL. |
| 277 net::HttpRequestInfo request; | 303 net::HttpRequestInfo request; |
| 278 request.method = FLAGS_body.empty() ? "GET" : "POST"; | 304 request.method = body.empty() ? "GET" : "POST"; |
| 279 request.url = url; | 305 request.url = url; |
| 280 | 306 |
| 281 // Append any additional headers supplied on the command line. | 307 // Append any additional headers supplied on the command line. |
| 282 for (const std::string& header : | 308 for (const std::string& header : |
| 283 base::SplitString(FLAGS_headers, ";", base::KEEP_WHITESPACE, | 309 base::SplitString(FLAGS_headers, ";", base::KEEP_WHITESPACE, |
| 284 base::SPLIT_WANT_NONEMPTY)) { | 310 base::SPLIT_WANT_NONEMPTY)) { |
| 285 string sp; | 311 string sp; |
| 286 base::TrimWhitespaceASCII(header, base::TRIM_ALL, &sp); | 312 base::TrimWhitespaceASCII(header, base::TRIM_ALL, &sp); |
| 287 if (sp.empty()) { | 313 if (sp.empty()) { |
| 288 continue; | 314 continue; |
| 289 } | 315 } |
| 290 vector<string> kv = | 316 vector<string> kv = |
| 291 base::SplitString(sp, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); | 317 base::SplitString(sp, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); |
| 292 CHECK_EQ(2u, kv.size()); | 318 CHECK_EQ(2u, kv.size()); |
| 293 string key; | 319 string key; |
| 294 base::TrimWhitespaceASCII(kv[0], base::TRIM_ALL, &key); | 320 base::TrimWhitespaceASCII(kv[0], base::TRIM_ALL, &key); |
| 295 string value; | 321 string value; |
| 296 base::TrimWhitespaceASCII(kv[1], base::TRIM_ALL, &value); | 322 base::TrimWhitespaceASCII(kv[1], base::TRIM_ALL, &value); |
| 297 request.extra_headers.SetHeader(key, value); | 323 request.extra_headers.SetHeader(key, value); |
| 298 } | 324 } |
| 299 | 325 |
| 300 // Make sure to store the response, for later output. | 326 // Make sure to store the response, for later output. |
| 301 client.set_store_response(true); | 327 client.set_store_response(true); |
| 302 | 328 |
| 303 // Send the request. | 329 // Send the request. |
| 304 net::SpdyHeaderBlock header_block; | 330 net::SpdyHeaderBlock header_block; |
| 305 net::CreateSpdyHeadersFromHttpRequest(request, request.extra_headers, | 331 net::CreateSpdyHeadersFromHttpRequest(request, request.extra_headers, |
| 306 net::HTTP2, /*direct=*/true, | 332 net::HTTP2, /*direct=*/true, |
| 307 &header_block); | 333 &header_block); |
| 308 client.SendRequestAndWaitForResponse(request, FLAGS_body, /*fin=*/true); | 334 client.SendRequestAndWaitForResponse(request, body, /*fin=*/true); |
| 309 | 335 |
| 310 // Print request and response details. | 336 // Print request and response details. |
| 311 if (!FLAGS_quiet) { | 337 if (!FLAGS_quiet) { |
| 312 cout << "Request:" << endl; | 338 cout << "Request:" << endl; |
| 313 cout << "headers:" << header_block.DebugString(); | 339 cout << "headers:" << header_block.DebugString(); |
| 314 cout << "body: " << FLAGS_body << endl; | 340 cout << "body: " << body << endl; |
| 315 cout << endl; | 341 cout << endl; |
| 316 cout << "Response:" << endl; | 342 cout << "Response:" << endl; |
| 317 cout << "headers: " << client.latest_response_headers() << endl; | 343 cout << "headers: " << client.latest_response_headers() << endl; |
| 318 cout << "body: " << client.latest_response_body() << endl; | 344 cout << "body: " << client.latest_response_body() << endl; |
| 319 } | 345 } |
| 320 | 346 |
| 321 size_t response_code = client.latest_response_code(); | 347 size_t response_code = client.latest_response_code(); |
| 322 if (response_code >= 200 && response_code < 300) { | 348 if (response_code >= 200 && response_code < 300) { |
| 323 cout << "Request succeeded (" << response_code << ")." << endl; | 349 cout << "Request succeeded (" << response_code << ")." << endl; |
| 324 return 0; | 350 return 0; |
| 325 } else if (response_code >= 300 && response_code < 400) { | 351 } else if (response_code >= 300 && response_code < 400) { |
| 326 if (FLAGS_redirect_is_success) { | 352 if (FLAGS_redirect_is_success) { |
| 327 cout << "Request succeeded (redirect " << response_code << ")." << endl; | 353 cout << "Request succeeded (redirect " << response_code << ")." << endl; |
| 328 return 0; | 354 return 0; |
| 329 } else { | 355 } else { |
| 330 cout << "Request failed (redirect " << response_code << ")." << endl; | 356 cout << "Request failed (redirect " << response_code << ")." << endl; |
| 331 return 1; | 357 return 1; |
| 332 } | 358 } |
| 333 } else { | 359 } else { |
| 334 cerr << "Request failed (" << response_code << ")." << endl; | 360 cerr << "Request failed (" << response_code << ")." << endl; |
| 335 return 1; | 361 return 1; |
| 336 } | 362 } |
| 337 } | 363 } |
| OLD | NEW |