diff --git a/CHANGES.md b/CHANGES.md index 0bb37b94b..5265d9d79 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,8 @@ * Add `ClientRequestBuilder::form()` for sending `application/x-www-form-urlencoded` requests. +* Add method to configure custom error handler to Form extractor. + * Add methods to `HttpResponse` to retrieve, add, and delete cookies * Add `.set_content_type()` and `.set_content_disposition()` methods diff --git a/src/extractor.rs b/src/extractor.rs index 175e948b8..0cdcb3afb 100644 --- a/src/extractor.rs +++ b/src/extractor.rs @@ -1,6 +1,7 @@ use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::{fmt, str}; +use std::rc::Rc; use bytes::Bytes; use encoding::all::UTF_8; @@ -11,7 +12,7 @@ use serde::de::{self, DeserializeOwned}; use serde_urlencoded; use de::PathDeserializer; -use error::{Error, ErrorBadRequest, ErrorNotFound}; +use error::{Error, ErrorBadRequest, ErrorNotFound, UrlencodedError}; use handler::{AsyncResult, FromRequest}; use httpmessage::{HttpMessage, MessageBody, UrlEncoded}; use httprequest::HttpRequest; @@ -261,15 +262,17 @@ where T: DeserializeOwned + 'static, S: 'static, { - type Config = FormConfig; + type Config = FormConfig; type Result = Box>; #[inline] fn from_request(req: &HttpRequest, cfg: &Self::Config) -> Self::Result { + let req = req.clone(); + let err = Rc::clone(&cfg.ehandler); Box::new( UrlEncoded::new(req.clone()) .limit(cfg.limit) - .from_err() + .map_err(move |e| (*err)(e, req)) .map(Form), ) } @@ -314,21 +317,34 @@ impl fmt::Display for Form { /// ); /// } /// ``` -pub struct FormConfig { +pub struct FormConfig { limit: usize, + ehandler: Rc) -> Error>, } -impl FormConfig { +impl FormConfig { /// Change max size of payload. By default max size is 256Kb pub fn limit(&mut self, limit: usize) -> &mut Self { self.limit = limit; self } + + /// Set custom error handler + pub fn error_handler(&mut self, f: F) -> &mut Self + where + F: Fn(UrlencodedError, HttpRequest) -> Error + 'static, + { + self.ehandler = Rc::new(f); + self + } } -impl Default for FormConfig { +impl Default for FormConfig { fn default() -> Self { - FormConfig { limit: 262_144 } + FormConfig { + limit: 262_144, + ehandler: Rc::new(|e, _| e.into()), + } } } diff --git a/tests/test_handlers.rs b/tests/test_handlers.rs index 8f1ee9439..e6738e8a1 100644 --- a/tests/test_handlers.rs +++ b/tests/test_handlers.rs @@ -125,6 +125,30 @@ fn test_form_extractor() { assert_eq!(bytes, Bytes::from_static(b"test")); } +#[test] +fn test_form_extractor2() { + let mut srv = test::TestServer::new(|app| { + app.resource("/{username}/index.html", |r| { + r.route().with(|form: Form| { + format!("{}", form.username) + }).error_handler(|err, res| { + error::InternalError::from_response( + err, HttpResponse::Conflict().finish()).into() + }); + }); + }); + + // client request + let request = srv + .post() + .uri(srv.url("/test1/index.html")) + .header("content-type", "application/x-www-form-urlencoded") + .body("918237129hdk:D:D:D:D:D:DjASHDKJhaswkjeq") + .unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_client_error()); +} + #[test] fn test_path_and_query_extractor() { let mut srv = test::TestServer::new(|app| {