ttpkit_http/server/
response.rs

1//! Response types.
2
3use std::{borrow::Borrow, ops::Deref};
4
5use crate::{
6    Body, Status,
7    connection::{UpgradeFuture, UpgradeRequest},
8    header::{HeaderField, HeaderFieldValue},
9    response::{Response, ResponseBuilder, ResponseHeader},
10};
11
12/// Builder for outgoing HTTP responses.
13pub struct OutgoingResponseBuilder {
14    inner: ResponseBuilder,
15    upgrade: Option<UpgradeRequest>,
16}
17
18impl OutgoingResponseBuilder {
19    /// Create a new response builder.
20    #[inline]
21    const fn new() -> Self {
22        Self {
23            inner: Response::builder(),
24            upgrade: None,
25        }
26    }
27
28    /// Set response status.
29    #[inline]
30    pub fn set_status(mut self, status: Status) -> Self {
31        self.inner = self.inner.set_status(status);
32        self
33    }
34
35    /// Replace the current list of header fields having the same name (if any)
36    /// with the given one.
37    pub fn set_header_field<T>(mut self, field: T) -> Self
38    where
39        T: Into<HeaderField>,
40    {
41        self.inner = self.inner.set_header_field(field);
42        self
43    }
44
45    /// Add a given header field.
46    pub fn add_header_field<T>(mut self, field: T) -> Self
47    where
48        T: Into<HeaderField>,
49    {
50        self.inner = self.inner.add_header_field(field);
51        self
52    }
53
54    /// Set the response body and complete the response object.
55    pub fn body<B>(self, body: B) -> OutgoingResponse<B> {
56        let inner = InnerResponse {
57            inner: self.inner.body(body),
58            upgrade: self.upgrade,
59        };
60
61        OutgoingResponse {
62            inner: Box::new(inner),
63        }
64    }
65
66    /// Make the response a connection upgrade.
67    ///
68    /// The underlying connection will be handed over in the returned future.
69    pub fn upgrade<B>(mut self) -> (OutgoingResponse<B>, UpgradeFuture)
70    where
71        B: Default,
72    {
73        let (rx, tx) = UpgradeFuture::new();
74
75        self.upgrade = Some(tx);
76
77        let response = self.body(B::default());
78
79        (response, rx)
80    }
81}
82
83impl From<ResponseHeader> for OutgoingResponseBuilder {
84    #[inline]
85    fn from(header: ResponseHeader) -> Self {
86        Self {
87            inner: header.into(),
88            upgrade: None,
89        }
90    }
91}
92
93/// Server response that can be sent to an HTTP client.
94pub struct OutgoingResponse<B = Body> {
95    inner: Box<InnerResponse<B>>,
96}
97
98impl OutgoingResponse<()> {
99    /// Get a builder for the outgoing response.
100    #[inline]
101    pub const fn builder() -> OutgoingResponseBuilder {
102        OutgoingResponseBuilder::new()
103    }
104}
105
106impl<B> OutgoingResponse<B> {
107    /// Deconstruct the response back into its response header and body.
108    #[inline]
109    pub fn deconstruct(self) -> (ResponseHeader, B, Option<UpgradeRequest>) {
110        let (header, body) = self.inner.inner.deconstruct();
111
112        (header, body, self.inner.upgrade)
113    }
114
115    /// Deconstruct the response back into a response builder and the body.
116    pub fn into_builder(self) -> (OutgoingResponseBuilder, B) {
117        let (header, body) = self.inner.inner.deconstruct();
118
119        let builder = OutgoingResponseBuilder {
120            inner: header.into(),
121            upgrade: self.inner.upgrade,
122        };
123
124        (builder, body)
125    }
126
127    /// Take the connection upgrade request (if any).
128    #[inline]
129    pub fn take_upgrade_request(&mut self) -> Option<UpgradeRequest> {
130        self.inner.upgrade.take()
131    }
132}
133
134impl<B> AsRef<Response<B>> for OutgoingResponse<B> {
135    #[inline]
136    fn as_ref(&self) -> &Response<B> {
137        &self.inner.inner
138    }
139}
140
141impl<B> Borrow<Response<B>> for OutgoingResponse<B> {
142    #[inline]
143    fn borrow(&self) -> &Response<B> {
144        &self.inner.inner
145    }
146}
147
148impl<B> Deref for OutgoingResponse<B> {
149    type Target = Response<B>;
150
151    #[inline]
152    fn deref(&self) -> &Self::Target {
153        &self.inner.inner
154    }
155}
156
157/// Inner struct for the outgoing response.
158///
159/// NOTE: The `OutgoingResponse` contains only a boxed struct (this one) to
160/// avoid passing around big objects.
161struct InnerResponse<B> {
162    inner: Response<B>,
163    upgrade: Option<UpgradeRequest>,
164}
165
166/// A function returning an empty response with a given status code.
167#[inline(never)]
168pub fn empty_response(status: Status) -> OutgoingResponse {
169    OutgoingResponse::builder()
170        .set_status(status)
171        .body(Body::empty())
172}
173
174/// A function returning No Content response.
175#[inline]
176pub fn no_content() -> OutgoingResponse {
177    empty_response(Status::NO_CONTENT)
178}
179
180/// A function returning Bad Request response.
181#[inline]
182pub fn bad_request() -> OutgoingResponse {
183    empty_response(Status::BAD_REQUEST)
184}
185
186/// A function returning Not Found response.
187#[inline]
188pub fn not_found() -> OutgoingResponse {
189    empty_response(Status::NOT_FOUND)
190}
191
192/// A function returning Method Not Allowed response.
193#[inline]
194pub fn method_not_allowed() -> OutgoingResponse {
195    empty_response(Status::METHOD_NOT_ALLOWED)
196}
197
198/// A function returning Unauthorized response.
199#[inline]
200pub fn unauthorized() -> OutgoingResponse {
201    empty_response(Status::UNAUTHORIZED)
202}
203
204/// A function returning Expectation Failed response.
205#[inline]
206pub fn expectation_failed() -> OutgoingResponse {
207    empty_response(Status::EXPECTATION_FAILED)
208}
209
210/// A function returning Not Implemented response.
211#[inline]
212pub fn not_implemented() -> OutgoingResponse {
213    empty_response(Status::NOT_IMPLEMENTED)
214}
215
216/// A function returning Bad Gateway response.
217#[inline]
218pub fn bad_gateway() -> OutgoingResponse {
219    empty_response(Status::BAD_GATEWAY)
220}
221
222/// A function returning Gateway Timeout response.
223#[inline]
224pub fn gateway_timeout() -> OutgoingResponse {
225    empty_response(Status::GATEWAY_TIMEOUT)
226}
227
228/// A function returning a response with Moved Permanently status and a given
229/// location.
230pub fn moved_permanently<T>(location: T) -> OutgoingResponse
231where
232    T: Into<HeaderFieldValue>,
233{
234    redirect(Status::MOVED_PERMANENTLY, location.into())
235}
236
237/// A function returning a response with See Other status and a given location.
238pub fn see_other<T>(location: T) -> OutgoingResponse
239where
240    T: Into<HeaderFieldValue>,
241{
242    redirect(Status::SEE_OTHER, location.into())
243}
244
245/// A function returning a redirect response with a given status and a given
246/// location.
247#[inline(never)]
248fn redirect(status: Status, location: HeaderFieldValue) -> OutgoingResponse {
249    OutgoingResponse::builder()
250        .set_status(status)
251        .set_header_field(("Location", location))
252        .body(Body::empty())
253}