rust_express/utils/
response.rs

1use std::{collections::HashMap, io::ErrorKind};
2
3use crate::utils::request::Request;
4use crate::utils::router::Router;
5use base64::prelude::*;
6use mime_guess::from_path;
7use serde_json::{json, Value};
8use std::fs;
9
10
11#[allow(dead_code)]
12pub struct Response {
13    pub content_type: String,
14    pub content_length: usize,
15    pub status_text: String,
16    pub status: i64,
17    pub body: Value,
18    pub raw: String,
19    pub cookies: HashMap<String, String>,
20    pub is_file: bool,
21}
22
23#[allow(dead_code)]
24impl Response {
25    pub fn new() -> Self {
26        Self {
27            content_length: 0,
28            content_type: "text/plain".to_owned(),
29            status_text: "OK".to_owned(),
30            status: 200,
31            body: json!(format!("")),
32            raw: format!("HTTP/1.1 200 OK\r\nContent-type: text/plain\r\n\r\n"),
33            cookies: HashMap::new(),
34            is_file: false,
35        }
36    }
37
38    pub fn text(&self, body: &str, status: i64) -> Response {
39        Response {
40            content_length: body.len(),
41            content_type: "text/plain".to_owned(),
42            status_text: "OK".to_owned(),
43            status,
44            body: json!(body),
45            raw: format!(
46                "HTTP/1.1 {}\r\nContent-Type: text/plain\r\n\r\n{}",
47                status,
48                body
49            ),
50            cookies: self.cookies.to_owned(),
51            is_file: false,
52        }
53    }
54
55    pub fn json(&self, body: Value, status: i64) -> Response {
56        Response {
57            content_length: body.to_string().len(),
58            content_type: "application/json".to_owned(),
59            status_text: "OK".to_owned(),
60            status,
61            body: body.to_owned(),
62            raw: format!(
63                "HTTP/1.1 {}\r\nContent-Type: application/json\r\n\r\n{}",
64                status,
65                serde_json::to_string(&body.to_owned()).unwrap()
66            ),
67            cookies: self.cookies.to_owned(),
68            is_file: false,
69        }
70    }
71
72    pub fn error(&self, body: &str, status: i64) -> Response {
73        Response {
74            status,
75            body: json!(body),
76            status_text: "Internal Server Error".to_owned(),
77            content_length: body.len(),
78            content_type: "text/plain".to_owned(),
79            raw: format!(
80                "HTTP/1.1 {} Internal Server Error\r\nContent-Type: text/plain\r\n\r\n{}",
81                status,
82                body
83            ),
84            cookies: self.cookies.to_owned(),
85            is_file: false,
86        }
87    }
88
89
90    pub fn send_file(&self, path: &str, status: i64) -> Response {
91        let filename = path.split("/").last().unwrap();
92        let file_type = from_path(path).first_or_octet_stream().to_string();
93        let mut file_content = String::new();
94
95        match fs::read_to_string(path) {
96            Ok(content) => file_content = content,
97            Err(err) => {
98                if err.kind() == ErrorKind::InvalidData {
99                    let file_bytes = fs::read(path).expect("Error while reading file bytes");
100                    file_content = BASE64_STANDARD.encode(file_bytes)
101                } else {
102                    eprint!("Error while reading file! {}", err.to_string())
103                }
104            }
105        }
106
107        Response {
108            content_length: file_content.len(),
109            content_type: file_type.to_owned(),
110            status_text: "OK".to_owned(),
111            status,
112            body: json!(format!("{filename}:{file_content}")),
113            raw: format!(
114                "HTTP/1.1 {}\r\nContent-Type: {}\r\n\r\n{}",
115                status, file_type, self.body
116            ),
117            cookies: self.cookies.to_owned(),
118            is_file: true,
119        }
120    }
121
122    pub fn render(&self, path: &str, status: i64) -> Response {
123        let file_content = fs::read_to_string(path).expect("Error while reading html content");
124        Response {
125            content_length: file_content.len(),
126            content_type: "text/html".to_owned(),
127            status_text: "OK".to_owned(),
128            status,
129            body: json!(file_content),
130            raw: format!(
131                "HTTP/1.1 {} OK\r\nContent-Type: text/html\r\nContent-Length: {}\r\n\r\n{}",
132                status,
133                file_content.len(),
134                file_content
135            ),
136            cookies: self.cookies.to_owned(),
137            is_file: false,
138        }
139    }
140
141}
142
143pub async fn handle_response(
144    stream: &mut tokio::net::TcpStream,
145    request: &Request,
146    router: &Router,
147) {
148    router.handle_request(stream, request).await;
149}