feat(lib): redesign API to use Futures and Tokio
There are many changes involved with this, but let's just talk about
user-facing changes.
- Creating a `Client` and `Server` now needs a Tokio `Core` event loop
to attach to.
- `Request` and `Response` both no longer implement the
`std::io::{Read,Write}` traits, but instead represent their bodies as a
`futures::Stream` of items, where each item is a `Chunk`.
- The `Client.request` method now takes a `Request`, instead of being
used as a builder, and returns a `Future` that resolves to `Response`.
- The `Handler` trait for servers is no more, and instead the Tokio
`Service` trait is used. This allows interoperability with generic
middleware.
BREAKING CHANGE: A big sweeping set of breaking changes.
This commit is contained in:
@@ -1,57 +0,0 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
|
||||
use http::{self, Next};
|
||||
use net::Transport;
|
||||
|
||||
use super::{Handler, request, response};
|
||||
|
||||
/// A `MessageHandler` for a Server.
|
||||
///
|
||||
/// This should be really thin glue between `http::MessageHandler` and
|
||||
/// `server::Handler`, but largely just providing the proper types one
|
||||
/// would expect in a Server Handler.
|
||||
pub struct Message<H: Handler<T>, T: Transport> {
|
||||
handler: H,
|
||||
_marker: PhantomData<T>
|
||||
}
|
||||
|
||||
impl<H: Handler<T>, T: Transport> Message<H, T> {
|
||||
pub fn new(handler: H) -> Message<H, T> {
|
||||
Message {
|
||||
handler: handler,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<H: Handler<T>, T: Transport> http::MessageHandler<T> for Message<H, T> {
|
||||
type Message = http::ServerMessage;
|
||||
|
||||
fn on_incoming(&mut self, head: http::RequestHead, transport: &T) -> Next {
|
||||
trace!("on_incoming {:?}", head);
|
||||
let req = request::new(head, transport);
|
||||
self.handler.on_request(req)
|
||||
}
|
||||
|
||||
fn on_decode(&mut self, transport: &mut http::Decoder<T>) -> Next {
|
||||
self.handler.on_request_readable(transport)
|
||||
}
|
||||
|
||||
fn on_outgoing(&mut self, head: &mut http::MessageHead<::status::StatusCode>) -> Next {
|
||||
let mut res = response::new(head);
|
||||
self.handler.on_response(&mut res)
|
||||
}
|
||||
|
||||
fn on_encode(&mut self, transport: &mut http::Encoder<T>) -> Next {
|
||||
self.handler.on_response_writable(transport)
|
||||
}
|
||||
|
||||
fn on_error(&mut self, error: ::Error) -> Next {
|
||||
self.handler.on_error(error)
|
||||
}
|
||||
|
||||
fn on_remove(self, transport: T) {
|
||||
self.handler.on_remove(transport);
|
||||
}
|
||||
}
|
||||
@@ -1,65 +1,55 @@
|
||||
//! HTTP Server
|
||||
//!
|
||||
//! A `Server` is created to listen on a port, parse HTTP requests, and hand
|
||||
//! them off to a `Handler`.
|
||||
//! them off to a `Service`.
|
||||
use std::fmt;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::time::Duration;
|
||||
use std::io;
|
||||
use std::net::{SocketAddr, TcpListener as StdTcpListener};
|
||||
|
||||
use rotor::mio::{EventSet, PollOpt};
|
||||
use rotor::{self, Scope};
|
||||
use futures::{Future, Map};
|
||||
use futures::stream::{Stream};
|
||||
use futures::sync::oneshot;
|
||||
|
||||
use tokio::io::Io;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::reactor::{Core, Handle};
|
||||
use tokio_proto::BindServer;
|
||||
use tokio_proto::streaming::Message;
|
||||
use tokio_proto::streaming::pipeline::ServerProto;
|
||||
pub use tokio_service::{NewService, Service};
|
||||
|
||||
pub use self::accept::Accept;
|
||||
pub use self::request::Request;
|
||||
pub use self::response::Response;
|
||||
|
||||
use http::{self, Next, ReadyResult};
|
||||
|
||||
pub use net::{Accept, HttpListener, HttpsListener};
|
||||
use net::{SslServer, Transport};
|
||||
|
||||
use http;
|
||||
|
||||
mod request;
|
||||
mod response;
|
||||
mod message;
|
||||
|
||||
/// A configured `Server` ready to run.
|
||||
pub struct ServerLoop<A, H> where A: Accept, H: HandlerFactory<A::Output> {
|
||||
inner: Option<(rotor::Loop<ServerFsm<A, H>>, Context<H>)>,
|
||||
}
|
||||
|
||||
impl<A: Accept, H: HandlerFactory<A::Output>> fmt::Debug for ServerLoop<A, H> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.pad("ServerLoop")
|
||||
}
|
||||
}
|
||||
type HttpIncoming = ::tokio::net::Incoming;
|
||||
|
||||
/// A Server that can accept incoming network requests.
|
||||
#[derive(Debug)]
|
||||
pub struct Server<A> {
|
||||
lead_listener: A,
|
||||
other_listeners: Vec<A>,
|
||||
accepter: A,
|
||||
addr: SocketAddr,
|
||||
keep_alive: bool,
|
||||
idle_timeout: Option<Duration>,
|
||||
max_sockets: usize,
|
||||
//idle_timeout: Option<Duration>,
|
||||
//max_sockets: usize,
|
||||
}
|
||||
|
||||
impl<A: Accept> Server<A> {
|
||||
/// Creates a new Server from one or more Listeners.
|
||||
/// Creates a new Server from a Stream of Ios.
|
||||
///
|
||||
/// Panics if listeners is an empty iterator.
|
||||
pub fn new<I: IntoIterator<Item = A>>(listeners: I) -> Server<A> {
|
||||
let mut listeners = listeners.into_iter();
|
||||
let lead_listener = listeners.next().expect("Server::new requires at least 1 listener");
|
||||
let other_listeners = listeners.collect::<Vec<_>>();
|
||||
|
||||
/// The addr is the socket address the accepter is listening on.
|
||||
pub fn new(accepter: A, addr: SocketAddr) -> Server<A> {
|
||||
Server {
|
||||
lead_listener: lead_listener,
|
||||
other_listeners: other_listeners,
|
||||
accepter: accepter,
|
||||
addr: addr,
|
||||
keep_alive: true,
|
||||
idle_timeout: Some(Duration::from_secs(10)),
|
||||
max_sockets: 4096,
|
||||
//idle_timeout: Some(Duration::from_secs(75)),
|
||||
//max_sockets: 4096,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,14 +61,17 @@ impl<A: Accept> Server<A> {
|
||||
self
|
||||
}
|
||||
|
||||
/*
|
||||
/// Sets how long an idle connection will be kept before closing.
|
||||
///
|
||||
/// Default is 10 seconds.
|
||||
/// Default is 75 seconds.
|
||||
pub fn idle_timeout(mut self, val: Option<Duration>) -> Server<A> {
|
||||
self.idle_timeout = val;
|
||||
self
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
/// Sets the maximum open sockets for this Server.
|
||||
///
|
||||
/// Default is 4096, but most servers can handle much more than this.
|
||||
@@ -86,20 +79,21 @@ impl<A: Accept> Server<A> {
|
||||
self.max_sockets = val;
|
||||
self
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
impl Server<HttpListener> { //<H: HandlerFactory<<HttpListener as Accept>::Output>> Server<HttpListener, H> {
|
||||
impl Server<HttpIncoming> {
|
||||
/// Creates a new HTTP server config listening on the provided address.
|
||||
pub fn http(addr: &SocketAddr) -> ::Result<Server<HttpListener>> {
|
||||
use ::rotor::mio::tcp::TcpListener;
|
||||
TcpListener::bind(addr)
|
||||
.map(HttpListener)
|
||||
.map(Server::new)
|
||||
.map_err(From::from)
|
||||
pub fn http(addr: &SocketAddr, handle: &Handle) -> ::Result<Server<HttpIncoming>> {
|
||||
let listener = try!(StdTcpListener::bind(addr));
|
||||
let addr = try!(listener.local_addr());
|
||||
let listener = try!(TcpListener::from_listener(listener, &addr, handle));
|
||||
Ok(Server::new(listener.incoming(), addr))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
impl<S: SslServer> Server<HttpsListener<S>> {
|
||||
/// Creates a new server config that will handle `HttpStream`s over SSL.
|
||||
///
|
||||
@@ -110,304 +104,227 @@ impl<S: SslServer> Server<HttpsListener<S>> {
|
||||
.map_err(From::from)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
impl<A: Accept> Server<A> {
|
||||
/// Binds to a socket and starts handling connections.
|
||||
pub fn handle<H>(self, factory: H) -> ::Result<(Listening, ServerLoop<A, H>)>
|
||||
where H: HandlerFactory<A::Output> {
|
||||
let shutdown = Arc::new(AtomicBool::new(false));
|
||||
|
||||
let mut config = rotor::Config::new();
|
||||
config.slab_capacity(self.max_sockets);
|
||||
config.mio().notify_capacity(self.max_sockets);
|
||||
let keep_alive = self.keep_alive;
|
||||
let idle_timeout = self.idle_timeout;
|
||||
let mut loop_ = rotor::Loop::new(&config).unwrap();
|
||||
|
||||
let mut addrs = Vec::with_capacity(1 + self.other_listeners.len());
|
||||
|
||||
// Add the lead listener. This one handles shutdown messages.
|
||||
let mut notifier = None;
|
||||
{
|
||||
let notifier = &mut notifier;
|
||||
let listener = self.lead_listener;
|
||||
addrs.push(try!(listener.local_addr()));
|
||||
let shutdown_rx = shutdown.clone();
|
||||
loop_.add_machine_with(move |scope| {
|
||||
*notifier = Some(scope.notifier());
|
||||
rotor_try!(scope.register(&listener, EventSet::readable(), PollOpt::level()));
|
||||
rotor::Response::ok(ServerFsm::Listener(listener, shutdown_rx))
|
||||
}).unwrap();
|
||||
}
|
||||
let notifier = notifier.expect("loop.add_machine failed");
|
||||
|
||||
// Add the other listeners.
|
||||
for listener in self.other_listeners {
|
||||
addrs.push(try!(listener.local_addr()));
|
||||
let shutdown_rx = shutdown.clone();
|
||||
loop_.add_machine_with(move |scope| {
|
||||
rotor_try!(scope.register(&listener, EventSet::readable(), PollOpt::level()));
|
||||
rotor::Response::ok(ServerFsm::Listener(listener, shutdown_rx))
|
||||
}).unwrap();
|
||||
}
|
||||
|
||||
let listening = Listening {
|
||||
addrs: addrs,
|
||||
shutdown: (shutdown, notifier),
|
||||
pub fn handle<H>(self, factory: H, handle: &Handle) -> ::Result<SocketAddr>
|
||||
where H: NewService<Request=Request, Response=Response, Error=::Error> + 'static {
|
||||
let binder = HttpServer {
|
||||
keep_alive: self.keep_alive,
|
||||
};
|
||||
let server = ServerLoop {
|
||||
inner: Some((loop_, Context {
|
||||
factory: factory,
|
||||
idle_timeout: idle_timeout,
|
||||
keep_alive: keep_alive,
|
||||
}))
|
||||
};
|
||||
Ok((listening, server))
|
||||
let inner_handle = handle.clone();
|
||||
handle.spawn(self.accepter.accept().for_each(move |(socket, remote_addr)| {
|
||||
let service = HttpService {
|
||||
inner: try!(factory.new_service()),
|
||||
remote_addr: remote_addr,
|
||||
};
|
||||
binder.bind_server(&inner_handle, socket, service);
|
||||
Ok(())
|
||||
}).map_err(|e| {
|
||||
error!("listener io error: {:?}", e);
|
||||
()
|
||||
}));
|
||||
|
||||
Ok(self.addr)
|
||||
}
|
||||
}
|
||||
|
||||
impl Server<()> {
|
||||
/// Create a server that owns its event loop.
|
||||
///
|
||||
/// The returned `ServerLoop` can be used to run the loop forever in the
|
||||
/// thread. The returned `Listening` can be sent to another thread, and
|
||||
/// used to shutdown the `ServerLoop`.
|
||||
pub fn standalone<F>(closure: F) -> ::Result<(Listening, ServerLoop)>
|
||||
where F: FnOnce(&Handle) -> ::Result<SocketAddr> {
|
||||
let core = try!(Core::new());
|
||||
let handle = core.handle();
|
||||
let addr = try!(closure(&handle));
|
||||
let (shutdown_tx, shutdown_rx) = oneshot::channel();
|
||||
Ok((
|
||||
Listening {
|
||||
addr: addr,
|
||||
shutdown: shutdown_tx,
|
||||
},
|
||||
ServerLoop {
|
||||
inner: Some((core, shutdown_rx)),
|
||||
}
|
||||
))
|
||||
|
||||
impl<A: Accept, H: HandlerFactory<A::Output>> ServerLoop<A, H> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A configured `Server` ready to run.
|
||||
pub struct ServerLoop {
|
||||
inner: Option<(Core, oneshot::Receiver<()>)>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for ServerLoop {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.pad("ServerLoop")
|
||||
}
|
||||
}
|
||||
|
||||
impl ServerLoop {
|
||||
/// Runs the server forever in this loop.
|
||||
///
|
||||
/// This will block the current thread.
|
||||
pub fn run(self) {
|
||||
// drop will take care of it.
|
||||
trace!("ServerLoop::run()");
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Accept, H: HandlerFactory<A::Output>> Drop for ServerLoop<A, H> {
|
||||
impl Drop for ServerLoop {
|
||||
fn drop(&mut self) {
|
||||
self.inner.take().map(|(loop_, ctx)| {
|
||||
let _ = loop_.run(ctx);
|
||||
self.inner.take().map(|(mut loop_, shutdown)| {
|
||||
debug!("ServerLoop::drop running");
|
||||
let _ = loop_.run(shutdown.or_else(|_dropped| ::futures::future::empty::<(), oneshot::Canceled>()));
|
||||
debug!("Server closed");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
struct Context<F> {
|
||||
factory: F,
|
||||
idle_timeout: Option<Duration>,
|
||||
keep_alive: bool,
|
||||
}
|
||||
|
||||
impl<F: HandlerFactory<T>, T: Transport> http::MessageHandlerFactory<(), T> for Context<F> {
|
||||
type Output = message::Message<F::Output, T>;
|
||||
|
||||
fn create(&mut self, seed: http::Seed<()>) -> Option<Self::Output> {
|
||||
Some(message::Message::new(self.factory.create(seed.control())))
|
||||
}
|
||||
|
||||
fn keep_alive_interest(&self) -> Next {
|
||||
if let Some(dur) = self.idle_timeout {
|
||||
Next::read().timeout(dur)
|
||||
} else {
|
||||
Next::read()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum ServerFsm<A, H>
|
||||
where A: Accept,
|
||||
A::Output: Transport,
|
||||
H: HandlerFactory<A::Output> {
|
||||
Listener(A, Arc<AtomicBool>),
|
||||
Conn(http::Conn<(), A::Output, message::Message<H::Output, A::Output>>)
|
||||
}
|
||||
|
||||
impl<A, H> rotor::Machine for ServerFsm<A, H>
|
||||
where A: Accept,
|
||||
A::Output: Transport,
|
||||
H: HandlerFactory<A::Output> {
|
||||
type Context = Context<H>;
|
||||
type Seed = A::Output;
|
||||
|
||||
fn create(seed: Self::Seed, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, rotor::Void> {
|
||||
rotor_try!(scope.register(&seed, EventSet::readable(), PollOpt::level()));
|
||||
rotor::Response::ok(
|
||||
ServerFsm::Conn(
|
||||
http::Conn::new((), seed, Next::read(), scope.notifier(), scope.now())
|
||||
.keep_alive(scope.keep_alive)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fn ready(self, events: EventSet, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
|
||||
match self {
|
||||
ServerFsm::Listener(listener, rx) => {
|
||||
match listener.accept() {
|
||||
Ok(Some(conn)) => {
|
||||
rotor::Response::spawn(ServerFsm::Listener(listener, rx), conn)
|
||||
},
|
||||
Ok(None) => rotor::Response::ok(ServerFsm::Listener(listener, rx)),
|
||||
Err(e) => {
|
||||
error!("listener accept error {}", e);
|
||||
// usually fine, just keep listening
|
||||
rotor::Response::ok(ServerFsm::Listener(listener, rx))
|
||||
}
|
||||
}
|
||||
},
|
||||
ServerFsm::Conn(conn) => {
|
||||
let mut conn = Some(conn);
|
||||
loop {
|
||||
match conn.take().unwrap().ready(events, scope) {
|
||||
ReadyResult::Continue(c) => conn = Some(c),
|
||||
ReadyResult::Done(res) => {
|
||||
return match res {
|
||||
Some((conn, None)) => rotor::Response::ok(ServerFsm::Conn(conn)),
|
||||
Some((conn, Some(dur))) => {
|
||||
rotor::Response::ok(ServerFsm::Conn(conn))
|
||||
.deadline(scope.now() + dur)
|
||||
}
|
||||
None => rotor::Response::done()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn spawned(self, _scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
|
||||
match self {
|
||||
ServerFsm::Listener(listener, rx) => {
|
||||
match listener.accept() {
|
||||
Ok(Some(conn)) => {
|
||||
rotor::Response::spawn(ServerFsm::Listener(listener, rx), conn)
|
||||
},
|
||||
Ok(None) => rotor::Response::ok(ServerFsm::Listener(listener, rx)),
|
||||
Err(e) => {
|
||||
error!("listener accept error {}", e);
|
||||
// usually fine, just keep listening
|
||||
rotor::Response::ok(ServerFsm::Listener(listener, rx))
|
||||
}
|
||||
}
|
||||
},
|
||||
sock => rotor::Response::ok(sock)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn timeout(self, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
|
||||
match self {
|
||||
ServerFsm::Listener(..) => unreachable!("Listener cannot timeout"),
|
||||
ServerFsm::Conn(conn) => {
|
||||
match conn.timeout(scope) {
|
||||
Some((conn, None)) => rotor::Response::ok(ServerFsm::Conn(conn)),
|
||||
Some((conn, Some(dur))) => {
|
||||
rotor::Response::ok(ServerFsm::Conn(conn))
|
||||
.deadline(scope.now() + dur)
|
||||
}
|
||||
None => rotor::Response::done()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn wakeup(self, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
|
||||
match self {
|
||||
ServerFsm::Listener(lst, shutdown) => {
|
||||
if shutdown.load(Ordering::Acquire) {
|
||||
let _ = scope.deregister(&lst);
|
||||
scope.shutdown_loop();
|
||||
rotor::Response::done()
|
||||
} else {
|
||||
rotor::Response::ok(ServerFsm::Listener(lst, shutdown))
|
||||
}
|
||||
},
|
||||
ServerFsm::Conn(conn) => match conn.wakeup(scope) {
|
||||
Some((conn, None)) => rotor::Response::ok(ServerFsm::Conn(conn)),
|
||||
Some((conn, Some(dur))) => {
|
||||
rotor::Response::ok(ServerFsm::Conn(conn))
|
||||
.deadline(scope.now() + dur)
|
||||
}
|
||||
None => rotor::Response::done()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A handle of the running server.
|
||||
pub struct Listening {
|
||||
addrs: Vec<SocketAddr>,
|
||||
shutdown: (Arc<AtomicBool>, rotor::Notifier),
|
||||
addr: SocketAddr,
|
||||
shutdown: ::futures::sync::oneshot::Sender<()>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Listening {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Listening")
|
||||
.field("addrs", &self.addrs)
|
||||
.field("closed", &self.shutdown.0.load(Ordering::Relaxed))
|
||||
.field("addr", &self.addr)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Listening {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
for (i, addr) in self.addrs().iter().enumerate() {
|
||||
if i > 1 {
|
||||
try!(f.write_str(", "));
|
||||
}
|
||||
try!(fmt::Display::fmt(addr, f));
|
||||
}
|
||||
Ok(())
|
||||
fmt::Display::fmt(&self.addr, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Listening {
|
||||
/// The addresses this server is listening on.
|
||||
pub fn addrs(&self) -> &[SocketAddr] {
|
||||
&self.addrs
|
||||
pub fn addr(&self) -> &SocketAddr {
|
||||
&self.addr
|
||||
}
|
||||
|
||||
/// Stop the server from listening to its socket address.
|
||||
pub fn close(self) {
|
||||
debug!("closing server {}", self);
|
||||
self.shutdown.0.store(true, Ordering::Release);
|
||||
self.shutdown.1.wakeup().unwrap();
|
||||
self.shutdown.complete(());
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait to react to server events that happen for each message.
|
||||
///
|
||||
/// Each event handler returns its desired `Next` action.
|
||||
pub trait Handler<T: Transport> {
|
||||
/// This event occurs first, triggering when a `Request` has been parsed.
|
||||
fn on_request(&mut self, request: Request<T>) -> Next;
|
||||
/// This event occurs each time the `Request` is ready to be read from.
|
||||
fn on_request_readable(&mut self, request: &mut http::Decoder<T>) -> Next;
|
||||
/// This event occurs after the first time this handled signals `Next::write()`.
|
||||
fn on_response(&mut self, response: &mut Response) -> Next;
|
||||
/// This event occurs each time the `Response` is ready to be written to.
|
||||
fn on_response_writable(&mut self, response: &mut http::Encoder<T>) -> Next;
|
||||
struct HttpServer {
|
||||
keep_alive: bool,
|
||||
}
|
||||
|
||||
/// This event occurs whenever an `Error` occurs outside of the other events.
|
||||
impl<T: Io + 'static> ServerProto<T> for HttpServer {
|
||||
type Request = http::RequestHead;
|
||||
type RequestBody = http::Chunk;
|
||||
type Response = ResponseHead;
|
||||
type ResponseBody = http::Chunk;
|
||||
type Error = ::Error;
|
||||
type Transport = http::Conn<T, http::ServerTransaction>;
|
||||
type BindTransport = io::Result<http::Conn<T, http::ServerTransaction>>;
|
||||
|
||||
fn bind_transport(&self, io: T) -> Self::BindTransport {
|
||||
let ka = if self.keep_alive {
|
||||
http::KA::Busy
|
||||
} else {
|
||||
http::KA::Disabled
|
||||
};
|
||||
Ok(http::Conn::new(io, ka))
|
||||
}
|
||||
}
|
||||
|
||||
struct HttpService<T> {
|
||||
inner: T,
|
||||
remote_addr: SocketAddr,
|
||||
}
|
||||
|
||||
fn map_response_to_message(res: Response) -> Message<ResponseHead, http::TokioBody> {
|
||||
let (head, body) = response::split(res);
|
||||
if let Some(body) = body {
|
||||
Message::WithBody(head, body.into())
|
||||
} else {
|
||||
Message::WithoutBody(head)
|
||||
}
|
||||
}
|
||||
|
||||
type ResponseHead = http::MessageHead<::StatusCode>;
|
||||
|
||||
impl<T> Service for HttpService<T>
|
||||
where T: Service<Request=Request, Response=Response, Error=::Error>,
|
||||
{
|
||||
type Request = Message<http::RequestHead, http::TokioBody>;
|
||||
type Response = Message<ResponseHead, http::TokioBody>;
|
||||
type Error = ::Error;
|
||||
type Future = Map<T::Future, fn(Response) -> Message<ResponseHead, http::TokioBody>>;
|
||||
|
||||
fn call(&self, message: Self::Request) -> Self::Future {
|
||||
let (head, body) = match message {
|
||||
Message::WithoutBody(head) => (head, http::Body::empty()),
|
||||
Message::WithBody(head, body) => (head, body.into()),
|
||||
};
|
||||
let req = request::new(self.remote_addr, head, body);
|
||||
self.inner.call(req).map(map_response_to_message)
|
||||
}
|
||||
}
|
||||
|
||||
//private so the `Acceptor` type can stay internal
|
||||
mod accept {
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use futures::{Stream, Poll};
|
||||
use tokio::io::Io;
|
||||
|
||||
/// An Acceptor is an incoming Stream of Io.
|
||||
///
|
||||
/// This could IO errors while waiting for events, or a timeout, etc.
|
||||
fn on_error(&mut self, err: ::Error) -> Next where Self: Sized {
|
||||
debug!("default Handler.on_error({:?})", err);
|
||||
http::Next::remove()
|
||||
/// This trait is not implemented directly, and only exists to make the
|
||||
/// intent clearer. A `Stream<Item=(Io, SocketAddr), Error=io::Error>`
|
||||
/// should be implemented instead.
|
||||
pub trait Accept: Stream<Error=io::Error> {
|
||||
#[doc(hidden)]
|
||||
type Output: Io + 'static;
|
||||
#[doc(hidden)]
|
||||
type Stream: Stream<Item=(Self::Output, SocketAddr), Error=io::Error> + 'static;
|
||||
|
||||
#[doc(hidden)]
|
||||
fn accept(self) -> Accepter<Self::Stream, Self::Output>
|
||||
where Self: Sized;
|
||||
}
|
||||
|
||||
/// This event occurs when this Handler has requested to remove the Transport.
|
||||
fn on_remove(self, _transport: T) where Self: Sized {
|
||||
debug!("default Handler.on_remove");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Used to create a `Handler` when a new message is received by the server.
|
||||
pub trait HandlerFactory<T: Transport> {
|
||||
/// The `Handler` to use for the incoming message.
|
||||
type Output: Handler<T>;
|
||||
/// Creates the associated `Handler`.
|
||||
fn create(&mut self, ctrl: http::Control) -> Self::Output;
|
||||
}
|
||||
|
||||
impl<F, H, T> HandlerFactory<T> for F
|
||||
where F: FnMut(http::Control) -> H, H: Handler<T>, T: Transport {
|
||||
type Output = H;
|
||||
fn create(&mut self, ctrl: http::Control) -> H {
|
||||
self(ctrl)
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct Accepter<T: Stream<Item=(I, SocketAddr), Error=io::Error> + 'static, I: Io + 'static>(T, ::std::marker::PhantomData<I>);
|
||||
|
||||
impl<T, I> Stream for Accepter<T, I>
|
||||
where T: Stream<Item=(I, SocketAddr), Error=io::Error>,
|
||||
I: Io + 'static,
|
||||
{
|
||||
type Item = T::Item;
|
||||
type Error = io::Error;
|
||||
|
||||
#[inline]
|
||||
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
|
||||
self.0.poll()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, I> Accept for T
|
||||
where T: Stream<Item=(I, SocketAddr), Error=io::Error> + 'static,
|
||||
I: Io + 'static,
|
||||
{
|
||||
type Output = I;
|
||||
type Stream = T;
|
||||
|
||||
fn accept(self) -> Accepter<Self, I> {
|
||||
Accepter(self, ::std::marker::PhantomData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,48 +4,25 @@
|
||||
//! target URI, headers, and message body.
|
||||
|
||||
use std::fmt;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use version::HttpVersion;
|
||||
use method::Method;
|
||||
use header::Headers;
|
||||
use http::{RequestHead, MessageHead, RequestLine};
|
||||
use http::{RequestHead, MessageHead, RequestLine, Body};
|
||||
use uri::RequestUri;
|
||||
|
||||
pub fn new<'a, T>(incoming: RequestHead, transport: &'a T) -> Request<'a, T> {
|
||||
let MessageHead { version, subject: RequestLine(method, uri), headers } = incoming;
|
||||
debug!("Request Line: {:?} {:?} {:?}", method, uri, version);
|
||||
debug!("{:#?}", headers);
|
||||
|
||||
Request {
|
||||
method: method,
|
||||
uri: uri,
|
||||
headers: headers,
|
||||
version: version,
|
||||
transport: transport,
|
||||
}
|
||||
}
|
||||
|
||||
/// A request bundles several parts of an incoming `NetworkStream`, given to a `Handler`.
|
||||
pub struct Request<'a, T: 'a> {
|
||||
pub struct Request {
|
||||
method: Method,
|
||||
uri: RequestUri,
|
||||
version: HttpVersion,
|
||||
headers: Headers,
|
||||
transport: &'a T,
|
||||
remote_addr: SocketAddr,
|
||||
body: Body,
|
||||
}
|
||||
|
||||
impl<'a, T> fmt::Debug for Request<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Request")
|
||||
.field("method", &self.method)
|
||||
.field("uri", &self.uri)
|
||||
.field("version", &self.version)
|
||||
.field("headers", &self.headers)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Request<'a, T> {
|
||||
impl Request {
|
||||
/// The `Method`, such as `Get`, `Post`, etc.
|
||||
#[inline]
|
||||
pub fn method(&self) -> &Method { &self.method }
|
||||
@@ -54,10 +31,6 @@ impl<'a, T> Request<'a, T> {
|
||||
#[inline]
|
||||
pub fn headers(&self) -> &Headers { &self.headers }
|
||||
|
||||
/// The underlying `Transport` of this request.
|
||||
#[inline]
|
||||
pub fn transport(&self) -> &'a T { self.transport }
|
||||
|
||||
/// The target request-uri for this request.
|
||||
#[inline]
|
||||
pub fn uri(&self) -> &RequestUri { &self.uri }
|
||||
@@ -66,6 +39,10 @@ impl<'a, T> Request<'a, T> {
|
||||
#[inline]
|
||||
pub fn version(&self) -> &HttpVersion { &self.version }
|
||||
|
||||
/// The remote socket address of this request
|
||||
#[inline]
|
||||
pub fn remote_addr(&self) -> &SocketAddr { &self.remote_addr }
|
||||
|
||||
/// The target path of this Request.
|
||||
#[inline]
|
||||
pub fn path(&self) -> Option<&str> {
|
||||
@@ -86,12 +63,44 @@ impl<'a, T> Request<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Take the `Body` of this `Request`.
|
||||
#[inline]
|
||||
pub fn body(self) -> Body {
|
||||
self.body
|
||||
}
|
||||
|
||||
/// Deconstruct this Request into its pieces.
|
||||
///
|
||||
/// Modifying these pieces will have no effect on how hyper behaves.
|
||||
#[inline]
|
||||
pub fn deconstruct(self) -> (Method, RequestUri, HttpVersion, Headers) {
|
||||
(self.method, self.uri, self.version, self.headers)
|
||||
pub fn deconstruct(self) -> (Method, RequestUri, HttpVersion, Headers, Body) {
|
||||
(self.method, self.uri, self.version, self.headers, self.body)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Request {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Request")
|
||||
.field("method", &self.method)
|
||||
.field("uri", &self.uri)
|
||||
.field("version", &self.version)
|
||||
.field("remote_addr", &self.remote_addr)
|
||||
.field("headers", &self.headers)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(addr: SocketAddr, incoming: RequestHead, body: Body) -> Request {
|
||||
let MessageHead { version, subject: RequestLine(method, uri), headers } = incoming;
|
||||
debug!("Request Line: {:?} {:?} {:?}", method, uri, version);
|
||||
debug!("{:#?}", headers);
|
||||
|
||||
Request {
|
||||
method: method,
|
||||
uri: uri,
|
||||
headers: headers,
|
||||
version: version,
|
||||
remote_addr: addr,
|
||||
body: body,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,22 +1,26 @@
|
||||
//! Server Responses
|
||||
//!
|
||||
//! These are responses sent by a `hyper::Server` to clients, after
|
||||
//! receiving a request.
|
||||
use std::fmt;
|
||||
|
||||
use header;
|
||||
use http;
|
||||
use http::{self, Body};
|
||||
use status::StatusCode;
|
||||
use version;
|
||||
|
||||
|
||||
/// The outgoing half for a Tcp connection, created by a `Server` and given to a `Handler`.
|
||||
/// The Response sent to a client after receiving a Request in a Service.
|
||||
///
|
||||
/// The default `StatusCode` for a `Response` is `200 OK`.
|
||||
#[derive(Debug)]
|
||||
pub struct Response<'a> {
|
||||
head: &'a mut http::MessageHead<StatusCode>,
|
||||
#[derive(Default)]
|
||||
pub struct Response {
|
||||
head: http::MessageHead<StatusCode>,
|
||||
body: Option<Body>,
|
||||
}
|
||||
|
||||
impl<'a> Response<'a> {
|
||||
impl Response {
|
||||
/// Create a new Response.
|
||||
#[inline]
|
||||
pub fn new() -> Response {
|
||||
Response::default()
|
||||
}
|
||||
|
||||
/// The headers of this response.
|
||||
#[inline]
|
||||
pub fn headers(&self) -> &header::Headers { &self.head.headers }
|
||||
@@ -35,16 +39,65 @@ impl<'a> Response<'a> {
|
||||
#[inline]
|
||||
pub fn headers_mut(&mut self) -> &mut header::Headers { &mut self.head.headers }
|
||||
|
||||
/// Set the status of this response.
|
||||
/// Set the `StatusCode` for this response.
|
||||
#[inline]
|
||||
pub fn set_status(&mut self, status: StatusCode) {
|
||||
self.head.subject = status;
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new Response that can be used to write to a network stream.
|
||||
pub fn new(head: &mut http::MessageHead<StatusCode>) -> Response {
|
||||
Response {
|
||||
head: head
|
||||
/// Set the body.
|
||||
#[inline]
|
||||
pub fn set_body<T: Into<Body>>(&mut self, body: T) {
|
||||
self.body = Some(body.into());
|
||||
}
|
||||
|
||||
/// Set the status and move the Response.
|
||||
///
|
||||
/// Useful for the "builder-style" pattern.
|
||||
#[inline]
|
||||
pub fn with_status(mut self, status: StatusCode) -> Self {
|
||||
self.set_status(status);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set a header and move the Response.
|
||||
///
|
||||
/// Useful for the "builder-style" pattern.
|
||||
#[inline]
|
||||
pub fn with_header<H: header::Header>(mut self, header: H) -> Self {
|
||||
self.head.headers.set(header);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the headers and move the Response.
|
||||
///
|
||||
/// Useful for the "builder-style" pattern.
|
||||
#[inline]
|
||||
pub fn with_headers(mut self, headers: header::Headers) -> Self {
|
||||
self.head.headers = headers;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the body and move the Response.
|
||||
///
|
||||
/// Useful for the "builder-style" pattern.
|
||||
#[inline]
|
||||
pub fn with_body<T: Into<Body>>(mut self, body: T) -> Self {
|
||||
self.set_body(body);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Response {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Response")
|
||||
.field("status", &self.head.subject)
|
||||
.field("version", &self.head.version)
|
||||
.field("headers", &self.head.headers)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn split(res: Response) -> (http::MessageHead<StatusCode>, Option<Body>) {
|
||||
(res.head, res.body)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user