diff --git a/CHANGES.md b/CHANGES.md index 64e0891e548..bf8fc942438 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,7 +4,12 @@ ### Added * `HttpResponse` and `HttpResponseBuilder` structs. [#2065] +### Changed +* Most error types are now marked `#[non_exhaustive]`. [#2148] + [#2065]: https://github.com/actix/actix-web/pull/2065 +[#2148]: https://github.com/actix/actix-web/pull/2148 + ## 4.0.0-beta.5 - 2021-04-02 ### Added diff --git a/actix-http/CHANGES.md b/actix-http/CHANGES.md index 5e42586779b..e50259634a3 100644 --- a/actix-http/CHANGES.md +++ b/actix-http/CHANGES.md @@ -6,8 +6,13 @@ * Top-level `cookies` mod (re-export). [#2065] * `HttpMessage` trait loses the `cookies` and `cookie` methods. [#2065] * `impl ResponseError for CookieParseError`. [#2065] +* Deprecated methods on `ResponseBuilder`: `if_true`, `if_some`. [#2148] +* `ResponseBuilder::json`. [#2148] +* `ResponseBuilder::{set_header, header}`. [#2148] +* `impl From for Body`. [#2148] [#2065]: https://github.com/actix/actix-web/pull/2065 +[#2148]: https://github.com/actix/actix-web/pull/2148 ## 3.0.0-beta.5 - 2021-04-02 diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml index 573376b0744..4bef9e37c67 100644 --- a/actix-http/Cargo.toml +++ b/actix-http/Cargo.toml @@ -68,8 +68,6 @@ pin-project-lite = "0.2" rand = "0.8" regex = "1.3" serde = "1.0" -serde_json = "1.0" -serde_urlencoded = "0.7" sha-1 = "0.9" smallvec = "1.6" time = { version = "0.2.23", default-features = false, features = ["std"] } @@ -89,6 +87,7 @@ criterion = "0.3" env_logger = "0.8" rcgen = "0.8" serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" tls-openssl = { version = "0.10", package = "openssl" } tls-rustls = { version = "0.19", package = "rustls" } diff --git a/actix-http/src/body/body.rs b/actix-http/src/body/body.rs index a3fd7d41c7c..6814d54f743 100644 --- a/actix-http/src/body/body.rs +++ b/actix-http/src/body/body.rs @@ -132,12 +132,6 @@ impl From for Body { } } -impl From for Body { - fn from(v: serde_json::Value) -> Body { - Body::Bytes(v.to_string().into()) - } -} - impl From> for Body where S: Stream> + Unpin + 'static, diff --git a/actix-http/src/body/mod.rs b/actix-http/src/body/mod.rs index fa43e1b0323..f5664e1dca9 100644 --- a/actix-http/src/body/mod.rs +++ b/actix-http/src/body/mod.rs @@ -174,13 +174,15 @@ mod tests { #[actix_rt::test] async fn test_serde_json() { - use serde_json::json; + use serde_json::{json, Value}; assert_eq!( - Body::from(serde_json::Value::String("test".into())).size(), + Body::from(serde_json::to_vec(&Value::String("test".to_owned())).unwrap()) + .size(), BodySize::Sized(6) ); assert_eq!( - Body::from(json!({"test-key":"test-value"})).size(), + Body::from(serde_json::to_vec(&json!({"test-key":"test-value"})).unwrap()) + .size(), BodySize::Sized(25) ); } diff --git a/actix-http/src/error.rs b/actix-http/src/error.rs index 03693ff2fab..60a870ecc06 100644 --- a/actix-http/src/error.rs +++ b/actix-http/src/error.rs @@ -1,18 +1,18 @@ //! Error and Result module -use std::cell::RefCell; -use std::io::Write; -use std::str::Utf8Error; -use std::string::FromUtf8Error; -use std::{fmt, io, result}; +use std::{ + cell::RefCell, + fmt, + io::{self, Write as _}, + str::Utf8Error, + string::FromUtf8Error, +}; use bytes::BytesMut; -use derive_more::{Display, From}; +use derive_more::{Display, Error, From}; use http::uri::InvalidUri; use http::{header, Error as HttpError, StatusCode}; use serde::de::value::Error as DeError; -use serde_json::error::Error as JsonError; -use serde_urlencoded::ser::Error as FormError; use crate::{body::Body, helpers::Writer, Response, ResponseBuilder}; @@ -22,7 +22,7 @@ use crate::{body::Body, helpers::Writer, Response, ResponseBuilder}; /// This typedef is generally used to avoid writing out /// `actix_http::error::Error` directly and is otherwise a direct mapping to /// `Result`. -pub type Result = result::Result; +pub type Result = std::result::Result; /// General purpose actix web error. /// @@ -147,14 +147,8 @@ struct UnitError; /// Returns [`StatusCode::INTERNAL_SERVER_ERROR`] for [`UnitError`]. impl ResponseError for UnitError {} -/// Returns [`StatusCode::INTERNAL_SERVER_ERROR`] for [`JsonError`]. -impl ResponseError for JsonError {} - -/// Returns [`StatusCode::INTERNAL_SERVER_ERROR`] for [`FormError`]. -impl ResponseError for FormError {} - -#[cfg(feature = "openssl")] /// Returns [`StatusCode::INTERNAL_SERVER_ERROR`] for [`actix_tls::accept::openssl::SslError`]. +#[cfg(feature = "openssl")] impl ResponseError for actix_tls::accept::openssl::SslError {} /// Returns [`StatusCode::BAD_REQUEST`] for [`DeError`]. @@ -421,18 +415,17 @@ pub enum DispatchError { } /// A set of error that can occur during parsing content type -#[derive(PartialEq, Debug, Display)] +#[derive(Debug, PartialEq, Display, Error)] pub enum ContentTypeError { /// Can not parse content type #[display(fmt = "Can not parse content type")] ParseError, + /// Unknown content encoding #[display(fmt = "Unknown content encoding")] UnknownEncoding, } -impl std::error::Error for ContentTypeError {} - /// Return `BadRequest` for `ContentTypeError` impl ResponseError for ContentTypeError { fn status_code(&self) -> StatusCode { diff --git a/actix-http/src/response.rs b/actix-http/src/response.rs index a96a13bd3b6..046c4ca5639 100644 --- a/actix-http/src/response.rs +++ b/actix-http/src/response.rs @@ -2,7 +2,6 @@ use std::{ cell::{Ref, RefMut}, - convert::TryInto, fmt, future::Future, pin::Pin, @@ -12,17 +11,13 @@ use std::{ use bytes::{Bytes, BytesMut}; use futures_core::Stream; -use serde::Serialize; use crate::{ body::{Body, BodyStream, MessageBody, ResponseBody}, error::Error, extensions::Extensions, header::{IntoHeaderPair, IntoHeaderValue}, - http::{ - header::{self, HeaderName}, - Error as HttpError, HeaderMap, StatusCode, - }, + http::{header, Error as HttpError, HeaderMap, StatusCode}, message::{BoxedResponseHead, ConnectionType, ResponseHead}, }; @@ -335,54 +330,6 @@ impl ResponseBuilder { self } - /// Replaced with [`Self::insert_header()`]. - #[deprecated( - since = "4.0.0", - note = "Replaced with `insert_header((key, value))`. Will be removed in v5." - )] - pub fn set_header(&mut self, key: K, value: V) -> &mut Self - where - K: TryInto, - K::Error: Into, - V: IntoHeaderValue, - { - if self.err.is_some() { - return self; - } - - match (key.try_into(), value.try_into_value()) { - (Ok(name), Ok(value)) => return self.insert_header((name, value)), - (Err(err), _) => self.err = Some(err.into()), - (_, Err(err)) => self.err = Some(err.into()), - } - - self - } - - /// Replaced with [`Self::append_header()`]. - #[deprecated( - since = "4.0.0", - note = "Replaced with `append_header((key, value))`. Will be removed in v5." - )] - pub fn header(&mut self, key: K, value: V) -> &mut Self - where - K: TryInto, - K::Error: Into, - V: IntoHeaderValue, - { - if self.err.is_some() { - return self; - } - - match (key.try_into(), value.try_into_value()) { - (Ok(name), Ok(value)) => return self.append_header((name, value)), - (Err(err), _) => self.err = Some(err.into()), - (_, Err(err)) => self.err = Some(err.into()), - } - - self - } - /// Set the custom reason for the response. #[inline] pub fn reason(&mut self, reason: &'static str) -> &mut Self { @@ -456,32 +403,6 @@ impl ResponseBuilder { self } - /// This method calls provided closure with builder reference if value is `true`. - #[doc(hidden)] - #[deprecated = "Use an if statement."] - pub fn if_true(&mut self, value: bool, f: F) -> &mut Self - where - F: FnOnce(&mut ResponseBuilder), - { - if value { - f(self); - } - self - } - - /// This method calls provided closure with builder reference if value is `Some`. - #[doc(hidden)] - #[deprecated = "Use an if-let construction."] - pub fn if_some(&mut self, value: Option, f: F) -> &mut Self - where - F: FnOnce(T, &mut ResponseBuilder), - { - if let Some(val) = value { - f(val, self); - } - self - } - /// Responses extensions #[inline] pub fn extensions(&self) -> Ref<'_, Extensions> { @@ -496,10 +417,10 @@ impl ResponseBuilder { head.extensions.borrow_mut() } - #[inline] /// Set a body and generate `Response`. /// /// `ResponseBuilder` can not be used after this call. + #[inline] pub fn body>(&mut self, body: B) -> Response { self.message_body(body.into()) } @@ -521,10 +442,10 @@ impl ResponseBuilder { } } - #[inline] /// Set a streaming body and generate `Response`. /// /// `ResponseBuilder` can not be used after this call. + #[inline] pub fn streaming(&mut self, stream: S) -> Response where S: Stream> + Unpin + 'static, @@ -533,32 +454,10 @@ impl ResponseBuilder { self.body(Body::from_message(BodyStream::new(stream))) } - /// Set a json body and generate `Response` - /// - /// `ResponseBuilder` can not be used after this call. - pub fn json(&mut self, value: impl Serialize) -> Response { - match serde_json::to_string(&value) { - Ok(body) => { - let contains = if let Some(parts) = parts(&mut self.head, &self.err) { - parts.headers.contains_key(header::CONTENT_TYPE) - } else { - true - }; - - if !contains { - self.insert_header((header::CONTENT_TYPE, mime::APPLICATION_JSON)); - } - - self.body(Body::from(body)) - } - Err(e) => Error::from(e).into(), - } - } - - #[inline] /// Set an empty body and generate `Response` /// /// `ResponseBuilder` can not be used after this call. + #[inline] pub fn finish(&mut self) -> Response { self.body(Body::Empty) } @@ -706,11 +605,9 @@ impl From for Response { #[cfg(test)] mod tests { - use serde_json::json; - use super::*; use crate::body::Body; - use crate::http::header::{HeaderValue, CONTENT_TYPE, COOKIE}; + use crate::http::header::{HeaderName, HeaderValue, CONTENT_TYPE, COOKIE}; #[test] fn test_debug() { @@ -754,38 +651,6 @@ mod tests { assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "text/plain") } - #[test] - fn test_json() { - let resp = Response::Ok().json(vec!["v1", "v2", "v3"]); - let ct = resp.headers().get(CONTENT_TYPE).unwrap(); - assert_eq!(ct, HeaderValue::from_static("application/json")); - assert_eq!(resp.body().get_ref(), b"[\"v1\",\"v2\",\"v3\"]"); - - let resp = Response::Ok().json(&["v1", "v2", "v3"]); - let ct = resp.headers().get(CONTENT_TYPE).unwrap(); - assert_eq!(ct, HeaderValue::from_static("application/json")); - assert_eq!(resp.body().get_ref(), b"[\"v1\",\"v2\",\"v3\"]"); - } - - #[test] - fn test_json_ct() { - let resp = Response::build(StatusCode::OK) - .insert_header((CONTENT_TYPE, "text/json")) - .json(&vec!["v1", "v2", "v3"]); - let ct = resp.headers().get(CONTENT_TYPE).unwrap(); - assert_eq!(ct, HeaderValue::from_static("text/json")); - assert_eq!(resp.body().get_ref(), b"[\"v1\",\"v2\",\"v3\"]"); - } - - #[test] - fn test_serde_json_in_body() { - use serde_json::json; - - let resp = - Response::build(StatusCode::OK).body(json!({"test-key":"test-value"})); - assert_eq!(resp.body().get_ref(), br#"{"test-key":"test-value"}"#); - } - #[test] fn test_into_response() { let resp: Response = "test".into(); diff --git a/awc/CHANGES.md b/awc/CHANGES.md index eb008ff9820..a0bfcac86b8 100644 --- a/awc/CHANGES.md +++ b/awc/CHANGES.md @@ -1,6 +1,10 @@ # Changes ## Unreleased - 2021-xx-xx +### Removed +* Deprecated methods on `ClientRequest`: `if_true`, `if_some`. [#2148] + +[#2148]: https://github.com/actix/actix-web/pull/2148 ## 3.0.0-beta.4 - 2021-04-02 diff --git a/awc/src/request.rs b/awc/src/request.rs index f5cb08f15a4..483524102ac 100644 --- a/awc/src/request.rs +++ b/awc/src/request.rs @@ -311,34 +311,6 @@ impl ClientRequest { self } - /// This method calls provided closure with builder reference if value is `true`. - #[doc(hidden)] - #[deprecated = "Use an if statement."] - pub fn if_true(self, value: bool, f: F) -> Self - where - F: FnOnce(ClientRequest) -> ClientRequest, - { - if value { - f(self) - } else { - self - } - } - - /// This method calls provided closure with builder reference if value is `Some`. - #[doc(hidden)] - #[deprecated = "Use an if-let construction."] - pub fn if_some(self, value: Option, f: F) -> Self - where - F: FnOnce(T, ClientRequest) -> ClientRequest, - { - if let Some(val) = value { - f(val, self) - } else { - self - } - } - /// Sets the query part of the request pub fn query( mut self, diff --git a/awc/src/sender.rs b/awc/src/sender.rs index 1170c69a012..0e63be22106 100644 --- a/awc/src/sender.rs +++ b/awc/src/sender.rs @@ -1,6 +1,6 @@ use std::{ future::Future, - net, + io, net, pin::Pin, rc::Rc, task::{Context, Poll}, @@ -209,7 +209,8 @@ impl RequestSender { ) -> SendClientRequest { let body = match serde_json::to_string(value) { Ok(body) => body, - Err(e) => return Error::from(e).into(), + // TODO: own error type + Err(e) => return Error::from(io::Error::new(io::ErrorKind::Other, e)).into(), }; if let Err(e) = self.set_header_if_none(header::CONTENT_TYPE, "application/json") { @@ -235,7 +236,8 @@ impl RequestSender { ) -> SendClientRequest { let body = match serde_urlencoded::to_string(value) { Ok(body) => body, - Err(e) => return Error::from(e).into(), + // TODO: own error type + Err(e) => return Error::from(io::Error::new(io::ErrorKind::Other, e)).into(), }; // set content-type diff --git a/src/error.rs b/src/error.rs index 25cdc9feba5..cc1a055b85b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -3,12 +3,15 @@ pub use actix_http::error::*; use derive_more::{Display, Error, From}; use serde_json::error::Error as JsonError; +use serde_urlencoded::de::Error as FormDeError; +use serde_urlencoded::ser::Error as FormError; use url::ParseError as UrlParseError; use crate::http::StatusCode; /// Errors which can occur when attempting to generate resource uri. -#[derive(Debug, PartialEq, Display, From)] +#[derive(Debug, PartialEq, Display, Error, From)] +#[non_exhaustive] pub enum UrlGenerationError { /// Resource not found #[display(fmt = "Resource not found")] @@ -23,13 +26,12 @@ pub enum UrlGenerationError { ParseError(UrlParseError), } -impl std::error::Error for UrlGenerationError {} - /// `InternalServerError` for `UrlGeneratorError` impl ResponseError for UrlGenerationError {} /// A set of errors that can occur during parsing urlencoded payloads #[derive(Debug, Display, Error, From)] +#[non_exhaustive] pub enum UrlencodedError { /// Can not decode chunked transfer encoding. #[display(fmt = "Can not decode chunked transfer encoding.")] @@ -52,8 +54,16 @@ pub enum UrlencodedError { ContentType, /// Parse error. - #[display(fmt = "Parse error.")] - Parse, + #[display(fmt = "Parse error: {}.", _0)] + Parse(FormDeError), + + /// Encoding error. + #[display(fmt = "Encoding error.")] + Encoding, + + /// Serialize error. + #[display(fmt = "Serialize error: {}.", _0)] + Serialize(FormError), /// Payload error. #[display(fmt = "Error that occur during reading payload: {}.", _0)] @@ -63,52 +73,66 @@ pub enum UrlencodedError { /// Return `BadRequest` for `UrlencodedError` impl ResponseError for UrlencodedError { fn status_code(&self) -> StatusCode { - match *self { - UrlencodedError::Overflow { .. } => StatusCode::PAYLOAD_TOO_LARGE, - UrlencodedError::UnknownLength => StatusCode::LENGTH_REQUIRED, + match self { + Self::Overflow { .. } => StatusCode::PAYLOAD_TOO_LARGE, + Self::UnknownLength => StatusCode::LENGTH_REQUIRED, + Self::Payload(err) => err.status_code(), _ => StatusCode::BAD_REQUEST, } } } /// A set of errors that can occur during parsing json payloads -#[derive(Debug, Display, From)] +#[derive(Debug, Display, Error)] +#[non_exhaustive] pub enum JsonPayloadError { /// Payload size is bigger than allowed. (default: 32kB) #[display(fmt = "Json payload size is bigger than allowed")] Overflow, + /// Content type error #[display(fmt = "Content type error")] ContentType, + /// Deserialize error #[display(fmt = "Json deserialize error: {}", _0)] Deserialize(JsonError), + + /// Serialize error + #[display(fmt = "Json serialize error: {}", _0)] + Serialize(JsonError), + /// Payload error #[display(fmt = "Error that occur during reading payload: {}", _0)] Payload(PayloadError), } -impl std::error::Error for JsonPayloadError {} +impl From for JsonPayloadError { + fn from(err: PayloadError) -> Self { + Self::Payload(err) + } +} impl ResponseError for JsonPayloadError { fn status_code(&self) -> StatusCode { - match *self { - JsonPayloadError::Overflow => StatusCode::PAYLOAD_TOO_LARGE, + match self { + Self::Overflow => StatusCode::PAYLOAD_TOO_LARGE, + Self::Serialize(_) => StatusCode::INTERNAL_SERVER_ERROR, + Self::Payload(err) => err.status_code(), _ => StatusCode::BAD_REQUEST, } } } /// A set of errors that can occur during parsing request paths -#[derive(Debug, Display, From)] +#[derive(Debug, Display, Error)] +#[non_exhaustive] pub enum PathError { /// Deserialize error #[display(fmt = "Path deserialize error: {}", _0)] Deserialize(serde::de::value::Error), } -impl std::error::Error for PathError {} - /// Return `BadRequest` for `PathError` impl ResponseError for PathError { fn status_code(&self) -> StatusCode { @@ -118,6 +142,7 @@ impl ResponseError for PathError { /// A set of errors that can occur during parsing query strings. #[derive(Debug, Display, Error, From)] +#[non_exhaustive] pub enum QueryPayloadError { /// Query deserialize error. #[display(fmt = "Query deserialize error: {}", _0)] @@ -132,25 +157,26 @@ impl ResponseError for QueryPayloadError { } /// Error type returned when reading body as lines. -#[derive(From, Display, Debug)] +#[derive(Debug, Display, Error, From)] +#[non_exhaustive] pub enum ReadlinesError { - /// Error when decoding a line. #[display(fmt = "Encoding error")] /// Payload size is bigger than allowed. (default: 256kB) EncodingError, + /// Payload error. #[display(fmt = "Error that occur during reading payload: {}", _0)] Payload(PayloadError), + /// Line limit exceeded. #[display(fmt = "Line limit exceeded")] LimitOverflow, + /// ContentType error. #[display(fmt = "Content-type error")] ContentTypeError(ContentTypeError), } -impl std::error::Error for ReadlinesError {} - /// Return `BadRequest` for `ReadlinesError` impl ResponseError for ReadlinesError { fn status_code(&self) -> StatusCode { diff --git a/src/response.rs b/src/response.rs index 1d017f080f6..ce6739dc8ed 100644 --- a/src/response.rs +++ b/src/response.rs @@ -24,7 +24,7 @@ use actix_http::http::header::HeaderValue; #[cfg(feature = "cookies")] use cookie::{Cookie, CookieJar}; -use crate::error::Error; +use crate::error::{Error, JsonPayloadError}; /// An HTTP Response pub struct HttpResponse { @@ -385,7 +385,10 @@ impl HttpResponseBuilder { } /// Replaced with [`Self::insert_header()`]. - #[deprecated = "Replaced with `insert_header((key, value))`."] + #[deprecated( + since = "4.0.0", + note = "Replaced with `insert_header((key, value))`. Will be removed in v5." + )] pub fn set_header(&mut self, key: K, value: V) -> &mut Self where K: TryInto, @@ -406,7 +409,10 @@ impl HttpResponseBuilder { } /// Replaced with [`Self::append_header()`]. - #[deprecated = "Replaced with `append_header((key, value))`."] + #[deprecated( + since = "4.0.0", + note = "Replaced with `append_header((key, value))`. Will be removed in v5." + )] pub fn header(&mut self, key: K, value: V) -> &mut Self where K: TryInto, @@ -572,7 +578,7 @@ impl HttpResponseBuilder { /// Set a body and generate `Response`. /// - /// `ResponseBuilder` can not be used after this call. + /// `HttpResponseBuilder` can not be used after this call. #[inline] pub fn body>(&mut self, body: B) -> HttpResponse { self.message_body(body.into()) @@ -580,7 +586,7 @@ impl HttpResponseBuilder { /// Set a body and generate `Response`. /// - /// `ResponseBuilder` can not be used after this call. + /// `HttpResponseBuilder` can not be used after this call. pub fn message_body(&mut self, body: B) -> HttpResponse { if let Some(err) = self.err.take() { return HttpResponse::from_error(Error::from(err)).into_body(); @@ -608,7 +614,7 @@ impl HttpResponseBuilder { /// Set a streaming body and generate `Response`. /// - /// `ResponseBuilder` can not be used after this call. + /// `HttpResponseBuilder` can not be used after this call. #[inline] pub fn streaming(&mut self, stream: S) -> HttpResponse where @@ -620,7 +626,7 @@ impl HttpResponseBuilder { /// Set a json body and generate `Response` /// - /// `ResponseBuilder` can not be used after this call. + /// `HttpResponseBuilder` can not be used after this call. pub fn json(&mut self, value: impl Serialize) -> HttpResponse { match serde_json::to_string(&value) { Ok(body) => { @@ -636,19 +642,19 @@ impl HttpResponseBuilder { self.body(Body::from(body)) } - Err(e) => HttpResponse::from_error(Error::from(e)), + Err(err) => HttpResponse::from_error(JsonPayloadError::Serialize(err).into()), } } /// Set an empty body and generate `Response` /// - /// `ResponseBuilder` can not be used after this call. + /// `HttpResponseBuilder` can not be used after this call. #[inline] pub fn finish(&mut self) -> HttpResponse { self.body(Body::Empty) } - /// This method construct new `ResponseBuilder` + /// This method construct new `HttpResponseBuilder` pub fn take(&mut self) -> Self { Self { head: self.head.take(), @@ -814,32 +820,33 @@ mod http_codes { #[cfg(test)] mod tests { use bytes::{Bytes, BytesMut}; - use serde_json::json; - use super::{HttpResponse as Response, HttpResponseBuilder as ResponseBuilder}; + use super::{HttpResponse, HttpResponseBuilder}; use crate::dev::{Body, MessageBody, ResponseBody}; use crate::http::header::{self, HeaderValue, CONTENT_TYPE, COOKIE}; use crate::http::StatusCode; #[test] fn test_debug() { - let resp = Response::Ok() + let resp = HttpResponse::Ok() .append_header((COOKIE, HeaderValue::from_static("cookie1=value1; "))) .append_header((COOKIE, HeaderValue::from_static("cookie2=value2; "))) .finish(); let dbg = format!("{:?}", resp); - assert!(dbg.contains("Response")); + assert!(dbg.contains("HttpResponse")); } #[test] fn test_basic_builder() { - let resp = Response::Ok().insert_header(("X-TEST", "value")).finish(); + let resp = HttpResponse::Ok() + .insert_header(("X-TEST", "value")) + .finish(); assert_eq!(resp.status(), StatusCode::OK); } #[test] fn test_upgrade() { - let resp = ResponseBuilder::new(StatusCode::OK) + let resp = HttpResponseBuilder::new(StatusCode::OK) .upgrade("websocket") .finish(); assert!(resp.upgrade()); @@ -851,13 +858,15 @@ mod tests { #[test] fn test_force_close() { - let resp = ResponseBuilder::new(StatusCode::OK).force_close().finish(); + let resp = HttpResponseBuilder::new(StatusCode::OK) + .force_close() + .finish(); assert!(!resp.keep_alive()) } #[test] fn test_content_type() { - let resp = ResponseBuilder::new(StatusCode::OK) + let resp = HttpResponseBuilder::new(StatusCode::OK) .content_type("text/plain") .body(Body::Empty); assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "text/plain") @@ -878,7 +887,7 @@ mod tests { #[actix_rt::test] async fn test_json() { - let mut resp = Response::Ok().json(vec!["v1", "v2", "v3"]); + let mut resp = HttpResponse::Ok().json(vec!["v1", "v2", "v3"]); let ct = resp.headers().get(CONTENT_TYPE).unwrap(); assert_eq!(ct, HeaderValue::from_static("application/json")); assert_eq!( @@ -886,7 +895,7 @@ mod tests { br#"["v1","v2","v3"]"# ); - let mut resp = Response::Ok().json(&["v1", "v2", "v3"]); + let mut resp = HttpResponse::Ok().json(&["v1", "v2", "v3"]); let ct = resp.headers().get(CONTENT_TYPE).unwrap(); assert_eq!(ct, HeaderValue::from_static("application/json")); assert_eq!( @@ -895,7 +904,7 @@ mod tests { ); // content type override - let mut resp = Response::Ok() + let mut resp = HttpResponse::Ok() .insert_header((CONTENT_TYPE, "text/json")) .json(&vec!["v1", "v2", "v3"]); let ct = resp.headers().get(CONTENT_TYPE).unwrap(); @@ -908,8 +917,10 @@ mod tests { #[actix_rt::test] async fn test_serde_json_in_body() { - use serde_json::json; - let mut resp = Response::Ok().body(json!({"test-key":"test-value"})); + let mut resp = HttpResponse::Ok().body( + serde_json::to_vec(&serde_json::json!({ "test-key": "test-value" })).unwrap(), + ); + assert_eq!( read_body(resp.take_body()).await.as_ref(), br#"{"test-key":"test-value"}"# @@ -918,7 +929,7 @@ mod tests { #[test] fn response_builder_header_insert_kv() { - let mut res = Response::Ok(); + let mut res = HttpResponse::Ok(); res.insert_header(("Content-Type", "application/octet-stream")); let res = res.finish(); @@ -930,7 +941,7 @@ mod tests { #[test] fn response_builder_header_insert_typed() { - let mut res = Response::Ok(); + let mut res = HttpResponse::Ok(); res.insert_header((header::CONTENT_TYPE, mime::APPLICATION_OCTET_STREAM)); let res = res.finish(); @@ -942,7 +953,7 @@ mod tests { #[test] fn response_builder_header_append_kv() { - let mut res = Response::Ok(); + let mut res = HttpResponse::Ok(); res.append_header(("Content-Type", "application/octet-stream")); res.append_header(("Content-Type", "application/json")); let res = res.finish(); @@ -955,7 +966,7 @@ mod tests { #[test] fn response_builder_header_append_typed() { - let mut res = Response::Ok(); + let mut res = HttpResponse::Ok(); res.append_header((header::CONTENT_TYPE, mime::APPLICATION_OCTET_STREAM)); res.append_header((header::CONTENT_TYPE, mime::APPLICATION_JSON)); let res = res.finish(); diff --git a/src/types/form.rs b/src/types/form.rs index 14c1369ffe9..9d2311a4510 100644 --- a/src/types/form.rs +++ b/src/types/form.rs @@ -163,7 +163,7 @@ impl Responder for Form { Ok(body) => HttpResponse::Ok() .content_type(mime::APPLICATION_WWW_FORM_URLENCODED) .body(body), - Err(err) => HttpResponse::from_error(err.into()), + Err(err) => HttpResponse::from_error(UrlencodedError::Serialize(err).into()), } } } @@ -346,14 +346,14 @@ where } if encoding == UTF_8 { - serde_urlencoded::from_bytes::(&body).map_err(|_| UrlencodedError::Parse) + serde_urlencoded::from_bytes::(&body).map_err(UrlencodedError::Parse) } else { let body = encoding .decode_without_bom_handling_and_without_replacement(&body) .map(|s| s.into_owned()) - .ok_or(UrlencodedError::Parse)?; + .ok_or(UrlencodedError::Encoding)?; - serde_urlencoded::from_str::(&body).map_err(|_| UrlencodedError::Parse) + serde_urlencoded::from_str::(&body).map_err(UrlencodedError::Parse) } } .boxed_local(), diff --git a/src/types/json.rs b/src/types/json.rs index 265beb56c64..322e5cbf3d7 100644 --- a/src/types/json.rs +++ b/src/types/json.rs @@ -127,7 +127,7 @@ impl Responder for Json { Ok(body) => HttpResponse::Ok() .content_type(mime::APPLICATION_JSON) .body(body), - Err(err) => HttpResponse::from_error(err.into()), + Err(err) => HttpResponse::from_error(JsonPayloadError::Serialize(err).into()), } } } @@ -412,7 +412,8 @@ where } } None => { - let json = serde_json::from_slice::(&buf)?; + let json = serde_json::from_slice::(&buf) + .map_err(JsonPayloadError::Deserialize)?; return Poll::Ready(Ok(json)); } } diff --git a/src/types/path.rs b/src/types/path.rs index 69a75e9cfc0..50e2cb510f7 100644 --- a/src/types/path.rs +++ b/src/types/path.rs @@ -93,7 +93,7 @@ where T: de::DeserializeOwned, { type Error = Error; - type Future = Ready>; + type Future = Ready>; type Config = PathConfig; #[inline] @@ -106,17 +106,17 @@ where ready( de::Deserialize::deserialize(PathDeserializer::new(req.match_info())) .map(Path) - .map_err(move |e| { + .map_err(move |err| { log::debug!( "Failed during Path extractor deserialization. \ Request path: {:?}", req.path() ); if let Some(error_handler) = error_handler { - let e = PathError::Deserialize(e); + let e = PathError::Deserialize(err); (error_handler)(e, req) } else { - ErrorNotFound(e) + ErrorNotFound(err) } }), ) @@ -303,7 +303,7 @@ mod tests { let s = Path::<(usize,)>::from_request(&req, &mut pl) .await .unwrap_err(); - let res = HttpResponse::from_error(s.into()); + let res = HttpResponse::from_error(s); assert_eq!(res.status(), http::StatusCode::CONFLICT); }