feat(lib): replace types with those from http crate

BREAKING CHANGE: `Method`, `Request`, `Response`, `StatusCode`,
  `Version`, and `Uri` have been replaced with types from the `http`
  crate. The `hyper::header` module is gone for now.

  Removed `Client::get`, since it needed to construct a `Request<B>`
  with an empty body. Just use `Client::request` instead.

  Removed `compat` cargo feature, and `compat` related API.
This commit is contained in:
Sean McArthur
2018-02-28 16:37:17 -08:00
parent a37e6b59e6
commit 3cd48b45fb
109 changed files with 1004 additions and 14411 deletions

View File

@@ -11,7 +11,7 @@ use std::io::{self, Write};
use futures::Future;
use futures::stream::Stream;
use hyper::Client;
use hyper::{Body, Client, Request};
fn main() {
pretty_env_logger::init();
@@ -25,7 +25,7 @@ fn main() {
};
let url = url.parse::<hyper::Uri>().unwrap();
if url.scheme() != Some("http") {
if url.scheme_part().map(|s| s.as_ref()) != Some("http") {
println!("This example only works with 'http' URLs.");
return;
}
@@ -34,11 +34,13 @@ fn main() {
let handle = core.handle();
let client = Client::new(&handle);
let work = client.get(url).and_then(|res| {
let mut req = Request::new(Body::empty());
*req.uri_mut() = url;
let work = client.request(req).and_then(|res| {
println!("Response: {}", res.status());
println!("Headers: \n{}", res.headers());
println!("Headers: {:#?}", res.headers());
res.body().for_each(|chunk| {
res.into_parts().1.for_each(|chunk| {
io::stdout().write_all(&chunk).map_err(From::from)
})
}).map(|_| {

View File

@@ -3,8 +3,8 @@ extern crate hyper;
extern crate futures;
extern crate pretty_env_logger;
use hyper::header::{ContentLength, ContentType};
use hyper::server::{Http, Response, const_service, service_fn};
use hyper::{Body, Response};
use hyper::server::{Http, const_service, service_fn};
static PHRASE: &'static [u8] = b"Hello World!";
@@ -13,10 +13,7 @@ fn main() {
let addr = ([127, 0, 0, 1], 3000).into();
let new_service = const_service(service_fn(|_| {
Ok(Response::<hyper::Body>::new()
.with_header(ContentLength(PHRASE.len() as u64))
.with_header(ContentType::plaintext())
.with_body(PHRASE))
Ok(Response::new(Body::from(PHRASE)))
}));
let server = Http::new()

View File

@@ -7,10 +7,9 @@ extern crate pretty_env_logger;
use futures::{Future, Stream};
use futures::future::FutureResult;
use hyper::{Get, StatusCode};
use hyper::{Body, Method, Request, Response, StatusCode};
use tokio_core::reactor::Core;
use hyper::header::ContentLength;
use hyper::server::{Http, Service, Request, Response};
use hyper::server::{Http, Service};
static INDEX1: &'static [u8] = b"The 1st service!";
static INDEX2: &'static [u8] = b"The 2nd service!";
@@ -18,21 +17,21 @@ static INDEX2: &'static [u8] = b"The 2nd service!";
struct Srv(&'static [u8]);
impl Service for Srv {
type Request = Request;
type Response = Response;
type Request = Request<Body>;
type Response = Response<Body>;
type Error = hyper::Error;
type Future = FutureResult<Response, hyper::Error>;
type Future = FutureResult<Response<Body>, hyper::Error>;
fn call(&self, req: Request) -> Self::Future {
futures::future::ok(match (req.method(), req.path()) {
(&Get, "/") => {
Response::new()
.with_header(ContentLength(self.0.len() as u64))
.with_body(self.0)
fn call(&self, req: Request<Body>) -> Self::Future {
futures::future::ok(match (req.method(), req.uri().path()) {
(&Method::GET, "/") => {
Response::new(self.0.into())
},
_ => {
Response::new()
.with_status(StatusCode::NotFound)
Response::builder()
.status(StatusCode::NOT_FOUND)
.body(Body::empty())
.unwrap()
}
})
}

View File

@@ -6,9 +6,8 @@ extern crate url;
use futures::{Future, Stream};
use hyper::{Get, Post, StatusCode};
use hyper::header::ContentLength;
use hyper::server::{Http, Service, Request, Response};
use hyper::{Body, Method, Request, Response, StatusCode};
use hyper::server::{Http, Service};
use std::collections::HashMap;
use url::form_urlencoded;
@@ -20,20 +19,18 @@ static NOTNUMERIC: &[u8] = b"Number field is not numeric";
struct ParamExample;
impl Service for ParamExample {
type Request = Request;
type Response = Response;
type Request = Request<Body>;
type Response = Response<Body>;
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()) {
(&Get, "/") | (&Get, "/post") => {
Box::new(futures::future::ok(Response::new()
.with_header(ContentLength(INDEX.len() as u64))
.with_body(INDEX)))
fn call(&self, req: Request<Body>) -> Self::Future {
match (req.method(), req.uri().path()) {
(&Method::GET, "/") | (&Method::GET, "/post") => {
Box::new(futures::future::ok(Response::new(INDEX.into())))
},
(&Post, "/post") => {
Box::new(req.body().concat2().map(|b| {
(&Method::POST, "/post") => {
Box::new(req.into_parts().1.concat2().map(|b| {
// Parse the request body. form_urlencoded::parse
// always succeeds, but in general parsing may
// fail (for example, an invalid post of json), so
@@ -52,25 +49,25 @@ impl Service for ParamExample {
let name = if let Some(n) = params.get("name") {
n
} else {
return Response::new()
.with_status(StatusCode::UnprocessableEntity)
.with_header(ContentLength(MISSING.len() as u64))
.with_body(MISSING);
return Response::builder()
.status(StatusCode::UNPROCESSABLE_ENTITY)
.body(MISSING.into())
.unwrap();
};
let number = if let Some(n) = params.get("number") {
if let Ok(v) = n.parse::<f64>() {
v
} else {
return Response::new()
.with_status(StatusCode::UnprocessableEntity)
.with_header(ContentLength(NOTNUMERIC.len() as u64))
.with_body(NOTNUMERIC);
return Response::builder()
.status(StatusCode::UNPROCESSABLE_ENTITY)
.body(NOTNUMERIC.into())
.unwrap();
}
} else {
return Response::new()
.with_status(StatusCode::UnprocessableEntity)
.with_header(ContentLength(MISSING.len() as u64))
.with_body(MISSING);
return Response::builder()
.status(StatusCode::UNPROCESSABLE_ENTITY)
.body(MISSING.into())
.unwrap();
};
// Render the response. This will often involve
@@ -80,14 +77,14 @@ impl Service for ParamExample {
// responses such as InternalServiceError may be
// needed here, too.
let body = format!("Hello {}, your number is {}", name, number);
Response::new()
.with_header(ContentLength(body.len() as u64))
.with_body(body)
Response::new(body.into())
}))
},
_ => {
Box::new(futures::future::ok(Response::new()
.with_status(StatusCode::NotFound)))
Box::new(futures::future::ok(Response::builder()
.status(StatusCode::NOT_FOUND)
.body(Body::empty())
.unwrap()))
}
}
}

View File

@@ -4,12 +4,11 @@ extern crate hyper;
extern crate pretty_env_logger;
use futures::{Future, Sink};
use futures::sync::{mpsc, oneshot};
use futures::sync::oneshot;
use hyper::{Chunk, Get, StatusCode};
use hyper::{Body, Chunk, Method, Request, Response, StatusCode};
use hyper::error::Error;
use hyper::header::ContentLength;
use hyper::server::{Http, Service, Request, Response};
use hyper::server::{Http, Service};
use std::fs::File;
use std::io::{self, copy, Read};
@@ -18,7 +17,7 @@ use std::thread;
static NOTFOUND: &[u8] = b"Not Found";
static INDEX: &str = "examples/send_file_index.html";
fn simple_file_send(f: &str) -> Box<Future<Item = Response, Error = hyper::Error>> {
fn simple_file_send(f: &str) -> Box<Future<Item = Response<Body>, Error = hyper::Error>> {
// Serve a file by reading it entirely into memory. As a result
// this is limited to serving small files, but it is somewhat
// simpler with a little less overhead.
@@ -31,10 +30,10 @@ fn simple_file_send(f: &str) -> Box<Future<Item = Response, Error = hyper::Error
let mut file = match File::open(filename) {
Ok(f) => f,
Err(_) => {
tx.send(Response::new()
.with_status(StatusCode::NotFound)
.with_header(ContentLength(NOTFOUND.len() as u64))
.with_body(NOTFOUND))
tx.send(Response::builder()
.status(StatusCode::NOT_FOUND)
.body(NOTFOUND.into())
.unwrap())
.expect("Send error on open");
return;
},
@@ -42,14 +41,15 @@ fn simple_file_send(f: &str) -> Box<Future<Item = Response, Error = hyper::Error
let mut buf: Vec<u8> = Vec::new();
match copy(&mut file, &mut buf) {
Ok(_) => {
let res = Response::new()
.with_header(ContentLength(buf.len() as u64))
.with_body(buf);
let res = Response::new(buf.into());
tx.send(res).expect("Send error on successful file read");
},
Err(_) => {
tx.send(Response::new().with_status(StatusCode::InternalServerError)).
expect("Send error on error reading file");
tx.send(Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(Body::empty())
.unwrap())
.expect("Send error on error reading file");
},
};
});
@@ -60,17 +60,17 @@ fn simple_file_send(f: &str) -> Box<Future<Item = Response, Error = hyper::Error
struct ResponseExamples;
impl Service for ResponseExamples {
type Request = Request;
type Response = Response;
type Request = Request<Body>;
type Response = Response<Body>;
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()) {
(&Get, "/") | (&Get, "/index.html") => {
fn call(&self, req: Request<Body>) -> Self::Future {
match (req.method(), req.uri().path()) {
(&Method::GET, "/") | (&Method::GET, "/index.html") => {
simple_file_send(INDEX)
},
(&Get, "/big_file.html") => {
(&Method::GET, "/big_file.html") => {
// Stream a large file in chunks. This requires a
// little more overhead with two channels, (one for
// the response future, and a second for the response
@@ -83,16 +83,16 @@ impl Service for ResponseExamples {
let mut file = match File::open(INDEX) {
Ok(f) => f,
Err(_) => {
tx.send(Response::new()
.with_status(StatusCode::NotFound)
.with_header(ContentLength(NOTFOUND.len() as u64))
.with_body(NOTFOUND))
tx.send(Response::builder()
.status(StatusCode::NOT_FOUND)
.body(NOTFOUND.into())
.unwrap())
.expect("Send error on open");
return;
},
};
let (mut tx_body, rx_body) = mpsc::channel(1);
let res = Response::new().with_body(rx_body);
let (mut tx_body, rx_body) = Body::pair();
let res = Response::new(rx_body.into());
tx.send(res).expect("Send error on successful file read");
let mut buf = [0u8; 16];
loop {
@@ -114,16 +114,18 @@ impl Service for ResponseExamples {
}
}
});
Box::new(rx.map_err(|e| Error::from(io::Error::new(io::ErrorKind::Other, e))))
},
(&Get, "/no_file.html") => {
(&Method::GET, "/no_file.html") => {
// Test what happens when file cannot be be found
simple_file_send("this_file_should_not_exist.html")
},
_ => {
Box::new(futures::future::ok(Response::new()
.with_status(StatusCode::NotFound)))
Box::new(futures::future::ok(Response::builder()
.status(StatusCode::NOT_FOUND)
.body(Body::empty())
.unwrap()))
}
}
}

View File

@@ -5,37 +5,31 @@ extern crate pretty_env_logger;
use futures::future::FutureResult;
use hyper::{Get, Post, StatusCode};
use hyper::header::ContentLength;
use hyper::server::{Http, Service, Request, Response};
use hyper::{Body, Method, Request, Response, StatusCode};
use hyper::server::{Http, Service};
static INDEX: &'static [u8] = b"Try POST /echo";
struct Echo;
impl Service for Echo {
type Request = Request;
type Response = Response;
type Request = Request<Body>;
type Response = Response<Body>;
type Error = hyper::Error;
type Future = FutureResult<Response, hyper::Error>;
type Future = FutureResult<Self::Response, Self::Error>;
fn call(&self, req: Request) -> Self::Future {
futures::future::ok(match (req.method(), req.path()) {
(&Get, "/") | (&Get, "/echo") => {
Response::new()
.with_header(ContentLength(INDEX.len() as u64))
.with_body(INDEX)
fn call(&self, req: Self::Request) -> Self::Future {
futures::future::ok(match (req.method(), req.uri().path()) {
(&Method::GET, "/") | (&Method::POST, "/") => {
Response::new(INDEX.into())
},
(&Post, "/echo") => {
let mut res = Response::new();
if let Some(len) = req.headers().get::<ContentLength>() {
res.headers_mut().set(len.clone());
}
res.with_body(req.body())
(&Method::POST, "/echo") => {
Response::new(req.into_parts().1)
},
_ => {
Response::new()
.with_status(StatusCode::NotFound)
let mut res = Response::new(Body::empty());
*res.status_mut() = StatusCode::NOT_FOUND;
res
}
})
}

View File

@@ -6,10 +6,9 @@ extern crate tokio_core;
use futures::{Future, Stream};
use hyper::{Body, Chunk, Client, Get, Post, StatusCode};
use hyper::{Body, Chunk, Client, Method, Request, Response, StatusCode};
use hyper::error::Error;
use hyper::header::ContentLength;
use hyper::server::{Http, Service, Request, Response};
use hyper::server::{Http, Service};
#[allow(unused)]
use std::ascii::AsciiExt;
@@ -24,50 +23,51 @@ pub type ResponseStream = Box<Stream<Item=Chunk, Error=Error>>;
struct ResponseExamples(tokio_core::reactor::Handle);
impl Service for ResponseExamples {
type Request = Request;
type Request = Request<Body>;
type Response = Response<ResponseStream>;
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()) {
(&Get, "/") | (&Get, "/index.html") => {
fn call(&self, req: Self::Request) -> Self::Future {
match (req.method(), req.uri().path()) {
(&Method::GET, "/") | (&Method::GET, "/index.html") => {
let body: ResponseStream = Box::new(Body::from(INDEX));
Box::new(futures::future::ok(Response::new()
.with_header(ContentLength(INDEX.len() as u64))
.with_body(body)))
Box::new(futures::future::ok(Response::new(body)))
},
(&Get, "/test.html") => {
(&Method::GET, "/test.html") => {
// Run a web query against the web api below
let client = Client::configure().build(&self.0);
let mut req = Request::new(Post, URL.parse().unwrap());
req.set_body(LOWERCASE);
let req = Request::builder()
.method(Method::POST)
.uri(URL)
.body(LOWERCASE.into())
.unwrap();
let web_res_future = client.request(req);
Box::new(web_res_future.map(|web_res| {
let body: ResponseStream = Box::new(web_res.body().map(|b| {
let body: ResponseStream = Box::new(web_res.into_parts().1.map(|b| {
Chunk::from(format!("before: '{:?}'<br>after: '{:?}'",
std::str::from_utf8(LOWERCASE).unwrap(),
std::str::from_utf8(&b).unwrap()))
}));
Response::new().with_body(body)
Response::new(body)
}))
},
(&Post, "/web_api") => {
(&Method::POST, "/web_api") => {
// A web api to run against. Simple upcasing of the body.
let body: ResponseStream = Box::new(req.body().map(|chunk| {
let body: ResponseStream = Box::new(req.into_parts().1.map(|chunk| {
let upper = chunk.iter().map(|byte| byte.to_ascii_uppercase())
.collect::<Vec<u8>>();
Chunk::from(upper)
}));
Box::new(futures::future::ok(Response::new().with_body(body)))
Box::new(futures::future::ok(Response::new(body)))
},
_ => {
let body: ResponseStream = Box::new(Body::from(NOTFOUND));
Box::new(futures::future::ok(Response::new()
.with_status(StatusCode::NotFound)
.with_header(ContentLength(NOTFOUND.len() as u64))
.with_body(body)))
Box::new(futures::future::ok(Response::builder()
.status(StatusCode::NOT_FOUND)
.body(body)
.unwrap()))
}
}
}