tuli_lib/
server.rs

1use std::{convert::TryFrom, fs, io::Read, net::TcpListener};
2
3use crate::http::{Method, ParseError, Request, Response, StatusCode};
4
5const BUFFER_SIZE: usize = 16 * 1024;
6
7#[derive(Debug)]
8pub struct Server {
9    pub port: u16,
10    pub public_path: String,
11}
12
13impl Default for Server {
14    fn default() -> Self {
15        Server {
16            port: 8080,
17            public_path: String::from("./"),
18        }
19    }
20}
21
22impl Server {
23    fn read_file(&self, file_path: &str) -> Option<String> {
24        let path = format!("{}/{}", self.public_path, file_path);
25        fs::read_to_string(path).ok()
26    }
27
28    /// The main request handler method.
29    /// GET requests sent to "/" will read the contents from a index.html file located in the public directory
30    fn handle_request(&mut self, request: &Request) -> Response {
31        match request.method() {
32            Method::GET => match request.path() {
33                "/" => Response::new(StatusCode::Ok, self.read_file("index.html")),
34                path => match self.read_file(path) {
35                    Some(contents) => Response::new(StatusCode::Ok, Some(contents)),
36                    None => Response::new(StatusCode::NotFound, None),
37                },
38            },
39            _ => Response::new(
40                StatusCode::NotFound,
41                Some(String::from(
42                    "Could not find a index.html file in this dir...",
43                )),
44            ),
45        }
46    }
47
48    fn handle_bad_request(&mut self, err: &ParseError) -> Response {
49        println!("Failed to parse a request: {}", err);
50        Response::new(
51            StatusCode::BadRequest,
52            Some("Nothing to see here...".to_string()),
53        )
54    }
55}
56
57impl Server {
58    pub fn new(port: u16, public_path: String) -> Self {
59        Server { port, public_path }
60    }
61
62    pub fn run(mut self) {
63        let address = format!("127.0.0.1:{}", self.port);
64        println!("Server running on http://{}", &address);
65        let listener = TcpListener::bind(address).expect("Error binding TcpListener");
66
67        loop {
68            match listener.accept() {
69                Ok((mut stream, _)) => {
70                    let mut buffer = [0; BUFFER_SIZE];
71                    match stream.read(&mut buffer) {
72                        Ok(_) => {
73                            let response = match Request::try_from(&buffer[..]) {
74                                Ok(request) => self.handle_request(&request),
75                                Err(err) => self.handle_bad_request(&err),
76                            };
77
78                            if let Err(err) = response.send(&mut stream) {
79                                println!("Failed to send response, {}", err);
80                            }
81                        }
82                        Err(err) => println!("Failed to read from connection: {}", err),
83                    }
84                }
85                Err(err) => println!("Failed to establish a connection: {}", err),
86            }
87        }
88    }
89}