use std::fmt;
use crate::http::body::{Body, MessageBody, ResponseBody};
use crate::http::{HeaderMap, Response, ResponseHead, StatusCode};
use super::{AppState, HttpRequest, WebResponseError};
pub struct WebResponse {
request: HttpRequest,
response: Response<Body>,
}
impl WebResponse {
pub fn new(response: Response<Body>, request: HttpRequest) -> Self {
WebResponse { request, response }
}
#[must_use]
pub fn from_err<St>(
st: &St,
mut err: impl WebResponseError<St, St::Error>,
request: HttpRequest,
) -> Self
where
St: AppState,
{
let res = err.error_response(st);
if res.head().status == StatusCode::INTERNAL_SERVER_ERROR {
log::error!("Internal Server Error: {err:?}");
} else {
log::debug!("Error in response: {err:?}");
}
WebResponse {
request,
response: res.into_body(),
}
}
#[inline]
#[must_use]
pub fn error_response<St>(self, st: &St, err: impl WebResponseError<St, St::Error>) -> Self
where
St: AppState,
{
Self::from_err(st, err, self.request)
}
#[inline]
#[must_use]
pub fn into_response(self, response: Response) -> WebResponse {
WebResponse::new(response, self.request)
}
#[inline]
#[must_use]
pub fn request(&self) -> &HttpRequest {
&self.request
}
#[inline]
pub fn response(&self) -> &Response<Body> {
&self.response
}
#[inline]
pub fn response_mut(&mut self) -> &mut Response<Body> {
&mut self.response
}
#[inline]
pub fn status(&self) -> StatusCode {
self.response.status()
}
#[inline]
pub fn headers(&self) -> &HeaderMap {
self.response.headers()
}
#[inline]
pub fn headers_mut(&mut self) -> &mut HeaderMap {
self.response.headers_mut()
}
#[must_use]
pub fn take_body(&mut self) -> ResponseBody<Body> {
self.response.take_body()
}
#[must_use]
pub fn map_body<F>(self, f: F) -> WebResponse
where
F: FnOnce(&mut ResponseHead, ResponseBody<Body>) -> ResponseBody<Body>,
{
let response = self.response.map_body(f);
WebResponse {
response,
request: self.request,
}
}
pub fn into_parts(self) -> (Response<Body>, HttpRequest) {
(self.response, self.request)
}
}
impl From<WebResponse> for Response<Body> {
fn from(res: WebResponse) -> Response<Body> {
res.response
}
}
impl fmt::Debug for WebResponse {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let res = writeln!(
f,
"\nWebResponse {:?} {}{}",
self.response.head().version,
self.response.head().status,
self.response.head().reason.unwrap_or(""),
);
let _ = writeln!(f, " headers:");
for (key, val) in &self.response.head().headers {
let _ = writeln!(f, " {key:?}: {val:?}");
}
let _ = writeln!(f, " body: {:?}", self.response.body().size());
res
}
}
#[cfg(test)]
mod tests {
use crate::http::{self, StatusCode};
use crate::web::{HttpResponse, test::TestRequest};
#[test]
fn test_response() {
let res = TestRequest::default().to_srv_response(HttpResponse::Ok().build());
let res = res.into_response(HttpResponse::BadRequest().build());
assert_eq!(res.response().status(), StatusCode::BAD_REQUEST);
let err = http::error::PayloadError::Overflow;
let res = res.error_response::<()>(&(), err);
assert_eq!(res.response().status(), StatusCode::PAYLOAD_TOO_LARGE);
}
}