coa_website/httpserver/
mod.rs1use 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}