Skip to main content

ntex/web/
response.rs

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
8/// An http service response.
9pub struct WebResponse {
10    request: HttpRequest,
11    response: Response<Body>,
12}
13
14impl WebResponse {
15    /// Create web response instance.
16    pub fn new(response: Response<Body>, request: HttpRequest) -> Self {
17        WebResponse { request, response }
18    }
19
20    #[must_use]
21    /// Create web response from the error.
22    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    /// Create web response for error.
47    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    /// Create web response.
57    pub fn into_response(self, response: Response) -> WebResponse {
58        WebResponse::new(response, self.request)
59    }
60
61    #[inline]
62    #[must_use]
63    /// Get reference to original request.
64    pub fn request(&self) -> &HttpRequest {
65        &self.request
66    }
67
68    #[inline]
69    /// Get reference to response.
70    pub fn response(&self) -> &Response<Body> {
71        &self.response
72    }
73
74    #[inline]
75    /// Get mutable reference to response.
76    pub fn response_mut(&mut self) -> &mut Response<Body> {
77        &mut self.response
78    }
79
80    #[inline]
81    /// Get the response status code.
82    pub fn status(&self) -> StatusCode {
83        self.response.status()
84    }
85
86    #[inline]
87    /// Returns response's headers.
88    pub fn headers(&self) -> &HeaderMap {
89        self.response.headers()
90    }
91
92    #[inline]
93    /// Returns mutable response's headers.
94    pub fn headers_mut(&mut self) -> &mut HeaderMap {
95        self.response.headers_mut()
96    }
97
98    #[must_use]
99    /// Extract response body.
100    pub fn take_body(&mut self) -> ResponseBody<Body> {
101        self.response.take_body()
102    }
103
104    #[must_use]
105    /// Set a new body.
106    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    /// Destruct response into parts.
119    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}