Merge pull request #565 from hyperium/dox-server

docs(server): greatly expand how to use a Server
This commit is contained in:
Sean McArthur
2015-06-14 08:41:44 -07:00
3 changed files with 136 additions and 1 deletions

View File

@@ -1,6 +1,112 @@
//! HTTP Server //! HTTP Server
//! //!
//! # Example //! # Server
//!
//! A `Server` is created to listen on port, parse HTTP requests, and hand
//! them off to a `Handler`. By default, the Server will listen across multiple
//! threads, but that can be configured to a single thread if preferred.
//!
//! # Handling requests
//!
//! You must pass a `Handler` to the Server that will handle requests. There is
//! a default implementation for `fn`s and closures, allowing you pass one of
//! those easily.
//!
//!
//! ```no_run
//! use hyper::server::{Server, Request, Response};
//!
//! fn hello(req: Request, res: Response) {
//! // handle things here
//! }
//!
//! Server::http(hello).listen("0.0.0.0:0").unwrap();
//! ```
//!
//! As with any trait, you can also define a struct and implement `Handler`
//! directly on your own type, and pass that to the `Server` instead.
//!
//! ```no_run
//! use std::sync::Mutex;
//! use std::sync::mpsc::{channel, Sender};
//! use hyper::server::{Handler, Server, Request, Response};
//!
//! struct SenderHandler {
//! sender: Mutex<Sender<&'static str>>
//! }
//!
//! impl Handler for SenderHandler {
//! fn handle(&self, req: Request, res: Response) {
//! self.sender.lock().unwrap().send("start").unwrap();
//! }
//! }
//!
//!
//! let (tx, rx) = channel();
//! Server::http(SenderHandler {
//! sender: Mutex::new(tx)
//! }).listen("0.0.0.0:0").unwrap();
//! ```
//!
//! Since the `Server` will be listening on multiple threads, the `Handler`
//! must implement `Sync`: any mutable state must be synchronized.
//!
//! ```no_run
//! use std::sync::atomic::{AtomicUsize, Ordering};
//! use hyper::server::{Server, Request, Response};
//!
//! let counter = AtomicUsize::new(0);
//! Server::http(move |req: Request, res: Response| {
//! counter.fetch_add(1, Ordering::Relaxed);
//! }).listen("0.0.0.0:0").unwrap();
//! ```
//!
//! # The `Request` and `Response` pair
//!
//! A `Handler` receives a pair of arguments, a `Request` and a `Response`. The
//! `Request` includes access to the `method`, `uri`, and `headers` of the
//! incoming HTTP request. It also implements `std::io::Read`, in order to
//! read any body, such as with `POST` or `PUT` messages.
//!
//! Likewise, the `Response` includes ways to set the `status` and `headers`,
//! and implements `std::io::Write` to allow writing the response body.
//!
//! ```no_run
//! use std::io;
//! use hyper::server::{Server, Request, Response};
//! use hyper::status::StatusCode;
//!
//! Server::http(|mut req: Request, mut res: Response| {
//! match req.method {
//! hyper::Post => {
//! io::copy(&mut req, &mut res.start().unwrap()).unwrap();
//! },
//! _ => *res.status_mut() = StatusCode::MethodNotAllowed
//! }
//! }).listen("0.0.0.0:0").unwrap();
//! ```
//!
//! ## An aside: Write Status
//!
//! The `Response` uses a phantom type parameter to determine its write status.
//! What does that mean? In short, it ensures you never write a body before
//! adding all headers, and never add a header after writing some of the body.
//!
//! This is often done in most implementations by include a boolean property
//! on the response, such as `headers_written`, checking that each time the
//! body has something to write, so as to make sure the headers are sent once,
//! and only once. But this has 2 downsides:
//!
//! 1. You are typically never notified that your late header is doing nothing.
//! 2. There's a runtime cost to checking on every write.
//!
//! Instead, hyper handles this statically, or at compile-time. A
//! `Response<Fresh>` includes a `headers_mut()` method, allowing you add more
//! headers. It also does not implement `Write`, so you can't accidentally
//! write early. Once the "head" of the response is correct, you can "send" it
//! out by calling `start` on the `Request<Fresh>`. This will return a new
//! `Request<Streaming>` object, that no longer has `headers_mut()`, but does
//! implement `Write`.
//! //!
//! ```no_run //! ```no_run
//! use hyper::server::{Server, Request, Response}; //! use hyper::server::{Server, Request, Response};

View File

@@ -65,6 +65,7 @@ impl<'a, 'b: 'a> Request<'a, 'b> {
} }
/// Deconstruct a Request into its constituent parts. /// Deconstruct a Request into its constituent parts.
#[inline]
pub fn deconstruct(self) -> (SocketAddr, Method, Headers, pub fn deconstruct(self) -> (SocketAddr, Method, Headers,
RequestUri, HttpVersion, RequestUri, HttpVersion,
HttpReader<&'a mut BufReader<&'b mut NetworkStream>>) { HttpReader<&'a mut BufReader<&'b mut NetworkStream>>) {
@@ -74,6 +75,7 @@ impl<'a, 'b: 'a> Request<'a, 'b> {
} }
impl<'a, 'b> Read for Request<'a, 'b> { impl<'a, 'b> Read for Request<'a, 'b> {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.body.read(buf) self.body.read(buf)
} }

View File

@@ -19,6 +19,12 @@ use version;
/// The outgoing half for a Tcp connection, created by a `Server` and given to a `Handler`. /// The outgoing half for a Tcp connection, created by a `Server` and given to a `Handler`.
///
/// The default `StatusCode` for a `Response` is `200 OK`.
///
/// There is a `Drop` implementation for `Response` that will automatically
/// write the head and flush the body, if the handler has not already done so,
/// so that the server doesn't accidentally leave dangling requests.
#[derive(Debug)] #[derive(Debug)]
pub struct Response<'a, W: Any = Fresh> { pub struct Response<'a, W: Any = Fresh> {
/// The HTTP version of this response. /// The HTTP version of this response.
@@ -39,9 +45,11 @@ impl<'a, W: Any> Response<'a, W> {
pub fn status(&self) -> status::StatusCode { self.status } pub fn status(&self) -> status::StatusCode { self.status }
/// The headers of this response. /// The headers of this response.
#[inline]
pub fn headers(&self) -> &header::Headers { &*self.headers } pub fn headers(&self) -> &header::Headers { &*self.headers }
/// Construct a Response from its constituent parts. /// Construct a Response from its constituent parts.
#[inline]
pub fn construct(version: version::HttpVersion, pub fn construct(version: version::HttpVersion,
body: HttpWriter<&'a mut (Write + 'a)>, body: HttpWriter<&'a mut (Write + 'a)>,
status: status::StatusCode, status: status::StatusCode,
@@ -56,6 +64,7 @@ impl<'a, W: Any> Response<'a, W> {
} }
/// Deconstruct this Response into its constituent parts. /// Deconstruct this Response into its constituent parts.
#[inline]
pub fn deconstruct(self) -> (version::HttpVersion, HttpWriter<&'a mut (Write + 'a)>, pub fn deconstruct(self) -> (version::HttpVersion, HttpWriter<&'a mut (Write + 'a)>,
status::StatusCode, &'a mut header::Headers) { status::StatusCode, &'a mut header::Headers) {
unsafe { unsafe {
@@ -126,6 +135,9 @@ impl<'a> Response<'a, Fresh> {
/// Writes the body and ends the response. /// Writes the body and ends the response.
/// ///
/// This is a shortcut method for when you have a response with a fixed
/// size, and would only need a single `write` call normally.
///
/// # Example /// # Example
/// ///
/// ``` /// ```
@@ -134,6 +146,21 @@ impl<'a> Response<'a, Fresh> {
/// res.send(b"Hello World!").unwrap(); /// res.send(b"Hello World!").unwrap();
/// } /// }
/// ``` /// ```
///
/// The above is the same, but shorter, than the longer:
///
/// ```
/// # use hyper::server::Response;
/// use std::io::Write;
/// use hyper::header::ContentLength;
/// fn handler(mut res: Response) {
/// let body = b"Hello World!";
/// res.headers_mut().set(ContentLength(body.len() as u64));
/// let mut res = res.start().unwrap();
/// res.write_all(body).unwrap();
/// }
/// ```
#[inline]
pub fn send(mut self, body: &[u8]) -> io::Result<()> { pub fn send(mut self, body: &[u8]) -> io::Result<()> {
self.headers.set(header::ContentLength(body.len() as u64)); self.headers.set(header::ContentLength(body.len() as u64));
let mut stream = try!(self.start()); let mut stream = try!(self.start());