1pub use my_threadpool::ThreadPool;
6
7use std::collections::HashMap;
8use std::net::TcpListener;
9use std::net::TcpStream;
10use std::net::Shutdown;
11use std::io::prelude::*;
12use std::sync::{Arc, Mutex};
13
14pub type ErrorMessage = &'static str;
17
18#[derive(PartialEq, Eq, Hash, Clone, Debug, Copy)]
21pub enum RequestType {
22 Get,
23 Post,
24 Put,
25 Patch,
26 Delete,
27}
28
29impl RequestType {
30 fn stringify(&self) -> &str {
31 match self {
32 RequestType::Get => "GET",
33 RequestType::Post=> "POST",
34 RequestType::Put => "PUT",
35 RequestType::Patch => "PATCH",
36 RequestType::Delete => "DELETE",
37 }
38 }
39}
40
41
42#[derive(PartialEq, Eq, Hash, Clone)]
43struct Route {
44 req_type: RequestType,
45 route: String,
46}
47
48#[derive(PartialEq, Eq, Hash, Clone)]
49enum RouteIndex {
50 Route(Route),
51 AllRoute(Route)
52}
53
54#[derive(PartialEq, Eq, Clone, Hash, Debug, Copy)]
55pub struct DebugOptions {
77 pub show_response_body: bool,
78 pub show_request_query: bool,
79 pub show_request_body: bool,
80 pub show_middleware: bool,
81 pub show_middleware_request_changes: bool,
82}
83
84#[derive(PartialEq, Eq, Clone, Hash, Debug, Copy)]
85pub enum Mode {
105 Default,
106 Debug(DebugOptions),
107}
108
109
110#[derive(Clone, Debug, PartialEq)]
111
112pub struct Request {
130 pub route: String,
131 pub host: String,
132 pub request_type: RequestType,
133 pub query: HashMap<String, String>,
134 pub cookie: HashMap<String, String>,
135 pub body: String,
136}
137
138impl Request {
139 fn new(req: String) -> Option<Self> {
140 let req_split = req.split("\n").collect::<Vec<&str>>();
141 let split = req_split[0].split(" ").collect::<Vec<&str>>();
142
143 let request_type = match split[0] {
144 "GET" => RequestType::Get,
145 "POST" => RequestType::Post,
146 "PUT" => RequestType::Put,
147 "PATCH" => RequestType::Patch,
148 "DELETE" => RequestType::Delete,
149 _ => {return None;},
150 };
151
152 let mut query = HashMap::new();
153 match split[1].split("?").collect::<Vec<&str>>().get(1) {
154 Some(n) => {
155 for i in n.split("&").collect::<Vec<&str>>() {
156 let querys = i.split("=").collect::<Vec<&str>>();
157 let (name, val) = match querys.get(1) {
158 Some(n) => (querys[0], n),
159 _ => continue,
160 };
161 query.insert(name.to_string(), val.to_string());
162 }
163 },
164 _ => {
165 },
166 }
167
168 let mut cookie = HashMap::new();
169
170 match req_split
171 .iter()
172 .filter(|x| x
173 .split(" ")
174 .collect::<Vec<&str>>()[0] == "Cookie:"
175 ).collect::<Vec<&&str>>().get(0) {
176 Some(n) => {
177 for i in n.split(": ").collect::<Vec<&str>>()[1].split("; ") {
178 let i = i.trim();
179 let i = i.split("=").collect::<Vec<&str>>();
180
181 cookie.insert(i[0].to_string(), i[1].to_string());
182 }
183 },
184 None => {}
185 }
186
187 Some(Request {
188 query,
189 route: split[1].to_string(),
190 host: req_split.iter().filter(|x| x.split(" ").collect::<Vec<&str>>()[0] == "Host:").collect::<Vec<&&str>>()[0].split(" ").collect::<Vec<&str>>()[1].to_string(),
191 request_type,
192 cookie,
193 body: req.split("\r\n\r\n").collect::<Vec<&str>>()[1].to_string().split("\0").collect::<Vec<&str>>()[0].to_string(),
194 })
195 }
196}
197
198#[derive(Clone)]
199enum ResponseType {
200 Static(String),
201 Function(Arc<dyn Fn(Request) -> (String, ResponseCode) + Send + Sync + 'static>)
202}
203
204pub enum ResponseCode {
216 Rc200,
217 Rc201,
218 Rc204,
219 Rc304,
220 Rc400,
221 Rc404,
222 Rc429,
223 Rc500,
224}
225
226pub struct WebServer {
228 pool: ThreadPool,
229 not_found: String,
230 routes: HashMap<RouteIndex, ResponseType>,
231 existing_routes: String,
232 middleware: HashMap<String, Arc<dyn Fn(Request) -> Request + Send + Sync + 'static>>,
233 existing_middleware: String,
234 mode: Mode,
235}
236
237pub fn HttpRequest(request: Request) -> Result<String, ErrorMessage> {
249 let mut stream = match TcpStream::connect(request.host.clone()) {
250 Ok(n) => n,
251 Err(_) => {return Err("Could not connect")}
252 };
253
254 let mut req = String::new();
255 let req_type = request.request_type.stringify();
256 req.push_str(&format!("{} {} HTTP/1.1\r\n", req_type, request.route));
257 req.push_str(&format!("Host: {}\r\n", request.host.clone()));
258 req.push_str("Connection: close\r\n");
259 if req_type == "POST" || req_type == "PUT" || req_type == "PATCH" {
260 req.push_str(&format!("Content-Length: {}\r\n\r\n{}", request.body.clone().len(), request.body));
261 } else {
262 req.push_str("\r\n");
263 }
264
265 if let Err(_) = stream.write_all(req.as_bytes()) {return Err("Could not write the bytes for the request");}
266
267 let mut res = String::new();
268 if let Err(_) = stream.read_to_string(&mut res) {return Err("Could not read the response");};
269
270 if let Err(_) = stream.shutdown(Shutdown::Both) {return Err("failed to close stream");};
271
272 Ok(res)
273}
274
275fn create_response(n: &ResponseType, data: String, req: Option<Request>) -> String {
276 match n {
277 ResponseType::Static(n) => format!("HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n{}", n.len(), n),
278 ResponseType::Function(n) => {
279 let resp = n(match req {
280 Some(n) => n,
281 _ => {
282 Request::new(data.to_string()).unwrap()
283 }
284 });
285 let res: String = match resp.1 {
286 ResponseCode::Rc200 => format!("HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n{}", resp.0.len(), resp.0),
287 ResponseCode::Rc201 => format!("HTTP/1.1 201 CREATED\r\nContent-Length: {}\r\n\r\n{}", resp.0.len(), resp.0),
288 ResponseCode::Rc204 => format!("HTTP/1.1 204 NO CONTENT\r\n\r\n\r\n"),
289 ResponseCode::Rc304 => format!("HTTP/1.1 304 NOT MODIFIED\r\nContent-Length: {}\r\n\r\n{}", resp.0.len(), resp.0),
290 ResponseCode::Rc400 => format!("HTTP/1.1 400 BAD REQUEST\r\nContent-Length: {}\r\n\r\n{}", resp.0.len(), resp.0),
291 ResponseCode::Rc404 => format!("HTTP/1.1 404 NOT FOUND\r\nContent-Length: {}\r\n\r\n{}", resp.0.len(), resp.0),
292 ResponseCode::Rc429 => format!("HTTP/1.1 429 TOO MANY REQUESTS\r\nContent-Length: {}\r\n\r\n{}", resp.0.len(), resp.0),
293 ResponseCode::Rc500 => format!("HTTP/1.1 500 INTERNAL SERVER ERROR\r\nContent-Length: {}\r\n\r\n{}", resp.0.len(), resp.0),
294 };
295 res
296 }
297 }
298}
299
300
301
302impl WebServer {
303 pub fn new() -> Self {
313 WebServer {
314 pool: ThreadPool::new(4),
315 not_found: String::from("<h1>404 NOT FOUND</h1>"),
316 routes: HashMap::new(),
317 middleware: HashMap::new(),
318 existing_middleware: String::new(),
319 existing_routes: String::new(),
320 mode: Mode::Default,
321 }
322 }
323
324 pub fn from_threads(threads: usize) -> Self {
334 WebServer {
335 pool: ThreadPool::new(threads),
336 not_found: String::from("<h1>404 NOT FOUND</h1>"),
337 routes: HashMap::new(),
338 middleware: HashMap::new(),
339 existing_middleware: String::new(),
340 existing_routes: String::new(),
341 mode: Mode::Default,
342 }
343 }
344
345 pub fn on_static(&mut self, req_type: RequestType, route: &str, res: &str) {
365 self.routes.insert(RouteIndex::Route(Route {
366 req_type,
367 route: route.to_string(),
368 }), ResponseType::Static(res.to_string()));
369 self.existing_routes.push_str(&format!(
370 "\n --> Static response for {} requests on route '{}'",
371 req_type.stringify(),
372 route
373 ));
374 }
375
376 pub fn on<F: Fn(Request) -> (String, ResponseCode) + Send + Sync + 'static>(&mut self, req_type: RequestType, route: &str, res: F) {
390 self.routes.insert(RouteIndex::Route(Route {
391 req_type,
392 route: route.to_string(),
393 }), ResponseType::Function(Arc::new(res)));
394 self.existing_routes.push_str(&format!(
395 "\n --> response for {} requests on route '{}'",
396 req_type.stringify(),
397 route
398 ));
399 }
400
401 pub fn on_all<F: Fn(Request) -> (String, ResponseCode) + Send + Sync + 'static>(&mut self, req_type: RequestType, route: &str, res: F) {
419 self.routes.insert(RouteIndex::AllRoute(Route {
420 req_type,
421 route: route.to_string(),
422 }), ResponseType::Function(Arc::new(res)));
423 self.existing_routes.push_str(&format!(
424 "\n --> response for All {} requests that start with '{}'",
425 req_type.stringify(),
426 route
427 ));
428 }
429
430 pub fn not_found(&mut self, html: &str) {
451 self.not_found = html.to_string();
452 self.existing_routes.push_str(&format!(
453 "\n --> Set default 404 response to '{}'",
454 html
455 ));
456 }
457
458 pub fn mode(&mut self, mode: Mode) {
475 self.mode = mode;
476 }
477
478 pub fn listen(self, addr: &str) -> Result<(), ()> {
490 println!("--------- Route Handlers ---------\n{}\n\n--------- Middleware ---------\n{}\n\n\nListening on http://{}\n\n",
491 self.existing_routes,
492 self.existing_middleware,
493 addr
494 );
495 let pool = Arc::new(Mutex::new(self.pool));
496 let pool2 = pool.clone();
497 ctrlc::set_handler(move || {
498 println!("----- Starting Gracefull Shutdown -----\n");
499 pool2.lock().unwrap().shutdown();
500 std::process::exit(0);
501 }).unwrap();
502 let listener = match TcpListener::bind(addr) {
503 Ok(n) => n,
504 Err(_) => {
505 return Err(());
506 }
507 };
508 for stream in listener.incoming() {
509 let mut stream = match stream {
510 Ok(n) => n,
511 Err(_) => continue,
512 };
513 let routes = self.routes.clone();
514 let middleware = self.middleware.clone();
515 let not_found = self.not_found.clone();
516 pool.lock().unwrap().execute(move || {
517 let mut options = None;
518 if let Mode::Debug(mode_options) = self.mode {
519 options = Some(mode_options);
520 }
521
522 let mut debug_str = String::new();
523 let mut data = [0; 4096];
524 stream.read(&mut data).unwrap();
525 let mut data = String::from_utf8_lossy(&data);
526 let req_raw = data.clone();
527 let mut request = None;
528 let response;
529 let req = data.split("\n").collect::<Vec<&str>>()[0];
530 let split = req.split(" ").collect::<Vec<&str>>();
531
532 debug_str.push_str(split[0]);
533 debug_str.push(' ');
534
535 if let Some(options) = options {
536 if options.show_request_query {
537 debug_str.push_str(split[1]);
538 } else {
539 debug_str.push_str(split[1].split("?").collect::<Vec<&str>>()[0]);
540 }
541 } else {
542 debug_str.push_str(split[1].split("?").collect::<Vec<&str>>()[0]);
543 }
544 if let Some(options) = options {
545 if options.show_request_body {
546 debug_str.push_str("\n -> request body '");
547 if let Some(n) = req_raw.split("\r\n\r\n").collect::<Vec<&str>>().get(1) {
548 debug_str.push_str(n);
549 };
550 debug_str.push_str("'")
551 }
552 }
553
554
555 let s = split[1].split("?").collect::<Vec<&str>>()[0].to_string();
556 let mut s2 = &mut s.split("/").collect::<Vec<&str>>();
557 let s2 = &s2[1..].iter().map(|x| format!("/{}", x)).collect::<Vec<String>>();
558
559 let mut route2 = vec![];
560 for route in &s2[..] {
561 route2.push(route.to_string());
562 if let Some(n) = middleware.get(route) {
563 let original_req = match request {
564 Some(n) => n,
565 _ => {
566 Request::new(data.to_string()).unwrap()
567 }
568 };
569 let finished_request = n(original_req.clone());
570 if let Some(options) = options {
571 if options.show_middleware_request_changes {
572 debug_str.push_str("\n -> response went through middleware: ");
573 debug_str.push_str(&route2.join(""));
574 }
575 if options.show_middleware {
576 let request = finished_request.clone();
577 if request != original_req {
578 if request.route != original_req.route {
579 debug_str.push_str(&format!(
580 "\n -> redirected request from '{}' to '{}'"
581 ,original_req.route,
582 request.route
583 ));
584 }
585 if request.request_type != original_req.request_type {
586 debug_str.push_str(&format!(
587 "\n -> modified request type from {} to {}"
588 ,original_req.request_type.stringify(),
589 request.request_type.stringify()
590 ));
591 }
592 if request.body != original_req.body {
593 debug_str.push_str(&format!(
594 "\n -> modified request body from '{}' to '{}'"
595 ,original_req.body,
596 request.body
597 ));
598 }
599 if request.host != original_req.host {
600 debug_str.push_str(&format!(
601 "\n -> modified request host from '{}' to '{}'"
602 ,original_req.host,
603 request.host
604 ));
605 }
606 if request.query != original_req.query {
607 debug_str.push_str(&format!(
608 "\n -> modified request query from {:?} to {:?}"
609 ,original_req.query,
610 request.query
611 ));
612 }
613 if request.cookie != original_req.cookie {
614 debug_str.push_str(&format!(
615 "\n -> modified request cookie from {:?} to {:?}"
616 ,original_req.cookie,
617 request.cookie
618 ));
619 }
620 }
621 }
622 }
623 request = Some(finished_request);
624 }
625 }
626 let req_route = match request {
627 Some(n) => {
628 request = Some(n.clone());
629 n.route
630 },
631 None => split[1].split("?").collect::<Vec<&str>>()[0].to_string()
632 };
633
634 let req_type = match request {
635 Some(n) => {
636 request = Some(n.clone());
637 n.request_type
638 },
639 None => match split[0] {
640 "GET" => {
641 RequestType::Get
642 },
643 "POST" => {
644 RequestType::Post
645 },
646 "PUT" => {
647 RequestType::Put
648 },
649 "PATCH" => {
650 RequestType::Patch
651 },
652 "DELETE" => {
653 RequestType::Delete
654 },
655 _ => {
656 let contents = "";
657 response = format!("HTTP/1.1 400 BAD REQUEST\r\nContent-Length: {}\r\n\r\n{}", contents.len(), contents);
658 return;
659 }
660 }
661 };
662
663 match routes.get(&&RouteIndex::Route(Route { req_type, route: req_route.clone() })) {
664 Some(n) => {
665 response = create_response(n, data.into(), request);
666 debug_str.push_str(&format!("\n -> resoponded with {}", response.split("\r\n").collect::<Vec<&str>>()[0]));
667 debug_str.push_str("\n -> resoponse successful");
668 },
669 None => {
670 let s = req_route;
671 let s2 = s.split("/").collect::<Vec<&str>>();
672 let mut route = String::from("/");
673
674 let route2 = Arc::new(Mutex::new(s2.clone()));
675 for _ in s2 {
676 let mut route2 = route2.lock().unwrap();
677 if let Some(_) = routes.get(&&RouteIndex::AllRoute(Route { req_type, route: route2.join("/").to_string() })) {
678 route = (*route2).clone().join("/");
679 break;
680 }
681
682 route2.pop();
683 }
684
685 match routes.get(&&RouteIndex::AllRoute(Route { req_type, route: route.clone() })) {
686 Some(n) => {
687 debug_str.push_str("\n -> Route was found on an on_all route: ");
688 debug_str.push_str(&route);
689 response = create_response(n, data.into(), request);
690 debug_str.push_str(&format!("\n -> resoponded with {}", response.split("\r\n").collect::<Vec<&str>>()[0].split("HTTP/1.1 ").collect::<Vec<&str>>()[0]));
691 debug_str.push_str("\n -> resoponse successful");
692 },
693 None => {
694 let contents = not_found;
695 response = format!("HTTP/1.1 404 NOT FOUND\r\nContent-Length: {}\r\n\r\n{}", contents.len(), contents);
696 debug_str.push_str("\n -> resoponded with HTTP/1.1 404 NOT FOUND");
697 debug_str.push_str("\n -> resoponse successfull");
698 }
699 }
700
701 }
702 }
703 if let Some(options) = options {
704 if options.show_response_body {
705 debug_str.push_str("\n -> response body: '");
706 debug_str.push_str(response.split("\r\n\r\n").collect::<Vec<&str>>()[1]);
707 debug_str.push_str("'");
708 }
709 }
710 stream.write(response.as_bytes()).unwrap();
711 stream.flush().unwrap();
712 if let Some(_) = options {
713 println!("{debug_str}\n\n");
714 }
715 return;
716 });
717 }
718
719 Ok(())
720 }
721 pub fn middleware<F: Fn(Request) -> Request + Send + Sync + 'static>(&mut self, route: &str, res: F) {
748 self.middleware.insert(route.to_string(), Arc::new(res));
749 self.existing_middleware.push_str(&format!("\n --> middleware for route '{}'", route));
750 }
751}