1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-12-30 12:00:38 +00:00

impl Responder for Form

This commit is contained in:
jesskfulwood 2019-07-20 12:55:52 +01:00 committed by jesskfullwood
parent c96068e78d
commit 8f48ed2597

View file

@ -3,20 +3,29 @@
use std::rc::Rc; use std::rc::Rc;
use std::{fmt, ops}; use std::{fmt, ops};
use actix_http::{Error, HttpMessage, Payload}; use actix_http::{Error, HttpMessage, Payload, Response};
use bytes::BytesMut; use bytes::BytesMut;
use encoding_rs::{Encoding, UTF_8}; use encoding_rs::{Encoding, UTF_8};
use futures::{Future, Poll, Stream}; use futures::{Future, Poll, Stream};
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde::Serialize;
use crate::dev::Decompress; use crate::dev::Decompress;
use crate::error::UrlencodedError; use crate::error::UrlencodedError;
use crate::extract::FromRequest; use crate::extract::FromRequest;
use crate::http::header::CONTENT_LENGTH; use crate::http::{
header::{ContentType, CONTENT_LENGTH},
StatusCode,
};
use crate::request::HttpRequest; use crate::request::HttpRequest;
use crate::responder::Responder;
#[derive(PartialEq, Eq, PartialOrd, Ord)] /// Form data helper (`application/x-www-form-urlencoded`)
/// Extract typed information from the request's body. ///
/// Can be use to extract url-encoded data from the request body,
/// or send url-encoded data as the response.
///
/// ## Extract
/// ///
/// To extract typed information from request's body, the type `T` must /// To extract typed information from request's body, the type `T` must
/// implement the `Deserialize` trait from *serde*. /// implement the `Deserialize` trait from *serde*.
@ -24,8 +33,7 @@ use crate::request::HttpRequest;
/// [**FormConfig**](struct.FormConfig.html) allows to configure extraction /// [**FormConfig**](struct.FormConfig.html) allows to configure extraction
/// process. /// process.
/// ///
/// ## Example /// ### Example
///
/// ```rust /// ```rust
/// # extern crate actix_web; /// # extern crate actix_web;
/// #[macro_use] extern crate serde_derive; /// #[macro_use] extern crate serde_derive;
@ -44,6 +52,36 @@ use crate::request::HttpRequest;
/// } /// }
/// # fn main() {} /// # fn main() {}
/// ``` /// ```
///
/// ## Respond
///
/// The `Form` type also allows you to respond with well-formed url-encoded data:
/// simply return a value of type Form<T> where T is the type to be url-encoded.
/// The type must implement `serde::Serialize`;
///
/// ### Example
/// ```rust
/// # #[macro_use] extern crate serde_derive;
/// # use actix_web::*;
/// #
/// #[derive(Serialize)]
/// struct SomeForm {
/// name: String,
/// age: u8
/// }
///
/// // Will return a 200 response with header
/// // `Content-Type: application/x-www-form-urlencoded`
/// // and body "name=actix&age=123"
/// fn index() -> web::Form<SomeForm> {
/// web::Form(SomeForm {
/// name: "actix".into(),
/// age: 123
/// })
/// }
/// # fn main() {}
/// ```
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub struct Form<T>(pub T); pub struct Form<T>(pub T);
impl<T> Form<T> { impl<T> Form<T> {
@ -110,6 +148,22 @@ impl<T: fmt::Display> fmt::Display for Form<T> {
} }
} }
impl<T: Serialize> Responder for Form<T> {
type Error = Error;
type Future = Result<Response, Error>;
fn respond_to(self, _: &HttpRequest) -> Self::Future {
let body = match serde_urlencoded::to_string(&self.0) {
Ok(body) => body,
Err(e) => return Err(e.into()),
};
Ok(Response::build(StatusCode::OK)
.set(ContentType::form_url_encoded())
.body(body))
}
}
/// Form extractor configuration /// Form extractor configuration
/// ///
/// ```rust /// ```rust
@ -304,15 +358,16 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use bytes::Bytes; use bytes::Bytes;
use serde::Deserialize; use serde::{Deserialize, Serialize};
use super::*; use super::*;
use crate::http::header::CONTENT_TYPE; use crate::http::header::{HeaderValue, CONTENT_TYPE};
use crate::test::{block_on, TestRequest}; use crate::test::{block_on, TestRequest};
#[derive(Deserialize, Debug, PartialEq)] #[derive(Deserialize, Serialize, Debug, PartialEq)]
struct Info { struct Info {
hello: String, hello: String,
counter: i64,
} }
#[test] #[test]
@ -320,11 +375,17 @@ mod tests {
let (req, mut pl) = let (req, mut pl) =
TestRequest::with_header(CONTENT_TYPE, "application/x-www-form-urlencoded") TestRequest::with_header(CONTENT_TYPE, "application/x-www-form-urlencoded")
.header(CONTENT_LENGTH, "11") .header(CONTENT_LENGTH, "11")
.set_payload(Bytes::from_static(b"hello=world")) .set_payload(Bytes::from_static(b"hello=world&counter=123"))
.to_http_parts(); .to_http_parts();
let s = block_on(Form::<Info>::from_request(&req, &mut pl)).unwrap(); let Form(s) = block_on(Form::<Info>::from_request(&req, &mut pl)).unwrap();
assert_eq!(s.hello, "world"); assert_eq!(
s,
Info {
hello: "world".into(),
counter: 123
}
);
} }
fn eq(err: UrlencodedError, other: UrlencodedError) -> bool { fn eq(err: UrlencodedError, other: UrlencodedError) -> bool {
@ -373,14 +434,15 @@ mod tests {
let (req, mut pl) = let (req, mut pl) =
TestRequest::with_header(CONTENT_TYPE, "application/x-www-form-urlencoded") TestRequest::with_header(CONTENT_TYPE, "application/x-www-form-urlencoded")
.header(CONTENT_LENGTH, "11") .header(CONTENT_LENGTH, "11")
.set_payload(Bytes::from_static(b"hello=world")) .set_payload(Bytes::from_static(b"hello=world&counter=123"))
.to_http_parts(); .to_http_parts();
let info = block_on(UrlEncoded::<Info>::new(&req, &mut pl)).unwrap(); let info = block_on(UrlEncoded::<Info>::new(&req, &mut pl)).unwrap();
assert_eq!( assert_eq!(
info, info,
Info { Info {
hello: "world".to_owned() hello: "world".to_owned(),
counter: 123
} }
); );
@ -389,15 +451,36 @@ mod tests {
"application/x-www-form-urlencoded; charset=utf-8", "application/x-www-form-urlencoded; charset=utf-8",
) )
.header(CONTENT_LENGTH, "11") .header(CONTENT_LENGTH, "11")
.set_payload(Bytes::from_static(b"hello=world")) .set_payload(Bytes::from_static(b"hello=world&counter=123"))
.to_http_parts(); .to_http_parts();
let info = block_on(UrlEncoded::<Info>::new(&req, &mut pl)).unwrap(); let info = block_on(UrlEncoded::<Info>::new(&req, &mut pl)).unwrap();
assert_eq!( assert_eq!(
info, info,
Info { Info {
hello: "world".to_owned() hello: "world".to_owned(),
counter: 123
} }
); );
} }
#[test]
fn test_responder() {
let req = TestRequest::default().to_http_request();
let form = Form(Info {
hello: "world".to_string(),
counter: 123,
});
let resp = form.respond_to(&req).unwrap();
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(
resp.headers().get(CONTENT_TYPE).unwrap(),
HeaderValue::from_static("application/x-www-form-urlencoded")
);
use crate::responder::tests::BodyTest;
assert_eq!(resp.body().bin_ref(), b"hello=world&counter=123");
}
} }