This project has been created as part of the 42 curriculum by dmelnyk, ogrativ, and szhong.
ServerX is a high-performance, non-blocking HTTP/1.1 server implemented in C++98. It is designed to handle thousands of simultaneous connections using I/O multiplexing, providing a lightweight and modular alternative to traditional servers.
The goal of this project was to build a functional HTTP server from scratch, following the RFC 2616 specifications. ServerX uses an event-driven architecture based on the Reactor Pattern, allowing it to process multiple requests efficiently without spawning a new thread for every client.
Key capabilities include:
- Serving static files (HTML, CSS, JS, images, etc.).
- Executing CGI scripts (Python, PHP, Bash) via
cgi_pass. - Handling file uploads and deletions.
- Managing multiple virtual hosts on different ports.
- HTTP/1.1 Support: Persistent connections (Keep-Alive), chunked request/response, and full header parsing.
- Non-blocking I/O: Built around a core
epollengine (Linux) for maximum efficiency. - Virtual Hosting: Support for multiple server blocks using
listenandserver_namedirectives. - Dynamic Content: Asynchronous CGI/1.1 support via the
cgi_passdirective, allowing direct execution or interpreter mapping. - Smart Routing: Match requests to locations based on prefix or exact match, with support for redirects and aliases.
- File Management: Built-in support for
POST(upload) andDELETEmethods, with configurableupload_path. - Customization: User-defined error pages, client body limits (
client_max_body_size), and directory listing (autoindex). - Graceful Shutdown: Cleanly closes all connections and releases resources on signals (SIGINT, SIGTERM).
Ensure you have a C++98-compatible compiler and make installed.
# Compile the server
make
# Clean object files
make clean
# Remove all build artifacts
make fcleanRun the server by providing a configuration file:
# Run with custom configuration
./webserv config/example.conf
# Quick run (builds if needed)
make run ARGS="config/example.conf"Unit tests (if present) are in the tests/ directory.
# Run tests
make testlisten: address:port or port.server_name: domain names.root/alias: document root or path translation.index: default file to serve.allow_methods: restrict toGET,POST, orDELETE.cgi_pass: enable CGI or map to an interpreter.upload_path: directory for file uploads.client_max_body_size: limit request body size.autoindex: enable directory listing (on/off).error_page: custom error pages.return: HTTP redirects.
server {
listen 8080;
server_name example.com;
root www;
index index.html;
location /uploads/ {
upload_path www/uploads;
allow_methods GET POST DELETE;
autoindex on;
}
location /cgi-bin/ {
cgi_pass /usr/bin/python3; # Map all files here to python3
allow_methods GET POST;
}
location /scripts/ {
cgi_pass; # Execute scripts directly (using shebang)
}
}Get a static file:
curl -i http://localhost:8080/index.htmlUpload a file:
curl -X POST -H "Content-Type: text/plain" --data "Hello, ServerX!" http://localhost:8080/uploads/test.txtRun a CGI script:
curl http://localhost:8080/cgi-bin/hello.pyInstead of a monolithic parser, we implemented a Configuration Pipeline. The process is split into several decoupled steps:
- Lexer: Tokenizes the configuration file.
- Parser: Builds an abstract tree of blocks and directives.
- Validator: Ensures configuration logic (e.g., no duplicate ports, correct contexts).
- Mapper: Converts the raw data into optimized runtime structures.
- DirectiveHandlers: Modular handlers that apply specific settings (e.g.
RootDirective,CgiPassDirective).
The "Network Pipeline" is the heartbeat of ServerX. It follows an event-driven flow:
- EpollManager: A low-level wrapper around the Linux
epollsystem call. It monitors multiple file descriptors (FDs) simultaneously. - EventDispatcher: A central singleton that dispatches events to registered handlers (
Acceptor,ClientHandler,CGIHandler). - I/O Multiplexing: While the core uses
epoll, the interface is designed to be extensible (e.g., forpollorselect).
Our RequestParser is a state-machine based engine. It reads data incrementally, "feeding" on whatever bytes are currently available in the buffer. This handles large bodies and slow clients without consuming excess memory or threads.
CGI execution is handled asynchronously to avoid blocking the main event loop. The server forks a process, manages pipes, and uses the EventDispatcher to stream output back to the client as it becomes available.
- HTTP/1.1 Specification: RFC 2616 / RFC 7230 — Defines the HTTP/1.1 protocol, including request/response structure and semantics.
- CGI Specification: RFC 3875 — Outlines the Common Gateway Interface (CGI) standard for interfacing external applications with web servers.
- Network Programming: Beej's Guide to Network Programming — A beginner-friendly guide to socket programming and network fundamentals in C/C++.
- Linux Manuals: epoll(7) — Official Linux documentation for the epoll I/O multiplexing facility.
- Design Inspiration: Nginx Documentation — Reference for server configuration, directives, and architecture ideas.
- Reactor Pattern: https://www.dre.vanderbilt.edu/~schmidt/PDF/reactor-siemens.pdf — Academic paper describing the Reactor Pattern for event-driven programming.
Artificial Intelligence was utilized during development for:
- Architecture: Designing the modular directive system and event dispatcher.
- Documentation: Drafting README content and generating command snippets.
- Refactoring: Proposing cleaner helper functions and troubleshooting state-machine edge cases.
- Testing: Assisting in the creation of unit test scenarios.