1use bytes::Bytes;
2use serde::Serialize;
3
4use crate::{
5 cookies::{Cookies, cookie::Cookie},
6 request::Request,
7 routing::next::Next,
8 session::Session,
9 utils::{Values, http::Headers},
10 view::{ViewBag, ViewData},
11};
12
13pub type StatusCode = u16;
14
15pub const HTTP_CONTINUE: StatusCode = 100;
16pub const HTTP_SWITCHING_PROTOCOLS: StatusCode = 101;
17pub const HTTP_PROCESSING: StatusCode = 102;
18pub const HTTP_EARLY_HINTS: StatusCode = 103;
19pub const HTTP_OK: StatusCode = 200;
20pub const HTTP_CREATED: StatusCode = 201;
21pub const HTTP_ACCEPTED: StatusCode = 202;
22pub const HTTP_NON_AUTHORITATIVE_INFORMATION: StatusCode = 203;
23pub const HTTP_NO_CONTENT: StatusCode = 204;
24pub const HTTP_RESET_CONTENT: StatusCode = 205;
25pub const HTTP_PARTIAL_CONTENT: StatusCode = 206;
26pub const HTTP_MULTI_STATUS: StatusCode = 207;
27pub const HTTP_ALREADY_REPORTED: StatusCode = 208;
28pub const HTTP_IM_USED: StatusCode = 226;
29pub const HTTP_MULTIPLE_CHOICES: StatusCode = 300;
30pub const HTTP_MOVED_PERMANENTLY: StatusCode = 301;
31pub const HTTP_FOUND: StatusCode = 302;
32pub const HTTP_SEE_OTHER: StatusCode = 303;
33pub const HTTP_NOT_MODIFIED: StatusCode = 304;
34pub const HTTP_USE_PROXY: StatusCode = 305;
35pub const HTTP_TEMPORARY_REDIRECT: StatusCode = 307;
36pub const HTTP_PERMANENT_REDIRECT: StatusCode = 308;
37pub const HTTP_BAD_REQUEST: StatusCode = 400;
38pub const HTTP_UNAUTHORIZED: StatusCode = 401;
39pub const HTTP_PAYMENT_REQUIRED: StatusCode = 402;
40pub const HTTP_FORBIDDEN: StatusCode = 403;
41pub const HTTP_NOT_FOUND: StatusCode = 404;
42pub const HTTP_METHOD_NOT_ALLOWED: StatusCode = 405;
43pub const HTTP_NOT_ACCEPTABLE: StatusCode = 406;
44pub const HTTP_PROXY_AUTHENTICATION_REQUIRED: StatusCode = 407;
45pub const HTTP_REQUEST_TIMEOUT: StatusCode = 408;
46pub const HTTP_CONFLICT: StatusCode = 409;
47pub const HTTP_GONE: StatusCode = 410;
48pub const HTTP_LENGTH_REQUIRED: StatusCode = 411;
49pub const HTTP_PRECONDITION_FAILED: StatusCode = 412;
50pub const HTTP_CONTENT_TOO_LARGE: StatusCode = 413;
51pub const HTTP_URI_TOO_LONG: StatusCode = 414;
52pub const HTTP_UNSUPPORTED_MEDIA_TYPE: StatusCode = 415;
53pub const HTTP_RANGE_NOT_SATISFIABLE: StatusCode = 416;
54pub const HTTP_EXPECTATION_FAILED: StatusCode = 417;
55pub const HTTP_IM_A_TEAPOT: StatusCode = 418;
56pub const HTTP_MISDIRECTED_REQUEST: StatusCode = 421;
57pub const HTTP_UNPROCESSABLE_CONTENT: StatusCode = 422;
58pub const HTTP_LOCKED: StatusCode = 423;
59pub const HTTP_FAILED_DEPENDENCY: StatusCode = 424;
60pub const HTTP_TOO_EARLY: StatusCode = 425;
61pub const HTTP_UPGRADE_REQUIRED: StatusCode = 426;
62pub const HTTP_PRECONDITION_REQUIRED: StatusCode = 428;
63pub const HTTP_TOO_MANY_REQUESTS: StatusCode = 429;
64pub const HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE: StatusCode = 431;
65pub const HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: StatusCode = 451;
66pub const HTTP_INTERNAL_SERVER_ERROR: StatusCode = 500;
67pub const HTTP_NOT_IMPLEMENTED: StatusCode = 501;
68pub const HTTP_BAD_GATEWAY: StatusCode = 502;
69pub const HTTP_SERVICE_UNAVAILABLE: StatusCode = 503;
70pub const HTTP_GATEWAY_TIMEOUT: StatusCode = 504;
71pub const HTTP_HTTP_VERSION_NOT_SUPPORTED: StatusCode = 505;
72pub const HTTP_VARIANT_ALSO_NEGOTIATES: StatusCode = 506;
73pub const HTTP_INSUFFICIENT_STORAGE: StatusCode = 507;
74pub const HTTP_LOOP_DETECTED: StatusCode = 508;
75pub const HTTP_NOT_EXTENDED: StatusCode = 510;
76pub const HTTP_NETWORK_AUTHENTICATION_REQUIRED: StatusCode = 511;
77
78#[derive(Clone)]
79pub struct Response {
80 pub(crate) next: Option<Next>,
81 pub(crate) status_code: StatusCode,
82 pub(crate) headers: Headers,
83 pub(crate) referer: String,
84 pub(crate) content: Bytes,
85 pub(crate) cookies: Cookies,
86 pub(crate) session: Session,
87 pub(crate) view: Option<ViewBag>,
88 is_next: bool,
89}
90
91impl Into<serde_json::Value> for Response {
92 fn into(self) -> serde_json::Value {
93 serde_json::json!({
94 "status_code": &self.status_code,
95 "headers": &self.headers,
96 "cookies": &self.cookies,
97 "session": &self.session,
98 "view": &self.view,
99 })
100 }
101}
102
103impl Default for Response {
104 fn default() -> Self {
105 Self {
106 next: None,
107 status_code: HTTP_OK,
108 headers: Headers::new(),
109 referer: String::from("/"),
110 content: Bytes::new(),
111 cookies: Default::default(),
112 session: Default::default(),
113 view: None,
114 is_next: false,
115 }
116 }
117}
118
119impl Response {
120 #[inline]
121 pub(crate) fn new() -> Self {
122 Self::default()
123 }
124
125 #[inline]
126 pub fn request(&mut self) -> Request {
127 self.next
128 .as_mut()
129 .expect("Middleware chain error: Next is None")
130 .request()
131 }
132
133 #[inline]
134 pub fn status_code(mut self, status_code: StatusCode) -> Self {
135 self.status_code = status_code;
136 self
137 }
138
139 pub fn header(&self, key: &str) -> String {
140 self.headers
141 .get(key)
142 .cloned()
143 .unwrap_or_default()
144 }
145
146 #[inline]
147 pub fn set_header(mut self, k: impl Into<String>, v: impl Into<String>) -> Self {
148 self.headers.insert(k.into(), v.into());
149 self
150 }
151
152 pub fn set_headers(mut self, headers: Headers) -> Self {
153 for (k, v) in headers {
154 self.headers.insert(k, v);
155 }
156 self
157 }
158
159 #[inline]
160 pub fn cookies(&mut self) -> &mut Cookies {
161 &mut self.cookies
162 }
163
164 #[inline]
165 pub fn set_cookie(&mut self, k: impl Into<String>, v: impl Into<String>) -> &mut Cookie {
166 self.cookies.set(k, v)
167 }
168
169 #[inline]
170 pub fn remove_cookie(mut self, k: impl Into<String>) -> Self {
171 self.cookies.remove(k);
172 self
173 }
174
175 #[inline]
176 pub fn session(&mut self) -> &mut Session {
177 &mut self.session
178 }
179
180 #[inline]
181 pub fn set_session(mut self, k: impl Into<String>, v: impl Into<String>) -> Self {
182 self.session.set(k, v);
183 self
184 }
185
186 #[inline]
187 pub fn remove_session(mut self, k: impl Into<String>) -> Self {
188 self.session.remove(k);
189 self
190 }
191
192 #[inline]
193 pub fn set_flash(mut self, k: impl Into<String>, v: impl Into<String>) -> Self {
194 self.session.set_flash(k, v);
195 self
196 }
197
198 #[inline]
199 pub fn body(mut self, body: impl Into<Bytes>) -> Self {
200 self.content = body.into();
201 self
202 }
203
204 pub fn json<J>(self, object: &J) -> Self
205 where
206 J: ?Sized + Serialize,
207 {
208 match serde_json::to_vec(object) {
209 Ok(bytes) => self
210 .set_header("Content-Type", "application/json")
211 .body(bytes),
212 Err(_) => self.status_code(HTTP_INTERNAL_SERVER_ERROR),
213 }
214 }
215
216 #[inline]
217 pub fn html(self, html: impl Into<String>) -> Self {
218 let html_str = html.into();
219 self.set_header("Content-Type", "text/html; charset=utf-8")
220 .body(html_str)
221 }
222
223 #[inline]
224 pub fn view(mut self, view: &str, data: Option<ViewData>) -> Self {
225 self.view = Some(ViewBag::new(view, data));
226 self
227 }
228
229 #[inline]
230 pub fn redirect(self, to: impl Into<String>) -> Self {
231 self.redirect_with_status_code(to, HTTP_TEMPORARY_REDIRECT)
232 }
233
234 #[inline]
235 pub fn redirect_permanent(self, to: impl Into<String>) -> Self {
236 self.redirect_with_status_code(to, HTTP_PERMANENT_REDIRECT)
237 }
238
239 fn redirect_with_status_code(self, to: impl Into<String>, status_code: StatusCode) -> Self {
240 let target = to.into();
241 let html = format!(
242 "<!DOCTYPE html><html><head><meta http-equiv=\"Refresh\" content=\"0; url='{target}'\"></head><body></body></html>"
243 );
244
245 self
246 .html(html)
247 .status_code(status_code)
248 }
249
250 pub fn back(self) -> Self {
251 if self.referer.is_empty() {
252 self.redirect("/")
253 } else {
254 let referer = self.referer.clone();
255 self.redirect(referer)
256 }
257 }
258
259 pub fn with_error(mut self, name: impl Into<String>, error: impl Into<String>) -> Self {
260 self.session.errors.insert(name.into(), error.into());
261 self
262 }
263
264 pub fn with_errors(mut self, errors: Values) -> Self {
265 for (name, error) in errors {
266 self.session.errors.insert(name, error);
267 }
268 self
269 }
270
271 pub fn with_flash(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
272 self.session.flash.insert(key.into(), value.into());
273 self
274 }
275
276 pub(crate) fn with_old(mut self, old: Values) -> Self {
277 for (k, v) in old {
278 self.session.old.insert(k, v);
279 }
280 self
281 }
282
283 #[inline]
284 pub(crate) fn next(&mut self, is: bool) {
285 self.is_next = is;
286 }
287
288 #[inline]
289 pub(crate) fn is_next(&self) -> bool {
290 self.is_next
291 }
292}