i think i might accidentally write a webserver

(i mean, not the heavy parts, most of it's going to be axum behind haproxy. but i'm finding i don't like ServeDir/ServeFile from tower_http so i'm just gonna try to do a naive implementation. get a url, check for shenanigans, translate to filename, send the file. and i'm chuffed to relearn enough rust and traits and into/from to be able to design handlers for axum and use the ? operator instead of filling my code up with error handling mess)

only 141 lines of rust including blanks and comments, 4.6kb, and i feel like i've learned a heck of a lot

i had this much "working" maybe a day and a half ago, but it felt gross and hard to read. now it feels like i'm doing things in a rusty way and working with the tools it offers me

right now it's just: write files on PUT request, serve files on GET. next up: make PUT handle If-Unmodified-Since. after that, etags, but i'll be abandoning ServeDir at that point and writing my own equivalent

whoa i just tried "cargo doc" for the first time and now i have a whole pile of crisp html documents about the stuff i just cobbled together that looks all professional, like the real software up on https://docs.rs/ ??

it was slicker and less effort than i expected... i could really get into this

Docs.rs

rust is a trip

axum is designed such that if you want your web request-handler function to operate on different information from the request, like you want the value of a header or the body decoded from json, all you do is add that as an argument to your function call signature, change nothing else, and now your function gets called with it

all due to the type system and automatic coersion, and it's fast, and the most unbelievable part yet, i almost understand how it works!

got a ways to go yet but, got my lil rust webserver that understands If-Unmodified-Since PUT requests plugged into the internet. it does the thing i wanted it to do!

pretty sure it's not vulnerable to directory traversal attacks

however it does not currently attempt to guard against users who would upload naughty scripts or media

if you want to poke it, dm me and if you don't seem like the type to upload an xss attack i'll give you a demo username/password

at 7mb res 4mb shared, it's smaller in memory than sshd, coturn, prosody, haproxy, caddy, or tailscale

next steps:

  • a nice editor ui sorta thing for making blogposts
  • sse and/or websockets to notify of updates and/or support crdt libraries (multiplayer editing like google docs) (not 100% convinced i even want that though)
  • tests lol
  • verify that when it gets a huge pile of concurrent writes it really won't lose any
rustin' makes me feel good

improved my error handling in rust/axum a bit! 🎉

i wanted to use the ? operator on fallible function calls to show an http error response instead of panic

i had written a helper function to convert Error into ErrorResponse that was short and worked, but made for calls like:

edit_file().await.map_err(to_err_response)?

now i learned how to create an error type with From<Error> and IntoResponse traits. so calls are now:

edit_file().await?

and bonus, where i previously was throwing custom errors like

if failure {
Err((statuscode, "an error message to be returned in the body of the error page"))?
}

now i can move the message text and status code into my error type, away from the normal logic path

if failure {
Err(UserError::BadArgument)?
}