A high-performance HTTP/1.1 web server implementation in C++98, similar to NGINX. This project demonstrates advanced network programming, event-driven architecture, and HTTP protocol handling.
- Features
- Requirements
- Installation
- Usage
- Configuration
- Project Structure
- Architecture
- Testing
- Documentation
- HTTP/1.1 compliant request/response handling
- Supported methods: GET, HEAD, POST, DELETE
- Keep-alive connections for improved performance
- Chunked transfer encoding
- Query string parsing
- Cookie handling and session management
- Multipart form data for file uploads
- Custom error pages (403, 404, 405, 413, 500)
- Request body size limiting
- Virtual hosting with multiple server blocks
- Multiple listen ports per server
- Server name matching (similar to NGINX)
- Location blocks with pattern matching
- Method restrictions per location
- Directory listing (autoindex)
- Custom root and index files
- HTTP redirects (return directive)
- File upload and deletion support
- CGI/1.1 implementation
- Multiple CGI handlers by file extension
- Environment variable population
- POST data handling
- Timeout protection for long-running scripts
- Support for Python scripts and compiled binaries
- Event-driven architecture using epoll (Linux) or poll (macOS)
- Non-blocking I/O throughout
- Connection timeout handling (2s)
- CGI timeout protection (20s)
- Request body buffering
- Path traversal attack protection
- C++ compiler with C++98 support (g++, clang++)
- POSIX-compliant operating system (Linux, macOS)
- make build system
- Python 3 (optional, for CGI scripts)
git clone <repository-url>
cd webservermakeFor Linux systems that want to force poll mode instead of epoll:
make pollmakeormake all- Build the webserv binarymake clean- Remove object filesmake fclean- Remove objects and binarymake re- Rebuild from scratch
Run with default configuration:
./webservRun with custom configuration:
./webserv config_file/eval.confThe server will start listening on the configured ports (default: 8080).
Open your browser and navigate to:
http://localhost:8080
http://localhost:8080/- Main index pagehttp://localhost:8080/upload.html- File upload interfacehttp://localhost:8080/cgi_post.html- CGI test pagehttp://localhost:8080/upload/- Directory listing (if autoindex is on)
Press Ctrl+C to gracefully shut down the server.
Webserv uses an NGINX-like configuration syntax. Configuration files are located in the config_file/ directory.
server {
host localhost;
listen 8080;
server_name www.example.com example.com;
root ./www;
index index.html index.htm;
autoindex on;
allow_methods GET POST DELETE;
error_page 404 /error_pages/404.html;
client_body_buffer_size 1000000;
cgi_ext .py;
cgi_path /usr/bin/python3;
location /upload {
root ./www/upload;
autoindex on;
allow_methods GET POST DELETE;
}
location /redirect {
return 301 https://www.example.com;
}
}| Directive | Description | Default |
|---|---|---|
listen |
Port number to listen on | 8080 |
host |
Host address to bind to | 0.0.0.0 |
server_name |
Space-separated list of server names | - |
root |
Document root directory | ./www |
index |
Space-separated list of index files | index.html |
autoindex |
Enable/disable directory listing (on/off) | off |
allow_methods |
Space-separated list of allowed HTTP methods | GET |
error_page |
Custom error page (code path) | - |
client_body_buffer_size |
Maximum request body size in bytes | 1000000 |
cgi_ext |
CGI file extension (can specify multiple) | - |
cgi_path |
CGI handler path (maps 1:1 with extensions) | - |
Location blocks inherit server block directives and can override:
rootindexautoindexallow_methodsreturn(for redirects)
config_file/default.conf- Minimal configurationconfig_file/eval.conf- Comprehensive example with multiple serversconfig_file/test.conf- Testing configuration with CGIconfig_file/siege.conf- Load testing configuration
webserver/
├── Makefile # Build configuration
├── README.md # This file
├── src/ # Source files
│ ├── main.cpp # Entry point
│ ├── ServerManager.cpp # Core event loop and connection handling
│ ├── Request.cpp # HTTP request parser
│ ├── Response.cpp # HTTP response builder
│ ├── Socket.cpp # Socket wrapper
│ ├── Connection.cpp # Client connection management
│ ├── ConfigFile.cpp # Configuration file parser
│ ├── ServerBlock.cpp # Server configuration
│ ├── LocationBlock.cpp # Location configuration
│ ├── Session.cpp # Session management
│ ├── UploadHandler.cpp # File upload handling
│ └── ...
├── inc/ # Header files
│ ├── ServerManager.hpp
│ ├── Request.hpp
│ ├── Response.hpp
│ └── ...
├── config_file/ # Configuration files
│ ├── default.conf
│ ├── eval.conf
│ └── ...
├── www/ # Web document root
│ ├── index.html
│ ├── upload.html
│ ├── error_pages/
│ └── upload/
├── cgi-bin/ # CGI scripts and handlers
│ ├── cgi_handler
│ ├── cgi_get.py
│ └── cgi_post.py
└── obj/ # Object files (generated)
Webserv uses an event-driven architecture with I/O multiplexing:
- Linux: Uses
epollfor efficient event notification - macOS: Uses
poll(automatically detected during compilation)
- Accept Connection: ServerManager accepts incoming connections
- Read Request: Non-blocking read into Connection buffer
- Parse Request: Request object parses HTTP request incrementally
- Route Request: ServerBlock and LocationBlock determine handler
- Generate Response: Response object builds HTTP response
- Write Response: Non-blocking write from Connection buffer
- Keep-Alive or Close: Connection maintained or closed based on headers
- Fork child process
- Set up pipes for stdin/stdout
- Set environment variables (REQUEST_METHOD, QUERY_STRING, etc.)
- Execute CGI script with execve
- Capture output with timeout protection
- Return output as HTTP response body
Use a web browser or command-line tools:
# Simple GET request
curl http://localhost:8080/
# POST request with data
curl -X POST -d "name=test&value=123" http://localhost:8080/cgi-bin/cgi_post.py
# File upload
curl -F "file=@test.txt" http://localhost:8080/upload
# DELETE request
curl -X DELETE http://localhost:8080/upload/test.txtUse siege or similar tools:
siege -c 100 -t 30s http://localhost:8080/The project includes a test binary:
./testerThe project includes Doxygen configuration:
doxygen DoxyfileThis will generate HTML documentation in the docs/ directory.
- HTTP/1.1 Specification: RFC 2616
- CGI Specification: RFC 3CGI
- Project Subject: See
en.subject.webserv.pdffor detailed requirements
This project strictly adheres to the C++98 standard:
- No external libraries beyond standard C/C++ libraries
- Compiled with
-std=c++98 -Wall -Werror -Wextra - Compatible with older systems
- Path traversal protection: Validates and sanitizes file paths
- Request size limits: Prevents memory exhaustion
- CGI timeout: Prevents infinite loops in CGI scripts
- Permission checking: Validates file access before serving
- Input validation: Sanitizes headers and request data
- RAII principles with proper resource cleanup
- Standard library containers for automatic memory management
- Proper signal handling for graceful shutdown
- No memory leaks under normal operation
- HTTP/1.1 only (no HTTP/2 or HTTP/3 support)
- IPv4 only (no IPv6 support)
- Single-threaded event loop (no worker processes)
- CGI/1.1 only (no FastCGI support)
This is an educational project demonstrating HTTP server implementation. Feel free to explore, learn from, and adapt the code for your own purposes.
This project is part of the 42 School curriculum.