coa_website/httpserver/
mod.rs

1use std::{fs, io::{BufRead, BufReader, Write}, net::{TcpListener, TcpStream}, path::Path};
2
3pub struct HttpServer {
4    addr: String
5}
6
7impl HttpServer {
8
9    pub fn new(socket_addr: &str) -> Self {
10        HttpServer { addr: socket_addr.to_string() }
11    }
12
13    pub fn start(&self) -> Result<(), Box<dyn std::error::Error>> {
14        let listener = TcpListener::bind(&self.addr)?;
15        for stream in listener.incoming() {
16            self.handle_connection(stream?);
17        }
18        Ok(())
19    }
20
21    fn handle_connection(&self, mut stream: TcpStream) {
22        let mut reader = BufReader::new(&stream);
23        let mut request_line = String::new();
24        reader.read_line(&mut request_line).unwrap();
25
26        let request_parts: Vec<&str> = request_line.split_whitespace().collect();
27        println!("{:?}", request_parts);
28        if request_parts.len() < 3 || request_parts[0] != "GET" {
29            return self.send_response(&mut stream, "HTTP/1.1 500 Internal Server Error", "text/plain", b"");
30        }
31
32        let path = if request_parts[1] == "/" {
33            "static/index.html".to_string()
34        } else {
35            request_parts[1].trim_start_matches('/').to_string()
36        };
37    
38        match fs::read(&path) {
39            Ok(contents) => {
40                let content_type = self.get_content_type(&path);
41                self.send_response(&mut stream, "HTTP/1.1 200 OK", content_type, &contents)
42            }
43            Err(_) => self.send_response(&mut stream, "HTTP/1.1 404 Not Found", "text/plain", b"Fichier non trouve"),
44        }
45    }
46
47    fn send_response(&self, stream: &mut TcpStream, status: &str, content_type: &str, body: &[u8]) {
48        let response = format!("{}\r\nContent-Type: {}\r\nContent-Length: {}\r\n\r\n", status, content_type, body.len());
49        stream.write_all(response.as_bytes()).unwrap();
50        stream.write_all(body).unwrap();
51        stream.flush().unwrap();
52    }
53
54    fn get_content_type(&self, path: &str) -> &str {
55        match Path::new(path).extension().and_then(|ext| ext.to_str()) {
56            Some("html") => "text/html",
57            Some("css") => "text/css",
58            Some("js") => "application/javascript",
59            Some("jpg") => "image/jpeg",
60            Some("png") => "image/png",
61            Some("svg") => "image/svg+xml",
62            Some("woff") => "font/woff",
63            Some("woff2") => "font/woff2",
64            _ => "text/plain",
65        }
66    }
67
68}