diff --git a/actix-http/CHANGES.md b/actix-http/CHANGES.md index 742ff8d3e..049f5328c 100644 --- a/actix-http/CHANGES.md +++ b/actix-http/CHANGES.md @@ -6,6 +6,8 @@ * Export IntoHeaderValue +* Render error and return as response body + ### Deleted * Removed PayloadBuffer diff --git a/actix-http/src/error.rs b/actix-http/src/error.rs index 45bf067dc..6098421a8 100644 --- a/actix-http/src/error.rs +++ b/actix-http/src/error.rs @@ -18,8 +18,6 @@ use tokio_timer::Error as TimerError; // re-export for convinience pub use crate::cookie::ParseError as CookieParseError; - -use crate::body::Body; use crate::response::Response; /// A specialized [`Result`](https://doc.rust-lang.org/std/result/enum.Result.html) @@ -49,13 +47,6 @@ impl Error { pub fn as_response_error(&self) -> &ResponseError { self.cause.as_ref() } - - /// Converts error to a response instance and set error message as response body - pub fn response_with_message(self) -> Response { - let message = format!("{}", self); - let resp: Response = self.into(); - resp.set_body(Body::from(message)) - } } /// Error that can be converted to `Response` diff --git a/actix-http/src/response.rs b/actix-http/src/response.rs index f82945526..ff0ce48de 100644 --- a/actix-http/src/response.rs +++ b/actix-http/src/response.rs @@ -1,7 +1,7 @@ //! Http response use std::cell::{Ref, RefMut}; use std::io::Write; -use std::{fmt, str}; +use std::{fmt, io, str}; use bytes::{BufMut, Bytes, BytesMut}; use futures::future::{ok, FutureResult, IntoFuture}; @@ -54,10 +54,13 @@ impl Response { /// Constructs an error response #[inline] pub fn from_error(error: Error) -> Response { - let resp = error.as_response_error().error_response(); - let mut resp = resp.set_body(Body::from(format!("{}", error))); + let mut resp = error.as_response_error().error_response(); + let mut buf = BytesMut::new(); + let _ = write!(Writer(&mut buf), "{}", error); + resp.headers_mut() + .insert(header::CONTENT_TYPE, HeaderValue::from_static("text/plain")); resp.error = Some(error); - resp + resp.set_body(Body::from(buf)) } /// Convert response to response with body @@ -300,6 +303,18 @@ impl<'a> Iterator for CookieIter<'a> { } } +pub struct Writer<'a>(pub &'a mut BytesMut); + +impl<'a> io::Write for Writer<'a> { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.extend_from_slice(buf); + Ok(buf.len()) + } + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + /// An HTTP response builder /// /// This type can be used to construct an instance of `Response` through a diff --git a/actix-http/tests/test_server.rs b/actix-http/tests/test_server.rs index 85cab929c..d777d3d1a 100644 --- a/actix-http/tests/test_server.rs +++ b/actix-http/tests/test_server.rs @@ -867,7 +867,7 @@ fn test_h1_response_http_error_handling() { // read response let bytes = srv.load_body(response).unwrap(); - assert!(bytes.is_empty()); + assert_eq!(bytes, Bytes::from_static(b"failed to parse header value")); } #[cfg(feature = "ssl")] @@ -900,7 +900,7 @@ fn test_h2_response_http_error_handling() { // read response let bytes = srv.load_body(response).unwrap(); - assert!(bytes.is_empty()); + assert_eq!(bytes, Bytes::from_static(b"failed to parse header value")); } #[test] diff --git a/src/middleware/logger.rs b/src/middleware/logger.rs index 3039b850f..f4b7517de 100644 --- a/src/middleware/logger.rs +++ b/src/middleware/logger.rs @@ -417,12 +417,7 @@ impl FormatText { )) }; } - FormatText::UrlPath => { - *self = FormatText::Str(format!( - "{}", - req.path() - )) - } + FormatText::UrlPath => *self = FormatText::Str(format!("{}", req.path())), FormatText::RequestTime => { *self = FormatText::Str(format!( "{:?}", @@ -489,7 +484,9 @@ mod tests { let req = TestRequest::with_header( header::USER_AGENT, header::HeaderValue::from_static("ACTIX-WEB"), - ).uri("/test/route/yeah").to_srv_request(); + ) + .uri("/test/route/yeah") + .to_srv_request(); let now = time::now(); for unit in &mut format.0 {