From 0e82eb0b3160d477a5657192051d883ffbb93b86 Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Fri, 3 Feb 2017 16:56:29 -0800 Subject: [PATCH] Fixup forms documentation for new features. --- lib/src/config/mod.rs | 2 +- lib/src/request/form/form_items.rs | 106 ++++++++++++++++++++++++++++- lib/src/request/form/from_form.rs | 18 +++-- lib/src/request/form/mod.rs | 11 ++- lib/src/request/from_request.rs | 2 +- lib/src/request/mod.rs | 3 +- lib/src/request/request.rs | 7 +- lib/src/request/state.rs | 2 +- 8 files changed, 128 insertions(+), 23 deletions(-) diff --git a/lib/src/config/mod.rs b/lib/src/config/mod.rs index cb405003..cc609a3c 100644 --- a/lib/src/config/mod.rs +++ b/lib/src/config/mod.rs @@ -102,7 +102,7 @@ //! address = "0.0.0.0" //! ``` //! -//! ## Environment Variables +//! ### Environment Variables //! //! All configuration parameters, including extras, can be overridden through //! environment variables. To override the configuration parameter `{param}`, diff --git a/lib/src/request/form/form_items.rs b/lib/src/request/form/form_items.rs index aeb753b2..daa92650 100644 --- a/lib/src/request/form/form_items.rs +++ b/lib/src/request/form/form_items.rs @@ -1,8 +1,6 @@ use memchr::memchr2; -/// Iterator over the key/value pairs of a given HTTP form string. You'll likely -/// want to use this if you're implementing [FromForm](trait.FromForm.html) -/// manually, for whatever reason, by iterating over the items in `form_string`. +/// Iterator over the key/value pairs of a given HTTP form string. /// /// **Note:** The returned key/value pairs are _not_ URL decoded. To URL decode /// the raw strings, use `String::from_form_value`: @@ -21,6 +19,23 @@ use memchr::memchr2; /// } /// ``` /// +/// # Completion +/// +/// The iterator keeps track of whether the form string was parsed to completion +/// to determine if the form string was malformed. The iterator can be queried +/// for completion via the [completed](#method.completed) method, which returns +/// `true` if the iterator parsed the entire string that was passed to it. The +/// iterator can also attempt to parse any remaining contents via +/// [exhausted](#method.exhausted); this method returns `true` if exhaustion +/// succeeded. +/// +/// This iterator guarantees that all valid form strings are parsed to +/// completion. The iterator attempts to be lenient. In particular, it allows +/// the following oddball behavior: +/// +/// * A single trailing `&` character is allowed. +/// * Empty values are allowed. +/// /// # Examples /// /// `FormItems` can be used directly as an iterator: @@ -53,11 +68,71 @@ pub struct FormItems<'f> { } impl<'f> FormItems<'f> { + /// Returns `true` if the form string was parsed to completion. Returns + /// `false` otherwise. All valid form strings will parse to completion, + /// while invalid form strings will not. + /// + /// # Example + /// + /// A valid form string parses to completion: + /// + /// ```rust + /// use rocket::request::FormItems; + /// + /// let mut items = FormItems::from("a=b&c=d"); + /// let key_values: Vec<_> = items.by_ref().collect(); + /// + /// assert_eq!(key_values.len(), 2); + /// assert_eq!(items.completed(), true); + /// ``` + /// + /// In invalid form string does not parse to completion: + /// + /// ```rust + /// use rocket::request::FormItems; + /// + /// let mut items = FormItems::from("a=b&=d"); + /// let key_values: Vec<_> = items.by_ref().collect(); + /// + /// assert_eq!(key_values.len(), 1); + /// assert_eq!(items.completed(), false); + /// ``` #[inline] pub fn completed(&self) -> bool { self.next_index >= self.string.len() } + /// Parses all remaining key/value pairs and returns `true` if parsing ran + /// to completion. All valid form strings will parse to completion, while + /// invalid form strings will not. + /// + /// # Example + /// + /// A valid form string can be exhausted: + /// + /// ```rust + /// use rocket::request::FormItems; + /// + /// let mut items = FormItems::from("a=b&c=d"); + /// + /// assert!(items.next().is_some()); + /// assert_eq!(items.completed(), false); + /// assert_eq!(items.exhausted(), true); + /// assert_eq!(items.completed(), true); + /// ``` + /// + /// An invalid form string cannot be exhausted: + /// + /// ```rust + /// use rocket::request::FormItems; + /// + /// let mut items = FormItems::from("a=b&=d"); + /// + /// assert!(items.next().is_some()); + /// assert_eq!(items.completed(), false); + /// assert_eq!(items.exhausted(), false); + /// assert_eq!(items.completed(), false); + /// ``` pub fn exhausted(&mut self) -> bool { while let Some(_) = self.next() { } self.completed() @@ -69,6 +144,28 @@ impl<'f> FormItems<'f> { self.next_index = self.string.len() } + /// Retrieves the original string being parsed by this iterator. The string + /// returned by this method does not change, regardless of the status of the + /// iterator. + /// + /// # Example + /// + /// ```rust + /// use rocket::request::FormItems; + /// + /// let form_string = "a=b&c=d"; + /// let mut items = FormItems::from(form_string); + /// assert_eq!(items.inner_str(), form_string); + /// + /// assert!(items.next().is_some()); + /// assert_eq!(items.inner_str(), form_string); + /// + /// assert!(items.next().is_some()); + /// assert_eq!(items.inner_str(), form_string); + /// + /// assert!(items.next().is_none()); + /// assert_eq!(items.inner_str(), form_string); + /// ``` #[inline] pub fn inner_str(&self) -> &'f str { self.string @@ -76,6 +173,8 @@ impl<'f> FormItems<'f> { } impl<'f> From<&'f str> for FormItems<'f> { + /// Returns an iterator over the key/value pairs in the + /// `x-www-form-urlencoded` form `string`. fn from(string: &'f str) -> FormItems<'f> { FormItems { string: string, @@ -159,6 +258,7 @@ mod test { check_form!("a=b&a=", &[("a", "b"), ("a", "")]); check_form!(@bad "user=&password"); + check_form!(@bad "user=x&&"); check_form!(@bad "a=b&a"); check_form!(@bad "="); check_form!(@bad "&"); diff --git a/lib/src/request/form/from_form.rs b/lib/src/request/form/from_form.rs index 0031e41d..006d13a3 100644 --- a/lib/src/request/form/from_form.rs +++ b/lib/src/request/form/from_form.rs @@ -1,8 +1,7 @@ use request::FormItems; -/// 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. +/// Trait to create an instance of some type from an HTTP form. +/// [Form](struct.Form.html) requires its generic type to implement this trait. /// /// This trait can be automatically derived via the /// [rocket_codegen](/rocket_codegen) plugin: @@ -44,17 +43,16 @@ use request::FormItems; /// /// # Implementing /// -/// If you implement `FormForm` yourself, use the -/// [FormItems](struct.FormItems.html) iterator to iterate through the form -/// key/value pairs. Be aware that form fields that are typically hidden from -/// your application, such as `_method`, will be present while iterating. +/// An implementation of `FromForm` uses the [FormItems](struct.FormItems.html) +/// iterator to iterate through the raw form key/value pairs. Be aware that form +/// fields that are typically hidden from your application, such as `_method`, +/// will be present while iterating. pub trait FromForm<'f>: Sized { /// The associated error to be returned when parsing fails. type Error; - /// 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. + /// Parses an instance of `Self` from the form items or returns an `Error` + /// if one cannot be parsed. fn from_form_items(form_items: &mut FormItems<'f>) -> Result; } diff --git a/lib/src/request/form/mod.rs b/lib/src/request/form/mod.rs index edf21852..e95c5bd0 100644 --- a/lib/src/request/form/mod.rs +++ b/lib/src/request/form/mod.rs @@ -37,7 +37,7 @@ use outcome::Outcome::*; /// 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. +/// parse arbitrary structures from incoming form data. /// /// # Usage /// @@ -251,12 +251,17 @@ impl<'f, T: FromForm<'f> + Debug + 'f> Debug for Form<'f, T> { /// /// 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). +/// data cannot be parsed into a `T`, a `Failure` with status code +/// `UnprocessableEntity` is returned. If the form string is malformed, a +/// `Failure` with status code `BadRequest` is returned. Finally, if reading the +/// incoming stream fails, returns a `Failure` with status code +/// `InternalServerError`. In all failure cases, the raw form string is returned +/// if it was able to be retrieved from the incoming stream. /// /// 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 { + /// The raw form string, if it was able to be retrieved from the request. type Error = Option; fn from_data(request: &Request, data: Data) -> data::Outcome { diff --git a/lib/src/request/from_request.rs b/lib/src/request/from_request.rs index ad84fa81..f6ea9052 100644 --- a/lib/src/request/from_request.rs +++ b/lib/src/request/from_request.rs @@ -71,7 +71,7 @@ impl IntoOutcome for Result { /// Rocket implements `FromRequest` for several built-in types. Their behavior /// is documented here. /// -/// * **URI** +/// * **&URI** /// /// Extracts the [URI](/rocket/http/uri/struct.URI.html) from the incoming /// request. diff --git a/lib/src/request/mod.rs b/lib/src/request/mod.rs index 825b4e7f..e94be1ab 100644 --- a/lib/src/request/mod.rs +++ b/lib/src/request/mod.rs @@ -12,5 +12,6 @@ pub use self::param::{FromParam, FromSegments}; pub use self::form::{Form, FromForm, FromFormValue, FormItems}; pub use self::state::State; -/// Type alias to retrieve flash messages from a request. +/// Type alias to retrieve [Flash](/rocket/response/struct.Flash.html) messages +/// from a request. pub type FlashMessage = ::response::Flash<()>; diff --git a/lib/src/request/request.rs b/lib/src/request/request.rs index 32de6a91..ea5d38f0 100644 --- a/lib/src/request/request.rs +++ b/lib/src/request/request.rs @@ -20,7 +20,7 @@ use http::hyper; /// /// This should be used sparingly in Rocket applications. In particular, it /// should likely only be used when writing -/// [FromRequest](/rocket/request/struct.Request.html) implementations. It +/// [FromRequest](/rocket/request/trait.FromRequest.html) implementations. It /// contains all of 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<'r> { @@ -319,7 +319,8 @@ impl<'r> Request<'r> { *self.params.borrow_mut() = route.get_param_indexes(self.uri()); } - /// Get the `n`th path parameter as a string, if it exists. + /// Get the `n`th path parameter as a string, if it exists. This is used by + /// codegen. #[doc(hidden)] pub fn get_param_str(&self, n: usize) -> Option<&str> { let params = self.params.borrow(); @@ -364,7 +365,7 @@ impl<'r> Request<'r> { } /// Get the segments beginning at the `n`th dynamic parameter, if they - /// exist. + /// exist. Used by codegen. #[doc(hidden)] pub fn get_raw_segments(&self, n: usize) -> Option { let params = self.params.borrow(); diff --git a/lib/src/request/state.rs b/lib/src/request/state.rs index 28d373ae..5fc37e24 100644 --- a/lib/src/request/state.rs +++ b/lib/src/request/state.rs @@ -11,7 +11,7 @@ use http::Status; /// number of handlers. A value for the given type must previously have been /// registered to be managed by Rocket via the /// [manage](/rocket/struct.Rocket.html#method.manage) method. The type being -/// managed must be thread safe and sendable across thread boundaries. In otehr +/// managed must be thread safe and sendable across thread boundaries. In other /// words, it must implement `Send + Sync + 'static`. /// /// # Example