This is our solution for the Webserv project of 42 School Berlin.
π₯ Team: Manuel Migoya, Sebastian Navarro, and Deniz Γzdemir.
β³ Timeline: 1.5 months.
π Grade: 125/100
webserv-demo.mp4
Above is a brief video demonstration of our server (server no. 7 in the default config) serving the Instaclone website, which has a picture size limit of 3MB.
- Summary
- Class Diagram
- Usage π
- Configuration File π οΈ
- Simple Testing π
- Stress Testing ποΈ
- Sources
Webserv is a minimal implementation of a web server, loosely following the nginx
approach. The subject requires the server to:
- Handle multiple client requests simultaneously using non-blocking I/O operations and the
poll()
system call (or equivalent). - Serve static websites.
- Handle CGIs.
- Manage file uploads.
- Listen on multiple ports.
- Never crash and handle all errors according to RFC standards.
In addition to the mandatory requirements, we implemented several bonus features to enhance our web server:
- Cookies and Session Management: Allows for more complex web applications requiring user state persistence.
- Multiple CGI Scripts: Enables dynamic content generation with languages like Python, JavaScript, and Rust.
Besides the bonus features, we added several extra functionalities:
- Test Suite: Utilized Criterion for thorough testing. Warning: this does not follow the subject requirements, as it needs cpp11.
- Custom Logger: Implemented a detailed, level-based logging system.
- Syntax Checks: Added a lot more syntax checks for HTTP requests than what the subject requires.
The following diagram illustrates the relationships and key methods of the main classes:
classDiagram
class ServerInput {
parseArg_()
}
class ServerConfig {
parseFile()
isConfigOK()
}
class ServerEngine {
Server[] servers_
Client[] clients_
initServerPollFds_()
initializePollEvents_()
processPollEvents_()
}
class Server {
init()
}
class Client {
readClientBuffer_()
}
class ConfigParser {
checkValues()
}
class ConfigValue {
getType()
}
class HttpErrorHandler {
getErrorPage()
}
class HttpMethodHandler {
handleRequest()
handleCgiRequest_()
}
class HttpRequest {
get...()
set...()
normalizeRequest_()
}
class HttpResponse {
set...()
toString()
}
ServerEngine --> Client : manages
ServerEngine --> Server : initializes
ServerEngine --> HttpMethodHandler : uses
Server --> ServerConfig : uses
Client --> HttpRequest : uses
HttpResponse --> HttpErrorHandler : uses
HttpMethodHandler --> HttpRequest : uses
HttpMethodHandler --> HttpResponse : creates
ServerConfig --> ConfigParser : uses
ServerConfig --> ServerInput : uses
ServerConfig --> ConfigValue : uses
In order to test our Webserv implementation, clone and make it.
git clone https://github.com/deniz-oezdemir/Webserv.git
cd Webserv
make
You can start by using the default config provided. This config has seven virtual servers listening on ports 8081 to 8087. We recommend starting with http://localhost:8087/
, our humble Instagram clone.
./webserv [OPTIONAL: flags] [OPTIONAL: config_file]
Flag | Description |
---|---|
-h, --help | Display help message |
-v, --version | Display WebServ version |
-V, --Version | Display WebServ version and extra info |
-t, --test | Check the configuration file and exit the server |
-T, --Test | Check and print the configuration file, then exit the server |
We implemented comprehensive unit testing using Criterion. Our tests cover critical components and edge cases, ensuring high code quality and reliability.
make test
make test T=SpecificTestName
Directive | Description |
---|---|
error_log |
Define the log level (debug, info, error) |
worker_processes |
Specifies the number of worker processes. |
worker_connections |
Specifies the maximum number of connections per worker process. |
Directive | Description |
---|---|
listen |
Specifies the port and optionally the host that the server listens on. |
server_name |
Defines the server name or domain name that this server block handles. |
error_page |
Sets custom error pages for specified HTTP error codes. |
client_max_body_size |
Limits the maximum size of the client request body. |
root |
Defines the root directory for serving files. |
index |
Specifies the default file to serve when a request is made to a directory. |
Directive | Description |
---|---|
root |
Sets the root directory for requests matching the location block. |
index |
Specifies the default file to serve if the request is a directory. |
limit_except |
Restricts allowed HTTP methods for the specified location. |
return |
Sets up HTTP redirection for the specified location. |
autoindex |
Enables or disables directory listing for the specified location. |
client_max_body_size |
Limits the maximum size of the client request body for a specific location. |
upload_store |
Specifies the directory where uploaded files should be saved. |
cgi |
Specifies the CGI extension script and the binary path to execute. e.g., cgi .py /usr/bin/python3 . |
The easiest way to test is going to http://localhost:8087/
with your browser. For more rigorous tests:
curl --resolve dog.com:8085:127.0.0.1 http://dog.com:8085/
curl --resolve dad.com:8086:127.0.0.1 http://dad.com:8086/
Or use telnet
and paste a request. There are some example requests in the test
directory. Remember to include the empty line at the end.
telnet localhost 8087
You can test non-blocking behavior from multiple terminal clients with different messages like yes "Example message 1" | telnet localhost 8080
To test the performance and measure its response under load, you use the siege
command. Here's an example of how to use it:
siege -c 255 -t 10s http://127.00.00:8080/
In this command, the options -c
and -t
are used to specify the number of concurrent users and the duration of the test. The URL http://127.00.00:8080/
should be replaced with the actual URL of your server.
Siege does not properly close client connections for time-based testing. But it does so when using a set number of connections:
siege -r 10 -c 255 http://127.00.00:8080/
- RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1
- 42 Resources - Webserv
- The computerscience book, pp. 117-120: High-level explanation of the HTTP client-server model
- How the web works: HTTP and CGI explained or with annotations
- CGI by IBM
- Basic CGI tutorial in C++
- Tiny server written in C++
- Evaluation sheet
- Sockets and network programming in C
- Basic webserver with Rust
- Siege, testing tool
- About sockaddr_in and sockaddr with bind()
- About header whitespaces
- Criterion Documentation
If you have any doubt about the project, or 42 in general, do not hesitate to contact us. You can do so via our emails listed in our GitHub profiles or via Slack, if you are a 42 student (denizod, jmigoya-, johnavar).