Webserv
42 Abu Dhabi

Webserv

HTTP Web Server Implementation

2 months
3
C++HTTP ProtocolSocket ProgrammingFile DescriptorsConfiguration Parsing

The Webserv project at 42 Abu Dhabi involved creating a fully functioning HTTP web server from scratch using C++. This project required deep understanding of how web servers work, including handling HTTP requests, serving static files, and generating dynamic content. One of the key learning outcomes was mastering the concept of file descriptor (fd) queues for managing multiple client connections simultaneously. Additionally, we delved into the intricacies of HTTP protocols, including GET and POST methods, as well as parsing and managing configuration files for server behavior. This project not only solidified my knowledge of network programming but also provided valuable experience in building scalable and efficient server-side applications.

Key Features

HTTP Request Handling

Complete implementation of HTTP GET and POST methods with proper request parsing, validation, and response generation following HTTP/1.1 standards.

File Descriptor Queues

Sophisticated fd queue management system for handling multiple simultaneous client connections efficiently without blocking operations.

Static File Serving

Efficient static file serving capabilities with MIME type detection and proper content delivery for various file formats.

Configuration Management

Flexible configuration file parsing system allowing customization of server behavior, ports, routes, and various settings.

Multi-Client Support

Concurrent handling of multiple client connections with efficient resource management and scalable architecture design.

Error Handling

Robust error handling system with proper HTTP status codes, error pages, and graceful failure management.

Development Journey

Phase 1

Architecture Design

Designed the server architecture, defined the HTTP protocol implementation strategy, and established the file descriptor management system.

Phase 2

Core Server Implementation

Implemented the basic HTTP server functionality with socket programming, request parsing, and response generation capabilities.

Phase 3

Advanced Features

Added file descriptor queues for multi-client support, configuration file parsing, and static file serving capabilities.

Phase 4

Testing & Optimization

Conducted comprehensive testing, performance optimization, error handling improvements, and scalability enhancements.

Challenges & Solutions

File Descriptor Management

Problem:

Implementing efficient fd queues for handling multiple simultaneous client connections without blocking operations or resource leaks.

Solution:

Developed a sophisticated queue system that manages file descriptors efficiently, allowing the server to handle multiple clients concurrently with proper resource cleanup.

HTTP Protocol Implementation

Problem:

Understanding and correctly implementing HTTP/1.1 protocol specifications from scratch with proper request parsing and response generation.

Solution:

Deep study of HTTP specifications and careful implementation of request parsing, response generation, and protocol compliance with comprehensive testing.

Configuration System

Problem:

Creating a flexible configuration system that allows customization of server behavior while maintaining simplicity and robustness.

Solution:

Built a robust parser that handles various configuration options for server ports, routes, and behavior settings with proper error handling.

http_request.cpp
cpp
// HTTP request parsing implementation
class HTTPRequest {
    std::string method;
    std::string uri;
    std::string version;
    std::map<std::string, std::string> headers;
    std::string body;

public:
    bool parseRequest(const std::string& rawRequest) {
        std::istringstream stream(rawRequest);
        std::string line;
        
        // Parse request line
        if (std::getline(stream, line)) {
            std::istringstream lineStream(line);
            lineStream >> method >> uri >> version;
        }
        
        // Parse headers
        while (std::getline(stream, line) && !line.empty()) {
            size_t colonPos = line.find(':');
            if (colonPos != std::string::npos) {
                std::string key = line.substr(0, colonPos);
                std::string value = line.substr(colonPos + 2);
                headers[key] = value;
            }
        }
        
        return !method.empty() && !uri.empty();
    }
};

// File descriptor queue for managing connections
class FDQueue {
    std::queue<int> availableFDs;
    std::map<int, ClientConnection> activeConnections;
    
public:
    int getNextFD() {
        if (!availableFDs.empty()) {
            int fd = availableFDs.front();
            availableFDs.pop();
            return fd;
        }
        return -1;
    }
    
    void releaseFD(int fd) {
        if (activeConnections.find(fd) != activeConnections.end()) {
            activeConnections.erase(fd);
            availableFDs.push(fd);
            close(fd);
        }
    }
};