A lightweight, non-blocking HTTP/1.1 server written in C++98 with event-driven architecture using epoll. Designed as a learning project to understand HTTP internals and modern web server patterns. Features NGINX-like configuration, CGI support (PHP, Python), and full HTTP request/response handling.
- Non-blocking Event Loop: Single-threaded epoll-based reactor pattern handles multiple concurrent connections
- Multi-port Support: NGINX-like configuration with multiple server blocks listening on different ports
- Platform Support: Linux (epoll) and macOS (kqueue via compatibility layer)
- Signal Handling: Graceful shutdown on SIGINT with full resource cleanup
- Request Parsing: Full HTTP/1.1 request line, headers, and body parsing
- Chunked Transfer Encoding: Full support for Transfer-Encoding: chunked (request and response)
- Content-Length: Proper request body size validation and limiting
- HTTP Methods: GET, POST, PUT, DELETE, HEAD
- Response Generation: Complete HTTP/1.1 responses with status codes, headers, and body
- MIME Type Detection: Automatic Content-Type detection for static files
- File Serving: Stream static files with proper headers and range support
- Directory Listing: Configurable auto-index with HTML directory browsing
- Index Files: Support for configurable index file names (e.g., index.html)
- Error Pages: Custom error pages for HTTP status codes (400, 401, 403, 404, 405, 413, 500, 501, 502, 503)
- NGINX-like Config Parser: Full-featured
server,location,listen,root,indexblocks - Location Matching: Longest-prefix matching for request paths to location blocks
- Method Control: Per-location allowed methods configuration
- HTTP Redirects: 307/308 temporary/permanent redirects with configurable targets
- Root & Index Configuration: Per-location root and index file overrides
- Multiple Interpreter Support: PHP (php-cgi) and Python (python3) out-of-the-box
- Async CGI Processing: Non-blocking CGI execution via child processes and pipe monitoring
- CGI Environment: Full CGI environment setup (REQUEST_METHOD, QUERY_STRING, PATH_INFO, etc.)
- Output Limits: Configurable
cgi_max_outputto prevent resource exhaustion - Timeout Handling: Configurable CGI execution timeouts with process cleanup
- Multipart Form Data: Support for file uploads via POST requests
- Upload Destinations: Configurable upload paths per location
- Size Limits: Per-location
client_max_body_sizeenforcement - Python CGI Upload Handler: Automatic filename collision detection and handling
- Max Body Size Enforcement: Prevent oversized requests (413 Payload Too Large)
- Method Validation: Per-location allowed methods with 405 Method Not Allowed responses
- Path Traversal Prevention: Safe path joining prevents directory traversal attacks
- Connection Timeouts: Configurable idle connection timeout with cleanup
- Logging System: Colored, leveled logging throughout the codebase (DEBUG, INFO, WARN, ERROR)
- Connection Tracking: Per-connection state machine (READING_HEADERS, READING_BODY, READY_TO_RESPOND, WRITING_RESPONSE, etc.)
- Debug Mode: AddressSanitizer support (
make debug) - Config Debug Output: Detailed configuration parsing and validation logging
Based on the official project specifications (webserv.txt), the following items are on the roadmap:
- β Non-blocking I/O with single poll() equivalent (epoll/kqueue)
- β Configuration file support
- β HTTP GET, POST, DELETE methods
- β Static file serving
- β File upload support
- β Default error pages
- β Browser compatibility
- β Cookies and Session Management: Track user sessions with HTTP cookies
- β Multiple CGI Types: Support for additional scripting languages beyond PHP and Python
- CGI Streaming: CGI output fully buffered before sending (not streamed)
- SSL/TLS: No HTTPS support
- Content Encoding: No gzip/deflate compression
make # Standard build with warnings-as-errors
make debug # Build with AddressSanitizer for memory debugging
make clean # Remove object files
make fclean # Remove objects and binary
make re # Clean rebuild./webserv [config_file] # Use config file (default: default.conf)
./webserv default.conf # Explicit config pathserver {
listen 127.0.0.1:8000;
server_name webserv;
root www_giulio/;
index index.html;
client_max_body_size 1M;
error_page 404 /errors/404.html;
location /cgi-bin {
cgi .php /usr/bin/php-cgi;
cgi .py /usr/bin/python3;
cgi_timeout 5000;
cgi_max_output 10M;
}
location /uploads {
allowed_methods GET POST DELETE;
client_max_body_size 50M;
}
}# Start server
./webserv default.conf &
# Test GET request
curl http://127.0.0.1:8000/
# Test POST with file upload
curl -F "file=@/path/to/file" http://127.0.0.1:8000/uploads
# Test CGI
curl "http://127.0.0.1:8000/cgi-bin/script.php?param=value"
# Kill server
pkill webservsrc/
βββ main.cpp # Entry point
βββ server/
β βββ Server.cpp/hpp # Main server loop & connection management
β βββ Router.cpp/hpp # Request routing & location matching
β βββ Router_Handler.cpp # Route handler implementations
β βββ Server_Response.cpp # Response preparation
β βββ Listener.cpp/hpp # TCP listener socket management
βββ core/
β βββ EpollReactor.cpp/hpp # Event multiplexing (epoll/kqueue)
β βββ EpollMac.hpp # macOS kqueue compatibility
βββ http/
β βββ HttpParser.cpp/hpp # HTTP request parsing
β βββ HttpRequest.cpp/hpp # Request object
β βββ HttpResponse.cpp/hpp # Response object
β βββ Connection.cpp/hpp # Per-connection state
β βββ ChunkedDecoder.cpp/hpp # Transfer-Encoding: chunked
βββ config/
β βββ Config.cpp # Config file parsing & validation
β βββ Config.hpp # Config data structures
β βββ Config_Debug.cpp # Debug output
β βββ Config_Error.cpp # Error handling
β βββ Config_Helpers.cpp # Helper functions
β βββ Config_Validation.cpp # Validation logic
βββ cgi/
β βββ Cgi.hpp # CGI handler interface
β βββ CgiData.hpp # CGI process data
β βββ Execute.cpp # Process execution
β βββ CgiTools.cpp # Environment setup
β βββ Respond.cpp # CGI response handling
βββ utils/
βββ Logger.cpp/hpp # Logging system
βββ Chrono.cpp/hpp # Timing utilities
βββ Colors.hpp # ANSI color codes
βββ Mime.hpp # MIME type detection
βββ Path.hpp # Path utilities
βββ File.hpp # File I/O helpers
βββ Utils.hpp # General utilities
www_giulio/ # Example web root with content
βββ index.html
βββ cgi-bin/ # CGI scripts (PHP, Python)
βββ errors/ # Error page templates
βββ ressources/ # Static content
βββ uploads/ # Upload destination
scripts/
βββ tests.sh # Integration test suite
βββ test.py # Python test utilities
The server uses a single-threaded event loop with epoll to handle thousands of concurrent connections. Each connection progresses through a state machine: reading headers β reading body β routing β writing response.
Large files are streamed directly from disk to socket without buffering the entire file in memory, enabling efficient handling of large responses.
Configuration uses NGINX-familiar syntax with server blocks, location blocks, and per-location directives, making it intuitive for those familiar with production web servers.
CGI scripts execute in child processes; output is collected asynchronously via epoll, preventing blocking on slow scripts.
- C++98 Only: No C++11+ features; limits template usage and modern conveniences
- Single-Threaded: No thread pool or multi-process worker model
- Memory Efficiency: CGI output fully buffered before sending (not streamed)
- No Clustering: Cannot distribute load across multiple servers
- No Caching: Every request is processed fresh
- Limited Logging: Debug logging only; no structured access logging
- HTTP/2 Support: Multiplexed streams and server push
- SSL/TLS: HTTPS support via OpenSSL
- WebSocket: Upgrade mechanism for real-time bidirectional communication
- Load Balancing: Upstream and health check support
- Caching: Response and asset caching strategies
- Rate Limiting: Per-IP and per-path request throttling
- Authentication: Built-in HTTP Basic/Digest auth
- Access Logging: Combined/JSON format logging to files