Files
hyper/src/server/mod.rs
Sean McArthur d127201ef2 feat(rt): make tokio runtime optional
A Cargo feature `runtime` is added, which is enabled by default, that
includes the following:

- The `client::HttpConnector`, which uses `tokio::net::TcpStream`.
- The `server::AddrStream`, which uses `tokio::net::TcpListener`.
- The `hyper::rt` module, which includes useful utilities to work with
  the runtime without needing to import `futures` or `tokio` explicity.

Disabling the feature removes many of these niceties, but allows people
to use hyper in environments that have an alternative runtime, without
needing to download an unused one.
2018-04-23 16:56:26 -07:00

244 lines
7.0 KiB
Rust

//! HTTP Server
//!
//! A `Server` is created to listen on a port, parse HTTP requests, and hand
//! them off to a `Service`.
//!
//! There are two levels of APIs provide for constructing HTTP servers:
//!
//! - The higher-level [`Server`](Server).
//! - The lower-level [conn](conn) module.
//!
//! # Server
//!
//! The [`Server`](Server) is main way to start listening for HTTP requests.
//! It wraps a listener with a [`NewService`](::service), and then should
//! be executed to start serving requests.
//!
//! ## Example
//!
//! ```no_run
//! extern crate hyper;
//!
//! use hyper::{Body, Response, Server};
//! use hyper::service::service_fn_ok;
//!
//! # #[cfg(feature = "runtime")]
//! fn main() {
//! # use hyper::rt::Future;
//! // Construct our SocketAddr to listen on...
//! let addr = ([127, 0, 0, 1], 3000).into();
//!
//! // And a NewService to handle each connection...
//! let new_service = || {
//! service_fn_ok(|_req| {
//! Response::new(Body::from("Hello World"))
//! })
//! };
//!
//! // Then bind and serve...
//! let server = Server::bind(&addr)
//! .serve(new_service);
//!
//! // Finally, spawn `server` onto an Executor...
//! hyper::rt::run(server.map_err(|e| {
//! eprintln!("server error: {}", e);
//! }));
//! }
//! # #[cfg(not(feature = "runtime"))]
//! # fn main() {}
//! ```
pub mod conn;
#[cfg(feature = "runtime")] mod tcp;
use std::fmt;
#[cfg(feature = "runtime")] use std::net::SocketAddr;
#[cfg(feature = "runtime")] use std::time::Duration;
use futures::{Future, Stream, Poll};
use tokio_io::{AsyncRead, AsyncWrite};
use body::{Body, Payload};
use service::{NewService, Service};
// Renamed `Http` as `Http_` for now so that people upgrading don't see an
// error that `hyper::server::Http` is private...
use self::conn::{Http as Http_, SpawnAll};
#[cfg(feature = "runtime")] use self::tcp::{AddrIncoming};
/// A listening HTTP server.
///
/// `Server` is a `Future` mapping a bound listener with a set of service
/// handlers. It is built using the [`Builder`](Builder), and the future
/// completes when the server has been shutdown. It should be run by an
/// `Executor`.
pub struct Server<I, S> {
spawn_all: SpawnAll<I, S>,
}
/// A builder for a [`Server`](Server).
#[derive(Debug)]
pub struct Builder<I> {
incoming: I,
protocol: Http_,
}
// ===== impl Server =====
impl<I> Server<I, ()> {
/// Starts a [`Builder`](Builder) with the provided incoming stream.
pub fn builder(incoming: I) -> Builder<I> {
Builder {
incoming,
protocol: Http_::new(),
}
}
}
#[cfg(feature = "runtime")]
impl Server<AddrIncoming, ()> {
/// Binds to the provided address, and returns a [`Builder`](Builder).
///
/// # Panics
///
/// This method will panic if binding to the address fails. For a method
/// to bind to an address and return a `Result`, see `Server::try_bind`.
pub fn bind(addr: &SocketAddr) -> Builder<AddrIncoming> {
let incoming = AddrIncoming::new(addr, None)
.unwrap_or_else(|e| {
panic!("error binding to {}: {}", addr, e);
});
Server::builder(incoming)
}
/// Tries to bind to the provided address, and returns a [`Builder`](Builder).
pub fn try_bind(addr: &SocketAddr) -> ::Result<Builder<AddrIncoming>> {
AddrIncoming::new(addr, None)
.map(Server::builder)
}
}
#[cfg(feature = "runtime")]
impl<S> Server<AddrIncoming, S> {
/// Returns the local address that this server is bound to.
pub fn local_addr(&self) -> SocketAddr {
self.spawn_all.local_addr()
}
}
impl<I, S, B> Future for Server<I, S>
where
I: Stream,
I::Error: Into<Box<::std::error::Error + Send + Sync>>,
I::Item: AsyncRead + AsyncWrite + Send + 'static,
S: NewService<ReqBody=Body, ResBody=B> + Send + 'static,
S::Error: Into<Box<::std::error::Error + Send + Sync>>,
S::Service: Send,
S::Future: Send + 'static,
<S::Service as Service>::Future: Send + 'static,
B: Payload,
{
type Item = ();
type Error = ::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
self.spawn_all.poll()
}
}
impl<I: fmt::Debug, S: fmt::Debug> fmt::Debug for Server<I, S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Server")
.field("listener", &self.spawn_all.incoming_ref())
.finish()
}
}
// ===== impl Builder =====
impl<I> Builder<I> {
/// Start a new builder, wrapping an incoming stream and low-level options.
///
/// For a more convenient constructor, see [`Server::bind`](Server::bind).
pub fn new(incoming: I, protocol: Http_) -> Self {
Builder {
incoming,
protocol,
}
}
/// Sets whether HTTP/2 is required.
///
/// Default is `false`.
pub fn http2_only(mut self, val: bool) -> Self {
self.protocol.http2_only(val);
self
}
/// Consume this `Builder`, creating a [`Server`](Server).
///
/// # Example
///
/// ```
/// # extern crate hyper;
/// # fn main() {}
/// # #[cfg(feature = "runtime")]
/// # fn run() {
/// use hyper::{Body, Response, Server};
/// use hyper::service::service_fn_ok;
///
/// // Construct our SocketAddr to listen on...
/// let addr = ([127, 0, 0, 1], 3000).into();
///
/// // And a NewService to handle each connection...
/// let new_service = || {
/// service_fn_ok(|_req| {
/// Response::new(Body::from("Hello World"))
/// })
/// };
///
/// // Then bind and serve...
/// let server = Server::bind(&addr)
/// .serve(new_service);
///
/// // Finally, spawn `server` onto an Executor...
/// # }
/// ```
pub fn serve<S, B>(self, new_service: S) -> Server<I, S>
where
I: Stream,
I::Error: Into<Box<::std::error::Error + Send + Sync>>,
I::Item: AsyncRead + AsyncWrite + Send + 'static,
S: NewService<ReqBody=Body, ResBody=B> + Send + 'static,
S::Error: Into<Box<::std::error::Error + Send + Sync>>,
S::Service: Send,
<S::Service as Service>::Future: Send + 'static,
B: Payload,
{
let serve = self.protocol.serve_incoming(self.incoming, new_service);
let spawn_all = serve.spawn_all();
Server {
spawn_all,
}
}
}
#[cfg(feature = "runtime")]
impl Builder<AddrIncoming> {
/// Set whether TCP keepalive messages are enabled on accepted connections.
///
/// If `None` is specified, keepalive is disabled, otherwise the duration
/// specified will be the time to remain idle before sending TCP keepalive
/// probes.
pub fn tcp_keepalive(mut self, keepalive: Option<Duration>) -> Self {
self.incoming.set_keepalive(keepalive);
self
}
/// Set the value of `TCP_NODELAY` option for accepted connections.
pub fn tcp_nodelay(mut self, enabled: bool) -> Self {
self.incoming.set_nodelay(enabled);
self
}
}