ttpkit_http/server/
response.rs1use 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
12pub struct OutgoingResponseBuilder {
14 inner: ResponseBuilder,
15 upgrade: Option<UpgradeRequest>,
16}
17
18impl OutgoingResponseBuilder {
19 #[inline]
21 const fn new() -> Self {
22 Self {
23 inner: Response::builder(),
24 upgrade: None,
25 }
26 }
27
28 #[inline]
30 pub fn set_status(mut self, status: Status) -> Self {
31 self.inner = self.inner.set_status(status);
32 self
33 }
34
35 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 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 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 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
93pub struct OutgoingResponse<B = Body> {
95 inner: Box<InnerResponse<B>>,
96}
97
98impl OutgoingResponse<()> {
99 #[inline]
101 pub const fn builder() -> OutgoingResponseBuilder {
102 OutgoingResponseBuilder::new()
103 }
104}
105
106impl<B> OutgoingResponse<B> {
107 #[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 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 #[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
157struct InnerResponse<B> {
162 inner: Response<B>,
163 upgrade: Option<UpgradeRequest>,
164}
165
166#[inline(never)]
168pub fn empty_response(status: Status) -> OutgoingResponse {
169 OutgoingResponse::builder()
170 .set_status(status)
171 .body(Body::empty())
172}
173
174#[inline]
176pub fn no_content() -> OutgoingResponse {
177 empty_response(Status::NO_CONTENT)
178}
179
180#[inline]
182pub fn bad_request() -> OutgoingResponse {
183 empty_response(Status::BAD_REQUEST)
184}
185
186#[inline]
188pub fn not_found() -> OutgoingResponse {
189 empty_response(Status::NOT_FOUND)
190}
191
192#[inline]
194pub fn method_not_allowed() -> OutgoingResponse {
195 empty_response(Status::METHOD_NOT_ALLOWED)
196}
197
198#[inline]
200pub fn unauthorized() -> OutgoingResponse {
201 empty_response(Status::UNAUTHORIZED)
202}
203
204#[inline]
206pub fn expectation_failed() -> OutgoingResponse {
207 empty_response(Status::EXPECTATION_FAILED)
208}
209
210#[inline]
212pub fn not_implemented() -> OutgoingResponse {
213 empty_response(Status::NOT_IMPLEMENTED)
214}
215
216#[inline]
218pub fn bad_gateway() -> OutgoingResponse {
219 empty_response(Status::BAD_GATEWAY)
220}
221
222#[inline]
224pub fn gateway_timeout() -> OutgoingResponse {
225 empty_response(Status::GATEWAY_TIMEOUT)
226}
227
228pub fn moved_permanently<T>(location: T) -> OutgoingResponse
231where
232 T: Into<HeaderFieldValue>,
233{
234 redirect(Status::MOVED_PERMANENTLY, location.into())
235}
236
237pub fn see_other<T>(location: T) -> OutgoingResponse
239where
240 T: Into<HeaderFieldValue>,
241{
242 redirect(Status::SEE_OTHER, location.into())
243}
244
245#[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}