update client example
This commit is contained in:
parent
3ffb736d5e
commit
b8e3fcb79e
@ -2,11 +2,12 @@
|
|||||||
name = "client"
|
name = "client"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["quininer <quininer@live.com>"]
|
authors = ["quininer <quininer@live.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
webpki = "0.19"
|
futures = { package = "futures-preview", version = "0.3.0-alpha.16", features = ["io-compat"] }
|
||||||
|
romio = "0.3.0-alpha.8"
|
||||||
|
structopt = "0.2"
|
||||||
tokio-rustls = { path = "../.." }
|
tokio-rustls = { path = "../.." }
|
||||||
tokio = "0.1"
|
|
||||||
clap = "2"
|
|
||||||
webpki-roots = "0.16"
|
webpki-roots = "0.16"
|
||||||
tokio-stdin-stdout = "0.1"
|
tokio-stdin-stdout = "0.1"
|
||||||
|
@ -1,74 +1,79 @@
|
|||||||
extern crate clap;
|
#![feature(async_await)]
|
||||||
extern crate tokio;
|
|
||||||
extern crate webpki;
|
|
||||||
extern crate webpki_roots;
|
|
||||||
extern crate tokio_rustls;
|
|
||||||
|
|
||||||
extern crate tokio_stdin_stdout;
|
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::net::ToSocketAddrs;
|
use std::net::ToSocketAddrs;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
use std::fs;
|
use structopt::StructOpt;
|
||||||
use tokio::io;
|
use romio::TcpStream;
|
||||||
use tokio::net::TcpStream;
|
use futures::prelude::*;
|
||||||
use tokio::prelude::*;
|
use futures::executor;
|
||||||
use clap::{ App, Arg };
|
use futures::compat::{ AsyncRead01CompatExt, AsyncWrite01CompatExt };
|
||||||
use tokio_rustls::{ TlsConnector, rustls::ClientConfig };
|
use tokio_rustls::{ TlsConnector, rustls::ClientConfig, webpki::DNSNameRef };
|
||||||
use tokio_stdin_stdout::{ stdin as tokio_stdin, stdout as tokio_stdout };
|
use tokio_stdin_stdout::{ stdin as tokio_stdin, stdout as tokio_stdout };
|
||||||
|
|
||||||
fn app() -> App<'static, 'static> {
|
|
||||||
App::new("client")
|
#[derive(StructOpt)]
|
||||||
.about("tokio-rustls client example")
|
struct Options {
|
||||||
.arg(Arg::with_name("host").value_name("HOST").required(true))
|
host: String,
|
||||||
.arg(Arg::with_name("port").short("p").long("port").value_name("PORT").help("port, default `443`"))
|
|
||||||
.arg(Arg::with_name("domain").short("d").long("domain").value_name("DOMAIN").help("domain"))
|
/// port
|
||||||
.arg(Arg::with_name("cafile").short("c").long("cafile").value_name("FILE").help("CA certificate chain"))
|
#[structopt(short="p", long="port", default_value="443")]
|
||||||
|
port: u16,
|
||||||
|
|
||||||
|
/// domain
|
||||||
|
#[structopt(short="d", long="domain")]
|
||||||
|
domain: Option<String>,
|
||||||
|
|
||||||
|
/// cafile
|
||||||
|
#[structopt(short="c", long="cafile", parse(from_os_str))]
|
||||||
|
cafile: Option<PathBuf>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() -> io::Result<()> {
|
||||||
let matches = app().get_matches();
|
let options = Options::from_args();
|
||||||
|
|
||||||
let host = matches.value_of("host").unwrap();
|
let addr = (options.host.as_str(), options.port)
|
||||||
let port = matches.value_of("port")
|
.to_socket_addrs()?
|
||||||
.map(|port| port.parse().unwrap())
|
.next()
|
||||||
.unwrap_or(443);
|
.ok_or_else(|| io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
let domain = matches.value_of("domain").unwrap_or(host).to_owned();
|
let domain = options.domain.unwrap_or(options.host);
|
||||||
let cafile = matches.value_of("cafile");
|
let content = format!(
|
||||||
let text = format!("GET / HTTP/1.0\r\nHost: {}\r\n\r\n", domain);
|
"GET / HTTP/1.0\r\nHost: {}\r\n\r\n",
|
||||||
|
domain
|
||||||
let addr = (host, port)
|
);
|
||||||
.to_socket_addrs().unwrap()
|
|
||||||
.next().unwrap();
|
|
||||||
|
|
||||||
let mut config = ClientConfig::new();
|
let mut config = ClientConfig::new();
|
||||||
if let Some(cafile) = cafile {
|
if let Some(cafile) = &options.cafile {
|
||||||
let mut pem = BufReader::new(fs::File::open(cafile).unwrap());
|
let mut pem = BufReader::new(File::open(cafile)?);
|
||||||
config.root_store.add_pem_file(&mut pem).unwrap();
|
config.root_store.add_pem_file(&mut pem)
|
||||||
|
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid cert"))?;
|
||||||
} else {
|
} else {
|
||||||
config.root_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
|
config.root_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
|
||||||
}
|
}
|
||||||
let config = TlsConnector::from(Arc::new(config));
|
let connector = TlsConnector::from(Arc::new(config));
|
||||||
|
|
||||||
let socket = TcpStream::connect(&addr);
|
let fut = async {
|
||||||
let (stdin, stdout) = (tokio_stdin(0), tokio_stdout(0));
|
let stream = TcpStream::connect(&addr).await?;
|
||||||
|
let (mut stdin, mut stdout) = (tokio_stdin(0).compat(), tokio_stdout(0).compat());
|
||||||
|
|
||||||
let done = socket
|
let domain = DNSNameRef::try_from_ascii_str(&domain)
|
||||||
.and_then(move |stream| {
|
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid dnsname"))?;
|
||||||
let domain = webpki::DNSNameRef::try_from_ascii_str(&domain).unwrap();
|
|
||||||
config.connect(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)
|
|
||||||
.select2(io::copy(stdin, w).map(drop))
|
|
||||||
.map_err(|res| res.split().0)
|
|
||||||
})
|
|
||||||
.map(drop)
|
|
||||||
.map_err(|err| eprintln!("{:?}", err));
|
|
||||||
|
|
||||||
tokio::run(done);
|
let mut stream = connector.connect(domain, stream).await?;
|
||||||
|
stream.write_all(content.as_bytes()).await?;
|
||||||
|
|
||||||
|
let (mut reader, mut writer) = stream.split();
|
||||||
|
future::try_join(
|
||||||
|
reader.copy_into(&mut stdout),
|
||||||
|
stdin.copy_into(&mut writer)
|
||||||
|
).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
|
executor::block_on(fut)
|
||||||
}
|
}
|
||||||
|
@ -7,5 +7,5 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
futures = { package = "futures-preview", version = "0.3.0-alpha.16" }
|
futures = { package = "futures-preview", version = "0.3.0-alpha.16" }
|
||||||
romio = "0.3.0-alpha.8"
|
romio = "0.3.0-alpha.8"
|
||||||
structopt = "*"
|
structopt = "0.2"
|
||||||
tokio-rustls = { path = "../.." }
|
tokio-rustls = { path = "../.." }
|
||||||
|
Loading…
Reference in New Issue
Block a user