[][src]Trait hyperdrive::service::ServiceExt

pub trait ServiceExt: Service + Sized {
    fn catch_unwind<H, R>(self, handler: H) -> CatchUnwind<Self, R, H>
    where
        Self: Service<ResBody = Body, Error = BoxedError> + Sync,
        Self::Future: Send,
        H: Fn(Box<dyn Any + Send>) -> R + Send + Sync + 'static,
        R: IntoFuture<Item = Response<Body>, Error = BoxedError>,
        R::Future: Send + 'static
;
fn make_service_by_cloning(self) -> MakeServiceByCloning<Self>
    where
        Self: Clone
; }

Extension trait for types implementing Hyper's Service trait.

This adds a number of convenience methods that can be used to build robust applications with Hyper and Hyperdrive.

Required methods

fn catch_unwind<H, R>(self, handler: H) -> CatchUnwind<Self, R, H> where
    Self: Service<ResBody = Body, Error = BoxedError> + Sync,
    Self::Future: Send,
    H: Fn(Box<dyn Any + Send>) -> R + Send + Sync + 'static,
    R: IntoFuture<Item = Response<Body>, Error = BoxedError>,
    R::Future: Send + 'static, 

Catches any panics that occur in the service self, and calls an asynchronous panic handler with the panic payload.

The handler can decide if and how the request should be answered. A common option is to return a 500 Internal Server Error response to the client. If the handler returns an error, the connection will be dropped and no response will be sent, which mirrors the behavior of Hyper.

Note: Panics occurring inside of handler will not be caught again. The behavior in this case depends on the futures executor in use. When using tokio, it will catch the panic in the worker thread and recover. The connection to the client will be dropped.

Note: Like std::panic::catch_unwind, this only works when the final binary is compiled with panic = unwind (the default). Using panic = abort will always abort the whole process on any panic and cannot be caught.

Note: This mechanism is not very suitable for logging panics, since no useful backtrace can be constructed and no location information is available. The panic hook mechanism in the standard library is better suited for that (see std::panic::set_hook).

Examples

use hyperdrive::{FromRequest, service::*};
use hyper::{Body, Server, Response};
use futures::Future;
use http::StatusCode;

#[derive(FromRequest)]
enum Routes {
    #[get("/")]
    Panic,
}

let service = SyncService::new(|route: Routes, orig_request| {
    match route {
        Routes::Panic => panic!("Oops, something went wrong!"),
    }
}).catch_unwind(|panic_payload| {
    // We ignore the payload here. We could also downcast it to `String`/`&'static str`
    // and include it in the response.
    let _ = panic_payload;

    let message = r#"
        <!DOCTYPE html>
        <html>
        <body>
            <h1>Internal Server Error</h1>
            <p>
                The server has encountered an internal error and can not process
                your request at this time. Please try again later or contact us
                at <pre>help@example.com</pre>.
            </p>
        </body>
        </html>
    "#;

    Ok(Response::builder()
        .status(StatusCode::INTERNAL_SERVER_ERROR)
        .header("Content-Type", "text/html")
        .body(Body::from(message))
        .expect("couldn't build response"))
}).make_service_by_cloning();

let server = Server::bind(&"127.0.0.1:0".parse().unwrap())
    .serve(service);

tokio::run(server.map_err(|e| {
    panic!("unexpected error: {}", e);
}));

fn make_service_by_cloning(self) -> MakeServiceByCloning<Self> where
    Self: Clone

Creates a type implementing MakeService by cloning self for every incoming connection.

The result of this can be directly passed to Hyper's Builder::serve.

Loading content...

Implementors

impl<T: Service> ServiceExt for T[src]

Loading content...