Skip to main content

Basic Web Server

A small HTTP/1.1 web server written from scratch in Python for educational purposes.

Purpose

The goal of this project is to understand what happens underneath higher-level Python web frameworks and production web servers. Instead of relying on an existing HTTP server implementation, the project builds the core request/response cycle directly on top of Python's TCP socket API.

The focus is therefore not on competing with production servers, but on learning and demonstrating the fundamentals of:

  • TCP socket creation, binding, listening, accepting, receiving, and sending;
  • HTTP/1.1 request framing and parsing;
  • persistent connections and multiple requests on one TCP connection;
  • request and response validation;
  • multithreaded client handling;
  • error classification and connection recovery;
  • configurable timeouts, request limits, and logging;
  • automated testing of normal and failure paths.

Current capabilities

The current implementation can:

  • create an IPv4 TCP listening socket on a configurable host and port;
  • accept multiple clients and handle each connection in a separate thread;
  • parse HTTP/1.1 request lines, headers, query strings, and request bodies;
  • require and validate the HTTP/1.1 Host header;
  • preserve repeated request and response headers;
  • frame request bodies using Content-Length;
  • keep a TCP connection open for subsequent requests when it is safe to do so;
  • honor Connection: close from the client;
  • convert a simple Python application return value into an HTTP response;
  • accept application results in the forms body, (body, status_code), or (body, status_code, headers);
  • automatically generate Content-Length for responses;
  • return controlled HTTP error responses for malformed, timed-out, oversized, or unsupported requests;
  • distinguish recoverable HTTP errors from framing errors that require the TCP connection to be closed;
  • isolate application failures and return 500 Internal Server Error without exposing the original exception to the client;
  • handle common socket, server startup, accept(), recv(), sendall(), and thread-start failures;
  • log server activity and errors to both the terminal and a configurable log file;
  • validate server configuration before startup;
  • provide an interactive terminal console with help, status, clients, config, run, stop, quit, clear, logs, and version commands.

The server currently includes explicit reason phrases for the status codes used internally (200, 201, 400, 404, 408, 413, 500, and 505). Other valid status codes can still be used by an application, but no reason phrase is added unless it exists in the server's status table.

Minimal example

from basic_web_server import Server, ServerConfig


def application(request):
    return (
        "Hello from Basic Web Server!",
        200,
        {"Content-Type": "text/plain; charset=utf-8"},
    )


config = ServerConfig()
server = Server(application, config)
server.start_console()

After starting the console, use the run command to choose the listening address and port.

The application callable receives a Request object containing the parsed method, target, path, query string, headers, and raw body.

Configuration

ServerConfig currently exposes:

  • client_timeout — timeout while receiving data from a connected client;
  • accept_timeout — timeout used by the listening socket so shutdown can be checked regularly;
  • recv_buffer_size — maximum number of bytes requested by each recv() call;
  • max_request_size — maximum accepted request size;
  • log_file — destination file for server logs;
  • log_level — standard Python logging level used by the server.

Invalid configuration values raise ConfigurationError during configuration creation, before the server starts.

Error handling

The project deliberately separates errors by responsibility.

HTTP-level errors are converted into HTTP responses. If the current request boundary is still known, the connection may remain usable. If request framing becomes unreliable—for example because of an invalid Content-Length, an incomplete request, or an oversized request—the server sends an error response with Connection: close and stops using that TCP stream.

Transport-level failures such as socket receive errors are treated differently: the connection is closed without attempting to continue HTTP communication. Application errors are logged on the server and converted into a generic 500 Internal Server Error response.

This separation is one of the main learning goals of the project: an HTTP error, an application error, and a TCP/socket failure are not the same kind of failure and should not be handled identically.

Intentional limitations

This project is a learning-oriented server, not a production-ready HTTP implementation. In its current form it does not provide, among other things:

  • HTTPS/TLS;
  • HTTP/2 or HTTP/3;
  • HTTP/1.0 compatibility;
  • chunked transfer encoding;
  • streaming request or response bodies;
  • compression or content negotiation;
  • routing, middleware, templates, sessions, cookies, authentication, or static-file serving as framework features;
  • asynchronous I/O or a configurable worker/thread pool;
  • production-grade protection against slow clients, denial-of-service attacks, or all HTTP request-smuggling/framing edge cases;
  • complete RFC-level HTTP syntax validation;
  • graceful process management, daemonization, hot reload, or zero-downtime restarts.

For these reasons it should not be exposed as an internet-facing production server in its current state.

Possible future development

The codebase can be extended in several directions depending on whether the project remains educational or evolves toward a more capable server. Useful next steps could include:

  • more complete HTTP/1.1 compliance and header/token validation;
  • support for chunked transfer encoding;
  • streaming bodies and responses instead of buffering complete messages in memory;
  • configurable header-size and body-size limits;
  • improved connection lifecycle and graceful shutdown behavior;
  • a worker pool or asynchronous architecture for higher concurrency;
  • TLS support;
  • richer request metadata and URL parsing;
  • routing and middleware abstractions;
  • static-file handling;
  • more configurable logging and log rotation;
  • packaging and command-line entry points for easier installation and startup;
  • interoperability and fuzz testing against a wider range of HTTP clients and malformed requests.

Some of these additions would intentionally move the project closer to a framework or production server. Others—especially stricter protocol handling, streaming, concurrency experiments, and additional tests—would preserve its value as a focused study of web-server internals.

Testing

The repository contains a pytest-based test suite covering request parsing, response construction, configuration, connection handling, server lifecycle behavior, error paths, and logging-related behavior.

Run the tests from the project root with:

pytest

For development dependencies:

pip install -e ".[dev]"

Project status

The current version is 0.1.0. It represents a functional educational HTTP/1.1 server with deliberate scope limitations and a strong emphasis on explicit control flow, understandable architecture, error handling, and tests.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lema_basic_web_server-0.1.0.tar.gz (21.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lema_basic_web_server-0.1.0-py3-none-any.whl (15.0 kB view details)

Uploaded Python 3

File details

Details for the file lema_basic_web_server-0.1.0.tar.gz.

File metadata

  • Download URL: lema_basic_web_server-0.1.0.tar.gz
  • Upload date:
  • Size: 21.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for lema_basic_web_server-0.1.0.tar.gz
Algorithm Hash digest
SHA256 61711dab011c4dd67b92cfbf9576b516b4f06c9a8e9dd983952e79cfa3a2a948
MD5 2b264c13558fe79cf40b3524a7edb421
BLAKE2b-256 dac89a54033db6d3f21815f0147933d555687a113d90abf296e5794f1f8c5912

See more details on using hashes here.

Provenance

The following attestation bundles were made for lema_basic_web_server-0.1.0.tar.gz:

Publisher: publish.yml on lema2000-dev/basic_web_server

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file lema_basic_web_server-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for lema_basic_web_server-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3ca4bb9f6df05e2c3bef44ba577b01563c3f565ac48862dbc533f759e66374cf
MD5 7fcf873ceefda7eeadeab892877383aa
BLAKE2b-256 1085996768e4ca6877e3c63c834f3ed3ca0c834d0b5eacbff48d641ca0ad1fb6

See more details on using hashes here.

Provenance

The following attestation bundles were made for lema_basic_web_server-0.1.0-py3-none-any.whl:

Publisher: publish.yml on lema2000-dev/basic_web_server

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page