1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//! A collection of useful HTTP middlewares.

mod router;

use futures::Future;
use http;

use {Body, Error, Handler, Responder, ResponseBuilder};

pub use self::router::SimpleRouter;

/// Middleware which outputs details of HTTP requests/responses to stdout.
///
/// This middleware wraps another HTTP handler, and logs details about each HTTP request (method and
/// URI) and the associated response (status) to stdout. The logging only occurs when the
/// [`Responder`] returned from the [`Handler`] resolved to a `http::Response`.
///
/// This middleware is intended to help during development. It is expected that any production
/// application creates its own version of this middleware, to integrate it into the application's
/// logging infrastructure.
///
/// [`Responder`]: ../trait.Responder.html [`Handler`]: ../trait.Handler.html [`http::Response`]:
/// https://docs.rs/http/0.1.7/http/response/struct.Response.html
///
/// # Example
///
/// ```no_run
/// extern crate aitch;
/// extern crate http;
///
/// use aitch::servers::hyper::Server;
/// use aitch::{middlewares, Responder, ResponseBuilder, Result};
/// use http::Request;
///
/// fn handler(_req: Request<()>, mut resp: ResponseBuilder) -> impl Responder {
///     resp.body("Hello, world!".to_owned())
/// }
///
/// fn main() -> Result<()> {
///     let wrapped = middlewares::with_stdout_logging(handler);
///
///     let addr = "127.0.0.1:3000".parse()?;
///     println!("Listening on http://{}", addr);
///     Server::new(addr, wrapped)?.run()
/// }
/// ```
///
/// Which outputs the following in response to requests:
///
/// ```ignore
/// Listening on http://127.0.0.1:3000"
/// GET / 200
/// GET /path/doesnt/matter/in/this/example 200
/// ...
/// ```
pub fn with_stdout_logging<B: Body>(handler: impl Handler<B>) -> impl Handler<B> {
    move |req: http::Request<B>, resp: ResponseBuilder| {
        let method = req.method().clone();
        let uri = req.uri().clone();

        handler.handle(req, resp).into_response().map(move |resp| {
            println!("{} {} {}", method, uri.path(), resp.status());
            resp
        })
    }
}

// TODO: Determine whether this pattern is useful, and consider exporting.
pub(crate) fn with_error_handling<B, F, R>(handler: impl Handler<B>, func: F) -> impl Handler<B>
where
    B: Body,
    F: Fn(Error) -> R + Clone + Send + Sync + 'static,
    R: Responder,
{
    with_context(func, move |func, req, resp| {
        handler
            .handle(req, resp)
            .into_response()
            .or_else(move |err| func(err).into_response())
    })
}

/// A middleware which injects shared context into HTTP handlers.
///
/// The `with_context` function is a convenience that makes writing handlers with shared state as
/// easy as possible. In many HTTP applications, handlers need access to shared context/state, such
/// as database connection pools, or configuration information.
///
/// When using `with_context`, handler functions are written using the slightly different type
/// signature, which accepts a context type as the first argument:
///
/// ```ignore
/// Fn(ContextType, http::Request<impl Body>, ResponseBuilder) -> impl Responder
/// ```
///
/// They are then wrapped with `with_context(ctx, func)`, which returns a [`Handler`] which can be
/// passed to middlewares/servers.
///
/// The only constraints on the context type, are that it implements `Clone + Send + Sync`. In many
/// applications, this type will be an [`Arc`], or something that uses [`Arc`] internally.
///
/// [`Handler`]: ../trait.Handler.html
/// [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html
///
/// # Example
///
/// ```no_run
/// extern crate aitch;
/// extern crate http;
///
/// use std::sync::Arc;
///
/// use aitch::servers::hyper::Server;
/// use aitch::{middlewares, Responder, ResponseBuilder, Result};
/// use http::Request;
///
/// struct Context {
///     message: String,
///     // In many applications, this context would also contain a database
///     // connection pool, configuration data, and anything other state that
///     // needs to be shared between handlers:
///     // pool: DatabasePool,
///     // config: Config,
/// }
///
/// fn handler(ctx: Arc<Context>, _req: Request<()>, mut resp: ResponseBuilder) -> impl Responder {
///     resp.body(ctx.message.clone())
/// }
///
/// fn main() -> Result<()> {
///     let ctx = Arc::new(Context {
///         message: "Hello from a world with context!".to_owned(),
///     });
///     let handler = middlewares::with_context(ctx, handler);
///     let wrapped = middlewares::with_stdout_logging(handler);
///
///     let addr = "127.0.0.1:3000".parse()?;
///     println!("Listening on http://{}", addr);
///     Server::new(addr, wrapped)?.run()
/// }
/// ```

pub fn with_context<Ctx, Func, ReqBody, Resp>(ctx: Ctx, handler: Func) -> impl Handler<ReqBody>
where
    Ctx: Clone + Send + Sync + 'static,
    Func: Fn(Ctx, http::Request<ReqBody>, ResponseBuilder) -> Resp + Send + Sync + 'static,
    ReqBody: Body,
    Resp: Responder,
{
    move |req, resp| handler(ctx.clone(), req, resp)
}