A high-performance HTTP/1.1 web server written in C++98, implementing core web server functionality with support for multiple virtual hosts, CGI execution, and comprehensive error handling.
- HTTP/1.1 Protocol Support: Full implementation of HTTP/1.1 specification
- Multiple Virtual Hosts: Support for multiple server blocks with different configurations
- Epoll-based I/O: High-performance event-driven architecture using Linux epoll
- Connection Management: Automatic connection handling with timeout support
- Request Parsing: Robust HTTP request parsing with header validation
- Response Generation: Dynamic HTTP response generation with proper status codes
- CGI Support: Execute Python and PHP scripts with proper environment setup
- Static File Serving: Serve static files with proper MIME type detection
- Directory Listing: Auto-index functionality for directory browsing
- Error Pages: Custom error pages for various HTTP status codes
- Upload Support: File upload functionality with configurable limits
- Redirection: HTTP redirection support
- Request Methods: Support for GET, POST, DELETE HTTP methods
- TOML Configuration: Human-readable configuration file format
- Flexible Routing: Configurable routes with method restrictions
- Server Blocks: Multiple server configurations with different ports and hostnames
- Error Page Mapping: Custom error pages for different status codes
webserv/
├── main.cpp # Main entry point
├── Makefile # Build configuration
├── config_parser/ # Configuration parsing
│ ├── Webserv.cpp # Main configuration parser
│ ├── server.cpp # Server configuration handling
│ ├── utilities/ # Parser utilities
│ └── tests/ # Parser tests
├── HttpRequest/ # HTTP request handling
│ ├── HttpRequest.cpp # Request object implementation
│ ├── HttpRequest.hpp # Request class definition
│ ├── HttpRequestParser.cpp # Request parsing logic
│ └── HttpRequestParser.hpp # Parser interface
├── HttpResponse/ # HTTP response handling
│ ├── HttpResponse.cpp # Response object implementation
│ ├── HttpResponse.hpp # Response class definition
│ ├── HttpResponseUtilities.cpp # Response utilities
│ └── GetMethod.cpp # GET method implementation
├── Connection/ # Connection management
│ ├── Connection.cpp # Connection handling
│ └── Connection.hpp # Connection class definition
├── CGI/ # CGI execution
│ └── Cgi.cpp # CGI script execution
├── SetupServer/ # Server setup
│ ├── MultipSockets.cpp # Multiple socket handling
│ ├── StartServerSetup.cpp # Server initialization
│ └── includes.hpp # Setup includes
├── Includes/ # Header files
├── www/ # Web root directory
│ ├── index.html # Default index page
│ └── html/ # Web content
│ ├── pepe/ # Test content
│ │ ├── v1/ # Version 1 content
│ │ ├── script.py # Python CGI script
│ │ └── script.php # PHP CGI script
│ └── ErrorPages/ # Custom error pages
└── nginx/ # Nginx configuration examples
- Linux operating system (for epoll support)
- GCC compiler with C++98 support
- Python 3 (for CGI scripts)
- PHP (for CGI scripts)
-
Clone the repository:
git clone <repository-url> cd webserv
-
Build the project:
make
-
Clean build artifacts:
make clean
-
Rebuild from scratch:
make re
The webserver uses TOML format for configuration. Create a config.toml file in the project root:
# Global settings
default_max_body_size = "123"
# Server block
[[server]]
host = "127.0.0.1"
port = [9090, 9091, 8080]
server_name = ["127.0.0.1:8080"]
max_body_size = "23"
# Error pages
[[server.error_pages]]
301 = "301.html"
400 = "400.html"
403 = "403.html"
404 = "404.html"
405 = "405.html"
500 = "500.html"
505 = "505.html"
# Route configuration
[[server.route]]
path = "/"
methods = ["GET", "POST", "DELETE"]
autoindex = true
index = "index.html"
root = "./www/html/pepe/v1"
CGI_extensions = {py = "/usr/bin/python3", php = "/usr/bin/php"}
upload = "./www/html/uploads/"
redirection = "lmao"| Option | Description | Default |
|---|---|---|
host |
Server host address | "127.0.0.1:port" |
port |
Server port(s) | [8080] |
server_name |
Server name(s) | [] |
max_body_size |
Maximum request body size | "123" |
path |
Route path | "/" |
methods |
Allowed HTTP methods | ["GET"] |
autoindex |
Enable directory listing | false |
index |
Default index file | "index.html" |
root |
Document root directory | "./www" |
CGI_extensions |
CGI script extensions and interpreters | {} |
upload |
Upload directory | "./uploads" |
redirection |
Redirect URL | "" |
-
With default configuration:
./webserv
-
With custom configuration:
./webserv config.toml
-
Basic HTTP request:
curl http://localhost:8080/
-
CGI script execution:
curl http://localhost:8080/script.py curl http://localhost:8080/script.php
-
File upload (if configured):
curl -X POST -F "file=@local_file.txt" http://localhost:8080/upload/ -
Different HTTP methods:
curl -X GET http://localhost:8080/ curl -X POST http://localhost:8080/ curl -X DELETE http://localhost:8080/
-
Main Loop (
main.cpp):- Server initialization
- Signal handling
- Configuration loading
-
Connection Manager (
Connection/):- Client connection handling
- Request/response lifecycle
- Timeout management
-
HTTP Parser (
HttpRequest/):- Request line parsing
- Header parsing
- Body handling
-
Response Generator (
HttpResponse/):- Status code generation
- Header construction
- Body formatting
-
CGI Executor (
CGI/):- Script execution
- Environment setup
- Output handling
The server uses Linux epoll for efficient I/O multiplexing:
// Epoll event loop
while (true) {
int n = epoll_wait(epollfd, events, MAX_EPOLL_EVENT, timeout);
for (int i = 0; i < n; i++) {
if (events[i].events & EPOLLIN) {
// Handle incoming data
}
if (events[i].events & EPOLLOUT) {
// Handle outgoing data
}
}
}-
Basic Functionality:
- Start the server
- Access via browser:
http://localhost:8080 - Verify static file serving
-
CGI Testing:
- Access Python script:
http://localhost:8080/script.py - Access PHP script:
http://localhost:8080/script.php - Verify script execution
- Access Python script:
-
Error Handling:
- Access non-existent file:
http://localhost:8080/notfound - Verify custom error pages
- Access non-existent file:
-
Method Testing:
- Test different HTTP methods
- Verify method restrictions
The project includes test scripts in the config_parser/tests/ directory for configuration parsing validation.
-
Port Already in Use:
# Check if port is in use netstat -tlnp | grep :8080 # Kill process using port sudo fuser -k 8080/tcp
-
Permission Issues:
# Make sure CGI scripts are executable chmod +x www/html/pepe/script.py chmod +x www/html/pepe/script.php -
Configuration Errors:
- Check TOML syntax
- Verify file paths exist
- Ensure proper indentation
The server includes debug output for:
- Request parsing
- Configuration loading
- Connection handling
- CGI execution
- GET: Retrieve resources
- POST: Submit data
- DELETE: Remove resources
- 200: OK
- 301: Moved Permanently
- 400: Bad Request
- 403: Forbidden
- 404: Not Found
- 405: Method Not Allowed
- 408: Request Timeout
- 413: Payload Too Large
- 500: Internal Server Error
- 505: HTTP Version Not Supported
REQUEST_METHODQUERY_STRINGCONTENT_LENGTHCONTENT_TYPESCRIPT_NAMEPATH_INFOHTTP_*headers
This project is part of the 42 school curriculum and follows the 42 coding standards.
- Saad ERRAOUI - Initial work (2024-12-22)
- BOUZID Hicham - Connection management and event handling
- Weismann - CGI, TOML Parser, Internal Logic and improvements
- 42 school for the project requirements
- Nginx for configuration inspiration
- Linux epoll documentation
- HTTP/1.1 RFC 2616 specification
Note: This webserver is designed for educational purposes and follows the 42 school coding standards. It implements core web server functionality while maintaining clean, readable code structure. This was made PURELY for the sake of learning about the internal work of servers, and not made for production