Skip to content

LowLevelLover/mini-http-server

Repository files navigation

progress-banner

This is a starting point for Python solutions to the "Build Your Own HTTP server" Challenge.

HTTP is the protocol that powers the web. In this challenge, you'll build a HTTP/1.1 server that is capable of serving multiple clients.

Along the way you'll learn about TCP servers, HTTP request syntax, and more.

Note: If you're viewing this repo on GitHub, head over to codecrafters.io to try the challenge.


Simple HTTP Server

A basic asynchronous HTTP server implemented in Python using the asyncio library. The server handles GET and POST requests for echoing text, retrieving user-agent information, and managing files in a specified directory.

Features

  • Root Endpoint (/): Returns a 200 OK response.
  • Echo Endpoint (/echo/{text}): Echoes back the provided text with optional gzip compression if supported by the client.
  • User-Agent Endpoint (/user-agent): Returns the client's User-Agent header value.
  • File Endpoints (/files/{filename}):
    • GET: Retrieves a file from the specified directory, with optional gzip compression.
    • POST: Creates or overwrites a file in the specified directory with the request body content.
  • Error Handling: Returns 404 Not Found for invalid endpoints or missing files.
  • Logging: Logs client connections, requests, and errors with timestamps.

Requirements

  • Python 3.10+
  • No external dependencies required (uses standard library modules: asyncio, socket, gzip, pathlib, logging)

Installation

  1. Clone or download the repository.
  2. Ensure Python 3.10 or higher is installed.

Usage

Run the server using the command below. Optionally, specify a directory for file operations:

./your_program.sh [--directory <path>]
  • Without directory: The /files/* endpoints will return 404 for GET requests and raise an error for POST requests.
  • With directory: Provide a path for file storage/retrieval (e.g., /tmp/files).

Example:

./your_program.sh --directory /tmp/files

The server listens on localhost:4221 by default.

Example Requests

  • Root:

    curl http://localhost:4221/

    Response: HTTP/1.1 200 OK

  • Echo:

    curl http://localhost:4221/echo/hello

    Response: hello (with Content-Type: text/plain)

    With compression:

    curl -H "Accept-Encoding: gzip" http://localhost:4221/echo/hello --compressed
  • User-Agent:

    curl -A "Mozilla/5.0" http://localhost:4221/user-agent

    Response: Mozilla/5.0

  • File GET (with --directory /tmp/files):

    curl http://localhost:4221/files/example.txt

    Response: Contents of /tmp/files/example.txt or 404 if not found.

  • File POST (with --directory /tmp/files):

    curl -X POST --data "Hello, World!" http://localhost:4221/files/example.txt

    Response: HTTP/1.1 201 Created (creates /tmp/files/example.txt).

Code Structure

  • HttpReqLine: Parses the HTTP request line (e.g., GET /path HTTP/1.1).
  • HttpHeaders: Handles HTTP headers as a dictionary-like object.
  • HttpRequest: Represents a parsed HTTP request with method, path, headers, and body.
  • HttpResponse: Constructs HTTP responses with status, headers, and body (supports gzip compression).
  • Handlers:
    • echo_handler: Returns the provided text.
    • user_agent_handler: Returns the client's User-Agent.
    • files_get_handler: Retrieves a file.
    • files_post_handler: Saves a file.
  • Main Loop: Uses asyncio to handle client connections concurrently.

Configuration

  • HOST: localhost (default)
  • PORT: 4221 (default)
  • BUFF_SIZE: 1024 bytes for receiving data
  • Directory: Optional, specified via --directory argument

Logging

The server logs:

  • Client connections and disconnections
  • Received requests
  • Errors (with stack traces)

Example log output:

2025-04-11 18:09:10,420 [SERVER STARTED] Listening on localhost:4221
2025-04-11 18:09:21,940 [CONNECTED] 127.0.0.1:47920
2025-04-11 18:09:21,940 [RECEIVED from 127.0.0.1:47920] b'GET /echo/abc HTTP/1.1\r\nHost: localhost:4221\r\nUser-Agent: curl/8.12.1\r\nAccept: */*\r\nAccept-Encoding: invalid-encoding\r\n\r\n'
2025-04-11 18:09:21,941 [DISCONNECTED] 127.0.0.1:47920

Limitations

  • Minimal error handling for malformed requests.
  • No support for advanced HTTP features (e.g., chunked encoding, keep-alive).
  • File operations are synchronous and may block the event loop for large files.
  • Single-threaded; relies on asyncio for concurrency.

Testing

Test the server using tools like curl, wget, or a browser. For automated testing, consider a framework like pytest with an HTTP client library (e.g., aiohttp).

Example test command:

curl http://localhost:4221/echo/test

Contributing

Contributions are welcome! Please:

  1. Fork the repository.
  2. Create a feature branch.
  3. Submit a pull request with clear descriptions.

License

This project is licensed under the MIT License. See the LICENSE file for details.

About

Mini HTTP Server from Code Crafters

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published