2018-09-20 04:14:30 +00:00
|
|
|
use request::{FormItems, FormItem, Form, LenientForm, FromForm};
|
|
|
|
|
2018-10-10 11:20:25 +00:00
|
|
|
/// Iterator over form items in a query string.
|
|
|
|
///
|
|
|
|
/// The `Query` type exists to separate, at the type level, _form_ form items
|
|
|
|
/// ([`FormItems`]) from _query_ form items (`Query`). A value of type `Query`
|
|
|
|
/// is passed in to implementations of the [`FromQuery`] trait by Rocket's code
|
|
|
|
/// generation for every trailing query parameter, `<params..>` below:
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # #![feature(proc_macro_hygiene, decl_macro)]
|
|
|
|
/// # #[macro_use] extern crate rocket;
|
|
|
|
/// #
|
|
|
|
/// # use rocket::request::Form;
|
|
|
|
/// # #[derive(FromForm)] struct Q { foo: usize }
|
|
|
|
/// # type T = Form<Q>;
|
|
|
|
/// #
|
|
|
|
/// #[get("/user?<params..>")]
|
|
|
|
/// fn user(params: T) { /* ... */ }
|
|
|
|
/// # fn main() { }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// # Usage
|
|
|
|
///
|
|
|
|
/// A value of type `Query` can only be used as an iterator over values of type
|
|
|
|
/// [`FormItem`]. As such, its usage is equivalent to that of [`FormItems`], and
|
|
|
|
/// we refer you to its documentation for further details.
|
|
|
|
///
|
|
|
|
/// ## Example
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use rocket::request::Query;
|
|
|
|
///
|
|
|
|
/// # use rocket::request::FromQuery;
|
|
|
|
/// #
|
|
|
|
/// # struct MyType;
|
|
|
|
/// # type Result = ::std::result::Result<MyType, ()>;
|
|
|
|
/// #
|
|
|
|
/// # impl<'q> FromQuery<'q> for MyType {
|
|
|
|
/// # type Error = ();
|
|
|
|
/// #
|
|
|
|
/// fn from_query(query: Query) -> Result {
|
|
|
|
/// for item in query {
|
|
|
|
/// println!("query key/value: ({}, {})", item.key, item.value);
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// // ...
|
|
|
|
/// # Ok(MyType)
|
|
|
|
/// }
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct Query<'q>(#[doc(hidden)] pub &'q [FormItem<'q>]);
|
2018-09-20 04:14:30 +00:00
|
|
|
|
2018-10-10 11:20:25 +00:00
|
|
|
impl<'q> Iterator for Query<'q> {
|
2018-09-20 04:14:30 +00:00
|
|
|
type Item = FormItem<'q>;
|
|
|
|
|
|
|
|
#[inline(always)]
|
2018-10-10 11:20:25 +00:00
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
if self.0.is_empty() {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
let next = self.0[0];
|
|
|
|
self.0 = &self.0[1..];
|
|
|
|
Some(next)
|
2018-09-20 04:14:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-10 11:20:25 +00:00
|
|
|
/// Trait implemented by query guards to derive a value from a query string.
|
|
|
|
///
|
|
|
|
/// # Query Guards
|
|
|
|
///
|
|
|
|
/// A query guard operates on multiple items of a request's query string. It
|
|
|
|
/// validates and optionally converts a query string into another value.
|
|
|
|
/// Validation and parsing/conversion is implemented through `FromQuery`. In
|
|
|
|
/// other words, every type that implements `FromQuery` is a query guard.
|
|
|
|
///
|
|
|
|
/// Query guards are used as the target of trailing query parameters, which
|
|
|
|
/// syntactically take the form `<param..>` after a `?` in a route's path. For
|
|
|
|
/// example, the parameter `user` is a trailing query parameter in the following
|
|
|
|
/// route:
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # #![feature(proc_macro_hygiene, decl_macro)]
|
|
|
|
/// # #[macro_use] extern crate rocket;
|
|
|
|
/// use rocket::request::Form;
|
|
|
|
///
|
|
|
|
/// #[derive(FromForm)]
|
|
|
|
/// struct User {
|
|
|
|
/// name: String,
|
|
|
|
/// account: usize,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// #[get("/item?<id>&<user..>")]
|
|
|
|
/// fn item(id: usize, user: Form<User>) { /* ... */ }
|
|
|
|
/// # fn main() { }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// The `FromQuery` implementation of `Form<User>` will be passed in a [`Query`]
|
|
|
|
/// that iterates over all of the query items that don't have the key `id`
|
|
|
|
/// (because of the `<id>` dynamic query parameter). For posterity, note that
|
|
|
|
/// the `value` of an `id=value` item in a query string will be parsed as a
|
|
|
|
/// `usize` and passed in to `item` as `id`.
|
|
|
|
///
|
|
|
|
/// # Forwarding
|
|
|
|
///
|
|
|
|
/// If the conversion fails, signaled by returning an `Err` from a `FromQuery`
|
|
|
|
/// implementation, the incoming request will be forwarded to the next matching
|
|
|
|
/// route, if any. For instance, in the `item` route above, if a query string is
|
|
|
|
/// missing either a `name` or `account` key/value pair, or there is a query
|
|
|
|
/// item with a key that is not `id`, `name`, or `account`, the request will be
|
|
|
|
/// forwarded. Note that this strictness is imposed by the [`Form`] type. As an
|
|
|
|
/// example, using the [`LenientForm`] type instead would allow extra form items
|
|
|
|
/// to be ignored without forwarding. Alternatively, _not_ having a trailing
|
|
|
|
/// parameter at all would result in the same.
|
|
|
|
///
|
|
|
|
/// # Provided Implementations
|
|
|
|
///
|
|
|
|
/// Rocket implements `FromQuery` for several standard types. Their behavior is
|
|
|
|
/// documented here.
|
|
|
|
///
|
|
|
|
/// * **Form<T>** _where_ **T: FromForm**
|
|
|
|
///
|
|
|
|
/// Parses the query as a strict form, where each key is mapped to a field
|
|
|
|
/// in `T`. See [`Form`] for more information.
|
|
|
|
///
|
|
|
|
/// * **LenientForm<T>** _where_ **T: FromForm**
|
|
|
|
///
|
|
|
|
/// Parses the query as a lenient form, where each key is mapped to a field
|
|
|
|
/// in `T`. See [`LenientForm`] for more information.
|
|
|
|
///
|
|
|
|
/// * **Option<T>** _where_ **T: FromQuery**
|
|
|
|
///
|
|
|
|
/// _This implementation always returns successfully._
|
|
|
|
///
|
|
|
|
/// The query is parsed by `T`'s `FromQuery` implementation. If the parse
|
|
|
|
/// succeeds, a `Some(parsed_value)` is returned. Otherwise, a `None` is
|
|
|
|
/// returned.
|
|
|
|
///
|
|
|
|
/// * **Result<T, T::Error>** _where_ **T: FromQuery**
|
|
|
|
///
|
|
|
|
/// _This implementation always returns successfully._
|
|
|
|
///
|
|
|
|
/// The path segment is parsed by `T`'s `FromQuery` mplementation. The
|
|
|
|
/// returned `Result` value is returned.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// Explicitly implementing `FromQuery` should be rare. For most use-cases, a
|
|
|
|
/// query guard of `Form<T>` or `LenientForm<T>`, coupled with deriving
|
|
|
|
/// `FromForm` (as in the previous example) will suffice. For special cases
|
|
|
|
/// however, an implementation of `FromQuery` may be warranted.
|
|
|
|
///
|
|
|
|
/// Consider a contrived scheme where we expect to recieve one query key, `key`,
|
|
|
|
/// three times and wish to take the middle value. For instance, consider the
|
|
|
|
/// query:
|
|
|
|
///
|
|
|
|
/// ```text
|
|
|
|
/// key=first_value&key=second_value&key=third_value
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// We wish to extract `second_value` from this query into a `Contrived` struct.
|
|
|
|
/// Because `Form` and `LenientForm` will take the _last_ value (`third_value`
|
|
|
|
/// here) and don't check that there are exactly three keys named `key`, we
|
|
|
|
/// cannot make use of them and must implement `FromQuery` manually. Such an
|
|
|
|
/// implementation might look like:
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use rocket::http::RawStr;
|
|
|
|
/// use rocket::request::{Query, FromQuery};
|
|
|
|
///
|
|
|
|
/// /// Our custom query guard.
|
|
|
|
/// struct Contrived<'q>(&'q RawStr);
|
|
|
|
///
|
|
|
|
/// impl<'q> FromQuery<'q> for Contrived<'q> {
|
|
|
|
/// /// The number of `key`s we actually saw.
|
|
|
|
/// type Error = usize;
|
|
|
|
///
|
|
|
|
/// fn from_query(query: Query<'q>) -> Result<Self, Self::Error> {
|
|
|
|
/// let mut key_items = query.filter(|i| i.key == "key");
|
|
|
|
///
|
|
|
|
/// // This is cloning an iterator, which is cheap.
|
|
|
|
/// let count = key_items.clone().count();
|
|
|
|
/// if count != 3 {
|
|
|
|
/// return Err(count);
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// // The `ok_or` gets us a `Result`. We will never see `Err(0)`.
|
|
|
|
/// key_items.map(|i| Contrived(i.value)).nth(1).ok_or(0)
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// ```
|
2018-09-20 04:14:30 +00:00
|
|
|
pub trait FromQuery<'q>: Sized {
|
2018-10-10 11:20:25 +00:00
|
|
|
/// The associated error to be returned if parsing/validation fails.
|
2018-09-20 04:14:30 +00:00
|
|
|
type Error;
|
|
|
|
|
2018-10-10 11:20:25 +00:00
|
|
|
/// Parses and validates an instance of `Self` from a query or returns an
|
|
|
|
/// `Error` if parsing or validation fails.
|
|
|
|
fn from_query(query: Query<'q>) -> Result<Self, Self::Error>;
|
2018-09-20 04:14:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'q, T: FromForm<'q>> FromQuery<'q> for Form<T> {
|
|
|
|
type Error = T::Error;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn from_query(q: Query<'q>) -> Result<Self, Self::Error> {
|
|
|
|
T::from_form(&mut FormItems::from(q.0), true).map(Form)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'q, T: FromForm<'q>> FromQuery<'q> for LenientForm<T> {
|
|
|
|
type Error = <T as FromForm<'q>>::Error;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn from_query(q: Query<'q>) -> Result<Self, Self::Error> {
|
|
|
|
T::from_form(&mut FormItems::from(q.0), false).map(LenientForm)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'q, T: FromQuery<'q>> FromQuery<'q> for Option<T> {
|
|
|
|
type Error = !;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn from_query(q: Query<'q>) -> Result<Self, Self::Error> {
|
|
|
|
Ok(T::from_query(q).ok())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'q, T: FromQuery<'q>> FromQuery<'q> for Result<T, T::Error> {
|
|
|
|
type Error = !;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn from_query(q: Query<'q>) -> Result<Self, Self::Error> {
|
|
|
|
Ok(T::from_query(q))
|
|
|
|
}
|
|
|
|
}
|