Skip to content

Commit 5396382

Browse files
authored
Merge pull request #174 from Fishrock123/response-optional-error
Response: add Error storage, retrieval, conversion
2 parents 8546b98 + 3b0407f commit 5396382

File tree

2 files changed

+96
-4
lines changed

2 files changed

+96
-4
lines changed

src/response.rs

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::headers::{
1515
};
1616
use crate::mime::Mime;
1717
use crate::trailers::{self, Trailers};
18-
use crate::{Body, Extensions, StatusCode, Version};
18+
use crate::{Body, Error, Extensions, StatusCode, Version};
1919

2020
cfg_unstable! {
2121
use crate::upgrade;
@@ -50,6 +50,7 @@ pin_project_lite::pin_project! {
5050
ext: Extensions,
5151
local_addr: Option<String>,
5252
peer_addr: Option<String>,
53+
error: Option<Error>,
5354
}
5455
}
5556

@@ -85,6 +86,7 @@ pin_project_lite::pin_project! {
8586
ext: Extensions,
8687
local_addr: Option<String>,
8788
peer_addr: Option<String>,
89+
error: Option<Error>,
8890
}
8991
}
9092

@@ -111,6 +113,7 @@ impl Response {
111113
ext: Extensions::new(),
112114
peer_addr: None,
113115
local_addr: None,
116+
error: None,
114117
}
115118
}
116119

@@ -140,6 +143,7 @@ impl Response {
140143
ext: Extensions::new(),
141144
peer_addr: None,
142145
local_addr: None,
146+
error: None,
143147
}
144148
}
145149

@@ -469,6 +473,21 @@ impl Response {
469473
self.body.is_empty()
470474
}
471475

476+
/// Returns an optional reference to the `Error` if the response was created from one, or else `None`.
477+
pub fn error(&self) -> Option<&Error> {
478+
self.error.as_ref()
479+
}
480+
481+
/// Takes the `Error` from the response if one exists, replacing it with `None`.
482+
pub fn take_error(&mut self) -> Option<Error> {
483+
self.error.take()
484+
}
485+
486+
/// Sets an `Error` on the response, accessible via `error()` and `take_error()`.
487+
pub fn set_error(&mut self, error: Error) {
488+
self.error = Some(error);
489+
}
490+
472491
/// Get the HTTP version, if one has been set.
473492
///
474493
/// # Examples
@@ -641,8 +660,10 @@ impl Response {
641660
}
642661

643662
impl Clone for Response {
644-
/// Clone the response, resolving the body to `Body::empty()` and removing
645-
/// extensions.
663+
/// Clone the response, with some exceptions:
664+
/// - The body is resolved to `Body::empty()`.
665+
/// - Any attached extensions are not cloned.
666+
/// - Any attached error is not cloned.
646667
fn clone(&self) -> Self {
647668
Self {
648669
status: self.status.clone(),
@@ -661,6 +682,7 @@ impl Clone for Response {
661682
ext: Extensions::new(),
662683
peer_addr: self.peer_addr.clone(),
663684
local_addr: self.local_addr.clone(),
685+
error: None,
664686
}
665687
}
666688
}
@@ -733,6 +755,58 @@ impl Index<&str> for Response {
733755
}
734756
}
735757

758+
#[cfg(not(feature = "unstable"))]
759+
impl From<Error> for Response {
760+
/// Create a new response from an `http_types::Error`.
761+
///
762+
/// This will store the error in the `Response`, allowing it to later be
763+
/// checked via `Response::error()`.
764+
fn from(error: Error) -> Self {
765+
let (trailers_sender, trailers_receiver) = sync::channel(1);
766+
Self {
767+
status: error.status(),
768+
headers: Headers::new(),
769+
version: None,
770+
body: Body::empty(),
771+
trailers_sender: Some(trailers_sender),
772+
trailers_receiver: Some(trailers_receiver),
773+
has_trailers: false,
774+
ext: Extensions::new(),
775+
peer_addr: None,
776+
local_addr: None,
777+
error: Some(error),
778+
}
779+
}
780+
}
781+
782+
#[cfg(feature = "unstable")]
783+
impl From<Error> for Response {
784+
/// Create a new response from an `http_types::Error`.
785+
///
786+
/// This will store the error in the `Response`, allowing it to later be
787+
/// checked via `Response::error()`.
788+
fn from(error: Error) -> Self {
789+
let (trailers_sender, trailers_receiver) = sync::channel(1);
790+
let (upgrade_sender, upgrade_receiver) = sync::channel(1);
791+
Self {
792+
status: error.status(),
793+
headers: Headers::new(),
794+
version: None,
795+
body: Body::empty(),
796+
trailers_sender: Some(trailers_sender),
797+
trailers_receiver: Some(trailers_receiver),
798+
has_trailers: false,
799+
upgrade_sender: Some(upgrade_sender),
800+
upgrade_receiver: Some(upgrade_receiver),
801+
has_upgrade: false,
802+
ext: Extensions::new(),
803+
peer_addr: None,
804+
local_addr: None,
805+
error: Some(error),
806+
}
807+
}
808+
}
809+
736810
impl From<StatusCode> for Response {
737811
fn from(s: StatusCode) -> Self {
738812
Response::new(s)

tests/error.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use http_types::{bail, ensure, ensure_eq, Error, StatusCode};
1+
use http_types::{bail, ensure, ensure_eq, Error, Response, StatusCode};
22
use std::io;
33

44
#[test]
@@ -71,3 +71,21 @@ fn option_ext() {
7171
let err = res.unwrap_err();
7272
assert_eq!(err.status(), StatusCode::NotFound);
7373
}
74+
75+
#[test]
76+
fn to_response() {
77+
let msg = "This is an error";
78+
79+
let error = Error::from_str(StatusCode::NotFound, msg);
80+
let mut res: Response = error.into();
81+
82+
assert!(res.error().is_some());
83+
// Ensure we did not consume the error
84+
assert!(res.error().is_some());
85+
86+
assert_eq!(res.error().unwrap().status(), StatusCode::NotFound);
87+
assert_eq!(res.error().unwrap().to_string(), msg);
88+
89+
res.take_error();
90+
assert!(res.error().is_none());
91+
}

0 commit comments

Comments
 (0)