1use std::{
2 collections::HashMap,
3 io::{Read, Write},
4 net::{TcpListener, TcpStream},
5};
6
7use log::{debug, error, info, trace};
8
9use crate::{request::http_method::HttpMethod, response::http_response::HttpResponse};
10
11pub type RouteFunc = fn() -> HttpResponse;
12
13struct RouteInfo {
14 method: HttpMethod,
15 callback: RouteFunc,
16}
17
18pub struct Server {
19 address: String,
20 routing_patterns: HashMap<String, RouteInfo>,
21}
22
23impl Server {
24 pub fn new(address: &str) -> Self {
25 Self {
26 address: address.to_owned(),
27 routing_patterns: HashMap::new(),
28 }
29 }
30
31 pub fn start_listening(self) -> Self {
32 trace!("About to start listening on {}", self.address);
33 match TcpListener::bind(&self.address) {
34 Ok(listener) => {
35 info!("Server running on \"{}\"", self.address);
36
37 for stream in listener.incoming() {
38 match stream {
39 Ok(mut stream) => self.handle_connection(&mut stream),
40 Err(error) => error!("{}", error.to_string()),
41 }
42 }
43 }
44 Err(error) => error!("{}", error.to_string()),
45 }
46
47 self
48 }
49
50 pub fn add_route(mut self, method: HttpMethod, pattern: &str, route_func: RouteFunc) -> Self {
51 trace!("Adding pattern \"{}\"", pattern);
52
53 if self.routing_patterns.contains_key(pattern) {
54 debug!(
55 "Pattern \"{}\" already exists, routing information will be overwritten",
56 pattern
57 );
58 }
59
60 self.routing_patterns.insert(
61 pattern.to_owned(),
62 RouteInfo {
63 method: method,
64 callback: route_func,
65 },
66 );
67
68 self
69 }
70
71 fn handle_connection(&self, stream: &mut TcpStream) {
72 let mut buffer = [0; 1024];
73 if stream.read(&mut buffer).is_err() {
74 return error!("Unable to read buffer from incoming TCP stream");
75 }
76
77 let route_to_execute = self.parse_request(&buffer);
78
79 if route_to_execute.is_none() {
80 trace!("Did not find a matching route to execute");
81 self.write_response(
82 stream,
83 HttpResponse::new().not_found().to_string().as_bytes(),
84 );
85 } else {
86 trace!("Executing matching route now");
87 let response = route_to_execute.unwrap();
88 self.write_response(stream, response.to_string().as_bytes());
89 }
90 }
91
92 fn parse_request(&self, buffer: &[u8]) -> Option<HttpResponse> {
93 let request_str = String::from_utf8_lossy(buffer).to_string();
94
95 let mut parts = request_str.split_whitespace();
96 let method = parts.next();
97 let route = parts.next();
98 let http_spec = parts.next();
99
100 if method.is_none() || route.is_none() || http_spec.is_none() {
101 error!("Malformed HTTP request");
102 return None;
103 }
104
105 for (pattern, route_info) in &self.routing_patterns {
107 if route.unwrap() == pattern {
108 if HttpMethod::from(method.unwrap()) == route_info.method {
109 debug!(
110 "Route \"{}\" matches pattern \"{}\"",
111 route.unwrap(),
112 pattern
113 );
114 return Some((route_info.callback)());
115 } else {
116 debug!(
117 "Route \"{}\" matches pattern \"{}\", but the method \"{}\" is not allowed",
118 route.unwrap(),
119 pattern,
120 method.unwrap()
121 );
122 return Some(HttpResponse::new().method_not_allowed());
123 }
124 }
125 }
126
127 None
128 }
129
130 fn write_response(&self, stream: &mut TcpStream, data: &[u8]) {
131 if stream.write(data).is_err() {
132 return error!("Unable to write response to TCP stream");
133 }
134
135 if stream.flush().is_err() {
136 return error!("Unable to flush TCP stream");
137 }
138 }
139}