This project has been created as part of the 42 curriculum by bewong, jboon, jstuhrin.
webserv is a C++ HTTP/1.1 web server inspired by the behaviour of nginx.
The goal of the project is to understand how configs files are parsed and validated, how locations are looked up and corresponding routeviews are dispatched, and how a real web server accepts clients, parses HTTP requests, routes them through a configuration file, serves files, handles uploads, runs CGI programs, and keeps multiple connections alive without blocking the whole server.
The server is built around Linux epoll and non-blocking sockets. It can listen on one or more configured addresses, choose a server block from the request Host header, apply longest-prefix location matching, and generate HTTP responses for static files, directory listings, uploads, deletes, redirects, custom error pages, and CGI scripts.
- Description
- Features
- Project Architecture
- Configuration Overview
- Instructions
- Usage Examples
- Technical Choices
- Project Boundaries
- Resources
- AI Usage
- Module READMEs
This project implements a small but functional HTTP server in C++.
The server starts from a configuration file, validates it, creates one or more listening sockets, and enters an event loop. Incoming client connections are accepted in non-blocking mode. Each connection owns an HTTP parser and an output queue, so the server can keep reading requests and writing responses without blocking on slow clients.
At a high level, a request goes through the following flow:
client socket
↓
epoll event loop
↓
Connection
↓
HTTPParser + HTTPValidator
↓
ServerRegistry route lookup
↓
Router
↓
RequestHandler or CGI handler
↓
HTTPResponse / CGIResponse
↓
ordered output queue
↓
client socket
The server supports regular HTTP handling and CGI handling in the same connection pipeline. When a CGI request is encountered, the connection keeps a reserved response slot in the output queue. Later HTTP requests may already be parsed, but responses are still sent back in the correct HTTP order.
- HTTP/1.1 request parsing.
- Non-blocking sockets.
- Linux
epollbased event loop. - Multiple listening servers.
- IPv4 and IPv6 support.
- Keep-alive connections.
- Ordered HTTP pipelining support.
- Graceful connection closing with
Connection: close. - Request timeout handling with
timerfd.
- nginx-like configuration syntax.
http,server, andlocationblocks.listendirective.server_namedirective.rootdirective.aliasdirective.indexdirective.autoindexdirective.allowed_methodsdirective.client_max_body_sizedirective.returndirective.error_pagedirective.- CGI configuration through
cgiandcgi_extension. - Validation for duplicate location prefixes.
- Validation for invalid or unsupported configuration values.
- Server selection by IP, port, and
Hostheader. - Default server fallback.
- Longest-prefix location matching.
- Route-level method restrictions.
- Internal error-page dispatch.
- External error-page redirects.
GETregular files.- Directory index lookup.
- Directory autoindex generation.
- Directory trailing-slash redirect.
- MIME type selection.
Last-Modifiedheader support.- Path traversal protection.
- Symlink/base-directory escape protection through canonical path checks.
POSTuploads request bodies to files.- Large/chunked bodies can be stored through a temporary file path before finalizing.
DELETEremoves regular files.- Permission checks for read, write, and execute access.
client_max_body_sizeenforcement.
- CGI route detection.
- CGI script resolution by configured extension.
- CGI execution with
fork/execve. - CGI environment construction.
- Request body forwarding to CGI process.
- CGI response parsing.
- CGI local redirect handling.
- CGI timeout/error handling.
- CGI process tracking through
ConnectionRegistry.
- Simple session creation/reuse.
session_idcookie support.- Cookie attributes such as
Path=/,HttpOnly, andSameSite=Lax. - Expired session cleanup.
The diagrams below give a visual overview of the server design. Store these images in docs/ so the relative links work from the repository root.
A typical configuration file may look like this:
http {
index index.html;
client_max_body_size 1m;
autoindex off;
server {
listen 8080;
server_name localhost;
root ./www;
index index.html;
allowed_methods GET POST DELETE;
error_page 404 /404.html;
error_page 500 /500.html;
cgi_extension .py /usr/bin/python3;
cgi_extension .sh /bin/bash;
location / {
root ./www;
index index.html;
autoindex on;
allowed_methods GET;
}
location /upload {
root ./www;
allowed_methods POST;
}
location /delete {
root ./www;
allowed_methods DELETE;
}
location /cgi-bin {
root ./www/cgi-bin;
cgi on;
allowed_methods GET POST;
}
location /redirect {
return 301 /;
}
}
}This project is intended for a Linux environment because it uses Linux-specific APIs such as:
epoll;timerfd;- non-blocking sockets;
fork/execvefor CGI.
You need:
- a C++ compiler with C++17 support;
make;- standard Linux development headers;
- optional interpreters for CGI routes, for example
python3orbash.
| Command | Description |
|---|---|
make |
Build the main webserv executable |
make debug |
Build webserv with debug symbols and DEBUG enabled |
make sanitize |
Build webserv with sanitizers enabled |
make test |
Build and run the unit tests |
make cgi_test |
Build the CGI integration test executable |
make cgi_clean |
Remove CGI test objects and binary |
make clean |
Remove object files and dependency files |
make fclean |
Remove all generated binaries and build files |
make re |
Clean everything and rebuild from scratch |
- For
make cgi_test, you can add optional flagFORK_COUNTPAIR_COUNTDUP_COUNT. By default, all sets toFORK_COUNT=10PAIR_COUNT=10DUP_COUNT=10
Run the server with a configuration file:
./webserv path/to/config.confExample:
./webserv ./configs/default.confThe config loader pipeline offers some tools that can help debug a config file:
- flag --print-tokenlist will print a list of all tokens extracted from the config file,
- flag --print-AST will print the AST,
- flag --config-debug will print the config file with all error tokens highlighted in red.
Example:
./webserv configs/multi-server.conf --config-debug
Run the integration test with bash scripts:
make fclean
make
bash tests/bash/run_all.sh Run only a specific integration test
make fclean
make
bash tests/bash/numberOfTheTestInBashDirectoryUse Ctrl+C in the terminal where the server is running.
The following examples assume the server is listening on port 8080.
curl -i http://localhost:8080/curl -i http://localhost:8080/index.htmlIf /dir is a directory, the server should redirect to /dir/:
curl -i http://localhost:8080/dircurl -i -X POST \
-H "Content-Type: text/plain" \
--data-binary @./local-file.txt \
http://localhost:8080/upload/local-file.txtExpected result:
201 Createdif the file did not exist;204 No Contentif the file was overwritten;413 Payload Too Largeif the body is larger thanclient_max_body_size.
curl -i -X DELETE http://localhost:8080/delete/file.txtExpected result:
204 No Contenton success;404 Not Foundif the file does not exist;403 Forbiddenif the target is not allowed.
curl -i -c /tmp/webserv_cookies.txt http://localhost:8080/
curl -i -b /tmp/webserv_cookies.txt http://localhost:8080/curl -i http://localhost:8080/cgi-bin/script.pyFor a POST CGI request:
curl -i -X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
--data "name=webserv" \
http://localhost:8080/cgi-bin/script.pyprintf 'GET / HTTP/1.1\r\nHost: localhost\r\n\r\nGET /index.html HTTP/1.1\r\nHost: localhost\r\n\r\n' | nc localhost 8080Useful curl flags:
-i show response headers
-v verbose connection/debug output
-X METHOD set HTTP method
-H HEADER add request header
--data-binary send raw body bytes
--path-as-is do not normalize path on curl side
-c file save cookies
-b file send cookies
-L follow redirectsThe server uses one event loop to monitor many file descriptors. This avoids creating a thread for every client and keeps the design closer to production event-driven servers.
Sockets are non-blocking so that one slow client, slow upload, or slow CGI process does not stop the rest of the server.
Each connection has an output queue. This is important for partial writes and HTTP pipelining. A response may be generated immediately, partially sent, or blocked behind an earlier CGI response slot.
The route is matched after request headers are parsed. This allows the server to apply route-specific settings, such as client_max_body_size, before reading the body.
Small request bodies can be stored in memory. Large or chunked bodies can be streamed into a temporary file and moved into place only after the full request is accepted.
Filesystem paths are canonicalized and checked against the configured base directory. This protects against path traversal and symlink escapes.
For an internal error page such as:
error_page 404 /404.html;The server creates an internal GET request to render the configured page, while preserving the original error status code if the page is served successfully.
This project is an educational HTTP server, not a complete nginx replacement.
Implemented or partially implemented scope includes:
- parsing and validating config files;
- matching locations and dispatching routeviews;
- HTTP/1.1 request parsing;
- static file serving;
- GET, POST, and DELETE;
- configuration-based routing;
- redirects;
- custom error pages;
- autoindex;
- CGI execution;
- cookies and basic sessions;
- non-blocking I/O and connection timeouts.
Out of scope:
- HTTPS/TLS;
- HTTP/2 or HTTP/3;
- reverse proxying;
- WebSocket support;
- advanced caching;
- gzip/brotli compression;
- virtual filesystem abstractions;
- production-grade access logs and metrics;
- full nginx configuration compatibility.
The following references were useful for understanding the concepts behind this project.
- Internet Sockets
- HTTP Comparison
- Internet Sockets
- Socket application designs
- Beej's Guide to Network Programming
- The TCP/IP Guide
- Linux man page: socket(2)
- Linux man page: bind(2)
- Linux man page: listen(2)
- Linux man page: accept(2)
- Linux man page: epoll(7)
- Linux man page: fcntl(2)
- Linux man page: read(2)
- Linux man page: write(2)
- nginx Beginner's Guide
- nginx
locationdirective documentation - nginx
rootdirective documentation - nginx
aliasdirective documentation
AI tools were used as a development assistant during the project.
AI was used for:
- explain project concepts;
- help generate the architecture image
Good areas to inspect during evaluation:
- how configuration is parsed and validated;
- how server blocks and location blocks are stored in
ServerRegistry; - how longest-prefix route matching works;
- how path traversal is prevented;
- how body storage switches between memory and temporary files;
- how the connection output queue preserves HTTP response order;
- how CGI processes are registered, monitored, and converted back into HTTP responses;
- how custom error pages are applied without losing the original status code.







