feather_runtime/http/
response.rs1use super::errors::HeaderError;
2use bytes::{Bytes, BytesMut};
3use http::{HeaderMap, HeaderName, HeaderValue, StatusCode};
4use serde::Serialize;
5use std::{fs::File, io::Read, str::FromStr};
6
7#[derive(Debug, Default)]
8pub struct Response {
9 pub status: StatusCode,
12 pub headers: HeaderMap,
15 pub body: Option<Bytes>,
19 pub version: http::Version,
21}
22
23impl Response {
24 const MAX_FILE_SIZE_BYTES: u64 = 4 * 1024 * 1024; fn set_common_headers(&mut self, content_type: Option<&'static str>, len: usize) {
28 if let Some(ct) = content_type {
29 self.headers.insert(HeaderName::from_static("content-type"), HeaderValue::from_static(ct));
30 }
31 self.headers.insert(HeaderName::from_static("content-length"), Self::len_to_header_value(len));
32 }
33
34 pub fn set_status(&mut self, status: u16) -> &mut Response {
39 self.status = StatusCode::from_u16(status).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);
40 self
41 }
42
43 pub fn add_header(&mut self, key: &str, value: &str) -> Result<(), HeaderError> {
47 let val = HeaderValue::from_str(value)?;
48 let key = HeaderName::from_str(key)?;
49 self.headers.insert(key, val);
50 return Ok(());
51 }
52 pub fn to_raw(&self) -> Bytes {
54 let body_len = self.body.as_ref().map_or(0, |b| b.len());
55 let mut buf = BytesMut::with_capacity(512 + body_len);
57
58 buf.extend_from_slice(b"HTTP/1.1 ");
60
61 let mut status_buffer = itoa::Buffer::new();
63 let status_code_str = status_buffer.format(self.status.as_u16());
64
65 buf.extend_from_slice(status_code_str.as_bytes());
66 buf.extend_from_slice(b" ");
67
68 buf.extend_from_slice(self.status.canonical_reason().unwrap_or("Unknown").as_bytes());
70 buf.extend_from_slice(b"\r\n");
71
72 for (key, value) in &self.headers {
74 buf.extend_from_slice(key.as_str().as_bytes());
76 buf.extend_from_slice(b": ");
77 buf.extend_from_slice(value.as_bytes());
79 buf.extend_from_slice(b"\r\n");
80 }
81
82 if !self.headers.contains_key("date") {
88 let date_str = chrono::Utc::now().to_rfc2822();
89 buf.extend_from_slice(b"date: ");
90 buf.extend_from_slice(date_str.as_bytes());
91 buf.extend_from_slice(b"\r\n");
92 }
93
94 if !self.headers.contains_key("content-length") && body_len > 0 {
97 buf.extend_from_slice(b"content-length: ");
98
99 let mut len_buffer = itoa::Buffer::new();
101 let len_str = len_buffer.format(body_len);
102
103 buf.extend_from_slice(len_str.as_bytes());
104 buf.extend_from_slice(b"\r\n");
105 }
106
107 buf.extend_from_slice(b"\r\n");
109
110 if let Some(ref body) = self.body {
112 buf.extend_from_slice(body);
113 }
114
115 buf.freeze()
117 }
118
119 pub fn send_text(&mut self, data: impl Into<String>) {
121 let body = data.into();
122 self.body = Some(Bytes::from(body));
123 self.set_common_headers(Some("text/plain;charset=utf-8"), self.body.as_ref().unwrap().len());
124 }
125
126 pub fn send_bytes(&mut self, data: impl Into<Vec<u8>>) {
128 let body = data.into();
129 self.body = Some(Bytes::from(body));
130 self.set_common_headers(None, self.body.as_ref().unwrap().len());
131 }
132
133 pub fn send_html(&mut self, data: impl Into<String>) {
135 let body = data.into();
136 self.body = Some(Bytes::from(body));
137 self.headers.insert(HeaderName::from_static("content-type"), HeaderValue::from_static("text/html"));
138 let len = self.body.as_ref().unwrap().len();
139 self.headers.insert(HeaderName::from_static("content-length"), Self::len_to_header_value(len));
140 }
141
142 #[cfg(feature = "json")]
144 pub fn send_json<T: Serialize>(&mut self, data: T) {
145 match serde_json::to_string(&data) {
146 Ok(json) => {
147 self.body = Some(Bytes::from(json));
148 self.headers.insert(HeaderName::from_static("content-type"), HeaderValue::from_static("application/json"));
149 let len = self.body.as_ref().unwrap().len();
150 self.headers.insert(HeaderName::from_static("content-length"), Self::len_to_header_value(len));
151 }
152 Err(_) => {
153 self.status = StatusCode::INTERNAL_SERVER_ERROR;
154 self.body = Some(Bytes::from("Internal Server Error"));
155 self.headers.insert(HeaderName::from_static("content-type"), HeaderValue::from_static("text/plain"));
156 let len = self.body.as_ref().unwrap().len();
157 self.headers.insert(HeaderName::from_static("content-length"), Self::len_to_header_value(len));
158 }
159 }
160 }
161 pub fn send_file(&mut self, mut file: File) {
164 let metadata = match file.metadata() {
165 Ok(m) => m,
166 Err(_) => {
167 self.status = StatusCode::INTERNAL_SERVER_ERROR;
168 self.body = Some(Bytes::from("Failed to read file metadata."));
169 return;
170 }
171 };
172
173 if metadata.len() > Self::MAX_FILE_SIZE_BYTES {
175 self.status = StatusCode::PAYLOAD_TOO_LARGE; self.body = Some(Bytes::from("File size exceeds 4MB limit. Use chunked encoding for larger files."));
177 return;
178 }
179
180 let mut buffer = Vec::new();
181 match file.read_to_end(&mut buffer) {
182 Ok(_) => {
183 self.body = Some(Bytes::from(buffer));
184 let len = self.body.as_ref().unwrap().len();
185 self.headers.insert(HeaderName::from_static("content-length"), Self::len_to_header_value(len));
186 }
188 Err(_) => {
189 self.status = StatusCode::INTERNAL_SERVER_ERROR;
190 self.body = Some(Bytes::from("Internal Server Error during file read."));
191 }
192 }
193 }
194
195 fn len_to_header_value(len: usize) -> HeaderValue {
197 let mut buffer = itoa::Buffer::new();
198 let len_str = buffer.format(len);
199
200 HeaderValue::from_bytes(len_str.as_bytes()).expect("itoa::Buffer output should be a valid HeaderValue")
202 }
203}