Skip to content

Implementing an HTTP/1.1 server in C++98 that supports configuration files and handles GET, POST, and DELETE requests

Notifications You must be signed in to change notification settings

deniz-oezdemir/Webserv

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

C++ Nginx Linux HTTP CGI Criterion Git GitHub Rust Python JavaScript

Webserv

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.

Table of Contents

Summary

Basic Requirements

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.

Bonus πŸŽ‰

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.

Extras ✨

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.

Class Diagram

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
Loading

Usage πŸš€

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]

Flags

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

Execute Tests πŸ§ͺ

We implemented comprehensive unit testing using Criterion. Our tests cover critical components and edge cases, ensuring high code quality and reliability.

Run all tests

make test

Run specific test

make test T=SpecificTestName

Configuration File πŸ› οΈ

General Directives

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.

General Server Directives

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.

Location-Specific Directives

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.

Simple Testing πŸ”

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

Stress Testing πŸ‹οΈ

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/

Sources

General

  1. RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1
  2. 42 Resources - Webserv
  3. The computerscience book, pp. 117-120: High-level explanation of the HTTP client-server model
  4. How the web works: HTTP and CGI explained or with annotations
  5. CGI by IBM
  6. Basic CGI tutorial in C++
  7. Tiny server written in C++
  8. Evaluation sheet
  9. Sockets and network programming in C
  10. Basic webserver with Rust
  11. Siege, testing tool
  12. About sockaddr_in and sockaddr with bind()
  13. About header whitespaces
  14. Criterion Documentation

Repositories

  1. Kaydooo/Webserv_42
  2. nicolasgasco/42_webserv
  3. mariiamakura/webserv

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).

About

Implementing an HTTP/1.1 server in C++98 that supports configuration files and handles GET, POST, and DELETE requests

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •