A simple HTTP server written in Rust, serving static HTML files.
To run the server, simply clone the repository and run the following command:
cargo runThis will start the server on http://localhost:8001. Open your favorite web browser and navigate to the URL to see the server in action.
use std::io::prelude::*;
use std::fs;
use std::net::TcpListener;
use std::net::TcpStream;Imagine you're building a Lego castle, and you need to use different types of Lego pieces. In programming, we use libraries to get access to different tools and functions that can help us build our program. The use keyword is like importing a box of Lego pieces into our program.
- std::io::prelude::* is like a box of Lego pieces for input/output operations, like reading and writing files.
- std::fs is like a box of Lego pieces for working with files and directories.
- std::net::TcpListener and std::net::TcpStream are like boxes of Lego pieces for working with the internet and networking.
fn handle_stream(mut stream: TcpStream) {
// code here
}A function is like a recipe for making a specific dish. You put in some ingredients (inputs), follow some steps (code), and get a result (output). In this case, our function is called handle_stream, and it takes one ingredient, stream, which is a type of Lego piece for working with the internet.
let mut buf = [0; 1024];
stream.read(&mut buf).expect("Failed to read from stream");Imagine you're trying to read a message from a friend, but the message is written on a piece of paper that's too big to hold in your hand. You need to use a special tool (a buffer) to hold the message, and then you can read it. That's what's happening here. We're creating a buffer (a special array of 1024 zeros) to hold the message from the stream, and then we're using the read function to fill the buffer with the message.
let get = b"GET / HTTP/1.1\r\n";
let (status_line, filename) =
if buf.starts_with(b"GET / HTTP/1.1\r\n"){
("HTTP/1.1 200 OK\r\n","src/index.html")
}else{
("HTTP/1.1 404 NOT FOUND\r\n","src/404.html")
};Imagine you're trying to understand what your friend's message says. You need to check if the message starts with a specific phrase (like "GET / HTTP/1.1\r\n"). If it does, you respond with a specific message (like "HTTP/1.1 200 OK\r\n") and a file (like "src/index.html"). If it doesn't, you respond with a different message (like "HTTP/1.1 404 NOT FOUND\r\n") and a different file (like "src/404.html").
let content = fs::read_to_string(filename).expect("Cannot HTML read file");Imagine you need to read a book, but the book is stored in a special place (a file). You need to use a special tool (the fs library) to read the book and turn it into a string of text. That's what's happening here. We're using the fs library to read the file and turn it into a string of text.
let response = format!("{}Content-Length: {}\r\n\r\n{}",status_line,content.len(),content);Imagine you're trying to write a response to your friend's message. You need to include the status line, the length of the content, and the content itself. That's what's happening here. We're using the format! function to create a string that includes all the necessary information.
stream.write(response.as_bytes()).expect("Cannot write to stream");
stream.flush().expect("Cannot flush stream");Imagine you're trying to send your response to your friend. You need to write the response to the stream (like sending a letter in the mail) and then flush the stream (like sending the letter on its way). That's what's happening here. We're using the write function to write the response to the stream and the flush function to send the response on its way.
fn main() {
// code here
}The main function is like the main recipe for our program. It's where we put all the ingredients (functions) together to make the final dish (our program).
let listener = TcpListener::bind("127.0.0.1:8001").expect("could not bind to addresss");Imagine you're trying to set up a phone number for your friend to call you. You need to create a special connection (a TCP listener) that listens for incoming calls. That's what's happening here. We're creating a TCP listener that listens for incoming connections on the address "127.0.0.1:8001".
for stream in listener.incoming() {
match stream {
Ok(stream) => {
handle_stream(stream);
}
Err(e) => {
println!("Failed to establish connection: {}", e);
}
}
}Imagine you're trying to answer the phone when your friend calls. You need to handle the incoming connection (the phone call) and respond accordingly. That's what's happening here. We're using a for loop to handle each incoming connection, and we're using a match statement to handle any errors that might occur.
To use the server, simply navigate to http://localhost:8001 in your web browser. If you want to serve a different HTML file, replace src/index.html with the path to your file.
This project is licensed under the MIT License. See the LICENSE file for details.