hyperdrive/
lib.rs

1//! Composable (a)synchronous HTTP request routing, guarding and decoding.
2//!
3//! This crate provides [Rocket]-inspired HTTP route definitions based on
4//! attributes (`#[get("/user/{id}")]`). It is based on the [`hyper`]
5//! and [`http`] crates, works on **stable Rust**, and supports writing both
6//! synchronous and asynchronous (via [futures 0.1]) apps.
7//!
8//! Check out the examples below for a small taste of how this library can be
9//! used. If you want to dive in deeper, you can check out the [`FromRequest`]
10//! trait, which provides the custom derive that powers most of the magic in
11//! this crate.
12//!
13//! [Rocket]: https://rocket.rs/
14//! [`hyper`]: https://hyper.rs/
15//! [`http`]: https://docs.rs/http
16//! [futures 0.1]: https://docs.rs/futures/0.1
17//! [`FromRequest`]: trait.FromRequest.html
18//!
19//! # Examples
20//!
21//! Use the hyper service adapter [`AsyncService`] to create your async
22//! server without much boilerplate:
23//!
24//! ```
25//! use hyper::{Server, Response, Body};
26//! use hyperdrive::{service::AsyncService, FromRequest};
27//! use futures::IntoFuture;
28//!
29//! #[derive(FromRequest)]
30//! enum Route {
31//!     #[get("/")]
32//!     Index,
33//!
34//!     #[get("/users/{id}")]
35//!     UserInfo { id: u32 },
36//! }
37//!
38//! let srv = Server::bind(&"127.0.0.1:0".parse().unwrap())
39//!     .serve(AsyncService::new(|route: Route, _| {
40//!         match route {
41//!             Route::Index => {
42//!                 Ok(Response::new(Body::from("Hello World!"))).into_future()
43//!             }
44//!             Route::UserInfo { id } => {
45//!                 // You could do an async database query to fetch the user data here
46//!                 Ok(Response::new(Body::from(format!("User #{}", id)))).into_future()
47//!             }
48//!         }
49//!     }));
50//! ```
51//!
52//! If your app doesn't need to be asynchronous and you'd prefer to write sync
53//! code, you can do that by using [`SyncService`]:
54//!
55//! ```
56//! use hyper::{Server, Response, Body};
57//! use hyperdrive::{service::SyncService, FromRequest};
58//!
59//! #[derive(FromRequest)]
60//! enum Route {
61//!     #[get("/")]
62//!     Index,
63//!
64//!     #[get("/users/{id}")]
65//!     UserInfo { id: u32 },
66//! }
67//!
68//! let srv = Server::bind(&"127.0.0.1:0".parse().unwrap())
69//!     .serve(SyncService::new(|route: Route, _| {
70//!         // This closure can block freely, and has to return a `Response<Body>`
71//!         match route {
72//!             Route::Index => {
73//!                 Response::new(Body::from("Hello World!"))
74//!             },
75//!             Route::UserInfo { id } => {
76//!                 Response::new(Body::from(format!("User #{}", id)))
77//!             }
78//!         }
79//!     }));
80//! ```
81//!
82//! If the provided service adapters aren't sufficient for your use case, you
83//! can always manually use the [`FromRequest`] methods, and hook it up to your
84//! hyper `Service` manually:
85//!
86//! ```
87//! use hyper::{Request, Response, Body, Method, service::Service};
88//! use futures::Future;
89//! use hyperdrive::{FromRequest, DefaultFuture, BoxedError, NoContext};
90//!
91//! #[derive(FromRequest)]
92//! enum Route {
93//!     #[get("/")]
94//!     Index,
95//!
96//!     #[get("/users/{id}")]
97//!     UserInfo { id: u32 },
98//! }
99//!
100//! // Define your hyper `Service`:
101//! struct MyService;
102//!
103//! impl Service for MyService {
104//!     type ReqBody = Body;
105//!     type ResBody = Body;
106//!     type Error = BoxedError;
107//!     type Future = DefaultFuture<Response<Body>, BoxedError>;
108//!
109//!     fn call(&mut self, req: Request<Body>) -> Self::Future {
110//!         let is_head = req.method() == Method::HEAD;
111//!         let future = Route::from_request(req, NoContext).and_then(|route| Ok(match route {
112//!             Route::Index => {
113//!                 Response::new(Body::from("Hello world!"))
114//!             }
115//!             Route::UserInfo { id } => {
116//!                 Response::new(Body::from(format!("User #{} is secret!", id)))
117//!             }
118//!         })).map(move |resp| {
119//!             if is_head {
120//!                 // Response to HEAD requests must have an empty body
121//!                 resp.map(|_| Body::empty())
122//!             } else {
123//!                 resp
124//!             }
125//!         });
126//!
127//!         Box::new(future)
128//!     }
129//! }
130//! ```
131//!
132//! For detailed documentation on the custom derive syntax, refer to the docs of
133//! [`FromRequest`].
134//!
135//! [`AsyncService`]: service/struct.AsyncService.html
136//! [`SyncService`]: service/struct.SyncService.html
137//! [`FromRequest`]: trait.FromRequest.html
138
139/*
140
141TODO:
142* How to handle 2015/2018 compat with the proc-macro?
143* Good example that fetches a session from a DB
144
145*/
146// Deny certain warnings inside doc tests / examples. When this isn't present, rustdoc doesn't show
147// *any* warnings at all.
148#![doc(test(attr(deny(unused_imports, unused_must_use))))]
149#![doc(html_root_url = "https://docs.rs/hyperdrive/0.2.0")]
150#![warn(missing_debug_implementations)]
151#![warn(missing_docs)]
152#![warn(rust_2018_idioms)]
153
154pub mod body;
155mod error;
156mod readme;
157pub mod service;
158
159pub use error::*;
160pub use hyperderive::*;
161
162// Reexport public deps for use by the custom derive
163pub use {futures, http, hyper, serde};
164
165// These are hidden because the user never actually interacts with them. They're
166// only used by the generated code internally.
167#[doc(hidden)]
168pub use {lazy_static::lazy_static, regex};
169
170use futures::{Future, IntoFuture};
171use std::sync::Arc;
172use tokio::runtime::current_thread::Runtime;
173
174/// A default boxed future that may be returned from [`FromRequest`],
175/// [`FromBody`] and [`Guard`] implementations.
176///
177/// The future is required to be `Send` to allow running it on a multi-threaded
178/// executor.
179///
180/// [`FromRequest`]: trait.FromRequest.html
181/// [`FromBody`]: trait.FromBody.html
182/// [`Guard`]: trait.Guard.html
183pub type DefaultFuture<T, E> = Box<dyn Future<Item = T, Error = E> + Send>;
184
185/// A boxed `std::error::Error` that can be used when the actual error type is
186/// unknown.
187pub type BoxedError = Box<dyn std::error::Error + Send + Sync>;
188
189/// Trait for asynchronous conversion from HTTP requests.
190///
191/// # `#[derive(FromRequest)]`
192///
193/// This trait can be derived for enums to generate a request router and
194/// decoder. Here's a simple example:
195///
196/// ```
197/// use hyperdrive::{FromRequest, body::Json};
198/// # use serde::Deserialize;
199///
200/// #[derive(FromRequest)]
201/// enum Routes {
202///     #[get("/")]
203///     Index,
204///
205///     #[get("/users/{id}")]
206///     User { id: u32 },
207///
208///     #[post("/login")]
209///     Login {
210///         #[body]
211///         data: Json<Login>,
212///     },
213/// }
214///
215/// #[derive(Deserialize)]
216/// struct Login {
217///     email: String,
218///     password: String,
219/// }
220/// ```
221///
222/// Calling `Routes::from_request` will result in `Routes::Index` for a `GET /`
223/// request, and in `Routes::User` for a `GET /users/123` request, for example.
224/// A `POST /login` request will end up as `Routes::Login`, decoding the POSTed
225/// JSON body.
226///
227/// The generated `FromRequest` implementation will always use
228/// [`DefaultFuture<Self, BoxedError>`][`DefaultFuture`] as the associated
229/// `Result` type.
230///
231/// Note that the generated implementation will make use of `.and_then()` to
232/// chain asynchronous operations instead of running them in parallel using
233/// `join_all`. This is because it simplifies the code and doesn't require
234/// making use of boxed futures everywhere in the generated code. Multiple
235/// requests will still be handled in parallel, so this should not negatively
236/// affect performance.
237///
238/// In order to keep the implementation simple and user code more easily
239/// understandable, overlapping paths are not allowed (unless the paths are
240/// *exactly* the same, and the method differs), so the following will fail to
241/// compile:
242///
243/// ```compile_fail
244/// use from_request::{FromRequest, body::Json};
245/// # use serde::Deserialize;
246///
247/// #[derive(FromRequest)]  //~ ERROR: route `#[get("/users/me")]` overlaps with ...
248/// enum Routes {
249///     #[get("/users/{id}")]
250///     User { id: u32 },
251///
252///     #[get("/users/me")]
253///     Me,
254/// }
255/// ```
256///
257/// To fix this, you can define a custom type implementing `FromStr` and use
258/// that:
259///
260/// ```
261/// use hyperdrive::FromRequest;
262/// # use std::str::FromStr;
263/// # use std::num::ParseIntError;
264///
265/// #[derive(FromRequest)]
266/// enum Routes {
267///     #[get("/users/{id}")]
268///     User { id: UserId },
269/// }
270///
271/// enum UserId {
272///     /// User by database ID.
273///     Id(u32),
274///     /// The currently logged-in user.
275///     Me,
276/// }
277///
278/// impl FromStr for UserId {
279///     type Err = ParseIntError;
280///
281///     fn from_str(s: &str) -> Result<Self, Self::Err> {
282///         if s == "me" {
283///             Ok(UserId::Me)
284///         } else {
285///             Ok(UserId::Id(s.parse()?))
286///         }
287///     }
288/// }
289/// ```
290///
291/// ## Implicit `HEAD` routes
292///
293/// The custom derive will create a `HEAD` route for every defined `GET` route,
294/// unless you define one yourself. If your app uses [`AsyncService`] or
295/// [`SyncService`], those adapters will automatically take care of dropping the
296/// body from the response to `HEAD` requests. If you manually call
297/// [`FromRequest::from_request`][`from_request`], you have to make sure no body
298/// is sent back for `HEAD` requests.
299///
300/// ## Extracting Request Data
301///
302/// The custom derive provides easy access to various kinds of data encoded in a
303/// request:
304///
305/// * The Request path (`/users/or/other/stuff`)
306/// * Query parameters (`?name=val`)
307/// * The request body
308///
309/// ### Extracting Path Segments (`{field}` syntax)
310///
311/// In a route attribute, the `{field}` placeholder syntax will match a path
312/// segment and convert it to the type of the named field using `FromStr`:
313///
314/// ```notrust
315/// #[get("/users/{id}")]
316/// ```
317///
318/// To extract multiple path segments this way, the `{field...}` syntax can be
319/// used at the end of the path, which will consume the rest of the path:
320///
321/// ```notrust
322/// #[get("/static/{path...}")]
323/// ```
324///
325/// If the `FromStr` conversion fails, the generated `FromRequest`
326/// implementation will bail out with an error (in other words, this feature
327/// cannot be used to try multiple routes in sequence until one matches).
328///
329/// ### Extracting the request body (`#[body]` attribute)
330///
331/// Putting `#[body]` on a field of a variant will deserialize the request body
332/// using the [`FromBody`] trait and store the result in the annotated field:
333///
334/// ```notrust
335/// #[post("/login")]
336/// Login {
337///     #[body]
338///     data: Json<Login>,
339/// },
340/// ```
341///
342/// The type of the field must implement [`FromBody`]. The [`body`] module
343/// contains predefined adapters implementing that trait, which work with any
344/// type implementing `Deserialize`.
345///
346/// ### Extracting query parameters (`#[query_params]` attribute)
347///
348/// The route attribute cannot match or extract query parameters (`?name=val`).
349/// Instead, query parameters can be extracted by marking a field in the struct
350/// with the `#[query_params]` attribute:
351///
352/// ```
353/// use hyperdrive::FromRequest;
354/// # use serde::Deserialize;
355///
356/// #[derive(FromRequest)]
357/// enum Routes {
358///     #[get("/users")]
359///     UserList {
360///         #[query_params]
361///         pagination: Option<Pagination>,
362///     },
363/// }
364///
365/// #[derive(Deserialize)]
366/// struct Pagination {
367///     start_id: u32,
368///     count: u32,
369/// }
370/// ```
371///
372/// A request like `GET /users?start_id=42&count=10` would thus end up with a
373/// corresponding `Pagination` object, while `GET /users` would store `None` in
374/// the `pagination` field.
375///
376/// The type of the `#[query_params]` field must implement serde's `Deserialize`
377/// trait and the conversion will be performed using the `serde_urlencoded`
378/// crate.
379///
380/// ## Guards
381///
382/// Guards can be used to prevent a route from being called when a condition is
383/// not fulfilled (for example, when the user isn't logged in). They can also
384/// extract arbitrary data from the request headers (eg. a session ID, or the
385/// User-Agent string).
386///
387/// All fields that are neither mentioned in the route path nor annotated with
388/// an attribute are considered guards and thus must implement the [`Guard`]
389/// trait.
390///
391/// ```
392/// use hyperdrive::{FromRequest, Guard};
393/// # use hyperdrive::{BoxedError, NoContext};
394/// # use std::sync::Arc;
395///
396/// struct User {
397///     id: u32,
398///     // ...
399/// }
400///
401/// impl Guard for User {
402///     // (omitted for brevity)
403/// #     type Context = NoContext;
404/// #     type Result = Result<Self, BoxedError>;
405/// #     fn from_request(_: &Arc<http::Request<()>>, _: &NoContext) -> Result<Self, BoxedError> {
406/// #         User { id: 0 }.id;
407/// #         Ok(User { id: 0 })
408/// #     }
409/// }
410///
411/// #[derive(FromRequest)]
412/// enum Route {
413///     #[get("/login")]
414///     LoginForm,
415///
416///     #[get("/staff")]
417///     Staff {
418///         // Require a logged-in user to make this request
419///         user: User,
420///     },
421/// }
422/// ```
423///
424/// ## Forwarding
425///
426/// A field whose type implements `FromRequest` can be marked with `#[forward]`.
427/// The library will then generate code that invokes this nested `FromRequest`
428/// implementation.
429///
430/// This feature can not be combined with `#[body]` inside the same variant,
431/// since both consume the request body.
432///
433/// Currently, this is limited to `FromRequest` implementations that use the
434/// same [`RequestContext`] as the outer type (ie. no automatic `AsRef`
435/// conversion will take place).
436///
437/// A variant or struct defining a `#[forward]` field does not have to define
438/// a route. If no other route matches, this variant will automatically be
439/// created, and is considered a *fallback route*.
440///
441/// Combined with generics, this feature can be used to make request wrappers
442/// that attach a guard or a guard group to any type implementing `FromRequest`:
443///
444/// ```
445/// use hyperdrive::{FromRequest, Guard};
446/// # use hyperdrive::{NoContext, BoxedError};
447/// # use std::sync::Arc;
448///
449/// struct User;
450/// impl Guard for User {
451///     // (omitted for brevity)
452/// #     type Context = NoContext;
453/// #     type Result = Result<Self, BoxedError>;
454/// #     fn from_request(_: &Arc<http::Request<()>>, _: &NoContext) -> Result<Self, BoxedError> {
455/// #         Ok(User)
456/// #     }
457/// }
458///
459/// #[derive(FromRequest)]
460/// struct Authenticated<T> {
461///     user: User,
462///
463///     #[forward]
464///     inner: T,
465/// }
466/// ```
467///
468/// ## Changing the `Context` type
469///
470/// By default, the generated code will use [`NoContext`] as the associated
471/// `Context` type. You can change this to any other type that implements
472/// [`RequestContext`] by putting a `#[context(MyContext)]` attribute on the
473/// type:
474///
475/// ```
476/// # struct MyDatabaseConnection;
477/// use hyperdrive::{FromRequest, RequestContext};
478///
479/// #[derive(RequestContext)]
480/// struct MyContext {
481///     db: MyDatabaseConnection,
482/// }
483///
484/// #[derive(FromRequest)]
485/// #[context(MyContext)]
486/// enum Routes {
487///     #[get("/users")]
488///     UserList,
489/// }
490/// ```
491///
492/// For more info on this, refer to the [`RequestContext`] trait.
493///
494/// [`AsyncService`]: service/struct.AsyncService.html
495/// [`SyncService`]: service/struct.SyncService.html
496/// [`FromBody`]: trait.FromBody.html
497/// [`RequestContext`]: trait.RequestContext.html
498/// [`Guard`]: trait.Guard.html
499/// [`NoContext`]: struct.NoContext.html
500/// [`DefaultFuture`]: type.DefaultFuture.html
501/// [`body`]: body/index.html
502/// [`from_request`]: #tymethod.from_request
503pub trait FromRequest: Sized {
504    /// A context parameter passed to [`from_request`].
505    ///
506    /// This can be used to pass application-specific data like a logger or a
507    /// database connection around.
508    ///
509    /// If no context is needed, this should be set to [`NoContext`], which is a
510    /// context type that can be obtained from any [`RequestContext`] via
511    /// `AsRef`.
512    ///
513    /// [`from_request`]: #tymethod.from_request
514    /// [`NoContext`]: struct.NoContext.html
515    /// [`RequestContext`]: trait.RequestContext.html
516    type Context: RequestContext;
517
518    /// The future returned by [`from_request`].
519    ///
520    /// Because `impl Trait` cannot be used inside traits (and named
521    /// existential types aren't yet stable), the type here might not be
522    /// nameable. In that case, you can set it to
523    /// [`DefaultFuture<Self, BoxedError>`][`DefaultFuture`] and box the
524    /// returned future.
525    ///
526    /// [`DefaultFuture`]: type.DefaultFuture.html
527    /// [`from_request`]: #tymethod.from_request
528    type Future: Future<Item = Self, Error = BoxedError> + Send;
529
530    /// Creates a `Self` from an HTTP request, asynchronously.
531    ///
532    /// This takes the request metadata, body, and a user-defined context. Only
533    /// the body is consumed.
534    ///
535    /// Implementations of this function must not block, since this function is
536    /// always run on a futures executor. If you need to perform blocking I/O or
537    /// long-running computations, you can call [`tokio_threadpool::blocking`].
538    ///
539    /// # Parameters
540    ///
541    /// * **`request`**: HTTP request data (headers, path, method, etc.).
542    /// * **`body`**: The streamed HTTP body.
543    /// * **`context`**: The user-defined context.
544    ///
545    /// [`tokio_threadpool::blocking`]: ../tokio_threadpool/fn.blocking.html
546    fn from_request_and_body(
547        request: &Arc<http::Request<()>>,
548        body: hyper::Body,
549        context: Self::Context,
550    ) -> Self::Future;
551
552    /// Create a `Self` from an HTTP request, asynchronously.
553    ///
554    /// This consumes the request *and* the context.
555    ///
556    /// Implementations of this function must not block, since this function is
557    /// always run on a futures executor. If you need to perform blocking I/O or
558    /// long-running computations, you can call [`tokio_threadpool::blocking`].
559    ///
560    /// A blocking wrapper around this method is provided by
561    /// [`from_request_sync`].
562    ///
563    /// # Parameters
564    ///
565    /// * **`request`**: An HTTP request from the `http` crate, containing a
566    ///   `hyper::Body`.
567    /// * **`context`**: User-defined context.
568    ///
569    /// [`from_request_sync`]: #method.from_request_sync
570    /// [`tokio_threadpool::blocking`]: ../tokio_threadpool/fn.blocking.html
571    fn from_request(request: http::Request<hyper::Body>, context: Self::Context) -> Self::Future {
572        let (parts, body) = request.into_parts();
573        let request = Arc::new(http::Request::from_parts(parts, ()));
574
575        Self::from_request_and_body(&request, body, context)
576    }
577
578    /// Create a `Self` from an HTTP request, synchronously.
579    ///
580    /// This is a blocking version of [`from_request`]. The provided default
581    /// implementation will internally create a single-threaded tokio runtime to
582    /// perform the conversion and receive the request body.
583    ///
584    /// Note that this does not provide a way to *write* a blocking version of
585    /// [`from_request`]. Implementors of this trait must always implement
586    /// [`from_request`] in a non-blocking fashion, even if they *also*
587    /// implement this method.
588    ///
589    /// [`from_request`]: #tymethod.from_request
590    fn from_request_sync(
591        request: http::Request<hyper::Body>,
592        context: Self::Context,
593    ) -> Result<Self, BoxedError> {
594        let mut rt = Runtime::new().expect("couldn't start single-threaded tokio runtime");
595        rt.block_on(Self::from_request(request, context).into_future())
596    }
597}
598
599/// A request guard that checks a condition or extracts data out of an incoming
600/// request.
601///
602/// For example, this could be used to extract an `Authorization` header and
603/// verify user credentials, or to look up a session token in a database.
604///
605/// A `Guard` can not access the request body. If you need to do that, implement
606/// [`FromBody`] instead.
607///
608/// # Examples
609///
610/// Define a guard that ensures that required request headers are present:
611///
612/// ```
613/// # use hyperdrive::{Guard, NoContext, BoxedError};
614/// # use std::sync::Arc;
615/// struct MustFrobnicate;
616///
617/// impl Guard for MustFrobnicate {
618///     type Context = NoContext;
619///     type Result = Result<Self, BoxedError>;
620///
621///     fn from_request(request: &Arc<http::Request<()>>, context: &Self::Context) -> Self::Result {
622///         if request.headers().contains_key("X-Frobnicate") {
623///             Ok(MustFrobnicate)
624///         } else {
625///             let msg = "request did not contain mandatory `X-Frobnicate` header";
626///             Err(String::from(msg).into())
627///         }
628///     }
629/// }
630/// ```
631///
632/// Use server settings stored in a [`RequestContext`] to exclude certain user
633/// agents:
634///
635/// ```
636/// # use hyperdrive::{Guard, RequestContext, BoxedError};
637/// # use std::sync::Arc;
638/// #[derive(RequestContext)]
639/// struct ForbiddenAgents {
640///     agents: Vec<String>,
641/// }
642///
643/// struct RejectForbiddenAgents;
644///
645/// impl Guard for RejectForbiddenAgents {
646///     type Context = ForbiddenAgents;
647///     type Result = Result<Self, BoxedError>;
648///
649///     fn from_request(request: &Arc<http::Request<()>>, context: &Self::Context) -> Self::Result {
650///         let agent = request.headers().get("User-Agent")
651///             .ok_or_else(|| String::from("No User-Agent header"))?;
652///
653///         if context.agents.iter().any(|f| f == agent) {
654///             Err(String::from("This User-Agent is forbidden!").into())
655///         } else {
656///             Ok(RejectForbiddenAgents)
657///         }
658///     }
659/// }
660/// ```
661///
662/// [`FromBody`]: trait.FromBody.html
663/// [`RequestContext`]: trait.RequestContext.html
664pub trait Guard: Sized {
665    /// A context parameter passed to [`Guard::from_request`].
666    ///
667    /// This can be used to pass application-specific data like a database
668    /// connection or server configuration (eg. for limiting the maximum HTTP
669    /// request size) around.
670    ///
671    /// If no context is needed, this should be set to [`NoContext`].
672    ///
673    /// [`Guard::from_request`]: #tymethod.from_request
674    /// [`NoContext`]: struct.NoContext.html
675    type Context: RequestContext;
676
677    /// The result returned by [`Guard::from_request`].
678    ///
679    /// Because `impl Trait` cannot be used inside traits (and named
680    /// existential types aren't stable), the type here might not be
681    /// nameable. In that case, you can set it to
682    /// [`DefaultFuture<Self, Error>`][`DefaultFuture`] and box the returned
683    /// future.
684    ///
685    /// If your guard doesn't need to return a future (eg. because it's just a
686    /// parsing step), you can set this to `Result<Self, BoxedError>` and
687    /// immediately return the result of the conversion.
688    ///
689    /// [`Guard::from_request`]: #tymethod.from_request
690    /// [`DefaultFuture`]: type.DefaultFuture.html
691    type Result: IntoFuture<Item = Self, Error = BoxedError>;
692
693    /// Create an instance of this type from HTTP request data, asynchronously.
694    ///
695    /// This can inspect HTTP headers and other data provided by
696    /// [`http::Request`], but can not access the body of the request. If access
697    /// to the body is needed, [`FromBody`] must be implemented instead.
698    ///
699    /// Implementations of this function must not block, since this function is
700    /// always run on a futures executor. If you need to perform blocking I/O or
701    /// long-running computations, you can call [`tokio_threadpool::blocking`].
702    ///
703    /// # Parameters
704    ///
705    /// * **`request`**: An HTTP request (without body) from the `http` crate.
706    /// * **`context`**: User-defined context needed by the guard.
707    ///
708    /// [`http::Request`]: ../http/request/struct.Request.html
709    /// [`FromBody`]: trait.FromBody.html
710    /// [`tokio_threadpool::blocking`]: ../tokio_threadpool/fn.blocking.html
711    fn from_request(request: &Arc<http::Request<()>>, context: &Self::Context) -> Self::Result;
712}
713
714/// Asynchronous conversion from an HTTP request body.
715///
716/// Types implementing this trait are provided in the [`body`] module. They
717/// allow easy deserialization from a variety of data formats.
718///
719/// # Examples
720///
721/// Collect the whole body and then deserialize it using a serde data format
722/// crate `serde_whatever`:
723///
724/// ```
725/// # use hyperdrive::{FromBody, NoContext, DefaultFuture, BoxedError};
726/// # use futures::prelude::*;
727/// # use serde_json as serde_whatever;
728/// # use std::sync::Arc;
729/// struct CustomFormat<T>(T);
730///
731/// impl<T: serde::de::DeserializeOwned + Send + 'static> FromBody for CustomFormat<T> {
732///     type Context = NoContext;
733///     type Result = DefaultFuture<Self, BoxedError>;
734///
735///     fn from_body(
736///         request: &Arc<http::Request<()>>,
737///         body: hyper::Body,
738///         context: &Self::Context,
739///     ) -> Self::Result {
740///         Box::new(body.concat2().map_err(Into::into).and_then(|body| {
741///             match serde_whatever::from_slice(&body) {
742///                 Ok(t) => Ok(CustomFormat(t)),
743///                 Err(e) => Err(e.into()),
744///             }
745///         }))
746///     }
747/// }
748/// ```
749///
750/// Process the body stream on-the-fly and calculate a checksum by adding all
751/// the bytes:
752///
753/// ```
754/// # use hyperdrive::{FromBody, NoContext, DefaultFuture, BoxedError};
755/// # use futures::prelude::*;
756/// # use std::sync::Arc;
757/// struct BodyChecksum(u8);
758///
759/// impl FromBody for BodyChecksum {
760///     type Context = NoContext;
761///     type Result = DefaultFuture<Self, BoxedError>;
762///
763///     fn from_body(
764///         request: &Arc<http::Request<()>>,
765///         body: hyper::Body,
766///         context: &Self::Context,
767///     ) -> Self::Result {
768///         Box::new(body
769///             .map_err(BoxedError::from)
770///             .fold(0, |checksum, chunk| -> Result<_, BoxedError> {
771///                 Ok(chunk.as_ref().iter()
772///                     .fold(checksum, |checksum: u8, byte| {
773///                         checksum.wrapping_add(*byte)
774///                 }))
775///             })
776///             .map(|checksum| BodyChecksum(checksum))  // wrap it up to create a `Self`
777///         )
778///     }
779/// }
780/// ```
781///
782/// [`body`]: body/index.html
783pub trait FromBody: Sized {
784    /// A context parameter passed to [`from_body`].
785    ///
786    /// This can be used to pass application-specific data like a logger or a
787    /// database connection around.
788    ///
789    /// If no context is needed, this should be set to [`NoContext`].
790    ///
791    /// [`from_body`]: #tymethod.from_body
792    /// [`NoContext`]: struct.NoContext.html
793    type Context: RequestContext;
794
795    /// The result returned by [`from_body`].
796    ///
797    /// Because `impl Trait` cannot be used inside traits (and named
798    /// existential types aren't stable), the type here might not be
799    /// nameable. In that case, you can set it to
800    /// [`DefaultFuture<Self, Error>`][`DefaultFuture`] and box the returned
801    /// future.
802    ///
803    /// If your `FromBody` implementation doesn't need to return a future, you
804    /// can set this to `Result<Self, BoxedError>` and immediately return the
805    /// result of the conversion.
806    ///
807    /// [`DefaultFuture`]: type.DefaultFuture.html
808    /// [`from_body`]: #tymethod.from_body
809    type Result: IntoFuture<Item = Self, Error = BoxedError>;
810
811    /// Create an instance of this type from an HTTP request body,
812    /// asynchronously.
813    ///
814    /// This will consume the body, so only one `FromBody` type can be used for
815    /// every processed request.
816    ///
817    /// Implementations of this function must not block, since this function is
818    /// always run on a futures executor. If you need to perform blocking I/O or
819    /// long-running computations, you can call [`tokio_threadpool::blocking`].
820    ///
821    /// **Note**: You probably want to limit the size of the body to prevent
822    /// denial of service attacks.
823    ///
824    /// # Parameters
825    ///
826    /// * **`request`**: An HTTP request (without body) from the `http` crate.
827    /// * **`body`**: The body stream. Implements `futures::Stream`.
828    /// * **`context`**: User-defined context.
829    ///
830    /// [`Guard`]: trait.Guard.html
831    /// [`tokio_threadpool::blocking`]: ../tokio_threadpool/fn.blocking.html
832    fn from_body(
833        request: &Arc<http::Request<()>>,
834        body: hyper::Body,
835        context: &Self::Context,
836    ) -> Self::Result;
837}
838
839/// A default [`RequestContext`] containing no data.
840///
841/// This context type should be used in [`FromRequest`], [`FromBody`] and
842/// [`Guard`] implementations whenever no application-specific context is
843/// needed. It can be created from any [`RequestContext`] via
844/// `AsRef<NoContext>`.
845///
846/// [`FromRequest`]: trait.FromRequest.html
847/// [`FromBody`]: trait.FromBody.html
848/// [`Guard`]: trait.Guard.html
849/// [`RequestContext`]: trait.RequestContext.html
850#[derive(Debug, Copy, Clone, Default)]
851pub struct NoContext;
852
853/// Trait for context types passed to [`FromRequest`], [`FromBody`] and
854/// [`Guard`].
855///
856/// # `#[derive(RequestContext)]`
857///
858/// This trait can be derived automatically. This will also implement
859/// `AsRef<Self>` and `AsRef<NoContext>`.
860///
861/// On structs, fields can also be annotated using `#[as_ref]`, which generates
862/// an additional implementation of `AsRef` for that field (note that all
863/// `#[as_ref]` fields must have distinct types). This will automatically use
864/// the field's type as a context when required by a `FromRequest` impl.
865///
866/// # Examples
867///
868/// Create your own context that allows running database queries in [`Guard`]s
869/// and elsewhere:
870/// ```
871/// # use hyperdrive::RequestContext;
872/// # struct ConnectionPool {}
873/// #[derive(RequestContext)]
874/// struct MyContext {
875///     db: ConnectionPool,
876/// }
877/// ```
878///
879/// Create a context that contains the above context and additional data:
880/// ```
881/// # use hyperdrive::RequestContext;
882/// # struct Logger {}
883/// # #[derive(RequestContext)]
884/// # struct MyContext {}
885/// #[derive(RequestContext)]
886/// struct BigContext {
887///     #[as_ref]
888///     inner: MyContext,
889///     logger: Logger,
890/// }
891/// ```
892/// This context can be used in the same places where `MyContext` is accepted,
893/// but provides additional data that may be used only by a few [`Guard`],
894/// [`FromRequest`] or [`FromBody`] implementations.
895///
896/// [`Guard`]: trait.Guard.html
897/// [`FromRequest`]: trait.FromRequest.html
898/// [`FromBody`]: trait.FromBody.html
899pub trait RequestContext: AsRef<Self> + AsRef<NoContext> {}
900
901impl RequestContext for NoContext {}
902
903impl AsRef<NoContext> for NoContext {
904    fn as_ref(&self) -> &Self {
905        &NoContext
906    }
907}
908
909/// Turns a blocking closure into an asynchronous `Future`.
910///
911/// This function takes a blocking closure that does synchronous I/O or heavy
912/// computations, and turns it into a well-behaved asynchronous `Future` by
913/// running it on a thread pool.
914///
915/// The returned future will have `'static` lifetime if the passed closure and
916/// the success and error types do.
917///
918/// This is a convenience wrapper around [`tokio_threadpool::blocking`].
919///
920/// [`tokio_threadpool::blocking`]: ../tokio_threadpool/fn.blocking.html
921pub fn blocking<F, T, E>(f: F) -> impl Future<Item = T, Error = E>
922where
923    F: FnOnce() -> Result<T, E>,
924{
925    // Needs a small `Option` dance because `poll_fn` takes an `FnMut`
926    let mut f = Some(f);
927
928    futures::future::poll_fn(move || {
929        tokio_threadpool::blocking(|| f.take().unwrap()()).map_err(|blocking_err| {
930            // `blocking` only returns errors in critical situations:
931            // - when the threadpool has already shut down
932            // - when tokio isn't running
933            // This wrapper just panics in that situation.
934            panic!(
935                "`tokio_threadpool::blocking` returned error: {}",
936                blocking_err
937            );
938        })
939    })
940    .and_then(|result| result)
941}