diff --git a/lib/src/lib.rs b/lib/src/lib.rs
index 088739fa..fedc1bbc 100644
--- a/lib/src/lib.rs
+++ b/lib/src/lib.rs
@@ -52,7 +52,7 @@
//! 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:
//!
//! ```rust
diff --git a/lib/src/request/data/data.rs b/lib/src/request/data/data.rs
index 896392db..a9c83b53 100644
--- a/lib/src/request/data/data.rs
+++ b/lib/src/request/data/data.rs
@@ -9,6 +9,34 @@ use http::hyper::{HyperBodyReader, HyperHttpStream};
use http::hyper::HyperNetworkStream;
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 = ""` route parameter as follows:
+///
+/// ```rust,ignore
+/// #[post("/submit", data = "")]
+/// 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 {
buffer: Vec,
is_done: bool,
@@ -20,6 +48,12 @@ pub struct 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 {
// Swap out the buffer and stream for empty ones so we can move.
let mut buffer = vec![];
@@ -68,21 +102,37 @@ impl Data {
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)]
pub fn peek(&self) -> &[u8] {
&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)]
pub fn peek_complete(&self) -> bool {
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)]
pub fn stream_to(self, writer: &mut W) -> io::Result {
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)]
pub fn stream_to_file>(self, path: P) -> io::Result {
io::copy(&mut self.open(), &mut File::create(path)?)
diff --git a/lib/src/request/data/from_data.rs b/lib/src/request/data/from_data.rs
index c1552e33..a7d2eb01 100644
--- a/lib/src/request/data/from_data.rs
+++ b/lib/src/request/data/from_data.rs
@@ -2,6 +2,7 @@ use outcome::Outcome;
use http::StatusCode;
use request::{Request, Data};
+/// Type alias for the `Outcome` of a `FromData` conversion.
pub type DataOutcome = Outcome;
impl DataOutcome {
@@ -30,12 +31,51 @@ impl DataOutcome {
}
/// Trait used to derive an object from incoming request data.
+///
+/// Type that implement this trait can be used as target for the `data =
+/// ""` route parmater, as illustrated below:
+///
+/// ```rust,ignore
+/// #[post("/submit", data = "")]
+/// 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` and `Option`
+/// 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` to catch `Forward`s.
pub trait FromData: Sized {
+ /// The associated error to be returned when parsing fails.
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;
}
+/// The identity implementation of `FromData`. Always returns `Success`.
impl FromData for Data {
type Error = ();
fn from_data(_: &Request, data: Data) -> DataOutcome {
diff --git a/lib/src/request/form/from_form.rs b/lib/src/request/form/from_form.rs
index 849c2eb7..08848aa5 100644
--- a/lib/src/request/form/from_form.rs
+++ b/lib/src/request/form/from_form.rs
@@ -1,12 +1,13 @@
use error::Error;
-/// Trait to create instance of some type from an HTTP form; used by code
-/// generation for `form` route parameters.
+/// Trait to create an instance of some type from an HTTP form. The
+/// [Form](struct.Form.html) type requires that its generic parameter implements
+/// this trait.
///
/// This trait can be automatically derived via the
/// [rocket_codegen](/rocket_codegen) plugin:
///
-/// ```rust,ignore
+/// ```rust
/// #![feature(plugin, custom_derive)]
/// #![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 = "")]
+/// fn submit_task(task: Form) -> String {
+/// format!("New task: {}", task.get().description)
+/// }
+/// # fn main() { }
+/// ```
+///
/// When deriving `FromForm`, every field in the structure must implement
/// [FromFormValue](trait.FromFormValue.html). If you implement `FormForm`
/// yourself, use the [FormItems](struct.FormItems.html) iterator to iterate
/// through the form key/value pairs.
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;
- /// 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
/// cannot be parsed.
fn from_form_string(form_string: &'f str) -> Result;
diff --git a/lib/src/request/form/mod.rs b/lib/src/request/form/mod.rs
index 9cacd6fc..ee906a9a 100644
--- a/lib/src/request/form/mod.rs
+++ b/lib/src/request/form/mod.rs
@@ -30,7 +30,122 @@ use std::io::Read;
use http::StatusCode;
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 = ""` 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 = "")]
+/// fn submit(form: Form) ... { ... }
+/// ```
+///
+/// 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 = "")]
+/// 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 = "")]
+/// fn submit_task(user_input: Form) -> 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> {
object: T,
form_string: String,
@@ -38,14 +153,18 @@ pub struct Form<'f, T: FromForm<'f> + 'f> {
}
impl<'f, T: FromForm<'f> + 'f> Form<'f, T> {
+ /// Immutably borrow the parsed type.
pub fn get(&'f self) -> &'f T {
&self.object
}
+ /// Mutably borrow the parsed type.
pub fn get_mut(&'f mut self) -> &'f mut T {
&mut self.object
}
+ /// Returns the raw form string that was used to parse the encapsulated
+ /// object.
pub fn raw_form_string(&self) -> &str {
&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> {
+ /// Consume this object and move out the parsed object.
pub fn into_inner(self) -> T {
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 {
type Error = Option;
diff --git a/lib/src/request/from_request.rs b/lib/src/request/from_request.rs
index 6cd3b2cf..0cb4393f 100644
--- a/lib/src/request/from_request.rs
+++ b/lib/src/request/from_request.rs
@@ -4,6 +4,7 @@ use request::Request;
use outcome::Outcome;
use http::{StatusCode, ContentType, Method, Cookies};
+/// Type alias for the `Outcome` of a `FromRequest` conversion.
pub type RequestOutcome = Outcome;
impl RequestOutcome {
diff --git a/lib/src/request/mod.rs b/lib/src/request/mod.rs
index d69c565e..b7d8eee3 100644
--- a/lib/src/request/mod.rs
+++ b/lib/src/request/mod.rs
@@ -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 param;
diff --git a/lib/src/request/param.rs b/lib/src/request/param.rs
index 43802633..6dae4b8c 100644
--- a/lib/src/request/param.rs
+++ b/lib/src/request/param.rs
@@ -5,8 +5,54 @@ use url;
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 `` 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 `"/"` path:
+///
+/// ```rust
+/// #![feature(plugin)]
+/// #![plugin(rocket_codegen)]
+///
+/// extern crate rocket;
+///
+/// #[get("/")]
+/// 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 {
+ /// The associated error to be returned when parsing fails.
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;
}
@@ -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,
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 ``, 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 {
+ /// The associated error to be returned when parsing fails.
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;
}
diff --git a/lib/src/request/request.rs b/lib/src/request/request.rs
index 0d3c08e7..1b6e6925 100644
--- a/lib/src/request/request.rs
+++ b/lib/src/request/request.rs
@@ -12,29 +12,20 @@ use http::uri::{URI, URIBuf};
use http::hyper::{header, HyperCookie, HyperHeaders, HyperMethod, HyperRequestUri};
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
/// should likely only be used when writing
/// [FromRequest](trait.FromRequest.html) implementations. It contains all of
-/// the information for a given web request. This includes the HTTP method, URI,
-/// cookies, headers, and more.
+/// the information for a given web request except for the body data. This
+/// includes the HTTP method, URI, cookies, headers, and more.
pub struct Request {
/// The HTTP method associated with the request.
pub method: Method,
- ///
- ///
- /// Unstable
- /// (#17):
- /// The underlying HTTP library/types are likely to change before v1.0.
- ///
- ///
- ///
- /// The data in the request.
- uri: URIBuf, // FIXME: Should be URI (without Hyper).
+ uri: URIBuf, // FIXME: Should be URI (without hyper).
params: RefCell>,
cookies: Cookies,
- headers: HyperHeaders, // This sucks.
+ headers: HyperHeaders, // Don't use hyper's headers.
}
impl Request {
@@ -140,6 +131,14 @@ impl Request {
hyp_ct.map_or(ContentType::any(), |ct| ContentType::from(&ct.0))
}
+ ///
+ ///
+ /// Unstable
+ /// (#17):
+ /// The underlying HTTP library/types are likely to change before v1.0.
+ ///
+ ///
+ ///
/// Returns the first content-type accepted by this request.
pub fn accepts(&self) -> ContentType {
let accept = self.headers().get::();
diff --git a/lib/src/rocket.rs b/lib/src/rocket.rs
index 02e92811..cdcb8283 100644
--- a/lib/src/rocket.rs
+++ b/lib/src/rocket.rs
@@ -19,6 +19,8 @@ use http::{Method, StatusCode};
use http::hyper::{HyperRequest, FreshHyperResponse};
use http::hyper::{HyperServer, HyperHandler, HyperSetCookie, header};
+/// The Rocket type used to mount routes and catchers and launch the
+/// application.
pub struct Rocket {
address: String,
port: usize,