webserver_colin_ugo/http/
response.rs1use std::io::{Result, Write};
2use crate::http::StatusCode;
3use crate::utils::{get_http_date, get_server_version};
4
5pub fn send_get_response<W: Write>(
19 stream: &mut W,
20 status_line: &str,
21 content_type: &str,
22 contents: String,
23 connection: &str,
24) -> Result<()> {
25 let length = contents.len();
26 let date = get_http_date();
27 let server = get_server_version();
28
29 let response = format!(
30 "{}\r\nServer: {}\r\nDate: {}\r\nContent-Length: {}\r\nContent-Type: {}\r\nConnection: {}\r\n\r\n{}",
31 status_line, server, date, length, content_type, connection, contents
32 );
33
34 stream.write_all(response.as_bytes())
35}
36
37pub fn send_binary_response<W: Write>(
51 stream: &mut W,
52 status_line: &str,
53 content_type: &str,
54 contents: &[u8],
55 connection: &str,
56) -> Result<()> {
57 let length = contents.len();
58 let date = get_http_date();
59 let server = get_server_version();
60
61 let header = format!(
62 "{}\r\nServer: {}\r\nDate: {}\r\nContent-Length: {}\r\nContent-Type: {}\r\nConnection: {}\r\n\r\n",
63 status_line, server, date, length, content_type, connection
64 );
65
66 stream.write_all(header.as_bytes())?;
67
68 stream.write_all(contents)
69}
70
71pub fn send_head_response<W: Write>(
84 stream: &mut W,
85 status_line: &str,
86 content_type: &str,
87 connection: &str,
88) -> Result<()> {
89 let date = get_http_date();
90 let server = get_server_version();
91
92 let response = format!(
93 "{}\r\nServer: {}\r\nDate: {}\r\nContent-Length: 0\r\nContent-Type: {}\r\nConnection: {}\r\n\r\n",
94 status_line, server, date, content_type, connection
95 );
96
97 stream.write_all(response.as_bytes())
98}
99
100pub fn send_bad_request_response<W: Write>(
111 stream: &mut W,
112 connection: &str,
113) -> Result<()> {
114 let contents = "<h1>400 Bad Request</h1>".to_string();
115 let length = contents.len();
116 let date = get_http_date();
117 let server = get_server_version();
118
119 let response = format!(
120 "{}\r\nServer: {}\r\nDate: {}\r\nContent-Length: {}\r\nContent-Type: text/html\r\nConnection: {}\r\n\r\n{}",
121 StatusCode::BAD_REQUEST, server, date, length, connection, contents
122 );
123
124 stream.write_all(response.as_bytes())
125}
126
127pub fn send_forbidden_response<W: Write>(
138 stream: &mut W,
139 connection: &str,
140) -> Result<()> {
141 let contents = "<h1>403 Forbidden</h1>".to_string();
142 let length = contents.len();
143 let date = get_http_date();
144 let server = get_server_version();
145
146 let response = format!(
147 "{}\r\nServer: {}\r\nDate: {}\r\nContent-Length: {}\r\nContent-Type: text/html\r\nConnection: {}\r\n\r\n{}",
148 StatusCode::FORBIDDEN, server, date, length, connection, contents
149 );
150
151 stream.write_all(response.as_bytes())
152}
153
154pub fn send_not_found_response<W: Write>(
165 stream: &mut W,
166 connection: &str,
167) -> Result<()> {
168 let contents = "<h1>404 Not Found</h1>".to_string();
169 let length = contents.len();
170 let date = get_http_date();
171 let server = get_server_version();
172
173 let response = format!(
174 "{}\r\nServer: {}\r\nDate: {}\r\nContent-Length: {}\r\nContent-Type: text/html\r\nConnection: {}\r\n\r\n{}",
175 StatusCode::NOT_FOUND, server, date, length, connection, contents
176 );
177
178 stream.write_all(response.as_bytes())
179}
180
181pub fn send_method_not_allowed_response<W: Write>(
192 stream: &mut W,
193 connection: &str,
194) -> Result<()> {
195 let contents = "<h1>405 Method Not Allowed</h1>".to_string();
196 let length = contents.len();
197 let date = get_http_date();
198 let server = get_server_version();
199
200 let response = format!(
201 "{}\r\nServer: {}\r\nDate: {}\r\nContent-Length: {}\r\nContent-Type: text/html\r\nConnection: {}\r\n\r\n{}",
202 StatusCode::METHOD_NOT_ALLOWED, server, date, length, connection, contents
203 );
204
205 stream.write_all(response.as_bytes())
206}
207
208pub fn send_internal_server_error_response<W: Write>(
219 stream: &mut W,
220 connection: &str,
221) -> Result<()> {
222 let contents = "<h1>500 Internal Server Error</h1>".to_string();
223 let length = contents.len();
224 let date = get_http_date();
225 let server = get_server_version();
226
227 let response = format!(
228 "{}\r\nServer: {}\r\nDate: {}\r\nContent-Length: {}\r\nContent-Type: text/html\r\nConnection: {}\r\n\r\n{}",
229 StatusCode::INTERNAL_SERVER_ERROR, server, date, length, connection, contents
230 );
231
232 stream.write_all(response.as_bytes())
233}
234
235pub fn send_not_implemented_response<W: Write>(
246 stream: &mut W,
247 connection: &str,
248) -> Result<()> {
249 let contents = "<h1>501 Not Implemented</h1>".to_string();
250 let length = contents.len();
251 let date = get_http_date();
252 let server = get_server_version();
253
254 let response = format!(
255 "{}\r\nServer: {}\r\nDate: {}\r\nContent-Length: {}\r\nContent-Type: text/html\r\nConnection: {}\r\n\r\n{}",
256 StatusCode::NOT_IMPLEMENTED, server, date, length, connection, contents
257 );
258
259 stream.write_all(response.as_bytes())
260}
261
262pub fn send_http_version_not_supported_response<W: Write>(
273 stream: &mut W,
274 connection: &str,
275) -> Result<()> {
276 let contents = "<h1>505 HTTP Version Not Supported</h1>".to_string();
277 let length = contents.len();
278 let date = get_http_date();
279 let server = get_server_version();
280
281 let response = format!(
282 "{}\r\nServer: {}\r\nDate: {}\r\nContent-Length: {}\r\nContent-Type: text/html\r\nConnection: {}\r\n\r\n{}",
283 StatusCode::HTTP_VERSION_NOT_SUPPORTED, server, date, length, connection, contents
284 );
285
286 stream.write_all(response.as_bytes())
287}
288
289#[cfg(test)]
290mod tests {
291 use super::*;
292 use std::io::{Cursor, Read};
293
294 fn read_response(cursor: &mut Cursor<Vec<u8>>) -> String {
295 let mut content = String::new();
296 cursor.set_position(0);
297 cursor.read_to_string(&mut content).unwrap();
298 content
299 }
300
301 #[test]
302 fn test_send_get_response() {
303 let mut cursor = Cursor::new(vec![]);
304 let test_content = "<h1>Hello</h1>".to_string();
305 let content_length = test_content.len().to_string();
306
307 send_get_response(
308 &mut cursor,
309 StatusCode::OK,
310 "text/html",
311 test_content,
312 "close",
313 )
314 .unwrap();
315
316 let response = read_response(&mut cursor);
317 assert!(response.contains("HTTP/1.1 200 OK"));
318 assert!(response.contains("Content-Type: text/html"));
319 assert!(response.contains(&format!("Content-Length: {}", content_length)));
320 assert!(response.contains("Connection: close"));
321 assert!(response.contains("<h1>Hello</h1>"));
322 assert!(response.contains("Server: Rust-WebServer"));
323 assert!(response.contains("Date: "));
324 }
325
326 #[test]
327 fn test_send_head_response() {
328 let mut cursor = Cursor::new(vec![]);
329 send_head_response(&mut cursor, StatusCode::OK, "text/html", "close").unwrap();
330
331 let response = read_response(&mut cursor);
332 assert!(response.contains("HTTP/1.1 200 OK"));
333 assert!(response.contains("Content-Type: text/html"));
334 assert!(response.contains("Content-Length: 0"));
335 assert!(response.contains("Connection: close"));
336 assert!(response.contains("Server: Rust-WebServer"));
337 assert!(response.contains("Date: "));
338 assert!(!response.contains("<h1>"));
339 }
340
341 #[test]
342 fn test_error_responses() {
343 let mut cursor = Cursor::new(vec![]);
345 send_not_found_response(&mut cursor, "close").unwrap();
346 let response = read_response(&mut cursor);
347 assert!(response.contains("404"));
348 assert!(response.contains("Server: Rust-WebServer"));
349 assert!(response.contains("Date: "));
350
351 let mut cursor = Cursor::new(vec![]);
352 send_forbidden_response(&mut cursor, "close").unwrap();
353 let response = read_response(&mut cursor);
354 assert!(response.contains("403"));
355 assert!(response.contains("Server: Rust-WebServer"));
356
357 let mut cursor = Cursor::new(vec![]);
358 send_method_not_allowed_response(&mut cursor, "close").unwrap();
359 let response = read_response(&mut cursor);
360 assert!(response.contains("405"));
361
362 let mut cursor = Cursor::new(vec![]);
363 send_internal_server_error_response(&mut cursor, "close").unwrap();
364 let response = read_response(&mut cursor);
365 assert!(response.contains("500"));
366
367 let mut cursor = Cursor::new(vec![]);
368 send_not_implemented_response(&mut cursor, "close").unwrap();
369 let response = read_response(&mut cursor);
370 assert!(response.contains("501"));
371
372 let mut cursor = Cursor::new(vec![]);
373 send_http_version_not_supported_response(&mut cursor, "close").unwrap();
374 let response = read_response(&mut cursor);
375 assert!(response.contains("505"));
376 }
377}