|
|
|
@ -1,19 +1,19 @@ |
|
|
|
|
extern crate clap; |
|
|
|
|
extern crate rustls; |
|
|
|
|
extern crate tokio; |
|
|
|
|
extern crate tokio_core; |
|
|
|
|
extern crate webpki; |
|
|
|
|
extern crate webpki_roots; |
|
|
|
|
extern crate tokio_rustls; |
|
|
|
|
|
|
|
|
|
#[cfg(unix)] |
|
|
|
|
extern crate tokio_file_unix; |
|
|
|
|
#[cfg(unix)] extern crate tokio_file_unix; |
|
|
|
|
#[cfg(not(unix))] extern crate tokio_fs; |
|
|
|
|
|
|
|
|
|
use std::sync::Arc; |
|
|
|
|
use std::net::ToSocketAddrs; |
|
|
|
|
use std::io::{ BufReader, stdout, stdin }; |
|
|
|
|
use std::io::BufReader; |
|
|
|
|
use std::fs; |
|
|
|
|
use tokio::io; |
|
|
|
|
use tokio::net::TcpStream; |
|
|
|
|
use tokio::prelude::*; |
|
|
|
|
use clap::{ App, Arg }; |
|
|
|
|
use rustls::ClientConfig; |
|
|
|
@ -36,7 +36,7 @@ fn main() { |
|
|
|
|
let port = matches.value_of("port") |
|
|
|
|
.map(|port| port.parse().unwrap()) |
|
|
|
|
.unwrap_or(443); |
|
|
|
|
let domain = matches.value_of("domain").unwrap_or(host); |
|
|
|
|
let domain = matches.value_of("domain").unwrap_or(host).to_owned(); |
|
|
|
|
let cafile = matches.value_of("cafile"); |
|
|
|
|
let text = format!("GET / HTTP/1.0\r\nHost: {}\r\n\r\n", domain); |
|
|
|
|
|
|
|
|
@ -52,61 +52,61 @@ fn main() { |
|
|
|
|
config.root_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS); |
|
|
|
|
} |
|
|
|
|
let arc_config = Arc::new(config); |
|
|
|
|
let domain = webpki::DNSNameRef::try_from_ascii_str(domain).unwrap(); |
|
|
|
|
|
|
|
|
|
// Use async non-blocking I/O for stdin/stdout on Unixy platforms.
|
|
|
|
|
let socket = TcpStream::connect(&addr); |
|
|
|
|
|
|
|
|
|
#[cfg(unix)] |
|
|
|
|
{ |
|
|
|
|
use tokio::io::AsyncRead; |
|
|
|
|
use tokio_core::reactor::Core; |
|
|
|
|
use tokio_core::net::TcpStream; |
|
|
|
|
use tokio_file_unix::{ StdFile, File }; |
|
|
|
|
|
|
|
|
|
let mut core = Core::new().unwrap(); |
|
|
|
|
let handle = core.handle(); |
|
|
|
|
let socket = TcpStream::connect(&addr, &handle); |
|
|
|
|
|
|
|
|
|
let stdin = stdin(); |
|
|
|
|
let stdin = File::new_nb(StdFile(stdin.lock())).unwrap() |
|
|
|
|
.into_io(&handle).unwrap(); |
|
|
|
|
|
|
|
|
|
let stdout = stdout(); |
|
|
|
|
let stdout = File::new_nb(StdFile(stdout.lock())).unwrap() |
|
|
|
|
.into_io(&handle).unwrap(); |
|
|
|
|
|
|
|
|
|
let resp = socket |
|
|
|
|
.and_then(|stream| arc_config.connect_async(domain, stream)) |
|
|
|
|
.and_then(|stream| io::write_all(stream, text.as_bytes())) |
|
|
|
|
.and_then(|(stream, _)| { |
|
|
|
|
let resp = { |
|
|
|
|
use tokio::reactor::Handle; |
|
|
|
|
use tokio_file_unix::{ raw_stdin, raw_stdout, File }; |
|
|
|
|
|
|
|
|
|
let stdin = raw_stdin() |
|
|
|
|
.and_then(File::new_nb) |
|
|
|
|
.and_then(|fd| fd.into_reader(&Handle::current())) |
|
|
|
|
.unwrap(); |
|
|
|
|
let stdout = raw_stdout() |
|
|
|
|
.and_then(File::new_nb) |
|
|
|
|
.and_then(|fd| fd.into_io(&Handle::current())) |
|
|
|
|
.unwrap(); |
|
|
|
|
|
|
|
|
|
socket |
|
|
|
|
.and_then(move |stream| { |
|
|
|
|
let domain = webpki::DNSNameRef::try_from_ascii_str(&domain).unwrap(); |
|
|
|
|
arc_config.connect_async(domain, stream) |
|
|
|
|
}) |
|
|
|
|
.and_then(move |stream| io::write_all(stream, text)) |
|
|
|
|
.and_then(move |(stream, _)| { |
|
|
|
|
let (r, w) = stream.split(); |
|
|
|
|
io::copy(r, stdout) |
|
|
|
|
.map(|_| ()) |
|
|
|
|
.select(io::copy(stdin, w).map(|_| ())) |
|
|
|
|
.map_err(|(e, _)| e) |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
core.run(resp).unwrap(); |
|
|
|
|
} |
|
|
|
|
.map(drop) |
|
|
|
|
.select2(io::copy(stdin, w).map(drop)) |
|
|
|
|
.map_err(|res| res.split().0) |
|
|
|
|
}) |
|
|
|
|
.map(drop) |
|
|
|
|
.map_err(|err| eprintln!("{:?}", err)) |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// XXX: For now, just use blocking I/O for stdin/stdout on other platforms.
|
|
|
|
|
// The network I/O will still be asynchronous and non-blocking.
|
|
|
|
|
#[cfg(not(unix))] |
|
|
|
|
{ |
|
|
|
|
use std::io::{ Read, Write }; |
|
|
|
|
use tokio::net::TcpStream; |
|
|
|
|
|
|
|
|
|
let socket = TcpStream::connect(&addr); |
|
|
|
|
|
|
|
|
|
let mut input = Vec::new(); |
|
|
|
|
stdin().read_to_end(&mut input).unwrap(); |
|
|
|
|
|
|
|
|
|
let resp = socket |
|
|
|
|
.and_then(|stream| arc_config.connect_async(domain, stream)) |
|
|
|
|
.and_then(|stream| io::write_all(stream, text.as_bytes())) |
|
|
|
|
.and_then(|(stream, _)| io::write_all(stream, &input)) |
|
|
|
|
.and_then(|(stream, _)| io::read_to_end(stream, Vec::new())) |
|
|
|
|
.and_then(|(_, output)| stdout().write_all(&output)); |
|
|
|
|
|
|
|
|
|
resp.wait().unwrap(); |
|
|
|
|
} |
|
|
|
|
let resp = { |
|
|
|
|
use tokio_fs::{ stdin as tokio_stdin, stdout as tokio_stdout }; |
|
|
|
|
|
|
|
|
|
let (stdin, stdout) = (tokio_stdin(), tokio_stdout()); |
|
|
|
|
|
|
|
|
|
socket |
|
|
|
|
.and_then(move |stream| { |
|
|
|
|
let domain = webpki::DNSNameRef::try_from_ascii_str(&domain).unwrap(); |
|
|
|
|
arc_config.connect_async(domain, stream) |
|
|
|
|
}) |
|
|
|
|
.and_then(move |stream| io::write_all(stream, text)) |
|
|
|
|
.and_then(move |(stream, _)| { |
|
|
|
|
let (r, w) = stream.split(); |
|
|
|
|
io::copy(r, stdout) |
|
|
|
|
.map(drop) |
|
|
|
|
.join(io::copy(stdin, w).map(drop)) |
|
|
|
|
}) |
|
|
|
|
.map(drop) |
|
|
|
|
.map_err(|err| eprintln!("{:?}", err)) |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
tokio::run(resp); |
|
|
|
|
} |
|
|
|
|