Skip to content

Commit c37d857

Browse files
committed
Merge pull request #565 from hyperium/dox-server
docs(server): greatly expand how to use a Server
2 parents 5a9c41a + ae5c727 commit c37d857

File tree

3 files changed

+136
-1
lines changed

3 files changed

+136
-1
lines changed

src/server/mod.rs

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,112 @@
11
//! HTTP Server
22
//!
3-
//! # Example
3+
//! # Server
4+
//!
5+
//! A `Server` is created to listen on port, parse HTTP requests, and hand
6+
//! them off to a `Handler`. By default, the Server will listen across multiple
7+
//! threads, but that can be configured to a single thread if preferred.
8+
//!
9+
//! # Handling requests
10+
//!
11+
//! You must pass a `Handler` to the Server that will handle requests. There is
12+
//! a default implementation for `fn`s and closures, allowing you pass one of
13+
//! those easily.
14+
//!
15+
//!
16+
//! ```no_run
17+
//! use hyper::server::{Server, Request, Response};
18+
//!
19+
//! fn hello(req: Request, res: Response) {
20+
//! // handle things here
21+
//! }
22+
//!
23+
//! Server::http(hello).listen("0.0.0.0:0").unwrap();
24+
//! ```
25+
//!
26+
//! As with any trait, you can also define a struct and implement `Handler`
27+
//! directly on your own type, and pass that to the `Server` instead.
28+
//!
29+
//! ```no_run
30+
//! use std::sync::Mutex;
31+
//! use std::sync::mpsc::{channel, Sender};
32+
//! use hyper::server::{Handler, Server, Request, Response};
33+
//!
34+
//! struct SenderHandler {
35+
//! sender: Mutex<Sender<&'static str>>
36+
//! }
37+
//!
38+
//! impl Handler for SenderHandler {
39+
//! fn handle(&self, req: Request, res: Response) {
40+
//! self.sender.lock().unwrap().send("start").unwrap();
41+
//! }
42+
//! }
43+
//!
44+
//!
45+
//! let (tx, rx) = channel();
46+
//! Server::http(SenderHandler {
47+
//! sender: Mutex::new(tx)
48+
//! }).listen("0.0.0.0:0").unwrap();
49+
//! ```
50+
//!
51+
//! Since the `Server` will be listening on multiple threads, the `Handler`
52+
//! must implement `Sync`: any mutable state must be synchronized.
53+
//!
54+
//! ```no_run
55+
//! use std::sync::atomic::{AtomicUsize, Ordering};
56+
//! use hyper::server::{Server, Request, Response};
57+
//!
58+
//! let counter = AtomicUsize::new(0);
59+
//! Server::http(move |req: Request, res: Response| {
60+
//! counter.fetch_add(1, Ordering::Relaxed);
61+
//! }).listen("0.0.0.0:0").unwrap();
62+
//! ```
63+
//!
64+
//! # The `Request` and `Response` pair
65+
//!
66+
//! A `Handler` receives a pair of arguments, a `Request` and a `Response`. The
67+
//! `Request` includes access to the `method`, `uri`, and `headers` of the
68+
//! incoming HTTP request. It also implements `std::io::Read`, in order to
69+
//! read any body, such as with `POST` or `PUT` messages.
70+
//!
71+
//! Likewise, the `Response` includes ways to set the `status` and `headers`,
72+
//! and implements `std::io::Write` to allow writing the response body.
73+
//!
74+
//! ```no_run
75+
//! use std::io;
76+
//! use hyper::server::{Server, Request, Response};
77+
//! use hyper::status::StatusCode;
78+
//!
79+
//! Server::http(|mut req: Request, mut res: Response| {
80+
//! match req.method {
81+
//! hyper::Post => {
82+
//! io::copy(&mut req, &mut res.start().unwrap()).unwrap();
83+
//! },
84+
//! _ => *res.status_mut() = StatusCode::MethodNotAllowed
85+
//! }
86+
//! }).listen("0.0.0.0:0").unwrap();
87+
//! ```
88+
//!
89+
//! ## An aside: Write Status
90+
//!
91+
//! The `Response` uses a phantom type parameter to determine its write status.
92+
//! What does that mean? In short, it ensures you never write a body before
93+
//! adding all headers, and never add a header after writing some of the body.
94+
//!
95+
//! This is often done in most implementations by include a boolean property
96+
//! on the response, such as `headers_written`, checking that each time the
97+
//! body has something to write, so as to make sure the headers are sent once,
98+
//! and only once. But this has 2 downsides:
99+
//!
100+
//! 1. You are typically never notified that your late header is doing nothing.
101+
//! 2. There's a runtime cost to checking on every write.
102+
//!
103+
//! Instead, hyper handles this statically, or at compile-time. A
104+
//! `Response<Fresh>` includes a `headers_mut()` method, allowing you add more
105+
//! headers. It also does not implement `Write`, so you can't accidentally
106+
//! write early. Once the "head" of the response is correct, you can "send" it
107+
//! out by calling `start` on the `Request<Fresh>`. This will return a new
108+
//! `Request<Streaming>` object, that no longer has `headers_mut()`, but does
109+
//! implement `Write`.
4110
//!
5111
//! ```no_run
6112
//! use hyper::server::{Server, Request, Response};

src/server/request.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ impl<'a, 'b: 'a> Request<'a, 'b> {
6565
}
6666

6767
/// Deconstruct a Request into its constituent parts.
68+
#[inline]
6869
pub fn deconstruct(self) -> (SocketAddr, Method, Headers,
6970
RequestUri, HttpVersion,
7071
HttpReader<&'a mut BufReader<&'b mut NetworkStream>>) {
@@ -74,6 +75,7 @@ impl<'a, 'b: 'a> Request<'a, 'b> {
7475
}
7576

7677
impl<'a, 'b> Read for Request<'a, 'b> {
78+
#[inline]
7779
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
7880
self.body.read(buf)
7981
}

src/server/response.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ use version;
1919

2020

2121
/// The outgoing half for a Tcp connection, created by a `Server` and given to a `Handler`.
22+
///
23+
/// The default `StatusCode` for a `Response` is `200 OK`.
24+
///
25+
/// There is a `Drop` implementation for `Response` that will automatically
26+
/// write the head and flush the body, if the handler has not already done so,
27+
/// so that the server doesn't accidentally leave dangling requests.
2228
#[derive(Debug)]
2329
pub struct Response<'a, W: Any = Fresh> {
2430
/// The HTTP version of this response.
@@ -39,9 +45,11 @@ impl<'a, W: Any> Response<'a, W> {
3945
pub fn status(&self) -> status::StatusCode { self.status }
4046

4147
/// The headers of this response.
48+
#[inline]
4249
pub fn headers(&self) -> &header::Headers { &*self.headers }
4350

4451
/// Construct a Response from its constituent parts.
52+
#[inline]
4553
pub fn construct(version: version::HttpVersion,
4654
body: HttpWriter<&'a mut (Write + 'a)>,
4755
status: status::StatusCode,
@@ -56,6 +64,7 @@ impl<'a, W: Any> Response<'a, W> {
5664
}
5765

5866
/// Deconstruct this Response into its constituent parts.
67+
#[inline]
5968
pub fn deconstruct(self) -> (version::HttpVersion, HttpWriter<&'a mut (Write + 'a)>,
6069
status::StatusCode, &'a mut header::Headers) {
6170
unsafe {
@@ -126,6 +135,9 @@ impl<'a> Response<'a, Fresh> {
126135

127136
/// Writes the body and ends the response.
128137
///
138+
/// This is a shortcut method for when you have a response with a fixed
139+
/// size, and would only need a single `write` call normally.
140+
///
129141
/// # Example
130142
///
131143
/// ```
@@ -134,6 +146,21 @@ impl<'a> Response<'a, Fresh> {
134146
/// res.send(b"Hello World!").unwrap();
135147
/// }
136148
/// ```
149+
///
150+
/// The above is the same, but shorter, than the longer:
151+
///
152+
/// ```
153+
/// # use hyper::server::Response;
154+
/// use std::io::Write;
155+
/// use hyper::header::ContentLength;
156+
/// fn handler(mut res: Response) {
157+
/// let body = b"Hello World!";
158+
/// res.headers_mut().set(ContentLength(body.len() as u64));
159+
/// let mut res = res.start().unwrap();
160+
/// res.write_all(body).unwrap();
161+
/// }
162+
/// ```
163+
#[inline]
137164
pub fn send(mut self, body: &[u8]) -> io::Result<()> {
138165
self.headers.set(header::ContentLength(body.len() as u64));
139166
let mut stream = try!(self.start());

0 commit comments

Comments
 (0)