feat(server): re-design Server as higher-level API
The `hyper::Server` is now a proper higher-level API for running HTTP servers. There is a related `hyper::server::Builder` type, to construct a `Server`. All other types (`Http`, `Serve`, etc) were moved into the "lower-level" `hyper::server::conn` module. The `Server` is a `Future` representing a listening HTTP server. Options needed to build one are set on the `Builder`. As `Server` is just a `Future`, it no longer owns a thread-blocking executor, and can thus be run next to other servers, clients, or what-have-you. Closes #1322 Closes #1263 BREAKING CHANGE: The `Server` is no longer created from `Http::bind`, nor is it `run`. It is a `Future` that must be polled by an `Executor`. The `hyper::server::Http` type has move to `hyper::server::conn::Http`.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
#![deny(warnings)]
|
||||
#[macro_use]
|
||||
mod support;
|
||||
use self::support::*;
|
||||
|
||||
@@ -24,7 +24,6 @@ use futures::future::{self, FutureResult, Either};
|
||||
use futures::sync::oneshot;
|
||||
use futures_timer::Delay;
|
||||
use http::header::{HeaderName, HeaderValue};
|
||||
//use net2::TcpBuilder;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::runtime::Runtime;
|
||||
use tokio::reactor::Handle;
|
||||
@@ -32,7 +31,8 @@ use tokio_io::{AsyncRead, AsyncWrite};
|
||||
|
||||
|
||||
use hyper::{Body, Request, Response, StatusCode};
|
||||
use hyper::server::{Http, Service, NewService, service_fn};
|
||||
use hyper::server::{Service, NewService, service_fn};
|
||||
use hyper::server::conn::Http;
|
||||
|
||||
fn tcp_bind(addr: &SocketAddr, handle: &Handle) -> ::tokio::io::Result<TcpListener> {
|
||||
let std_listener = StdTcpListener::bind(addr).unwrap();
|
||||
@@ -1363,8 +1363,9 @@ fn serve_with_options(options: ServeOptions) -> Serve {
|
||||
let (msg_tx, msg_rx) = mpsc::channel();
|
||||
let (reply_tx, reply_rx) = spmc::channel();
|
||||
let (shutdown_tx, shutdown_rx) = oneshot::channel();
|
||||
let shutdown_rx = shutdown_rx.then(|_| Ok(()));
|
||||
|
||||
let addr = "127.0.0.1:0".parse().unwrap();
|
||||
let addr = ([127, 0, 0, 1], 0).into();
|
||||
|
||||
let keep_alive = !options.keep_alive_disabled;
|
||||
let pipeline = options.pipeline;
|
||||
@@ -1372,22 +1373,40 @@ fn serve_with_options(options: ServeOptions) -> Serve {
|
||||
|
||||
let thread_name = format!("test-server-{:?}", dur);
|
||||
let thread = thread::Builder::new().name(thread_name).spawn(move || {
|
||||
tokio::run(::futures::future::lazy(move || {
|
||||
let srv = Http::new()
|
||||
.keep_alive(keep_alive)
|
||||
.pipeline(pipeline)
|
||||
.bind(&addr, TestService {
|
||||
tx: Arc::new(Mutex::new(msg_tx.clone())),
|
||||
_timeout: dur,
|
||||
reply: reply_rx,
|
||||
}).unwrap();
|
||||
addr_tx.send(srv.local_addr().unwrap()).unwrap();
|
||||
srv.run_until(shutdown_rx.then(|_| Ok(())))
|
||||
.map_err(|err| println!("error {}", err))
|
||||
}))
|
||||
}).unwrap();
|
||||
let serve = Http::new()
|
||||
.keep_alive(keep_alive)
|
||||
.pipeline_flush(pipeline)
|
||||
.serve_addr(&addr, TestService {
|
||||
tx: Arc::new(Mutex::new(msg_tx.clone())),
|
||||
_timeout: dur,
|
||||
reply: reply_rx,
|
||||
})
|
||||
.expect("bind to address");
|
||||
|
||||
let addr = addr_rx.recv().unwrap();
|
||||
addr_tx.send(
|
||||
serve
|
||||
.incoming_ref()
|
||||
.local_addr()
|
||||
).expect("server addr tx");
|
||||
|
||||
// spawn_all() is private for now, so just duplicate it here
|
||||
let spawn_all = serve.for_each(|conn| {
|
||||
tokio::spawn(conn.map_err(|e| {
|
||||
println!("server error: {}", e);
|
||||
}));
|
||||
Ok(())
|
||||
}).map_err(|e| {
|
||||
println!("accept error: {}", e)
|
||||
});
|
||||
|
||||
let fut = spawn_all
|
||||
.select(shutdown_rx)
|
||||
.then(|_| Ok(()));
|
||||
|
||||
tokio::run(fut);
|
||||
}).expect("thread spawn");
|
||||
|
||||
let addr = addr_rx.recv().expect("server addr rx");
|
||||
|
||||
Serve {
|
||||
msg_rx: msg_rx,
|
||||
|
||||
@@ -123,9 +123,11 @@ macro_rules! __internal_req_res_prop {
|
||||
);
|
||||
(headers: $map:tt) => ({
|
||||
#[allow(unused_mut)]
|
||||
{
|
||||
let mut headers = HeaderMap::new();
|
||||
__internal_headers!(headers, $map);
|
||||
headers
|
||||
}
|
||||
});
|
||||
($prop_name:ident: $prop_val:expr) => (
|
||||
From::from($prop_val)
|
||||
@@ -228,7 +230,7 @@ pub fn __run_test(cfg: __TestConfig) {
|
||||
});
|
||||
let new_service = hyper::server::const_service(service);
|
||||
|
||||
let serve = hyper::server::Http::new()
|
||||
let serve = hyper::server::conn::Http::new()
|
||||
.http2_only(cfg.server_version == 2)
|
||||
.executor(rt.executor())
|
||||
.serve_addr_handle(
|
||||
@@ -244,7 +246,7 @@ pub fn __run_test(cfg: __TestConfig) {
|
||||
let (success_tx, success_rx) = oneshot::channel();
|
||||
let expected_connections = cfg.connections;
|
||||
let server = serve
|
||||
.fold(0, move |cnt, conn: hyper::server::Connection<_, _>| {
|
||||
.fold(0, move |cnt, conn| {
|
||||
exe.spawn(conn.map_err(|e| panic!("server connection error: {}", e)));
|
||||
Ok::<_, hyper::Error>(cnt + 1)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user