use std::convert::Infallible; use std::path::Path; use hyper::service::{make_service_fn, service_fn}; use hyper::{Body, Method, Request, Response, Server, StatusCode}; use pulldown_cmark::{html, Options, Parser}; async fn hello_world(req: Request) -> Result, Infallible> { println!("New request to '{}'", req.uri()); let path = &req .uri() .path()[1..] // Remove the first "/". We don't need it .replace("..", "") // Don't allow to go up in the hierarchy ; // Get the first part so we can route it let until = path.find('/').unwrap_or(path.len()); let mut response = Response::new(Body::empty()); match (req.method(), &path[..until]) { (&Method::GET, "blog") => { *response.body_mut() = Body::from(path_access(path)); } (_, path) => { *response.body_mut() = Body::from(format!("Access to '{path}' isn't allowed.")); *response.status_mut() = StatusCode::FORBIDDEN; } } Ok(response) } fn path_access(path_str: &str) -> String { let path = Path::new(path_str); if path.is_file() { file_to_md(path_str) } else if path.is_dir() { list_directory(path_str) } else { format!("Path '{path_str}' doesn't exist!") } } fn list_directory(path_str: &str) -> String { let folder = match Path::new(path_str).read_dir() { Err(_) => return "Failed to read directory.".to_string(), Ok(x) => x, }; let mut string = String::new(); for entry in folder { let entry = match entry { Err(_) => return "Failed to read entry".to_string(), Ok(x) => x, }; if let Some(filename) = entry.file_name().to_str() { string.push_str(format!(r#"{0}
"#, filename).as_str()); } } string } fn file_to_md(path: &str) -> String { let file = std::fs::read_to_string(path).unwrap_or("Couldn't read file.".to_string()); //let mut options = Options::empty(); //options.insert(Options::ENABLE_STRIKETHROUGH); let parser = Parser::new_ext(file.as_str(), Options::ENABLE_STRIKETHROUGH); // Write to String buffer. let mut html_output: String = String::with_capacity(file.len() * 3 / 2); html::push_html(&mut html_output, parser); html_output } #[tokio::main] async fn main() { let addr = ([127, 0, 0, 1], 3000).into(); let make_svc = make_service_fn(|_conn| async { Ok::<_, Infallible>(service_fn(hello_world)) }); let server = Server::bind(&addr).serve(make_svc); println!("Server listening on: http://{}", addr); if let Err(e) = server.await { eprintln!("server error: {}", e); } }