blogit/src/main.rs

96 lines
2.7 KiB
Rust

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<Body>) -> Result<Response<Body>, 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#"<a href="{path_str}/{0}">{0}</a><br/>"#, 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);
}
}