Add tiny webservers

This commit is contained in:
Tom 2025-06-11 10:42:04 +02:00
parent bd44164320
commit 45f07eb92a
6 changed files with 163 additions and 0 deletions

View File

@ -0,0 +1,3 @@
target/
Cargo.lock
.vscode/

View File

@ -0,0 +1,10 @@
[package]
name = "tiny_webserver"
version = "0.1.0"
edition = "2024"
[dependencies]
axum = "0.8.4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.140"
tokio = { version = "1.45.1", features = ["macros", "rt-multi-thread"] }

View File

@ -0,0 +1,34 @@
// use axum::{
// routing::{get,post},
// Router,
// };
// use serde_json::Result;
// use serde::{Deserialize, Serialize};
// #[derive(Serialize, Deserialize, Copy)]
// struct State {
// value: bool
// }
// static STATE: bool = false;
// async fn get_state() -> State {
// &STATE
// }
// #[tokio::main]
// async fn main() {
// // build our application with a single route
// let app = Router::new()
// .route("/get", get(get_state))
// .route("/set", post(set_state));
// // run our app with hyper, listening globally on port 3000
// let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
// axum::serve(listener, app).await.unwrap();
// }

View File

@ -0,0 +1,62 @@
use std::env;
use std::io;
use std::io::prelude::*;
use std::net::TcpListener;
use std::net::TcpStream;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
fn main() {
// The only shared state of this tiny webserver
let mut hitcount: Arc<AtomicUsize> = Arc::new(AtomicUsize::new(0));
// Bind to address given as argument or a default value.
let address = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
println!("Listening on {}", address);
let listener = TcpListener::bind(address).unwrap();
// Handle new connections in an infinite loop.
std::thread::scope(|scope| {
for stream in listener.incoming() {
let mut stream = stream.unwrap();
let hitcount_clone = Arc::clone(&hitcount);
let _ = scope.spawn(move || {
let re = handle_connection(&mut stream, hitcount_clone);
// Print out any errors
if re.is_err() {
println!("Error: {:?}", re);
}
});
}
})
}
fn handle_connection(stream: &mut TcpStream, hitcount: Arc<AtomicUsize>) -> io::Result<()> {
let mut buf = [0; 512];
stream.read(&mut buf).expect("Failed to read from socket.");
let request = str::from_utf8(&buf).expect("Request is not valid utf8");
println!("Got request: {}", request.split("\r\n").nth(0).unwrap_or(&request));
let (status, content) = if request.starts_with("GET / HTTP/1.1\r\n") {
let current_count = hitcount.fetch_add(1, Ordering::Relaxed) + 1;
("200 OK", format!("{{\"hits\": {}}}\n", current_count))
} else {
("404 NOT FOUND", "404 not found".to_string())
};
let length = content.len();
let response = format!(
"HTTP/1.1 {status}\r\n\
Content-Type: application/json\r\n\
Content-Length: {length}
\r\n\r\n\
{content}"
);
stream.write(response.as_bytes())?;
stream.flush()?;
Ok(())
}

View File

@ -0,0 +1,54 @@
use std::env;
use std::io;
use std::io::prelude::*;
use std::net::TcpListener;
use std::net::TcpStream;
fn main() {
// The only shared state of this tiny webserver
let mut hitcount: usize = 0;
// Bind to address given as argument or a default value.
let address = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
println!("Listening on {}", address);
let listener = TcpListener::bind(address).unwrap();
// Handle new connections in an infinite loop.
for stream in listener.incoming() {
let mut stream = stream.unwrap();
let re = handle_connection(&mut stream, &mut hitcount);
// Print out any errors
if re.is_err() {
println!("Error: {:?}", re);
}
}
}
fn handle_connection(stream: &mut TcpStream, hitcount: &mut usize) -> io::Result<()> {
let mut buf = [0; 512];
stream.read(&mut buf).expect("Failed to read from socket.");
let request = str::from_utf8(&buf).expect("Request is not valid utf8");
println!("Got request: {}", request.split("\r\n").nth(0).unwrap_or(&request));
let (status, content) = if request.starts_with("GET / HTTP/1.1\r\n") {
*hitcount = (*hitcount).saturating_add(1);
("200 OK", format!("{{\"hits\": {}}}\n", hitcount))
} else {
("404 NOT FOUND", "404 not found".to_string())
};
let length = content.len();
let response = format!(
"HTTP/1.1 {status}\r\n\
Content-Type: application/json\r\n\
Content-Length: {length}
\r\n\r\n\
{content}"
);
stream.write(response.as_bytes())?;
stream.flush()?;
Ok(())
}

View File