diff options
-rw-r--r-- | net/Cargo.toml | 5 | ||||
-rw-r--r-- | net/src/async.rs | 68 | ||||
-rw-r--r-- | net/src/lib.rs | 26 | ||||
-rw-r--r-- | net/tests/hkp.rs | 143 |
4 files changed, 124 insertions, 118 deletions
diff --git a/net/Cargo.toml b/net/Cargo.toml index bd97084b..c48a7be9 100644 --- a/net/Cargo.toml +++ b/net/Cargo.toml @@ -11,8 +11,9 @@ capnp-rpc = "0.8" failure = "0.1.1" fs2 = "0.4.2" futures = "0.1" -hyper = "0.11" -hyper-tls = "0.1.2" +http = "0.1.5" +hyper = "0.12" +hyper-tls = "0.2" libc = "0.2.33" native-tls = "0.1.4" percent-encoding = "1.0.1" diff --git a/net/src/async.rs b/net/src/async.rs index 9ee962e2..3095c3dc 100644 --- a/net/src/async.rs +++ b/net/src/async.rs @@ -5,9 +5,9 @@ use failure; use futures::{future, Future, Stream}; -use hyper::client::{FutureResponse, HttpConnector}; -use hyper::header::{ContentLength, ContentType}; -use hyper::{self, Client, StatusCode, Request, Method}; +use hyper::client::{ResponseFuture, HttpConnector}; +use hyper::header::{CONTENT_LENGTH, CONTENT_TYPE, HeaderValue}; +use hyper::{self, Client, Body, StatusCode, Request}; use hyper_tls::HttpsConnector; use native_tls::{Certificate, TlsConnector}; use percent_encoding::{percent_encode, DEFAULT_ENCODE_SET}; @@ -40,15 +40,14 @@ const DNS_WORKER: usize = 4; impl KeyServer { /// Returns a handle for the given URI. - pub fn new(ctx: &Context, uri: &str, handle: &Handle) -> Result<Self> { + pub fn new(ctx: &Context, uri: &str, _handle: &Handle) -> Result<Self> { let uri: Url = uri.parse()?; let client: Box<AClient> = match uri.scheme() { - "hkp" => Box::new(Client::new(handle)), + "hkp" => Box::new(Client::new()), "hkps" => { - Box::new(Client::configure() - .connector(HttpsConnector::new(DNS_WORKER, handle)?) - .build(handle)) + Box::new(Client::builder() + .build(HttpsConnector::new(DNS_WORKER)?)) }, _ => return Err(Error::MalformedUri.into()), }; @@ -60,7 +59,7 @@ impl KeyServer { /// /// `cert` is used to authenticate the server. pub fn with_cert(ctx: &Context, uri: &str, cert: Certificate, - handle: &Handle) -> Result<Self> { + _handle: &Handle) -> Result<Self> { let uri: Url = uri.parse()?; let client: Box<AClient> = { @@ -68,11 +67,10 @@ impl KeyServer { ssl.add_root_certificate(cert)?; let ssl = ssl.build()?; - let mut http = HttpConnector::new(DNS_WORKER, handle); + let mut http = HttpConnector::new(DNS_WORKER); http.enforce_http(false); - Box::new(Client::configure() - .connector(HttpsConnector::from((http, ssl))) - .build(handle)) + Box::new(Client::builder() + .build(HttpsConnector::from((http, ssl)))) }; Self::make(ctx, client, uri) @@ -127,14 +125,16 @@ impl KeyServer { .from_err() .and_then(|res| { let status = res.status(); - res.body().concat2().from_err() + res.into_body().concat2().from_err() .and_then(move |body| match status { - StatusCode::Ok => { + StatusCode::OK => { let c = Cursor::new(body.as_ref()); - let r = armor::Reader::new(c, armor::Kind::PublicKey); + let r = armor::Reader::new( + c, armor::Kind::PublicKey); future::done(TPK::from_reader(r)) }, - StatusCode::NotFound => future::err(Error::NotFound.into()), + StatusCode::NOT_FOUND => + future::err(Error::NotFound.into()), n => future::err(Error::HttpStatus(n).into()), }) })) @@ -165,18 +165,28 @@ impl KeyServer { let mut post_data = b"keytext=".to_vec(); post_data.extend_from_slice(percent_encode(&armored_blob, KEYSERVER_ENCODE_SET) .collect::<String>().as_bytes()); + let length = post_data.len(); - let mut request = Request::new(Method::Post, url2uri(uri)); - request.headers_mut().set(ContentType::form_url_encoded()); - request.headers_mut().set(ContentLength(post_data.len() as u64)); - request.set_body(post_data); + let mut request = match Request::post(url2uri(uri)) + .body(Body::from(post_data)) + { + Ok(r) => r, + Err(e) => return Box::new(future::err(Error::from(e).into())), + }; + request.headers_mut().insert( + CONTENT_TYPE, + HeaderValue::from_static("application/x-www-form-urlencoded")); + request.headers_mut().insert( + CONTENT_LENGTH, + HeaderValue::from_str(&format!("{}", length)) + .expect("cannot fail: only ASCII characters")); Box::new(self.client.do_request(request) .from_err() .and_then(|res| { match res.status() { - StatusCode::Ok => future::ok(()), - StatusCode::NotFound => future::err(Error::ProtocolViolation.into()), + StatusCode::OK => future::ok(()), + StatusCode::NOT_FOUND => future::err(Error::ProtocolViolation.into()), n => future::err(Error::HttpStatus(n).into()), } })) @@ -184,24 +194,24 @@ impl KeyServer { } trait AClient { - fn do_get(&mut self, uri: Url) -> FutureResponse; - fn do_request(&mut self, request: Request) -> FutureResponse; + fn do_get(&mut self, uri: Url) -> ResponseFuture; + fn do_request(&mut self, request: Request<Body>) -> ResponseFuture; } impl AClient for Client<HttpConnector> { - fn do_get(&mut self, uri: Url) -> FutureResponse { + fn do_get(&mut self, uri: Url) -> ResponseFuture { self.get(url2uri(uri)) } - fn do_request(&mut self, request: Request) -> FutureResponse { + fn do_request(&mut self, request: Request<Body>) -> ResponseFuture { self.request(request) } } impl AClient for Client<HttpsConnector<HttpConnector>> { - fn do_get(&mut self, uri: Url) -> FutureResponse { + fn do_get(&mut self, uri: Url) -> ResponseFuture { self.get(url2uri(uri)) } - fn do_request(&mut self, request: Request) -> FutureResponse { + fn do_request(&mut self, request: Request<Body>) -> ResponseFuture { self.request(request) } } diff --git a/net/src/lib.rs b/net/src/lib.rs index d01aa93d..bb9c0bf4 100644 --- a/net/src/lib.rs +++ b/net/src/lib.rs @@ -36,6 +36,7 @@ extern crate sequoia_core; #[macro_use] extern crate failure; extern crate futures; +extern crate http; extern crate hyper; extern crate hyper_tls; extern crate native_tls; @@ -47,8 +48,8 @@ extern crate url; extern crate capnp_rpc; -use hyper::client::{FutureResponse, HttpConnector}; -use hyper::{Client, Request}; +use hyper::client::{ResponseFuture, HttpConnector}; +use hyper::{Client, Request, Body}; use hyper_tls::HttpsConnector; use native_tls::Certificate; use std::convert::From; @@ -114,24 +115,24 @@ impl KeyServer { } trait AClient { - fn do_get(&mut self, uri: Url) -> FutureResponse; - fn do_request(&mut self, request: Request) -> FutureResponse; + fn do_get(&mut self, uri: Url) -> ResponseFuture; + fn do_request(&mut self, request: Request<Body>) -> ResponseFuture; } impl AClient for Client<HttpConnector> { - fn do_get(&mut self, uri: Url) -> FutureResponse { + fn do_get(&mut self, uri: Url) -> ResponseFuture { self.get(url2uri(uri)) } - fn do_request(&mut self, request: Request) -> FutureResponse { + fn do_request(&mut self, request: Request<Body>) -> ResponseFuture { self.request(request) } } impl AClient for Client<HttpsConnector<HttpConnector>> { - fn do_get(&mut self, uri: Url) -> FutureResponse { + fn do_get(&mut self, uri: Url) -> ResponseFuture { self.get(url2uri(uri)) } - fn do_request(&mut self, request: Request) -> FutureResponse { + fn do_request(&mut self, request: Request<Body>) -> ResponseFuture { self.request(request) } } @@ -160,6 +161,9 @@ pub enum Error { /// A `hyper::error::UriError` occurred. #[fail(display = "URI Error")] UriError(url::ParseError), + /// A `http::Error` occurred. + #[fail(display = "http Error")] + HttpError(http::Error), /// A `hyper::Error` occurred. #[fail(display = "Hyper Error")] HyperError(hyper::Error), @@ -168,6 +172,12 @@ pub enum Error { TlsError(native_tls::Error), } +impl From<http::Error> for Error { + fn from(e: http::Error) -> Error { + Error::HttpError(e) + } +} + impl From<hyper::Error> for Error { fn from(e: hyper::Error) -> Error { Error::HyperError(e) diff --git a/net/tests/hkp.rs b/net/tests/hkp.rs index d3da0f93..b2d68bb0 100644 --- a/net/tests/hkp.rs +++ b/net/tests/hkp.rs @@ -1,4 +1,5 @@ extern crate futures; +extern crate http; extern crate hyper; extern crate rand; extern crate url; @@ -7,8 +8,9 @@ use futures::Stream; use futures::future::Future; use futures::sync::oneshot; -use hyper::header::ContentLength; -use hyper::server::{Http, Request, Response, Service}; +use http::{Request, Response}; +use hyper::{Server, Body}; +use hyper::service::service_fn; use hyper::{Method, StatusCode}; use rand::Rng; use rand::os::OsRng; @@ -26,8 +28,6 @@ use openpgp::{Fingerprint, KeyID}; use sequoia_core::{Context, NetworkPolicy}; use sequoia_net::KeyServer; -struct HKPServer; - const RESPONSE: &'static str = "-----BEGIN PGP PUBLIC KEY BLOCK----- xsBNBFoVcvoBCACykTKOJddF8SSUAfCDHk86cNTaYnjCoy72rMgWJsrMLnz/V16B @@ -63,61 +63,53 @@ Pu1xwz57O4zo1VYf6TqHJzVC3OMvMUM2hhdecMUe5x6GorNaj6g= const FP: &'static str = "3E8877C877274692975189F5D03F6F865226FE8B"; const ID: &'static str = "D03F6F865226FE8B"; -impl Service for HKPServer { - type Request = Request; - type Response = Response; - type Error = hyper::Error; - type Future = Box<Future<Item=Self::Response, Error=Self::Error>>; - - fn call(&self, req: Request) -> Self::Future { - match (req.method(), req.path()) { - (&Method::Get, "/pks/lookup") => { - if let Some(args) = req.query() { - for (key, value) in url::form_urlencoded::parse(args.as_bytes()) { - match key.clone().into_owned().as_ref() { - "op" => assert_eq!(value, "get"), - "options" => assert_eq!(value, "mr"), - "search" => assert_eq!(value, "0xD03F6F865226FE8B"), - _ => panic!("Bad query: {}:{}", key, value), - } +fn service(req: Request<Body>) + -> Box<Future<Item=Response<Body>, Error=hyper::Error> + Send> { + let (parts, body) = req.into_parts(); + match (parts.method, parts.uri.path()) { + (Method::GET, "/pks/lookup") => { + if let Some(args) = parts.uri.query() { + for (key, value) in url::form_urlencoded::parse(args.as_bytes()) { + match key.clone().into_owned().as_ref() { + "op" => assert_eq!(value, "get"), + "options" => assert_eq!(value, "mr"), + "search" => assert_eq!(value, "0xD03F6F865226FE8B"), + _ => panic!("Bad query: {}:{}", key, value), } - } else { - panic!("Expected query string"); } + } else { + panic!("Expected query string"); + } - Box::new(futures::future::ok(Response::new() - .with_header(ContentLength(RESPONSE.len() as u64)) - .with_body(RESPONSE))) - }, - (&Method::Post, "/pks/add") => { - Box::new( - req.body().concat2() - .map(|b| { - for (key, value) in url::form_urlencoded::parse(b.as_ref()) { - match key.clone().into_owned().as_ref() { - "keytext" => { - let key = TPK::from_reader( - Reader::new(Cursor::new(value.into_owned()), - Kind::Any)).unwrap(); - assert_eq!( - key.fingerprint(), - Fingerprint::from_hex(FP) - .unwrap()); - }, - _ => panic!("Bad post: {}:{}", key, value), - } - } - - Response::new() - .with_header(ContentLength("Ok".len() as u64)) - .with_body("Ok") - })) - }, - _ => { - Box::new(futures::future::ok(Response::new() - .with_status(StatusCode::NotFound))) - }, - } + Box::new(futures::future::ok(Response::new(Body::from(RESPONSE)))) + }, + (Method::POST, "/pks/add") => { + Box::new( + body.concat2() + .map(|b| { + for (key, value) in url::form_urlencoded::parse(b.as_ref()) { + match key.clone().into_owned().as_ref() { + "keytext" => { + let key = TPK::from_reader( + Reader::new(Cursor::new(value.into_owned()), + Kind::Any)).unwrap(); + assert_eq!( + key.fingerprint(), + Fingerprint::from_hex(FP) + .unwrap()); + }, + _ => panic!("Bad post: {}:{}", key, value), + } + } + + Response::new(Body::from("Ok")) + })) + }, + _ => { + Box::new(futures::future::ok(Response::builder() + .status(StatusCode::NOT_FOUND) + .body(Body::from("Not found")).unwrap())) + }, } } @@ -125,25 +117,26 @@ impl Service for HKPServer { /// /// Returns the address, a channel to drop() to kill the server, and /// the thread handle to join the server thread. -fn start_server() -> (SocketAddr, oneshot::Sender<()>, thread::JoinHandle<()>) { - let (keep_going, done) = oneshot::channel::<()>(); +fn start_server() -> SocketAddr { let (tx, rx) = oneshot::channel::<SocketAddr>(); - let t = thread::spawn(move || { - let server = loop { + thread::spawn(move || { + let (addr, server) = loop { let port = OsRng::new().unwrap().next_u32() as u16; - if let Ok(s) = Http::new().bind( - &SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port), - || Ok(HKPServer)) { - break s; + let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), + port); + if let Ok(s) = Server::try_bind(&addr) { + break (addr, s); } }; - tx.send(server.local_addr().unwrap()).unwrap(); - server.run_until(done.map_err(|_| ())).unwrap(); + + tx.send(addr).unwrap(); + hyper::rt::run(server + .serve(|| service_fn(service)) + .map_err(|e| panic!(e))); }); let addr = rx.wait().unwrap(); - - (addr, keep_going, t) + addr } #[test] @@ -154,7 +147,7 @@ fn get() { .build().unwrap(); // Start server. - let (addr, keep_going, t) = start_server(); + let addr = start_server(); let mut keyserver = KeyServer::new(&ctx, &format!("hkp://{}", addr)).unwrap(); @@ -163,10 +156,6 @@ fn get() { assert_eq!(key.fingerprint(), Fingerprint::from_hex(FP).unwrap()); - - // Kill server, join. - drop(keep_going); - t.join().unwrap(); } #[test] @@ -177,15 +166,11 @@ fn send() { .build().unwrap(); // Start server. - let (addr, keep_going, t) = start_server(); - + let addr = start_server(); + eprintln!("{}", format!("hkp://{}", addr)); let mut keyserver = KeyServer::new(&ctx, &format!("hkp://{}", addr)).unwrap(); let key = TPK::from_reader(Reader::new(Cursor::new(RESPONSE), Kind::Any)).unwrap(); keyserver.send(&key).unwrap(); - - // Kill server, join. - drop(keep_going); - t.join().unwrap(); } |