https://github.com/explodingcamera/rust-http-server-from-scratch
https://github.com/explodingcamera/rust-http-server-from-scratch
Last synced: 9 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/explodingcamera/rust-http-server-from-scratch
- Owner: explodingcamera
- License: mit
- Created: 2021-09-13T10:50:57.000Z (about 4 years ago)
- Default Branch: main
- Last Pushed: 2021-12-14T11:54:45.000Z (almost 4 years ago)
- Last Synced: 2025-01-22T02:32:12.603Z (10 months ago)
- Language: Rust
- Size: 104 KB
- Stars: 1
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# Creating a Webserver from scratch (in rust)
# Getting Started
## 1. Install Dependencies
- [rust >= 1.56.0](https://rustup.rs/)
## 2. Run
```bash
$ cargo run --bin client
$ cargo run --bin server
```
# TODO:
- More Security Checks (Request Size limits)
- Websockets
- [x] websocket middleware
- [x] websocket upgrade
- [x] websocket frame parser
- [x] websocket masking
- [ ] websocket chunked messages
- [ ] websocket frame builder
- Partial request parsing
- Stream Abstraction (Chunked encoding)
- Revisit low level parallel processing of incoming sockets
# Full Example
```rust
use anyhow::Result;
use webserver_from_scratch::{middleware, router::Router, HTTPServer, LogLevel, StatusCode};
fn main() -> Result<()> {
let mut server = HTTPServer::new();
server.loglevel(LogLevel::Off);
let hello_world_handler = middleware!(|ctx| {
let resp = b"
Hello World
";
ctx.response.content_type("text/html");
ctx.response.write(resp);
ctx.end();
});
let hello_handler = middleware!(|ctx| {
ctx.response.content_type("text/html");
ctx.response.write(b"
Hello ");
let params = ctx.params.clone();
let name = params.get(":name");
let name = if let Some(name) = name {
name.value.as_bytes()
} else {
b"World"
};
ctx.response.write(name);
ctx.response.write(b"");
ctx.end();
});
server
.get("/", hello_world_handler)
.get("/:name", hello_handler);
server.any(
"*",
middleware!(|ctx| {
let resp = b"404";
ctx.response.status_code(StatusCode::NotFound);
ctx.response.write(resp);
}),
);
server.listen_blocking("[::1]:8080".parse().unwrap())
}
```
# Macro
## Usage
```rs
middleware!(|ctx| {
// User Code (can use .await)
})
```
## Resulting Code
```rs
{
let closure = |ctx: MiddlewareCtx| -> HandlerFut {
Box::pin(async move {
// We have to use a mutex for the request context since the
// borrow checker doesn't recognize that an async function has finished running and
let mut ctx = ctx.lock(); // will be locked after `ctx` is dropped at the end of this block
/// {User code}
Ok(()) // enable error catching by returning a result (enables using `?` for catching errors)
})
};
closure // return closure from this block
}
```
# Inspirations
- Websocket
- https://github.com/1tgr/rust-websocket-lite
- https://github.com/snapview/tungstenite-rs
- Http
- https://expressjs.com
- https://github.com/nickel-org/nickel.rs
- https://github.com/seanmonstar/httparse
- https://github.com/magic003/http-parser-rs