mirror of
https://github.com/RTFW-rs/rtfw-http-rs.git
synced 2026-07-20 18:54:57 +00:00
💀 Trying to implement an http server from scratch for fun
- Rust 100%
| .github/workflows | ||
| src | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| LICENSE | ||
| README.md | ||
🌐 rtfw-http-rs
A simple http server from scratch using std::net::tcp.
This is for learning and playing purpose only.
Should never be used in production for obvious reasons 💀
Roadmap
- HTTP 1.0/1.1 support ✨
HTTP 0.9 support 👴(support was temporarily dropped to simplify code, IT WILL COME BACK!)- Routing 🚆
- Multi-threading 🤹
- Headers + cookies 🍪
- MIME support 🎭
- support for file download (
HttpResponse.bodyis nowVec<u8>) - support for file upload (
HttpRequest.bodyis nowVec<u8>)
- support for file download (
- Body support
- Bytes body
- String body
- Multipart body
- Single part (useful for single file uploads)
- Multi parts
- HTTPS 🛡️
- Improved routing 🚄 (W.I.P)
- static file serving (using
mime_guessfor setting proper mime type) - support for dynamic paths:
/foo/:id/bar
- static file serving (using
Usage example
For an example webapp built using this HTTP server, checkout: rtfw-webapp-sample-rs
⚠️ The example code below might get outdated due to frequent refactors of the code. It's better to check the example webapp instead which is usel up-to-date.
use anyhow::Result;
use http_server::http::{HttpRequest, HttpResponse, HttpResponseBuilder};
use http_server::web_server::WebServer;
use std::fs;
fn main() -> Result<()> {
let router = Router::new()
// get routes
.get("/", routes::get_hello)?
.get("/hello", routes::get_hello)?
.get("/mirror", routes::get_mirror)?
// post route
.post("/paste", routes::post_paste_data)?
// 404 Catch all
.get("/*", routes::get_404)?;
let server = WebServer::new("127.0.0.1:7878", router)?;
server.run()
Ok(())
}
pub fn get_hello(request: &HttpRequest) -> Result<HttpResponse> {
let name = request.query.get("name").map_or("World", |v| v);
let body = format!("Hello {}!", name);
HttpResponseBuilder::new().set_html_body(&body).build()
}
pub fn get_mirror(request: &HttpRequest) -> Result<HttpResponse> {
HttpResponseBuilder::new().set_json_body(request)?.build()
}
pub fn post_paste_data(request: &HttpRequest) -> Result<HttpResponse> {
let body = request.body.clone().unwrap_or(String::new());
if body.len() > 1_000_000 {
return HttpResponseBuilder::new()
.set_status(HttpStatusCode::BadRequest)
.set_json_body(
&json!({"status": "400 Bad Request", "message": "too many characters!"}),
)?
.build();
}
// Do stuff...
HttpResponseBuilder::new()
.set_status(HttpStatusCode::OK)
.set_json_body(&json!({"status": "200 OK", "message": "data has been saved"}))?
.build()
}
pub fn get_404(_request: &HttpRequest) -> Result<HttpResponse> {
let body = fs::read_to_string("pages/404.html")?;
HttpResponseBuilder::new()
.set_status("404 NOT FOUND")
.set_html_body(&body)
.build()
}