mirror of https://github.com/rwf2/Rocket.git
Document most of the request module.
This commit is contained in:
parent
79eab0e907
commit
2da43e24f7
|
@ -52,7 +52,7 @@
|
||||||
//! extern crate rocket;
|
//! extern crate rocket;
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! See the [guide](https://guide.rocket.rs) for more information on how to
|
//! See the [guide](https://rocket.rs/guide) for more information on how to
|
||||||
//! write Rocket applications. Here's a simple example to get you started:
|
//! write Rocket applications. Here's a simple example to get you started:
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
|
|
|
@ -9,6 +9,34 @@ use http::hyper::{HyperBodyReader, HyperHttpStream};
|
||||||
use http::hyper::HyperNetworkStream;
|
use http::hyper::HyperNetworkStream;
|
||||||
use http::hyper::HyperHttpReader::*;
|
use http::hyper::HyperHttpReader::*;
|
||||||
|
|
||||||
|
/// Type representing the data in the body of an incoming request.
|
||||||
|
///
|
||||||
|
/// This type is the only means by which the body of a request can be retrieved.
|
||||||
|
/// This type is not usually used directly. Instead, types that implement
|
||||||
|
/// [FromData](trait.FromData.html) are used via code generation by specifying
|
||||||
|
/// the `data = "<param>"` route parameter as follows:
|
||||||
|
///
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// #[post("/submit", data = "<var>")]
|
||||||
|
/// fn submit(var: T) -> ... { ... }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Above, `T` can be any type that implements `FromData`. Note that `Data`
|
||||||
|
/// itself implements `FromData`.
|
||||||
|
///
|
||||||
|
/// # Reading Data
|
||||||
|
///
|
||||||
|
/// Data may be read from a `Data` object by calling either the
|
||||||
|
/// [open](#method.open) or [peek](#method.peek) methods.
|
||||||
|
///
|
||||||
|
/// The `open` method consumes the `Data` object and returns the raw data
|
||||||
|
/// stream. The `Data` object is consumed for safety reasons: consuming the
|
||||||
|
/// object ensures that holding a `Data` object means that all of the data is
|
||||||
|
/// available for reading.
|
||||||
|
///
|
||||||
|
/// The `peek` method returns a slice containing at most 4096 bytes of buffered
|
||||||
|
/// body data. This enables partially or fully reading from a `Data` object
|
||||||
|
/// without consuming the `Data` object.
|
||||||
pub struct Data {
|
pub struct Data {
|
||||||
buffer: Vec<u8>,
|
buffer: Vec<u8>,
|
||||||
is_done: bool,
|
is_done: bool,
|
||||||
|
@ -20,6 +48,12 @@ pub struct Data {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Data {
|
impl Data {
|
||||||
|
/// Returns the raw data stream.
|
||||||
|
///
|
||||||
|
/// The stream contains all of the data in the body of the request,
|
||||||
|
/// including that in the `peek` buffer. The method consumes the `Data`
|
||||||
|
/// instance. This ensures that a `Data` type _always_ represents _all_ of
|
||||||
|
/// the data in a request.
|
||||||
pub fn open(mut self) -> impl BufRead {
|
pub fn open(mut self) -> impl BufRead {
|
||||||
// Swap out the buffer and stream for empty ones so we can move.
|
// Swap out the buffer and stream for empty ones so we can move.
|
||||||
let mut buffer = vec![];
|
let mut buffer = vec![];
|
||||||
|
@ -68,21 +102,37 @@ impl Data {
|
||||||
Ok(Data::new(vec, pos, cap, stream))
|
Ok(Data::new(vec, pos, cap, stream))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieve the `peek` buffer.
|
||||||
|
///
|
||||||
|
/// The peek buffer contains at most 4096 bytes of the body of the request.
|
||||||
|
/// The actual size of the returned buffer varies by web request. The
|
||||||
|
/// [peek_complete](#method.peek_complete) can be used to determine if this
|
||||||
|
/// buffer contains _all_ of the data in the body of the request.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn peek(&self) -> &[u8] {
|
pub fn peek(&self) -> &[u8] {
|
||||||
&self.buffer[self.position..self.capacity]
|
&self.buffer[self.position..self.capacity]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the `peek` buffer contains all of the data in the body
|
||||||
|
/// of the request.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn peek_complete(&self) -> bool {
|
pub fn peek_complete(&self) -> bool {
|
||||||
self.is_done
|
self.is_done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A helper method to write the body of the request to any `Write` type.
|
||||||
|
///
|
||||||
|
/// This method is identical to `io::copy(&mut data.open(), writer)`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn stream_to<W: Write>(self, writer: &mut W) -> io::Result<u64> {
|
pub fn stream_to<W: Write>(self, writer: &mut W) -> io::Result<u64> {
|
||||||
io::copy(&mut self.open(), writer)
|
io::copy(&mut self.open(), writer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A helper method to write the body of the request to a file at the path
|
||||||
|
/// determined by `path`.
|
||||||
|
///
|
||||||
|
/// This method is identical to
|
||||||
|
/// `io::copy(&mut self.open(), &mut File::create(path)?)`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn stream_to_file<P: AsRef<Path>>(self, path: P) -> io::Result<u64> {
|
pub fn stream_to_file<P: AsRef<Path>>(self, path: P) -> io::Result<u64> {
|
||||||
io::copy(&mut self.open(), &mut File::create(path)?)
|
io::copy(&mut self.open(), &mut File::create(path)?)
|
||||||
|
|
|
@ -2,6 +2,7 @@ use outcome::Outcome;
|
||||||
use http::StatusCode;
|
use http::StatusCode;
|
||||||
use request::{Request, Data};
|
use request::{Request, Data};
|
||||||
|
|
||||||
|
/// Type alias for the `Outcome` of a `FromData` conversion.
|
||||||
pub type DataOutcome<S, E> = Outcome<S, (StatusCode, E), Data>;
|
pub type DataOutcome<S, E> = Outcome<S, (StatusCode, E), Data>;
|
||||||
|
|
||||||
impl<S, E> DataOutcome<S, E> {
|
impl<S, E> DataOutcome<S, E> {
|
||||||
|
@ -30,12 +31,51 @@ impl<S, E> DataOutcome<S, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait used to derive an object from incoming request data.
|
/// Trait used to derive an object from incoming request data.
|
||||||
|
///
|
||||||
|
/// Type that implement this trait can be used as target for the `data =
|
||||||
|
/// "<param>"` route parmater, as illustrated below:
|
||||||
|
///
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// #[post("/submit", data = "<var>")]
|
||||||
|
/// fn submit(var: T) -> ... { ... }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// In this example, `T` can be any type that implements `FromData.`
|
||||||
|
///
|
||||||
|
/// # Outcomes
|
||||||
|
///
|
||||||
|
/// The returned [Outcome](/rocket/outcome/index.html) of a `from_data` call
|
||||||
|
/// determines what will happen with the incoming request.
|
||||||
|
///
|
||||||
|
/// * **Success**
|
||||||
|
///
|
||||||
|
/// If the `Outcome` is `Success`, then the `Success` value will be used as
|
||||||
|
/// the value for the data parameter.
|
||||||
|
///
|
||||||
|
/// * **Failure**
|
||||||
|
///
|
||||||
|
/// If the `Outcome` is `Failure`, the request will fail with the given status
|
||||||
|
/// code. Note that users can request types of `Result<S, E>` and `Option<S>`
|
||||||
|
/// to catch `Failure`s.
|
||||||
|
///
|
||||||
|
/// * **Failure**
|
||||||
|
///
|
||||||
|
/// If the `Outcome` is `Forward`, the request will be forwarded to the next
|
||||||
|
/// matching request. This requires that no data has been read from the `Data`
|
||||||
|
/// parameter. Note that users can request an `Option<S>` to catch `Forward`s.
|
||||||
pub trait FromData: Sized {
|
pub trait FromData: Sized {
|
||||||
|
/// The associated error to be returned when parsing fails.
|
||||||
type Error;
|
type Error;
|
||||||
|
|
||||||
|
/// Parses an instance of `Self` from the incoming request body data.
|
||||||
|
///
|
||||||
|
/// If the parse is successful, an outcome of `Success` is returned. If the
|
||||||
|
/// data does not correspond to the type of `Self`, `Forward` is returned.
|
||||||
|
/// If parsing fails, `Failure` is returned.
|
||||||
fn from_data(request: &Request, data: Data) -> DataOutcome<Self, Self::Error>;
|
fn from_data(request: &Request, data: Data) -> DataOutcome<Self, Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The identity implementation of `FromData`. Always returns `Success`.
|
||||||
impl FromData for Data {
|
impl FromData for Data {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
fn from_data(_: &Request, data: Data) -> DataOutcome<Self, Self::Error> {
|
fn from_data(_: &Request, data: Data) -> DataOutcome<Self, Self::Error> {
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
use error::Error;
|
use error::Error;
|
||||||
|
|
||||||
/// Trait to create instance of some type from an HTTP form; used by code
|
/// Trait to create an instance of some type from an HTTP form. The
|
||||||
/// generation for `form` route parameters.
|
/// [Form](struct.Form.html) type requires that its generic parameter implements
|
||||||
|
/// this trait.
|
||||||
///
|
///
|
||||||
/// This trait can be automatically derived via the
|
/// This trait can be automatically derived via the
|
||||||
/// [rocket_codegen](/rocket_codegen) plugin:
|
/// [rocket_codegen](/rocket_codegen) plugin:
|
||||||
///
|
///
|
||||||
/// ```rust,ignore
|
/// ```rust
|
||||||
/// #![feature(plugin, custom_derive)]
|
/// #![feature(plugin, custom_derive)]
|
||||||
/// #![plugin(rocket_codegen)]
|
/// #![plugin(rocket_codegen)]
|
||||||
///
|
///
|
||||||
|
@ -19,15 +20,32 @@ use error::Error;
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// The type can then be parsed from incoming form data via the `data`
|
||||||
|
/// parameter and `Form` type.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #![feature(plugin, custom_derive)]
|
||||||
|
/// # #![plugin(rocket_codegen)]
|
||||||
|
/// # extern crate rocket;
|
||||||
|
/// # use rocket::request::Form;
|
||||||
|
/// # #[derive(FromForm)]
|
||||||
|
/// # struct TodoTask { description: String, completed: bool }
|
||||||
|
/// #[post("/submit", data = "<task>")]
|
||||||
|
/// fn submit_task(task: Form<TodoTask>) -> String {
|
||||||
|
/// format!("New task: {}", task.get().description)
|
||||||
|
/// }
|
||||||
|
/// # fn main() { }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
/// When deriving `FromForm`, every field in the structure must implement
|
/// When deriving `FromForm`, every field in the structure must implement
|
||||||
/// [FromFormValue](trait.FromFormValue.html). If you implement `FormForm`
|
/// [FromFormValue](trait.FromFormValue.html). If you implement `FormForm`
|
||||||
/// yourself, use the [FormItems](struct.FormItems.html) iterator to iterate
|
/// yourself, use the [FormItems](struct.FormItems.html) iterator to iterate
|
||||||
/// through the form key/value pairs.
|
/// through the form key/value pairs.
|
||||||
pub trait FromForm<'f>: Sized {
|
pub trait FromForm<'f>: Sized {
|
||||||
/// The associated error which can be returned from parsing.
|
/// The associated error to be returned when parsing fails.
|
||||||
type Error;
|
type Error;
|
||||||
|
|
||||||
/// Parses an instance of `Self` from a raw HTTP form
|
/// Parses an instance of `Self` from a raw HTTP form string
|
||||||
/// (`application/x-www-form-urlencoded data`) or returns an `Error` if one
|
/// (`application/x-www-form-urlencoded data`) or returns an `Error` if one
|
||||||
/// cannot be parsed.
|
/// cannot be parsed.
|
||||||
fn from_form_string(form_string: &'f str) -> Result<Self, Self::Error>;
|
fn from_form_string(form_string: &'f str) -> Result<Self, Self::Error>;
|
||||||
|
|
|
@ -30,7 +30,122 @@ use std::io::Read;
|
||||||
use http::StatusCode;
|
use http::StatusCode;
|
||||||
use request::{Request, FromData, Data, DataOutcome};
|
use request::{Request, FromData, Data, DataOutcome};
|
||||||
|
|
||||||
// This works, and it's safe, but it sucks to have the lifetime appear twice.
|
// TODO: This works and is safe, but the lifetime appears twice.
|
||||||
|
/// A `FromData` type for parsing `FromForm` types.
|
||||||
|
///
|
||||||
|
/// This type implements the `FromData` trait. It provides a generic means to
|
||||||
|
/// parse arbitrary structure from incoming form data.
|
||||||
|
///
|
||||||
|
/// # Usage
|
||||||
|
///
|
||||||
|
/// This type can be used with any type that implements the `FromForm` trait.
|
||||||
|
/// The trait can be automatically derived; see the
|
||||||
|
/// [FromForm](trait.FromForm.html) documentation for more information about
|
||||||
|
/// implementing the trait.
|
||||||
|
///
|
||||||
|
/// Because `Form` implement `FromData`, it can be used directly as a target of
|
||||||
|
/// the `data = "<param>"` route parameter. For instance, if some structure of
|
||||||
|
/// type `T` implements the `FromForm` trait, an incoming form can be
|
||||||
|
/// automatically parsed into the `T` structure with the following route and
|
||||||
|
/// handler:
|
||||||
|
///
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// #[post("/form_submit", data = "<param>")]
|
||||||
|
/// fn submit(form: Form<T>) ... { ... }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// To preserve memory safety, if the underlying structure type contains
|
||||||
|
/// references into form data, the type can only be borrowed via the
|
||||||
|
/// [get](#method.get) or [get_mut](#method.get_mut) methods. Otherwise, the
|
||||||
|
/// parsed structure can be retrieved with the [into_inner](#method.into_inner)
|
||||||
|
/// method.
|
||||||
|
///
|
||||||
|
/// ## With References
|
||||||
|
///
|
||||||
|
/// The simplest data structure with a reference into form data looks like this:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #![feature(plugin, custom_derive)]
|
||||||
|
/// # #![plugin(rocket_codegen)]
|
||||||
|
/// # extern crate rocket;
|
||||||
|
/// #[derive(FromForm)]
|
||||||
|
/// struct UserInput<'f> {
|
||||||
|
/// value: &'f str
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// This corresponds to a form with a single field named `value` that should be
|
||||||
|
/// a string. A handler for this type can be written as:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #![feature(plugin, custom_derive)]
|
||||||
|
/// # #![plugin(rocket_codegen)]
|
||||||
|
/// # extern crate rocket;
|
||||||
|
/// # use rocket::request::Form;
|
||||||
|
/// # #[derive(FromForm)]
|
||||||
|
/// # struct UserInput<'f> {
|
||||||
|
/// # value: &'f str
|
||||||
|
/// # }
|
||||||
|
/// #[post("/submit", data = "<user_input>")]
|
||||||
|
/// fn submit_task<'r>(user_input: Form<'r, UserInput<'r>>) -> String {
|
||||||
|
/// format!("Your value: {}", user_input.get().value)
|
||||||
|
/// }
|
||||||
|
/// # fn main() { }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Note that the ``r` lifetime is used _twice_ in the handler's signature: this
|
||||||
|
/// is necessary to tie the lifetime of the structure to the lifetime of the
|
||||||
|
/// request data.
|
||||||
|
///
|
||||||
|
/// ## Without References
|
||||||
|
///
|
||||||
|
/// The owned analog of the `UserInput` type above is:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #![feature(plugin, custom_derive)]
|
||||||
|
/// # #![plugin(rocket_codegen)]
|
||||||
|
/// # extern crate rocket;
|
||||||
|
/// #[derive(FromForm)]
|
||||||
|
/// struct OwnedUserInput {
|
||||||
|
/// value: String
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The handler is written similarly:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #![feature(plugin, custom_derive)]
|
||||||
|
/// # #![plugin(rocket_codegen)]
|
||||||
|
/// # extern crate rocket;
|
||||||
|
/// # use rocket::request::Form;
|
||||||
|
/// # #[derive(FromForm)]
|
||||||
|
/// # struct OwnedUserInput {
|
||||||
|
/// # value: String
|
||||||
|
/// # }
|
||||||
|
/// #[post("/submit", data = "<user_input>")]
|
||||||
|
/// fn submit_task(user_input: Form<OwnedUserInput>) -> String {
|
||||||
|
/// let input: OwnedUserInput = user_input.into_inner();
|
||||||
|
/// format!("Your value: {}", input.value)
|
||||||
|
/// }
|
||||||
|
/// # fn main() { }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Note that no lifetime annotations are required: Rust is able to infer the
|
||||||
|
/// lifetime as ``static`. Because the lifetime is ``static`, the `into_inner`
|
||||||
|
/// method can be used to directly retrieve the parsed value.
|
||||||
|
///
|
||||||
|
/// ## Performance and Correctness Considerations
|
||||||
|
///
|
||||||
|
/// Whether you should use a `str` or `String` in your `FromForm` type depends
|
||||||
|
/// on your use case. The primary question to answer is: _Can the input contain
|
||||||
|
/// characters that must be URL encoded?_ Note that this includes commmon
|
||||||
|
/// characters such as spaces. If so, then you must use `String`, whose
|
||||||
|
/// `FromFormValue` implementation deserializes the URL encoded string for you.
|
||||||
|
/// Because the `str` references will refer directly to the underlying form
|
||||||
|
/// data, they will be raw and URL encoded.
|
||||||
|
///
|
||||||
|
/// If your string values will not contain URL encoded characters, using `str`
|
||||||
|
/// will result in fewer allocation and is thus spreferred.
|
||||||
pub struct Form<'f, T: FromForm<'f> + 'f> {
|
pub struct Form<'f, T: FromForm<'f> + 'f> {
|
||||||
object: T,
|
object: T,
|
||||||
form_string: String,
|
form_string: String,
|
||||||
|
@ -38,14 +153,18 @@ pub struct Form<'f, T: FromForm<'f> + 'f> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'f, T: FromForm<'f> + 'f> Form<'f, T> {
|
impl<'f, T: FromForm<'f> + 'f> Form<'f, T> {
|
||||||
|
/// Immutably borrow the parsed type.
|
||||||
pub fn get(&'f self) -> &'f T {
|
pub fn get(&'f self) -> &'f T {
|
||||||
&self.object
|
&self.object
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Mutably borrow the parsed type.
|
||||||
pub fn get_mut(&'f mut self) -> &'f mut T {
|
pub fn get_mut(&'f mut self) -> &'f mut T {
|
||||||
&mut self.object
|
&mut self.object
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the raw form string that was used to parse the encapsulated
|
||||||
|
/// object.
|
||||||
pub fn raw_form_string(&self) -> &str {
|
pub fn raw_form_string(&self) -> &str {
|
||||||
&self.form_string
|
&self.form_string
|
||||||
}
|
}
|
||||||
|
@ -87,6 +206,7 @@ impl<'f, T: FromForm<'f> + 'f> Form<'f, T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'f, T: FromForm<'f> + 'static> Form<'f, T> {
|
impl<'f, T: FromForm<'f> + 'static> Form<'f, T> {
|
||||||
|
/// Consume this object and move out the parsed object.
|
||||||
pub fn into_inner(self) -> T {
|
pub fn into_inner(self) -> T {
|
||||||
self.object
|
self.object
|
||||||
}
|
}
|
||||||
|
@ -98,6 +218,15 @@ impl<'f, T: FromForm<'f> + Debug + 'f> Debug for Form<'f, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses a `Form` from incoming form data.
|
||||||
|
///
|
||||||
|
/// If the content type of the request data is not
|
||||||
|
/// `application/x-www-form-urlencoded`, `Forward`s the request. If the form
|
||||||
|
/// data cannot be parsed into a `T` or reading the incoming stream failed,
|
||||||
|
/// returns a `Failure` with the raw form string (if avaialble).
|
||||||
|
///
|
||||||
|
/// All relevant warnings and errors are written to the console in Rocket
|
||||||
|
/// logging format.
|
||||||
impl<'f, T: FromForm<'f>> FromData for Form<'f, T> where T::Error: Debug {
|
impl<'f, T: FromForm<'f>> FromData for Form<'f, T> where T::Error: Debug {
|
||||||
type Error = Option<String>;
|
type Error = Option<String>;
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ use request::Request;
|
||||||
use outcome::Outcome;
|
use outcome::Outcome;
|
||||||
use http::{StatusCode, ContentType, Method, Cookies};
|
use http::{StatusCode, ContentType, Method, Cookies};
|
||||||
|
|
||||||
|
/// Type alias for the `Outcome` of a `FromRequest` conversion.
|
||||||
pub type RequestOutcome<T, E> = Outcome<T, (StatusCode, E), ()>;
|
pub type RequestOutcome<T, E> = Outcome<T, (StatusCode, E), ()>;
|
||||||
|
|
||||||
impl<T, E> RequestOutcome<T, E> {
|
impl<T, E> RequestOutcome<T, E> {
|
||||||
|
|
|
@ -1,4 +1,18 @@
|
||||||
//! Types and traits that deal with request parsing and handling.
|
//! Types and traits for request parsing and handling.
|
||||||
|
//!
|
||||||
|
//! # Request and Data
|
||||||
|
//!
|
||||||
|
//! The [Request](struct.Request.html) and [Data](struct.Data.html) types
|
||||||
|
//! contain all of the available information for an incoming request. The
|
||||||
|
//! `Request` types contains all information _except_ the body, which is
|
||||||
|
//! contained in the `Data` type.
|
||||||
|
//!
|
||||||
|
//! # Code Generation Conversion Traits
|
||||||
|
//!
|
||||||
|
//! This module contains the core code generation data conversion traits. These
|
||||||
|
//! traits are used by Rocket's code generation facilities to automatically
|
||||||
|
//! derive values from incoming data based on the signature of a request
|
||||||
|
//! handler.
|
||||||
|
|
||||||
mod request;
|
mod request;
|
||||||
mod param;
|
mod param;
|
||||||
|
|
|
@ -5,8 +5,54 @@ use url;
|
||||||
|
|
||||||
use http::uri::Segments;
|
use http::uri::Segments;
|
||||||
|
|
||||||
|
/// Trait to convert a dynamic path segment string to a concrete value.
|
||||||
|
///
|
||||||
|
/// This trait is used by Rocket's code generation facilities to parse dynamic
|
||||||
|
/// path segment string values into a given type. That is, when a path contains
|
||||||
|
/// a dynamic segment `<param>` where `param` has some type `T` that
|
||||||
|
/// implements `FromParam`, `T::from_param` will be called.
|
||||||
|
///
|
||||||
|
/// # Forwarding
|
||||||
|
///
|
||||||
|
/// If the conversion fails, the incoming request will be forwarded to the next
|
||||||
|
/// matching route, if any. For instance, consider the following route and
|
||||||
|
/// handler for the dynamic `"/<id>"` path:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// #![feature(plugin)]
|
||||||
|
/// #![plugin(rocket_codegen)]
|
||||||
|
///
|
||||||
|
/// extern crate rocket;
|
||||||
|
///
|
||||||
|
/// #[get("/<id>")]
|
||||||
|
/// fn hello(id: usize) -> String {
|
||||||
|
/// # /*
|
||||||
|
/// ...
|
||||||
|
/// # */
|
||||||
|
/// # "".to_string()
|
||||||
|
/// }
|
||||||
|
/// # fn main() { }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// If `usize::from_param` returns an `Ok(usize)` variant, the encapsulated
|
||||||
|
/// value is used as the `id` function parameter. If not, the request is
|
||||||
|
/// forwarded to the next matching route. Since there are no additional matching
|
||||||
|
/// routes, this example will result in a 404 error for requests with invalid
|
||||||
|
/// `id` values.
|
||||||
|
///
|
||||||
|
/// # `str` vs. `String`
|
||||||
|
///
|
||||||
|
/// Paths are URL encoded. As a result, the `str` `FromParam` implementation
|
||||||
|
/// returns the raw, URL encoded version of the path segment string. On the
|
||||||
|
/// other hand, `String` decodes the path parameter, but requires an allocation
|
||||||
|
/// to do so. This tradeoff is similiar to that of form values, and you should
|
||||||
|
/// use whichever makes sense for your application.
|
||||||
pub trait FromParam<'a>: Sized {
|
pub trait FromParam<'a>: Sized {
|
||||||
|
/// The associated error to be returned when parsing fails.
|
||||||
type Error;
|
type Error;
|
||||||
|
|
||||||
|
/// Parses an instance of `Self` from a dynamic path parameter string or
|
||||||
|
/// returns an `Error` if one cannot be parsed.
|
||||||
fn from_param(param: &'a str) -> Result<Self, Self::Error>;
|
fn from_param(param: &'a str) -> Result<Self, Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,8 +86,21 @@ impl_with_fromstr!(f32, f64, isize, i8, i16, i32, i64, usize, u8, u16, u32, u64,
|
||||||
bool, IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6,
|
bool, IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6,
|
||||||
SocketAddr);
|
SocketAddr);
|
||||||
|
|
||||||
|
/// Trait to convert _many_ dynamic path segment strings to a concrete value.
|
||||||
|
///
|
||||||
|
/// This is the `..` analog to [FromParam](trait.FromParam.html), and its
|
||||||
|
/// functionality is identical to it with one exception: this trait applies to
|
||||||
|
/// segment parameters of the form `<param..>`, where `param` is of some type
|
||||||
|
/// `T` that implements `FromSegments`. `T::from_segments` is called to convert
|
||||||
|
/// the matched segments (via the
|
||||||
|
/// [Segments](/rocket/http/uri/struct.Segments.html) iterator) into the
|
||||||
|
/// implementing type.
|
||||||
pub trait FromSegments<'a>: Sized {
|
pub trait FromSegments<'a>: Sized {
|
||||||
|
/// The associated error to be returned when parsing fails.
|
||||||
type Error;
|
type Error;
|
||||||
|
|
||||||
|
/// Parses an instance of `Self` from many dynamic path parameter strings or
|
||||||
|
/// returns an `Error` if one cannot be parsed.
|
||||||
fn from_segments(segments: Segments<'a>) -> Result<Self, Self::Error>;
|
fn from_segments(segments: Segments<'a>) -> Result<Self, Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,29 +12,20 @@ use http::uri::{URI, URIBuf};
|
||||||
use http::hyper::{header, HyperCookie, HyperHeaders, HyperMethod, HyperRequestUri};
|
use http::hyper::{header, HyperCookie, HyperHeaders, HyperMethod, HyperRequestUri};
|
||||||
use http::{Method, ContentType, Cookies};
|
use http::{Method, ContentType, Cookies};
|
||||||
|
|
||||||
/// The type for all incoming web requests.
|
/// The type of an incoming web request.
|
||||||
///
|
///
|
||||||
/// This should be used sparingly in Rocket applications. In particular, it
|
/// This should be used sparingly in Rocket applications. In particular, it
|
||||||
/// should likely only be used when writing
|
/// should likely only be used when writing
|
||||||
/// [FromRequest](trait.FromRequest.html) implementations. It contains all of
|
/// [FromRequest](trait.FromRequest.html) implementations. It contains all of
|
||||||
/// the information for a given web request. This includes the HTTP method, URI,
|
/// the information for a given web request except for the body data. This
|
||||||
/// cookies, headers, and more.
|
/// includes the HTTP method, URI, cookies, headers, and more.
|
||||||
pub struct Request {
|
pub struct Request {
|
||||||
/// The HTTP method associated with the request.
|
/// The HTTP method associated with the request.
|
||||||
pub method: Method,
|
pub method: Method,
|
||||||
/// <div class="stability" style="margin-left: 0;">
|
uri: URIBuf, // FIXME: Should be URI (without hyper).
|
||||||
/// <em class="stab unstable">
|
|
||||||
/// Unstable
|
|
||||||
/// (<a href="https://github.com/SergioBenitez/Rocket/issues/17">#17</a>):
|
|
||||||
/// The underlying HTTP library/types are likely to change before v1.0.
|
|
||||||
/// </em>
|
|
||||||
/// </div>
|
|
||||||
///
|
|
||||||
/// The data in the request.
|
|
||||||
uri: URIBuf, // FIXME: Should be URI (without Hyper).
|
|
||||||
params: RefCell<Vec<&'static str>>,
|
params: RefCell<Vec<&'static str>>,
|
||||||
cookies: Cookies,
|
cookies: Cookies,
|
||||||
headers: HyperHeaders, // This sucks.
|
headers: HyperHeaders, // Don't use hyper's headers.
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Request {
|
impl Request {
|
||||||
|
@ -140,6 +131,14 @@ impl Request {
|
||||||
hyp_ct.map_or(ContentType::any(), |ct| ContentType::from(&ct.0))
|
hyp_ct.map_or(ContentType::any(), |ct| ContentType::from(&ct.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <div class="stability" style="margin-left: 0;">
|
||||||
|
/// <em class="stab unstable">
|
||||||
|
/// Unstable
|
||||||
|
/// (<a href="https://github.com/SergioBenitez/Rocket/issues/17">#17</a>):
|
||||||
|
/// The underlying HTTP library/types are likely to change before v1.0.
|
||||||
|
/// </em>
|
||||||
|
/// </div>
|
||||||
|
///
|
||||||
/// Returns the first content-type accepted by this request.
|
/// Returns the first content-type accepted by this request.
|
||||||
pub fn accepts(&self) -> ContentType {
|
pub fn accepts(&self) -> ContentType {
|
||||||
let accept = self.headers().get::<header::Accept>();
|
let accept = self.headers().get::<header::Accept>();
|
||||||
|
|
|
@ -19,6 +19,8 @@ use http::{Method, StatusCode};
|
||||||
use http::hyper::{HyperRequest, FreshHyperResponse};
|
use http::hyper::{HyperRequest, FreshHyperResponse};
|
||||||
use http::hyper::{HyperServer, HyperHandler, HyperSetCookie, header};
|
use http::hyper::{HyperServer, HyperHandler, HyperSetCookie, header};
|
||||||
|
|
||||||
|
/// The Rocket type used to mount routes and catchers and launch the
|
||||||
|
/// application.
|
||||||
pub struct Rocket {
|
pub struct Rocket {
|
||||||
address: String,
|
address: String,
|
||||||
port: usize,
|
port: usize,
|
||||||
|
|
Loading…
Reference in New Issue