diff --git a/src/client/request.rs b/src/client/request.rs index bb338482b..bc8feb3e7 100644 --- a/src/client/request.rs +++ b/src/client/request.rs @@ -10,6 +10,7 @@ use futures::Stream; use percent_encoding::{percent_encode, USERINFO_ENCODE_SET}; use serde::Serialize; use serde_json; +use serde_urlencoded; use url::Url; use super::body::ClientBody; @@ -658,6 +659,24 @@ impl ClientRequestBuilder { self.body(body) } + + /// Set a urlencoded body and generate `ClientRequest` + /// + /// `ClientRequestBuilder` can not be used after this call. + pub fn form(&mut self, value: T) -> Result { + let body = serde_urlencoded::to_string(&value)?; + + let contains = if let Some(parts) = parts(&mut self.request, &self.err) { + parts.headers.contains_key(header::CONTENT_TYPE) + } else { + true + }; + if !contains { + self.header(header::CONTENT_TYPE, "application/x-www-form-urlencoded"); + } + + self.body(body) + } /// Set a streaming body and generate `ClientRequest`. /// diff --git a/src/error.rs b/src/error.rs index f3327c2b6..39e66a0db 100644 --- a/src/error.rs +++ b/src/error.rs @@ -16,6 +16,7 @@ use http_range::HttpRangeParseError; use httparse; use serde::de::value::Error as DeError; use serde_json::error::Error as JsonError; +use serde_urlencoded::ser::Error as FormError; use tokio_timer::Error as TimerError; pub use url::ParseError as UrlParseError; @@ -205,6 +206,9 @@ impl From for Error { /// `InternalServerError` for `JsonError` impl ResponseError for JsonError {} +/// `InternalServerError` for `FormError` +impl ResponseError for FormError {} + /// `InternalServerError` for `TimerError` impl ResponseError for TimerError {} @@ -586,6 +590,47 @@ impl From for JsonPayloadError { } } +/// A set of errors that can occur during parsing json payloads +#[derive(Fail, Debug)] +pub enum FormPayloadError { + /// Payload size is bigger than allowed. (default: 256kB) + #[fail(display = "Form payload size is bigger than allowed. (default: 256kB)")] + Overflow, + /// Content type error + #[fail(display = "Content type error")] + ContentType, + /// Deserialize error + #[fail(display = "Form deserialize error: {}", _0)] + Deserialize(#[cause] FormError), + /// Payload error + #[fail(display = "Error that occur during reading payload: {}", _0)] + Payload(#[cause] PayloadError), +} + +/// Return `BadRequest` for `UrlencodedError` +impl ResponseError for FormPayloadError { + fn error_response(&self) -> HttpResponse { + match *self { + FormPayloadError::Overflow => { + HttpResponse::new(StatusCode::PAYLOAD_TOO_LARGE) + } + _ => HttpResponse::new(StatusCode::BAD_REQUEST), + } + } +} + +impl From for FormPayloadError { + fn from(err: PayloadError) -> FormPayloadError { + FormPayloadError::Payload(err) + } +} + +impl From for FormPayloadError { + fn from(err: FormError) -> FormPayloadError { + FormPayloadError::Deserialize(err) + } +} + /// Errors which can occur when attempting to interpret a segment string as a /// valid path segment. #[derive(Fail, Debug, PartialEq)]