1use std::fmt;
2
3use crate::http::body::{Body, MessageBody, ResponseBody};
4use crate::http::{HeaderMap, Response, ResponseHead, StatusCode};
5
6use super::{HttpRequest, State, WebResponseError};
7
8pub struct WebResponse {
10 request: HttpRequest,
11 response: Response<Body>,
12}
13
14impl WebResponse {
15 pub fn new(response: Response<Body>, request: HttpRequest) -> Self {
17 WebResponse { request, response }
18 }
19
20 #[must_use]
21 pub fn from_err<St>(
23 st: &St,
24 err: &impl WebResponseError<St, St::Error>,
25 request: HttpRequest,
26 ) -> Self
27 where
28 St: State,
29 {
30 let res = err.error_response(st);
31
32 if res.head().status == StatusCode::INTERNAL_SERVER_ERROR {
33 log::error!("Internal Server Error: {err:?}");
34 } else {
35 log::debug!("Error in response: {err:?}");
36 }
37
38 WebResponse {
39 request,
40 response: res.into_body(),
41 }
42 }
43
44 #[inline]
45 #[must_use]
46 pub fn error_response<St>(self, st: &St, err: &impl WebResponseError<St, St::Error>) -> Self
48 where
49 St: State,
50 {
51 Self::from_err(st, err, self.request)
52 }
53
54 #[inline]
55 #[must_use]
56 pub fn into_response(self, response: Response) -> WebResponse {
58 WebResponse::new(response, self.request)
59 }
60
61 #[inline]
62 #[must_use]
63 pub fn request(&self) -> &HttpRequest {
65 &self.request
66 }
67
68 #[inline]
69 pub fn response(&self) -> &Response<Body> {
71 &self.response
72 }
73
74 #[inline]
75 pub fn response_mut(&mut self) -> &mut Response<Body> {
77 &mut self.response
78 }
79
80 #[inline]
81 pub fn status(&self) -> StatusCode {
83 self.response.status()
84 }
85
86 #[inline]
87 pub fn headers(&self) -> &HeaderMap {
89 self.response.headers()
90 }
91
92 #[inline]
93 pub fn headers_mut(&mut self) -> &mut HeaderMap {
95 self.response.headers_mut()
96 }
97
98 #[must_use]
99 pub fn take_body(&mut self) -> ResponseBody<Body> {
101 self.response.take_body()
102 }
103
104 #[must_use]
105 pub fn map_body<F>(self, f: F) -> WebResponse
107 where
108 F: FnOnce(&mut ResponseHead, ResponseBody<Body>) -> ResponseBody<Body>,
109 {
110 let response = self.response.map_body(f);
111
112 WebResponse {
113 response,
114 request: self.request,
115 }
116 }
117
118 pub fn into_parts(self) -> (Response<Body>, HttpRequest) {
120 (self.response, self.request)
121 }
122}
123
124impl From<WebResponse> for Response<Body> {
125 fn from(res: WebResponse) -> Response<Body> {
126 res.response
127 }
128}
129
130impl fmt::Debug for WebResponse {
131 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132 let res = writeln!(
133 f,
134 "\nWebResponse {:?} {}{}",
135 self.response.head().version,
136 self.response.head().status,
137 self.response.head().reason.unwrap_or(""),
138 );
139 let _ = writeln!(f, " headers:");
140 for (key, val) in &self.response.head().headers {
141 let _ = writeln!(f, " {key:?}: {val:?}");
142 }
143 let _ = writeln!(f, " body: {:?}", self.response.body().size());
144 res
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use crate::http::{self, StatusCode};
151 use crate::web::{HttpResponse, test::TestRequest};
152
153 #[test]
154 fn test_response() {
155 let res = TestRequest::default().to_srv_response(HttpResponse::Ok().build());
156 let res = res.into_response(HttpResponse::BadRequest().build());
157 assert_eq!(res.response().status(), StatusCode::BAD_REQUEST);
158
159 let err = http::error::PayloadError::Overflow;
160 let res = res.error_response::<()>(&(), &err);
161 assert_eq!(res.response().status(), StatusCode::PAYLOAD_TOO_LARGE);
162 }
163
164 #[test]
165 fn test_response_accessors() {
166 use crate::http::body::{Body, ResponseBody};
167 use crate::util::Bytes;
168
169 let mut res =
170 TestRequest::with_uri("/path").to_srv_response(HttpResponse::Ok().body("body"));
171 assert_eq!(res.request().path(), "/path");
172 assert_eq!(res.status(), StatusCode::OK);
173 *res.response_mut().status_mut() = StatusCode::CREATED;
174 assert_eq!(res.status(), StatusCode::CREATED);
175 assert!(matches!(
176 res.take_body(),
177 ResponseBody::Body(Body::Bytes(b)) if b == Bytes::from_static(b"body")
178 ));
179
180 let (resp, req) = res.into_parts();
181 assert_eq!(resp.status(), StatusCode::CREATED);
182 assert_eq!(req.path(), "/path");
183 }
184
185 #[test]
186 fn test_from_err() {
187 let req = TestRequest::default().to_http_request();
188 let res = super::WebResponse::from_err(&(), &std::io::Error::other("err"), req);
189 assert_eq!(res.status(), StatusCode::INTERNAL_SERVER_ERROR);
190 }
191}