Skip to main content
>Ayoub Elmohamedi
SYSTEMS 05

Webserv

Completed (42 Curriculum)

An RFC-compliant HTTP/1.1 web server engineered from scratch in C++ using nonblocking POSIX sockets and multiplexed I/O.

LanguageC++98 (Strict Standard)
I/O MultiplexingPOSIX poll() / select()
Execution ModelSingle-Threaded Event Loop
Repositorygithub.com/webserv

01The Systems Challenge

As part of the 1337 / 42 school curriculum, Webserv required building a fully functional HTTP/1.1 server from the ground up without using any external web libraries, frameworks, or modern C++ convenience abstractions.

The primary architectural challenge was ensuring the entire server process never blocked on any socket or file descriptor. A slow or malicious client transmitting one byte every few seconds must never stall other concurrent connections, degrade throughput, or exhaust server resources.

02Request Lifecycle & State Machine

The diagram below illustrates how connections flow through the single-threaded multiplexer.

FIGURE 02 // WEBSERV EVENT LOOP & REQUEST LIFECYCLEverified 42 implementation
  +───────────────────────────────────────────────────────────────+
  │                  NONBLOCKING EVENT MULTIPLEXER                │
  │                  POSIX poll() / select() loop                 │
  +───────────────────────────────┬───────────────────────────────+
                                  │
             ┌────────────────────┴───────────────────┐
             ▼                                        ▼
    [POLLIN on Listen Socket]               [POLLIN on Client Socket]
             │                                        │
    accept() nonblocking                     recv() nonblocking chunk
    create ClientContext                              │
                                                      ▼
                                       +─────────────────────────────+
                                       │   HTTP/1.1 STATE MACHINE    │
                                       │  - Parse Request Line       │
                                       │  - Parse Headers map        │
                                       │  - Handle chunked/transfer  │
                                       +──────────────┬──────────────+
                                                      │
                                                      ▼
                                       [Route & Virtual Host Match]
                                                      │
                       ┌──────────────────────────────┴──────────────────────────────┐
                       │                                                             │
                       ▼                                                             ▼
             [Static File Request]                                         [CGI Script Request]
                       │                                                             │
             Open file nonblocking                                         fork() child process
             Stream chunks to buffer                                       dup2() stdin/stdout pipes
                       │                                                   execve() script runner
                       │                                                             │
                       └──────────────────────────────┬──────────────────────────────┘
                                                      │
                                                      ▼
                                         [POLLOUT on Client Socket]
                                         send() buffered response
                                         close / keep-alive timeout

* Every step in the connection lifecycle is strictly nonblocking. Socket readiness drives state transitions without worker threads or blocking I/O calls.

03Architecture & Core Components

1. Multiplexed Event Loop

The server maintains an array of monitored file descriptors passed to poll(). Sockets are flagged with O_NONBLOCK via fcntl(). When an event fires, the loop dispatches to the corresponding socket context without spawning worker threads.

2. Deterministic State Machine Parser

Because network data arrives in arbitrary fragmentation, the HTTP parser operates as a resumable state machine:

  • REQUEST_LINE: Extracts HTTP method (GET, POST, DELETE), URI, and protocol version.
  • HEADERS: Parses key-value header mappings, validating Host headers and Content-Length.
  • BODY / CHUNKED: Handles chunked transfer encoding (Transfer-Encoding: chunked) by parsing hex chunk lengths until the terminating 0-chunk.

3. CGI Execution Pipeline

Dynamic content (e.g., Python or PHP scripts) is executed by creating child processes using fork() and execve(). File descriptors are remapped with dup2() to unidirectional POSIX pipes, allowing the parent server to stream request bodies to CGI stdin and nonblockingly read generated HTML from CGI stdout.

04Tradeoffs & Constraints

Writing in C++98 meant no std::unique_ptr, no move semantics, and no standard threading library. Resource management relied on strict RAII patterns to guarantee that open file descriptors, dynamically allocated connection buffers, and child processes were properly closed and waited on during timeout or disconnect events.

05Verification & Delivery Status

Webserv was thoroughly evaluated under peer review and automated stress-testing using tools like Siege to verify that the server does not leak memory or hang under sustained load. The full source code and configuration syntax are available on GitHub.