Module hyper::server [] [src]

HTTP Server

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 fns and closures, allowing you pass one of those easily.

use hyper::server::{Server, Request, Response};

fn hello(req: Request, res: Response) {
    // handle things here
}

Server::http("0.0.0.0:0").unwrap().handle(hello).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.

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("0.0.0.0:0").unwrap().handle(SenderHandler {
    sender: Mutex::new(tx)
}).unwrap();

Since the Server will be listening on multiple threads, the Handler must implement Sync: any mutable state must be synchronized.

use std::sync::atomic::{AtomicUsize, Ordering};
use hyper::server::{Server, Request, Response};

let counter = AtomicUsize::new(0);
Server::http("0.0.0.0:0").unwrap().handle(move |req: Request, res: Response| {
    counter.fetch_add(1, Ordering::Relaxed);
}).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.

use std::io;
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;

Server::http("0.0.0.0:0").unwrap().handle(|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
    }
}).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 Response<Fresh>. This will return a new Response<Streaming> object, that no longer has headers_mut(), but does implement Write.

Re-exports

pub use self::request::Request;
pub use self::response::Response;
pub use net::Fresh;
pub use net::Streaming;

Modules

request

Server Requests

response

Server Responses

Structs

Listening

A listening server, which can later be closed.

Server

A server can listen on a TCP socket.

Traits

Handler

A handler that can handle incoming requests for a server.