refactored markdown parsing, added some documentation
All checks were successful
Test the running changes / Test (push) Successful in 40s

This commit is contained in:
2025-11-15 01:41:14 +02:00
parent 05a0b32d9b
commit 8d47704b7e
18 changed files with 428 additions and 290 deletions

View File

@@ -1,3 +1,5 @@
//! Simple and program specific command line argument parsing solution.
use std::path::PathBuf;
use crate::error::Error;

View File

@@ -1,10 +1,11 @@
//! FileServer
//! A simple server implementation that just responds with the contents of the file requested in
//! the provided directory.
use std::fs;
use std::path::PathBuf;
use crate::{
error::*,
error::{Error, ErrorKind, Result},
request::{HttpMethod, HttpRequest},
responder::Responder,
response::{HttpResponse, HttpStatus},
@@ -51,7 +52,6 @@ impl Responder for FileServer {
let content_type = match req.path.extension() {
Some(s) => match s.as_encoded_bytes() {
b"html" | b"htm" => "text/html",
b"txt" => "text/plain",
b"css" => "text/css",
b"js" => "text/javascript",
b"pdf" => "application/pdf",

View File

@@ -1,36 +1,38 @@
//! Wrapper type of a `HashMap` to contain HTTP headers and format them correctly.
use std::{collections::HashMap, fmt::Display};
#[derive(Debug)]
pub struct HttpHeaders {
_inner: HashMap<String, String>,
inner: HashMap<String, String>,
}
impl HttpHeaders {
pub fn new() -> Self {
HttpHeaders {
_inner: HashMap::new(),
inner: HashMap::new(),
}
}
pub fn add(&mut self, k: &str, v: &str) {
self._inner.insert(k.to_string(), v.to_string());
self.inner.insert(k.to_string(), v.to_string());
}
#[cfg(test)]
pub fn get(&self, k: &str) -> Option<&String> {
self._inner.get(k)
self.inner.get(k)
}
#[cfg(test)]
pub fn len(&self) -> usize {
self._inner.len()
self.inner.len()
}
}
impl Display for HttpHeaders {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for (k, v) in self._inner.iter() {
write!(f, "{}: {}\r\n", k, v)?;
for (k, v) in &self.inner {
write!(f, "{k}: {v}\r\n")?;
}
Ok(())
}

View File

@@ -24,6 +24,9 @@ impl Display for Level {
}
}
/// A logging macro. Takes a [`Level`] and a formatted string.
///
/// [`Level`]: ./logger/enum.Level.html
#[macro_export]
macro_rules! log {
($level:expr, $($arg:tt)*) => {{

View File

@@ -1,6 +1,4 @@
//! This is my very monolithic file server with zero dependencies (other than rust
//! stdlib).
//!
//! A simple web server with 0 dependencies (other than Rust's stdlib).
//! Documentation is a work in progress, go see my webpage at [jlux.dev](https://jlux.dev).
use std::{
@@ -32,7 +30,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
if args.generate {
match generate(&args.indir, &args.outdir, args.force) {
Ok(_) => log!(
Ok(()) => log!(
Level::Info,
"HTML generation from `{}` to `{}` successful",
args.indir.display(),
@@ -50,7 +48,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
log!(Level::Error, "HTML generation failed with error: {}", e,);
process::exit(1);
}
};
}
}
let listener = TcpListener::bind(&args.addr)?;
@@ -59,7 +57,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
for stream in listener.incoming() {
match stream {
Ok(stream) => {
let outdir = args.outdir.to_owned();
let outdir = args.outdir.clone();
std::thread::spawn(move || {
log!(Level::Debug, "TcpStream handler spawned");
let mut reader = BufReader::new(&stream);

View File

@@ -32,7 +32,7 @@ impl TryFrom<&str> for HttpMethod {
impl Display for HttpMethod {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
write!(f, "{self:?}")
}
}
@@ -154,7 +154,7 @@ impl TryFrom<&str> for HttpRequest {
for line in lines {
if let Some(v) = line.split_once(": ") {
headers.add(v.0, v.1)
headers.add(v.0, v.1);
}
}

View File

@@ -1,55 +1,12 @@
//! Traits helping HTTP connections
//! Helper trait(s).
use crate::request::HttpRequest;
use crate::response::HttpResponse;
/// Responder trait. Just a respond method that turns a HttpRequest to a HttpResponse.
/// Responder trait. Just a respond method that turns a [`HttpRequest`] to a [`HttpResponse`].
///
/// [`HttpRequest`]: ../request/struct.HttpRequest.html
/// [`HttpResponse`]: ../response/struct.HttpResponse.html
pub trait Responder {
fn respond(&self, req: HttpRequest) -> HttpResponse;
}
/*
/// Size trait. Number of bytes when encoded.
pub trait Size {
fn size(&self) -> usize;
}
// Standard implementations for Size trait
impl Size for u8 {
fn size(&self) -> usize {
1
}
}
impl<T> Size for Vec<T>
where
T: Size,
{
fn size(&self) -> usize {
if let Some(elem) = self.first() {
elem.size() * self.len()
} else {
0
}
}
}
impl<T> Size for Option<T>
where
T: Size,
{
fn size(&self) -> usize {
match self {
Some(t) => t.size(),
None => 0,
}
}
}
impl Size for String {
fn size(&self) -> usize {
self.len()
}
}
*/

View File

@@ -146,7 +146,7 @@ impl Display for HttpResponse {
write!(
f,
"{}\r\n",
String::from_utf8(s.to_vec()).unwrap_or("<binary data>".to_string())
String::from_utf8(s.clone()).unwrap_or("<binary data>".to_string())
)?;
}
Ok(())