% Server Guide # Hello, World Let's start off by creating a simple server to just serve a text response of "Hello, World!" to every request. ```no_run extern crate hyper; use hyper::{Decoder, Encoder, HttpStream as Http, Next}; use hyper::server::{Server, Handler, Request, Response}; struct Text(&'static [u8]); impl Handler for Text { fn on_request(&mut self, _req: Request) -> Next { Next::write() } fn on_request_readable(&mut self, _decoder: &mut Decoder) -> Next { Next::write() } fn on_response(&mut self, res: &mut Response) -> Next { use hyper::header::ContentLength; res.headers_mut().set(ContentLength(self.0.len() as u64)); Next::write() } fn on_response_writable(&mut self, encoder: &mut Encoder) -> Next { encoder.write(self.0).unwrap(); // for now Next::end() } } fn main() { let addr = "127.0.0.1:0".parse().unwrap(); let (listening, server) = Server::http(&addr).unwrap() .handle(|_| Text(b"Hello, World")).unwrap(); println!("Listening on http://{}", listening); server.run() } ``` There is quite a few concepts here, so let's tackle them one by one. ## Handler The [`Handler`][Handler] is how you define what should happen during the lifetime of an HTTP message. We've implemented it for the `Text`, defining what should happen at each event during an HTTP message. ## Next Every event in the [`Handler`][Handler] returns a [`Next`][Next]. This signals to hyper what the `Handler` would wishes to do next, and hyper will call the appropriate method of the `Handler` when the action is ready again. So, in our "Hello World" server, you'll notice that when a request comes in, we have no interest in the `Request` or its body. We immediately just wish to write "Hello, World!", and be done. So, in `on_request`, we return `Next::write()`, which tells hyper we wish to write the response. After `on_response` is called, we ask for `Next::write()` again, because we still need to write the response body. hyper knows that the next time the transport is ready to be written, since it already called `on_response`, it will call `on_response_writable`, which is where we can write the text body. Once we're all done with the response, we can tell hyper to finish by returning `Next::end()`. hyper will try to finish flushing all the output, and if the conditions are met, it may try to use the underlying transport for another request. This is also known as "keep-alive". ## Server In the `main` function, a [`Server`][Server] is created that will utilize our `Hello` handler. We use the default options, though you may wish to peruse them, especially the `max_sockets` option, as it is conservative by default. We pass a constructor closure to `Server.handle`, which constructs a `Handler` to be used for each incoming request. # Non-blocking IO ## Don't Panic There is actually a very bad practice in the "Hello, World" example. The usage of `decoder.write(x).unwrap()` will panic if the write operation fails. A panic will take down the whole thread, which means the event loop and all other in-progress requests. So don't do it. It's bad. What makes it worse, is that the write operation is much more likely to fail when using non-blocking IO. If the write would block the thread, instead of doing so, it will return an `io::Error` with the `kind` of `WouldBlock`. These are expected errors. ## WouldBlock Instead, we should inspect when there is a read or write error to see if the `kind` was a `WouldBlock` error. Since `WouldBlock` is so common when using non-blocking IO, the `Encoder` and `Decoder` provide `try_` methods that will special case `WouldBlock`, allowing you to treat all `Err` cases as actual errors. Additionally, it's possible there was a partial write of the response body, so we should probably change the example to keep track of it's progress. Can you see how we should change the example to better handle these conditions? This will just show the updated `on_response_writable` method, the rest stays the same: ```no_run # extern crate hyper; # use hyper::{Encoder, HttpStream as Http, Next}; # struct Text(&'static [u8]); # impl Text { fn on_response_writable(&mut self, encoder: &mut Encoder) -> Next { match encoder.try_write(self.0) { Ok(Some(n)) => { if n == self.0.len() { // all done! Next::end() } else { // a partial write! // with a static array, we can just move our pointer // another option could be to store a separate index field self.0 = &self.0[n..]; // there's still more to write, so ask to write again Next::write() } }, Ok(None) => { // would block, ask to write again Next::write() }, Err(e) => { println!("oh noes, we cannot say hello! {}", e); // remove (kill) this transport Next::remove() } } } # } # fn main() {} ``` # Routing What if we wanted to serve different messages depending on the URL of the request? Say, we wanted to respond with "Hello, World!" to `/hello`, but "Good-bye" with `/bye`. Let's adjust our example to do that. ```no_run extern crate hyper; use hyper::{Decoder, Encoder, HttpStream as Http, Next, StatusCode}; use hyper::server::{Server, Handler, Request, Response}; struct Text(StatusCode, &'static [u8]); impl Handler for Text { fn on_request(&mut self, req: Request) -> Next { use hyper::RequestUri; let path = match *req.uri() { RequestUri::AbsolutePath { path: ref p, .. } => p, RequestUri::AbsoluteUri(ref url) => url.path(), // other 2 forms are for CONNECT and OPTIONS methods _ => "" }; match path { "/hello" => { self.1 = b"Hello, World!"; }, "/bye" => { self.1 = b"Good-bye"; }, _ => { self.0 = StatusCode::NotFound; self.1 = b"Not Found"; } } Next::write() } # fn on_request_readable(&mut self, _decoder: &mut Decoder) -> Next { # Next::write() # } fn on_response(&mut self, res: &mut Response) -> Next { use hyper::header::ContentLength; // we send an HTTP Status Code, 200 OK, or 404 Not Found res.set_status(self.0); res.headers_mut().set(ContentLength(self.1.len() as u64)); Next::write() } # fn on_response_writable(&mut self, encoder: &mut Encoder) -> Next { # match encoder.try_write(self.1) { # Ok(Some(n)) => { # if n == self.1.len() { # Next::end() # } else { # self.1 = &self.1[n..]; # Next::write() # } # }, # Ok(None) => { # Next::write() # }, # Err(e) => { # println!("oh noes, we cannot say hello! {}", e); # Next::remove() # } # } # } } fn main() { let addr = "127.0.0.1:0".parse().unwrap(); let (listening, server) = Server::http(&addr).unwrap() .handle(|_| Text(StatusCode::Ok, b"")).unwrap(); println!("Listening on http://{}", listening); server.run() } ``` # Waiting More often than not, a server needs to something "expensive" before it can provide a response to a request. This may be talking to a database, reading a file, processing an image, sending its own HTTP request to another server, or anything else that would impede the event loop thread. These sorts of actions should be done off the event loop thread, when complete, should notify hyper that it can now proceed. This is done by combining `Next::wait()` and the [`Control`][Control]. ## Control The `Control` is provided to the `Handler` constructor; it is the argument we have so far been ignoring. It's not needed if we don't ever need to wait a transport. The `Control` is usually sent to a queue, or another thread, or wherever makes sense to be able to use it when the "blocking" operations are complete. To focus on hyper instead of obscure blocking operations, we'll use this useless sleeping thread to show it works. ```no_run extern crate hyper; use std::sync::mpsc; use std::thread; use std::time::Duration; use hyper::{Control, Next}; fn calculate_ultimate_question(rx: mpsc::Receiver<(Control, mpsc::Sender<&'static [u8]>)>) { thread::spawn(move || { while let Ok((ctrl, tx)) = rx.recv() { thread::sleep(Duration::from_millis(500)); tx.send(b"42").unwrap(); ctrl.ready(Next::write()).unwrap(); } }); } # fn main() {} ``` Our worker will spawn a thread that waits on messages. When receiving a message, after a short nap, it will send back the "result" of the work, and wake up the waiting transport with a `Next::write()` desire. ## Wait Finally, let's tie in our worker thread into our `Text` handler: ```no_run extern crate hyper; use hyper::{Control, Decoder, Encoder, HttpStream as Http, Next, StatusCode}; use hyper::server::{Server, Handler, Request, Response}; use std::sync::mpsc; struct Text { status: StatusCode, text: &'static [u8], control: Option, worker_tx: mpsc::Sender<(Control, mpsc::Sender<&'static [u8]>)>, worker_rx: Option>, } impl Handler for Text { fn on_request(&mut self, req: Request) -> Next { use hyper::RequestUri; let path = match *req.uri() { RequestUri::AbsolutePath { path: ref p, .. } => p, RequestUri::AbsoluteUri(ref url) => url.path(), _ => "" }; match path { "/hello" => { self.text = b"Hello, World!"; }, "/bye" => { self.text = b"Good-bye"; }, "/question" => { let (tx, rx) = mpsc::channel(); // queue work on our worker self.worker_tx.send((self.control.take().unwrap(), tx)).unwrap(); // save receive channel for response handling self.worker_rx = Some(rx); // tell hyper we need to wait until we can continue return Next::wait(); } _ => { self.status = StatusCode::NotFound; self.text = b"Not Found"; } } Next::write() } # fn on_request_readable(&mut self, _decoder: &mut Decoder) -> Next { # Next::write() # } # fn on_response(&mut self, res: &mut Response) -> Next { use hyper::header::ContentLength; res.set_status(self.status); if let Some(rx) = self.worker_rx.take() { self.text = rx.recv().unwrap(); } res.headers_mut().set(ContentLength(self.text.len() as u64)); Next::write() } # # fn on_response_writable(&mut self, encoder: &mut Encoder) -> Next { # unimplemented!() # } } # fn calculate_ultimate_question(rx: mpsc::Receiver<(Control, mpsc::Sender<&'static [u8]>)>) { # use std::sync::mpsc; # use std::thread; # use std::time::Duration; # thread::spawn(move || { # while let Ok((ctrl, tx)) = rx.recv() { # thread::sleep(Duration::from_millis(500)); # tx.send(b"42").unwrap(); # ctrl.ready(Next::write()).unwrap(); # } # }); # } fn main() { let (tx, rx) = mpsc::channel(); calculate_ultimate_question(rx); let addr = "127.0.0.1:0".parse().unwrap(); let (listening, server) = Server::http(&addr).unwrap() .handle(move |ctrl| Text { status: StatusCode::Ok, text: b"", control: Some(ctrl), worker_tx: tx.clone(), worker_rx: None, }).unwrap(); println!("Listening on http://{}", listening); server.run() } ``` [Control]: ../hyper/struct.Control.html [Handler]: ../hyper/server/trait.Handler.html [Next]: ../hyper/struct.Next.html [Server]: ../hyper/server/struct.Server.html