1use std::{collections::HashMap, fs::{self, File}, error::Error};
2
3use mime_guess::{MimeGuess};
4
5use crate::{HttpRequest, HttpServer, HttpStatusStruct, HttpResponse, RequestHandleFunc, RequestErrorHandleFunc};
6
7pub fn break_request_uri(req: &HttpRequest) -> (String, HashMap<String, String>) {
15 let uri = req.uri();
16 let parts: Vec<&str> = uri.split('?').collect();
17 let mut params = HashMap::<String, String>::new();
18 let path = String::from(if let Some(path) = parts.get(0) { path } else { "/" });
19 if parts.len() >= 2 {
20 let pairs: Vec<&str> = parts[1].split('&').collect();
21 for pair in pairs {
22 let key_val: Vec<&str> = pair.split('=').collect();
23 params.insert(String::from(key_val[0]), String::from(if let Some(val) = key_val.get(1) { val } else { "" }));
24 }
25 }
26 (path, params)
27}
28
29pub trait MoreDetailsRequest {
38 fn path(&self) -> String;
40
41 fn params(&self) -> HashMap<String, String>;
43}
44
45impl MoreDetailsRequest for HttpRequest {
46 fn path(&self) -> String {
47 break_request_uri(&self).0
48 }
49
50 fn params(&self) -> HashMap<String, String> {
51 break_request_uri(&self).1
52 }
53}
54
55pub trait ServeStatic {
61 fn serve_static(&mut self, root_dir: Option<String>);
63}
64
65impl ServeStatic for HttpServer {
66 fn serve_static(&mut self, root_dir: Option<String>) {
67 let roor_dir = root_dir.unwrap_or(String::from("public"));
68 self.insert_handler(move |req, mut res| {
69 let path = req.path();
70 let prefix = format!("/{}", &roor_dir);
71 if let Some(index) = path.find(&prefix) {
72 if index == 0 {
73 let path = String::from(&path[prefix.len()..path.len()]);
74 let file_path = format!("{}{}", &roor_dir, &path);
75 if let Ok(file) = File::open(&file_path) {
76 if let Ok(metadata) = file.metadata() {
77 if metadata.is_file() {
78 let data = fs::read(&file_path).unwrap_or(Vec::new());
79 let guess = MimeGuess::from_path(&file_path);
80 res.set_status(HttpStatusStruct(200, "OK"));
81 res.insert_header(String::from("Content-Type"), guess.first_or(mime_guess::mime::TEXT_PLAIN).to_string());
82 res.bytes(data);
83 }
84 }
85 }
86 }
87 }
88 Ok((req, res))
89 });
90 }
91}
92
93pub struct Route(String, RequestHandleFunc);
95
96impl Route {
97 pub fn all<F>(path: &str, handler: F) -> Self
98 where F: Fn(HttpRequest, HttpResponse) -> Result<(HttpRequest, HttpResponse), (HttpRequest, HttpResponse, Box<dyn Error>)> + Send + Sync + 'static {
99 Self(String::from(path), Box::new(handler))
100 }
101
102 pub fn get<F>(path: &str, handler: F) -> Self
103 where F: Fn(HttpRequest, HttpResponse) -> Result<(HttpRequest, HttpResponse), (HttpRequest, HttpResponse, Box<dyn Error>)> + Send + Sync + 'static {
104 Self(String::from(path), Box::new(move |req, res| {
105 if req.method() == "GET" {
106 handler(req, res)
107 } else {
108 Ok((req, res))
109 }
110 }))
111 }
112
113 pub fn post<F>(path: &str, handler: F) -> Self
114 where F: Fn(HttpRequest, HttpResponse) -> Result<(HttpRequest, HttpResponse), (HttpRequest, HttpResponse, Box<dyn Error>)> + Send + Sync + 'static {
115 Self(String::from(path), Box::new(move |req, res| {
116 if req.method() == "POST" {
117 handler(req, res)
118 } else {
119 Ok((req, res))
120 }
121 }))
122 }
123
124 pub fn put<F>(path: &str, handler: F) -> Self
125 where F: Fn(HttpRequest, HttpResponse) -> Result<(HttpRequest, HttpResponse), (HttpRequest, HttpResponse, Box<dyn Error>)> + Send + Sync + 'static {
126 Self(String::from(path), Box::new(move |req, res| {
127 if req.method() == "PUT" {
128 handler(req, res)
129 } else {
130 Ok((req, res))
131 }
132 }))
133 }
134
135 pub fn patch<F>(path: &str, handler: F) -> Self
136 where F: Fn(HttpRequest, HttpResponse) -> Result<(HttpRequest, HttpResponse), (HttpRequest, HttpResponse, Box<dyn Error>)> + Send + Sync + 'static {
137 Self(String::from(path), Box::new(move |req, res| {
138 if req.method() == "PATCH" {
139 handler(req, res)
140 } else {
141 Ok((req, res))
142 }
143 }))
144 }
145
146 pub fn delete<F>(path: &str, handler: F) -> Self
147 where F: Fn(HttpRequest, HttpResponse) -> Result<(HttpRequest, HttpResponse), (HttpRequest, HttpResponse, Box<dyn Error>)> + Send + Sync + 'static {
148 Self(String::from(path), Box::new(move |req, res| {
149 if req.method() == "DELETE" {
150 handler(req, res)
151 } else {
152 Ok((req, res))
153 }
154 }))
155 }
156}
157
158pub struct Router {
176 routes: Vec<Route>
177}
178
179impl Router {
180 pub fn new() -> Self {
181 Self { routes: Vec::new() }
182 }
183
184 pub fn define_route(&mut self, route: Route) {
185 self.routes.push(route);
186 }
187}
188
189pub trait Routing {
200 fn insert_router(&mut self, router: Router);
201}
202
203impl Routing for HttpServer {
204 fn insert_router(&mut self, router: Router) {
205 self.insert_handler(move |req, res| {
206 let path = req.path();
207 let mut routes = router.routes.iter();
208 loop {
209 if let Some(route) = routes.next() {
210 if route.0 == path {
211 break route.1(req, res);
212 }
213 } else {
214 break Ok((req, res));
215 }
216 }
217 });
218 }
219}