use std::io::{Write, BufReader, BufRead}; use std::net::{TcpListener, TcpStream}; use std::fs; use std::string::{String}; fn check_if_path_exists(path: String) -> bool { // This is probably not the best way of checking if a path // exists but I don't care :) let file = fs::metadata(path); match file { Ok(_) => true, Err(_) => false, } } fn check_if_dir(directory: String) -> bool { let path = directory + "/index.html"; let result = check_if_path_exists(path); return result; } fn generate_index(directory: String) -> String { let mut index = format!("

Directory of {}

", directory); for file in fs::read_dir(directory).unwrap() { index = format!("{}
{:#?}", index, file.as_ref().unwrap().path().display(), file.unwrap().file_name()); } return index.to_string(); } fn get_page(filename: String) -> String { // The loaded page should be left immutable as it does // not need to be modified by the server. let path = filename.to_string(); let checks = check_if_path_exists(path); let path = filename.to_string(); let index = check_if_dir(path); let path = filename.to_string(); println!("{} {} {}", path, checks, index); if checks == true && index == false { if path.contains(".") != true { let result = generate_index(filename); return result.to_string(); } } if filename == ".error_server_404" { let result = "

404 Not Found

The resource you are trying to locate cannot be accessed!

"; return result.to_string(); } else if filename == ".error_server_503" { let result = "

503 Not Implemented

The request sent by your web browser cannot be handled by this server software.

"; return result.to_string(); } else { let result = fs::read_to_string(filename); match result { Ok(i) => i.to_string(), Err(_e) => "

403 Forbidden

The resource you are trying to access cannot be read by the server.

".to_string(), } } } fn process_request(request: Vec) -> String { let mut input = String::from_utf8_lossy(&request).to_string(); let mut index = String::new(); let output; if input.contains("GET") { // To-do: find a less atrocious way to do this. println!("Stream sent GET request."); input = input.replace("GET ", ""); input = input.replace(" HTTP/1.1\r\n", ""); // Theoretically by this point, the request // will have been cut down to just the // requested resource, but in my experience // this code is gonna result in like 50k errors // and I'm gonna have to rewrite it to get it // to actually work the way I want it to. if input != "/" { let mut chars = input.chars(); chars.next(); let path = chars.as_str().to_string(); let exists = check_if_path_exists(path); if exists == false { output = ".error_server_404"; } else { let path = chars.as_str().to_string(); let dir = check_if_dir(path); if dir == true { let path = chars.as_str().to_string(); index += &path; index += "/index.html"; output = index.as_str().clone(); } else { output = chars.as_str(); } } } else { output = "index.html"; } } else { // It's get_page()'s problem now. println!("Stream sent unhandlable request."); output = ".error_server_503"; } // Did you want to see chars.as_str().to_string()? return output.to_string(); } fn serve(mut stream: TcpStream) { let mut request = Vec::new(); let mut reader = BufReader::new(&mut stream); reader .read_until(b'\n', &mut request) .expect("Failed to read from stream!"); let resource = process_request(request); let contents = get_page(resource); let header = "HTTP/1.1 200 OK\r\n\r\n"; let response = format!("{}{}", header, contents); stream.write(response.as_bytes()).unwrap(); stream.flush().unwrap(); } fn main() -> std::io::Result<()> { let listen = TcpListener::bind("127.0.0.1:8080")?; for stream in listen.incoming() { println!("Serving incoming stream."); serve(stream?); } Ok(()) }