Welcome to RustServe. This project began as a personal endeavor to deepen my understanding of the Rust programming language by building a web server from the ground up. My primary objective was to explore the fundamental principles of HTTP and server architecture, drawing inspiration from the minimalistic approach of frameworks like Python's Flask. RustServe is designed to be a lightweight, unopinionated server, focusing on clarity of core mechanics rather than providing a comprehensive, production-ready solution.
Repository Link: github.com/vibheksoni/rust-serve
- Lightweight Core: Developed with minimal external dependencies to maintain simplicity and transparency.
- Multi-threaded Concurrency: Capable of handling multiple client connections simultaneously through Rust's native threading model.
- Basic Routing: Implements a straightforward routing mechanism to direct incoming requests to designated handler functions based on URL endpoints.
- Simple Templating System: Includes a rudimentary template engine that facilitates dynamic content generation within HTML files, with built-in HTML escaping for enhanced security.
To set up and run RustServe on your local machine, follow these instructions.
Ensure you have Rust and Cargo installed. If not, you can obtain them via rustup.rs.
-
Clone the repository:
git clone https://github.com/vibheksoni/rust-serve.git
-
Navigate to the project directory:
cd rust-serve
-
Run the server:
cargo run
Upon execution, the server will initiate and display a message indicating it is operational at http://127.0.0.1:8080
.
RustServe is designed for ease of use in defining web server behavior. Its core functionality involves listening for HTTP requests, parsing them, and delegating them to pre-configured handler functions based on the request's endpoint. Responses are then constructed, optionally leveraging a simple templating system, and transmitted back to the client.
Server
: The central component responsible for managing network connections, route dispatching, and thread management.Request
: Encapsulates an incoming HTTP request, providing access to its method, endpoint, headers, query parameters, and body content.Response
: Facilitates the creation and transmission of HTTP responses, supporting various content types and a basic HTML templating mechanism.- Routes: User-defined functions that dictate the server's behavior for specific URL paths.
For a detailed examination of each component, refer to the dedicated documentation within the docs/ directory.
This section provides practical examples for defining routes and employing the built-in templating system.
Route definitions are managed within the src/main.rs
file.
-
Create a Handler Function: This function accepts a reference to the
Request
object and contains the specific logic for the route.// src/main.rs use crate::modules::request::Request; use crate::modules::response::{Response, TemplatePair, ResponseContentType}; fn my_custom_route(req: &Request) { let mut res = Response::new(200, req.stream.try_clone().unwrap(), vec![]); // Implement your route-specific logic here. // Example: Sending a plain text response: res.respond("Hello from my custom route!".to_string(), false, None, ResponseContentType::TextPlain).unwrap(); }
-
Register the Route in
main()
: Utilize theapp.add_route()
method to associate a URL endpoint with your newly defined handler function.// src/main.rs fn main() -> std::io::Result<()> { let mut app: Server = Server::new( String::from("127.0.0.1"), 8080, true ); app.add_route(String::from("/"), index_route); // Register your custom route here app.add_route(String::from("/custom"), my_custom_route); println!("Server running on http://{}:{}/", app.host, app.port); app.serve(); Ok(()) }
The server features a basic template system that enables the replacement of placeholders in HTML files with dynamic data.
-
Prepare an HTML Template: Create an HTML file containing placeholders denoted by the
{% key %}
syntax.<!-- src/index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>User Profile</title> </head> <body> <h1>Name: {% name %}</h1> <h2>Age: {% age %}</h2> </body> </html>
-
Utilize
res.respond()
in your Handler:- Specify the file path to your HTML template.
- Set
is_file
totrue
. - Provide a
Vec<TemplatePair>
containing the data for injection. - The
escape
property withinTemplatePair
dictates whether the corresponding value undergoes HTML escaping to mitigate Cross-Site Scripting (XSS) vulnerabilities.
// src/main.rs fn index_route(req: &Request) { let mut res = Response::new( 200, req.stream.try_clone().unwrap(), vec![] ); res.respond( // Specify the path to your template file String::from("src/index.html"), true, // Indicates that 'content' is a file path Some(vec![ TemplatePair { key: String::from("name"), value: String::from("John Doe"), escape: true // Value will be HTML-escaped }, TemplatePair { key: String::from("age"), value: String::from("<script>alert('XSS Attack!')</script>"), escape: true // Value will be HTML-escaped to prevent script execution } ]), ResponseContentType::TextHtml ).unwrap(); }
For a deeper dive into the architecture, components, and internal workings of RustServe, consult the detailed documentation files:
docs/request.md
: An extensive guide to theRequest
structure and its HTTP request parsing capabilities.docs/response.md
: Provides in-depth information on theResponse
structure, methods for crafting responses, and the templating system.docs/server.md
: Explains theServer
setup, lifecycle, connection handling, and concurrency model.docs/routing.md
: Offers a detailed exploration of how routes are defined, managed, and matched within the server.
RustServe is an ongoing learning project, and I have several plans for its continued development and feature expansion:
- Robust Error Handling: Implementing comprehensive error handling mechanisms to replace current
unwrap()
calls withResult
-based propagation for more graceful failure management. - Static File Serving: Adding dedicated support for efficiently serving static assets such as CSS stylesheets, JavaScript files, and images.
- Middleware Architecture: Integrating a middleware system to enable capabilities like centralized logging, authentication, and request preprocessing.
- External Configuration: Enhancing flexibility by allowing server settings (e.g., host, port) to be loaded from configuration files or environment variables.
- Advanced Request Parsing: Developing a more robust and feature-complete request parser to handle complex HTTP scenarios more effectively.
- HTTPS Support: Incorporating SSL/TLS capabilities to enable secure communication over HTTPS.
- Comprehensive Test Suite: Expanding the existing test coverage with extensive unit and integration tests to ensure stability and correctness across all components.
This project is distributed under the MIT License. Refer to the LICENSE
file for complete details.