morpho 0.18.3

magnusi-improved version of mdblog
#![allow(trivial_casts)]

use conduit_mime_types as mime;
use conduit::{
	box_error, header, Body, Handler, HandlerResult, RequestExt, Response, StatusCode,
};
use std::fs::File;
use std::path::{Path, PathBuf};

pub struct Static {
	path: PathBuf,
	types: mime::Types,
}

impl Static {
	pub fn new<P: AsRef<Path>>(path: P) -> Static {
		Static {
			path: path.as_ref().to_path_buf(),
			types: mime::Types::new().expect("Couldn't load mime-types"),
		}
	}
}

impl Handler for Static {
	#[allow(deprecated)]
	fn call(&self, request: &mut dyn RequestExt) -> HandlerResult {
		let request_path = &request.path()[1..];
		if request_path.contains("..") {
			return Ok(not_found());
		}

		let path = self.path.join(request_path);
		let mut mime = self.types.mime_for_path(&path);
		let file = match File::open(&path) {
			Ok(f) => {
				if path.is_dir() {
					mime = self.types.mime_for_path(&path.join("index.html"));
					match File::open(&path.join("index.html")) {
						Ok(f) => f,
						Err(..) => return Ok(not_found()),
					}
				} else {
					f
				}
			}
			Err(..) => return Ok(not_found()),
		};
		let data = file.metadata().map_err(box_error)?;
		if data.is_dir() {
			return Ok(not_found());
		}

		Response::builder()
			.header(header::CONTENT_TYPE, mime)
			.header(header::CONTENT_LENGTH, data.len())
			.body(Body::File(file))
			.map_err(box_error)
	}
}

fn not_found() -> Response<Body> {
	Response::builder()
		.status(StatusCode::NOT_FOUND)
		.header(header::CONTENT_LENGTH, 0)
		.header(header::CONTENT_TYPE, "text/plain")
		.body(Body::empty())
		.unwrap()
}