@@ -13,9 +13,9 @@ use crate::headers::{
1313 self , HeaderName , HeaderValue , HeaderValues , Headers , Names , ToHeaderValues , Values ,
1414 CONTENT_TYPE ,
1515} ;
16- use crate :: mime:: Mime ;
16+ use crate :: mime:: { self , Mime } ;
1717use crate :: trailers:: { self , Trailers } ;
18- use crate :: { Body , Extensions , StatusCode , Version } ;
18+ use crate :: { Body , Error , Extensions , StatusCode , Version } ;
1919
2020cfg_unstable ! {
2121 use crate :: upgrade;
@@ -49,6 +49,7 @@ pin_project_lite::pin_project! {
4949 ext: Extensions ,
5050 local_addr: Option <String >,
5151 peer_addr: Option <String >,
52+ error: Option <Error >,
5253 }
5354}
5455
@@ -83,6 +84,7 @@ pin_project_lite::pin_project! {
8384 ext: Extensions ,
8485 local_addr: Option <String >,
8586 peer_addr: Option <String >,
87+ error: Option <Error >,
8688 }
8789}
8890
@@ -108,6 +110,7 @@ impl Response {
108110 ext : Extensions :: new ( ) ,
109111 peer_addr : None ,
110112 local_addr : None ,
113+ error : None ,
111114 }
112115 }
113116
@@ -136,9 +139,93 @@ impl Response {
136139 ext : Extensions :: new ( ) ,
137140 peer_addr : None ,
138141 local_addr : None ,
142+ // XXX(Jeremiah): should this be autogenerated on 4xx and 5xx codes?
143+ error : None ,
139144 }
140145 }
141146
147+ /// Create a new response from an `http_types::Error`.
148+ ///
149+ /// This will store the error in the `Response`, allowing it to later be
150+ /// checked via `Response::error()`.
151+ ///
152+ /// If the `Error`'s status had a status code that was not a 5XX server
153+ /// error code, the response body will be set to the error's message, and
154+ /// the content-type header will be set to `http_types::mime::Plain`.
155+ #[ cfg( not( feature = "unstable" ) ) ]
156+ pub fn from_error ( error : Error ) -> Self {
157+ // Only send the message if it is a non-500 range error. All
158+ // errors default to 500 by default, so sending the error
159+ // body is opt-in at the call site.
160+ let was_server_error = error. status ( ) . is_server_error ( ) ;
161+ let body = if !was_server_error {
162+ Body :: from_string ( error. to_string ( ) )
163+ } else {
164+ Body :: empty ( )
165+ } ;
166+
167+ let ( trailers_sender, trailers_receiver) = sync:: channel ( 1 ) ;
168+ let mut res = Self {
169+ status : error. status ( ) ,
170+ headers : Headers :: new ( ) ,
171+ version : None ,
172+ body,
173+ trailers_sender : Some ( trailers_sender) ,
174+ trailers_receiver : Some ( trailers_receiver) ,
175+ ext : Extensions :: new ( ) ,
176+ peer_addr : None ,
177+ local_addr : None ,
178+ error : Some ( error) ,
179+ } ;
180+ if !was_server_error {
181+ res. set_content_type ( mime:: PLAIN ) ;
182+ }
183+ res
184+ }
185+
186+ /// Create a new response from an `http_types::Error`.
187+ ///
188+ /// This will store the error in the `Response`, allowing it to later be
189+ /// checked via `Response::error()`.
190+ ///
191+ /// If the `Error`'s status had a status code that was not a 5XX server
192+ /// error code, the response body will be set to the error's message, and
193+ /// the content-type header will be set to `http_types::mime::Plain`.
194+ #[ cfg( feature = "unstable" ) ]
195+ pub fn from_error ( error : Error ) -> Self {
196+ // Only send the message if it is a non-500 range error. All
197+ // errors default to 500 by default, so sending the error
198+ // body is opt-in at the call site.
199+ let was_server_error = error. status ( ) . is_server_error ( ) ;
200+ let body = if !was_server_error {
201+ Body :: from_string ( error. to_string ( ) )
202+ } else {
203+ Body :: empty ( )
204+ } ;
205+
206+ let ( trailers_sender, trailers_receiver) = sync:: channel ( 1 ) ;
207+ let ( upgrade_sender, upgrade_receiver) = sync:: channel ( 1 ) ;
208+ let mut res = Self {
209+ status : error. status ( ) ,
210+ headers : Headers :: new ( ) ,
211+ version : None ,
212+ body,
213+ trailers_sender : Some ( trailers_sender) ,
214+ trailers_receiver : Some ( trailers_receiver) ,
215+ upgrade_sender : Some ( upgrade_sender) ,
216+ upgrade_receiver : Some ( upgrade_receiver) ,
217+ has_upgrade : false ,
218+ ext : Extensions :: new ( ) ,
219+ peer_addr : None ,
220+ local_addr : None ,
221+ error : Some ( error) ,
222+ } ;
223+ if !was_server_error {
224+ res. set_content_type ( mime:: PLAIN ) ;
225+ }
226+ res
227+ }
228+
142229 /// Get the status
143230 pub fn status ( & self ) -> StatusCode {
144231 self . status
@@ -465,6 +552,16 @@ impl Response {
465552 self . body . is_empty ( )
466553 }
467554
555+ /// Returns an optional reference to the `Error` if the response was created from one, or else `None`.
556+ pub fn error ( & mut self ) -> Option < & Error > {
557+ self . error . as_ref ( )
558+ }
559+
560+ /// Takes the `Error` from the response if one exists, replacing it with `None`.
561+ pub fn take_error ( & mut self ) -> Option < Error > {
562+ self . error . take ( )
563+ }
564+
468565 /// Get the HTTP version, if one has been set.
469566 ///
470567 /// # Examples
@@ -631,8 +728,8 @@ impl Response {
631728}
632729
633730impl Clone for Response {
634- /// Clone the response, resolving the body to `Body::empty()` and removing
635- /// extensions.
731+ /// Clone the response, resolving the body to `Body::empty()`, removing
732+ /// extensions, and unsetting any `Error` .
636733 fn clone ( & self ) -> Self {
637734 Self {
638735 status : self . status . clone ( ) ,
@@ -650,6 +747,7 @@ impl Clone for Response {
650747 ext : Extensions :: new ( ) ,
651748 peer_addr : self . peer_addr . clone ( ) ,
652749 local_addr : self . local_addr . clone ( ) ,
750+ error : None ,
653751 }
654752 }
655753}
@@ -722,6 +820,12 @@ impl Index<&str> for Response {
722820 }
723821}
724822
823+ impl From < Error > for Response {
824+ fn from ( e : Error ) -> Self {
825+ Self :: from_error ( e)
826+ }
827+ }
828+
725829impl From < StatusCode > for Response {
726830 fn from ( s : StatusCode ) -> Self {
727831 Response :: new ( s)
0 commit comments