From ae5c7276c0e167df67d2e8a3e1e2f5fda70fb17c Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Fri, 12 Jun 2015 17:31:17 -0700 Subject: [PATCH] docs(server): greatly expand how to use a Server --- src/server/mod.rs | 108 ++++++++++++++++++++++++++++++++++++++++- src/server/request.rs | 2 + src/server/response.rs | 27 +++++++++++ 3 files changed, 136 insertions(+), 1 deletion(-) diff --git a/src/server/mod.rs b/src/server/mod.rs index 08b92e3e..0f9aee53 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,6 +1,112 @@ //! 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> +//! } +//! +//! 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` 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`. This will return a new +//! `Request` object, that no longer has `headers_mut()`, but does +//! implement `Write`. //! //! ```no_run //! use hyper::server::{Server, Request, Response}; diff --git a/src/server/request.rs b/src/server/request.rs index 48fcdea3..adda55ee 100644 --- a/src/server/request.rs +++ b/src/server/request.rs @@ -65,6 +65,7 @@ impl<'a, 'b: 'a> Request<'a, 'b> { } /// Deconstruct a Request into its constituent parts. + #[inline] pub fn deconstruct(self) -> (SocketAddr, Method, Headers, RequestUri, HttpVersion, 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> { + #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { self.body.read(buf) } diff --git a/src/server/response.rs b/src/server/response.rs index 9c8d43a8..b2d493e2 100644 --- a/src/server/response.rs +++ b/src/server/response.rs @@ -19,6 +19,12 @@ use version; /// 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)] pub struct Response<'a, W: Any = Fresh> { /// 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 } /// The headers of this response. + #[inline] pub fn headers(&self) -> &header::Headers { &*self.headers } /// Construct a Response from its constituent parts. + #[inline] pub fn construct(version: version::HttpVersion, body: HttpWriter<&'a mut (Write + 'a)>, status: status::StatusCode, @@ -56,6 +64,7 @@ impl<'a, W: Any> Response<'a, W> { } /// Deconstruct this Response into its constituent parts. + #[inline] pub fn deconstruct(self) -> (version::HttpVersion, HttpWriter<&'a mut (Write + 'a)>, status::StatusCode, &'a mut header::Headers) { unsafe { @@ -126,6 +135,9 @@ impl<'a> Response<'a, Fresh> { /// 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 /// /// ``` @@ -134,6 +146,21 @@ impl<'a> Response<'a, Fresh> { /// 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<()> { self.headers.set(header::ContentLength(body.len() as u64)); let mut stream = try!(self.start());