Skip to content

Commit

Permalink
Response: add Error storage, retrieval, conversion
Browse files Browse the repository at this point in the history
This allows for robust creation of Response-s directly from Error-s, with error
capture for future reference, and retrieval via `error() -> Option<&Error>`.

PR-URL: http-rs#174
Refs: http-rs#169
Refs: http-rs/tide#546
Refs: http-rs/tide#532
Refs: http-rs/tide#452
  • Loading branch information
Fishrock123 committed Jun 16, 2020
1 parent 0836aa5 commit 6e04e91
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 4 deletions.
75 changes: 72 additions & 3 deletions src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::headers::{
};
use crate::mime::Mime;
use crate::trailers::{self, Trailers};
use crate::{Body, Extensions, StatusCode, Version};
use crate::{Body, Error, Extensions, StatusCode, Version};

cfg_unstable! {
use crate::upgrade;
Expand Down Expand Up @@ -50,6 +50,7 @@ pin_project_lite::pin_project! {
ext: Extensions,
local_addr: Option<String>,
peer_addr: Option<String>,
error: Option<Error>,
}
}

Expand Down Expand Up @@ -85,6 +86,7 @@ pin_project_lite::pin_project! {
ext: Extensions,
local_addr: Option<String>,
peer_addr: Option<String>,
error: Option<Error>,
}
}

Expand All @@ -111,6 +113,7 @@ impl Response {
ext: Extensions::new(),
peer_addr: None,
local_addr: None,
error: None,
}
}

Expand Down Expand Up @@ -140,6 +143,7 @@ impl Response {
ext: Extensions::new(),
peer_addr: None,
local_addr: None,
error: None,
}
}

Expand Down Expand Up @@ -469,6 +473,16 @@ impl Response {
self.body.is_empty()
}

/// Returns an optional reference to the `Error` if the response was created from one, or else `None`.
pub fn error(&self) -> Option<&Error> {
self.error.as_ref()
}

/// Takes the `Error` from the response if one exists, replacing it with `None`.
pub fn take_error(&mut self) -> Option<Error> {
self.error.take()
}

/// Get the HTTP version, if one has been set.
///
/// # Examples
Expand Down Expand Up @@ -641,8 +655,10 @@ impl Response {
}

impl Clone for Response {
/// Clone the response, resolving the body to `Body::empty()` and removing
/// extensions.
/// Clone the response, with some exceptions:
/// - The body is resolved to `Body::empty()`.
/// - Any attached extensions are not cloned.
/// - Any attached error is not cloned.
fn clone(&self) -> Self {
Self {
status: self.status.clone(),
Expand All @@ -661,6 +677,7 @@ impl Clone for Response {
ext: Extensions::new(),
peer_addr: self.peer_addr.clone(),
local_addr: self.local_addr.clone(),
error: None,
}
}
}
Expand Down Expand Up @@ -733,6 +750,58 @@ impl Index<&str> for Response {
}
}

#[cfg(not(feature = "unstable"))]
impl From<Error> for Response {
/// Create a new response from an `http_types::Error`.
///
/// This will store the error in the `Response`, allowing it to later be
/// checked via `Response::error()`.
fn from(error: Error) -> Self {
let (trailers_sender, trailers_receiver) = sync::channel(1);
Self {
status: error.status(),
headers: Headers::new(),
version: None,
body: Body::empty(),
trailers_sender: Some(trailers_sender),
trailers_receiver: Some(trailers_receiver),
has_trailers: false,
ext: Extensions::new(),
peer_addr: None,
local_addr: None,
error: Some(error),
}
}
}

#[cfg(feature = "unstable")]
impl From<Error> for Response {
/// Create a new response from an `http_types::Error`.
///
/// This will store the error in the `Response`, allowing it to later be
/// checked via `Response::error()`.
fn from(error: Error) -> Self {
let (trailers_sender, trailers_receiver) = sync::channel(1);
let (upgrade_sender, upgrade_receiver) = sync::channel(1);
Self {
status: error.status(),
headers: Headers::new(),
version: None,
body: Body::empty(),
trailers_sender: Some(trailers_sender),
trailers_receiver: Some(trailers_receiver),
has_trailers: false,
upgrade_sender: Some(upgrade_sender),
upgrade_receiver: Some(upgrade_receiver),
has_upgrade: false,
ext: Extensions::new(),
peer_addr: None,
local_addr: None,
error: Some(error),
}
}
}

impl From<StatusCode> for Response {
fn from(s: StatusCode) -> Self {
Response::new(s)
Expand Down
20 changes: 19 additions & 1 deletion tests/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use http_types::{bail, ensure, ensure_eq, Error, StatusCode};
use http_types::{bail, ensure, ensure_eq, Error, Response, StatusCode};
use std::io;

#[test]
Expand Down Expand Up @@ -71,3 +71,21 @@ fn option_ext() {
let err = res.unwrap_err();
assert_eq!(err.status(), StatusCode::NotFound);
}

#[test]
fn to_response() {
let msg = "This is an error";

let error = Error::from_str(StatusCode::NotFound, msg);
let mut res: Response = error.into();

assert!(res.error().is_some());
// Ensure we did not consume the error
assert!(res.error().is_some());

assert_eq!(res.error().unwrap().status(), StatusCode::NotFound);
assert_eq!(res.error().unwrap().to_string(), msg);

res.take_error();
assert!(res.error().is_none());
}

0 comments on commit 6e04e91

Please sign in to comment.