π Webserv is a fully custom HTTP server written in C++17, designed to provide a deep understanding of the Hypertext Transfer Protocol (HTTP). Inspired by the principles and architecture of industry-standard servers like NGINX, this project was built from scratch to handle HTTP requests and responses, implement core web server functionality, and include advanced features such as file uploads, CGI execution, and serving static websites.
Much like NGINX, Webserv is designed to be:
- π‘οΈ Resilient: Built to handle stress tests and high traffic without crashing.
- β‘ Efficient: Implements non-blocking I/O using
poll()for scalable performance. - π οΈ Flexible: Supports multiple ports, virtual hosts, and customizable configurations.
Our implementation covers all mandatory requirements and extends functionality with bonus features for an enhanced user experience. Designed to be robust and fully compliant with HTTP 1.1 standards, Webserv has been rigorously tested against browsers and benchmarking tools like Siege, offering a solid foundation for anyone looking to explore or build modern web servers.
π‘ In essence, Webserv provides a simplified yet powerful approach to understanding and replicating the core functionalities of a web server like NGINX.
- Description
- Lifecycle
- Prerequisites
- Installation
- Features
- Configuration
- Technical Details
- Testing and Benchmarking
- Curl Examples
- C++17 Compiler: Ensure a compatible compiler is installed.
- Make: Required for building the project.
- Docker: Optional, for containerized deployment.
- Clone the Repository:
git clone https://github.com/dendeaisd/Webserv.git
cd Webserv- Build the Server:
make- Run the Server:
./webserv [configuration file]If no configuration file is specified, it defaults to ./configs/default.conf.
To run the server in a Docker container:
make docker-run- HTTP Methods: Supports GET, POST, PUT, etc. methods
- Non-Blocking I/O: Utilizes
poll()for efficient client handling. - Static File Serving: Delivers HTML, CSS, JavaScript, and image files.
- File Uploads: Allows clients to upload files to the server and download them.
- CGI Support: Executes scripts in various languages (e.g., Python, PHP, Ruby) based on configuration.
- Custom Error Pages: Provides user-friendly error messages.
- Cookies and Session Management: Implements stateful sessions; demonstrated with a To-Do application.
Upon starting the server, the default landing page (IRIDESCENT) is accessible at:
http://localhost:[port]Here you can see example of the features of the project like trying our ToDo App, the uploads page or various scripts showcasing the functionality of the CGI, when you open the menu on the top-right side of the page.
Example: Visit a static file served by the server.
http://localhost:[port]/index.htmlAdd your static HTML, CSS, and JS files in the directory defined in the root configuration.
Upload files directly through the Uploads interface on the default page or via HTTP POST.
http://localhost:[port]/uploadRun dynamic scripts written in various languages (e.g., Python, Perl, Ruby, Bash). Examples are available directly on the default page. Select a script to see its execution in real-time.
Examples:
- Python Script:
http://localhost:[port]/cgi-bin/hello.py - Ruby Script:
http://localhost:[port]/cgi-bin/hello.rb
Explore a fully functional To-Do application that showcases cookie-based session management. Add, remove, or manage tasks, with session persistence.
http://localhost:[port]/todoTrigger custom error responses by accessing routes with missing permissions or non-existent resources.
Examples:
The server's behavior is controlled by a configuration file that defines various settings, such as ports, error pages, routes, and upload locations. Below is an example of a configuration file and its features:
# Define server block
server {
listen 8080;
server_name localhost;
# Root directory for the server
root /var/www/html;
# Default error pages
error_page 404 /error_pages/404.html;
error_page 403 /error_pages/403.html;
# Route configuration
location / {
autoindex on;
index index.html;
}
# File upload settings
location /upload {
upload_store /var/www/upload;
upload_pass /cgi-bin/upload.cgi;
}
}
listen: Specifies the port the server will listen to.server_name: Defines the host or domain name.root: Sets the root directory from which files will be served.error_page: Maps HTTP error codes (e.g., 404, 403) to custom error pages.location: Defines specific routing behaviors:autoindex: Enables directory listing if no index file is found.index: Specifies the default file to serve when a directory is accessed.upload_storeandupload_pass: Configure file upload handling. This file serves as a template to demonstrate how to use the configuration system.
Additional configurations can be added to enable more advanced features like for example CGI handling.
The Webserv project is built using C++17, following object-oriented programming principles and modular design. Below is an overview of its core structure and how the server operates.
The server starts in main.cpp, where it:
-
Processes the Command-Line Arguments:
- Accepts an optional configuration file path as an argument.
- Defaults to
./configs/default.confif no argument is provided. - Validates the presence of the configuration file using
access().
-
Parses the Configuration File:
- The
ParseConfigFileclass is used to read and validate the configuration file. - If the configuration is invalid or missing, the program exits with an error message.
- The
-
Initializes Components:
- Logging: Configures logging using the
Logsingleton. - CGI Manager: Configures CGI routes via the
CGIFileManagerclass.
- Logging: Configures logging using the
-
Starts the Server:
- Creates and runs an instance of the
Serverclass, passing the parsed configuration.
- Creates and runs an instance of the
main.cpp includes error handling to capture and log:
- Socket Errors (e.g., binding or listening issues).
- Poll Manager Errors (e.g., issues with non-blocking I/O).
- General Exceptions for any unforeseen issues during runtime.
The project employs a modular structure for clear separation of concerns:
- Networking: Managed by the
Serverclass and supporting components. - Configuration: The
ParseConfigFileclass handles configuration parsing and validation. - Logging: The
Logsingleton enables debug-level logging for easier troubleshooting. - CGI Management: The
CGIFileManagerhandles dynamic content and script execution.
Paste this in chrome and disable the attr: chrome://flags/#block-insecure-private-network-requests
reference: https://developer.chrome.com/blog/cors-rfc1918-feedback
make docker-run
make re
./webserv
siege -b -c 100 -t 1m -T 2S http://127.0.0.1:8080/benchmarklet's agree, curl is cute
curl -v -s -w "\n-------\n\nDNS Lookup: %{time_namelookup}\nConnect: %{time_connect}\nStart Transfer: %{time_starttransfer}\nTotal: %{time_total}\n" http://localhost:8080/cgi-bin/blocking.py
curl -o /dev/null -s -w "DNS Lookup: %{time_namelookup}\nConnect: %{time_connect}\nStart Transfer: %{time_starttransfer}\nTotal: %{time_total}\n" http://localhost:8080/cgi-bin/blocking.py



