Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Multi-threaded HTTP Server (from-scratch)

A small educational HTTP server implemented in Python using raw sockets and a simple thread pool. It serves static files from the resources/ folder, accepts JSON uploads, and can stream a ZIP bundle of non-HTML resources on demand.

This repo is intended for learning and light testing — not production use.


Quick overview

  • Language: Python 3
  • Entry point: server.py
  • Static content directory: resources/
  • Uploads are stored under resources/uploads/
  • Default host: 127.0.0.1, default port: 8080
  • Thread pool size: configurable (default 10)

Key design points:

  • Simple socket-based HTTP parser and handlers in http_handler.py.
  • Streaming ZIP creation for the /download_all endpoint to avoid large memory usage.
  • Minimal dependencies (standard library only).

Files of interest

  • server.py — main server; reads command-line args (port, host, max_threads), accepts connections and dispatches them to the thread pool.
  • http_handler.py — request parser and request handlers (handle_get, handle_post). Handles static files, downloads, and uploads.
  • thread_pool.py — tiny thread pool implementation used by the server.
  • utils.py — small helpers (logging, safe path resolution, date formatting, upload filename generation).
  • resources/ — HTML, images, text samples and other static files. resources/uploads/ contains JSON files saved via POST.

Run (development)

  1. Make sure you are running Python 3.8+.
  2. From the project root, run:
python3 server.py

Optional arguments:

  • python3 server.py 9090 — start on port 9090 instead of 8080.
  • python3 server.py 8080 0.0.0.0 — specify port and bind host.
  • python3 server.py 8080 127.0.0.1 20 — port, host, max threads.

Server logs are printed to stdout. Use Ctrl+C to stop.

If you see OSError: [Errno 48] Address already in use when binding, another process is using that port. To find/stop it on macOS:

lsof -i :8080
kill -9 <PID>
# Or run the server on a different port:
python3 server.py 9090

HTTP endpoints and examples

Note: the server accepts basic HTTP methods (GET, HEAD, POST). Responses include standard headers and status codes.

  1. Serve static files (HTML, images, text)
  • GET / or /index.html — serves resources/index.html.
  • GET /about.html, /contact.html, or any other file under resources/ — returns the file when permitted.

Example (download an image):

curl -I http://127.0.0.1:8080/mikasa.jpeg   # HEAD to inspect headers
curl http://127.0.0.1:8080/mikasa.jpeg -o mikasa.jpeg

Supported binary extensions (configured in http_handler.py): .png, .jpg, .jpeg, .txt (these are served as attachment with Content-Disposition by default).

  1. Download all non-HTML resources as a ZIP
  • GET /download_all or /download-all — server creates a temporary zip (containing non-HTML files from resources/), streams it to the client, and removes the temporary file after streaming.
  • HEAD /download_all — returns the response headers only (and removes the temporary file).

Example:

# inspect headers
curl -I http://127.0.0.1:8080/download_all

# download the zip
curl http://127.0.0.1:8080/download_all -o all_resources.zip
unzip -l all_resources.zip

Notes:

  • The server dynamically includes non-HTML files from resources/ (excluding the uploads/ folder).
  • Temporary zip files are created on disk and removed after successful streaming; this avoids keeping large archives in memory.
  1. Upload JSON via POST
  • POST JSON (Content-Type: application/json) to any path (the server does not strictly require a specific upload path) — the JSON body will be parsed and saved to resources/uploads/ with a generated filename.

Example:

curl -v -X POST http://127.0.0.1:8080/upload \
  -H "Content-Type: application/json" \
  -d '{"name":"alice","message":"hello"}'

# Example response (JSON):
# {"status":"success","message":"File created successfully","filepath":"/uploads/upload-2025-10-10-...json"}
  • The server requires Content-Type: application/json. Other content types return 415 Unsupported Media Type.
  • Upload files are written to resources/uploads/ — directory is created if missing.

Behavior and limitations

  • The HTTP parser in http_handler.py is intentionally simple and not fully RFC-compliant. It works for basic requests used in this project, but edge cases (chunked transfer, multipart/form-data, very long headers) are not supported.
  • The server sends HTML responses with Content-Type: text/html; charset=utf-8 and binary responses as application/octet-stream with Content-Disposition: attachment.
  • For /download_all, the server streams a temporary ZIP to avoid high memory usage. If an error occurs during ZIP creation, the server returns 500 Internal Server Error.

Troubleshooting

  • Port in use: see the bind error section above (use lsof to locate and kill).
  • Large downloads: /download_all uses temporary files — if the server crashes while streaming, temporary files may remain in /tmp/ (or system temp). They are removed automatically after successful transfers but can be manually inspected/removed if needed.
  • If static files return 403 or 404, check that resources/ contains the file and paths are correct. The server protects against directory traversal; malformed path requests will return 403 Forbidden.

Development tips

  • Make visual/style changes by editing the HTML files in resources/ (they use inline <style> blocks in this repository).
  • If you want to consolidate CSS into a single file for maintainability, move the shared rules to resources/styles.css and link it from the HTML head.

Contributing / Improvements (ideas)

  • Replace the simple HTTP parser with a library (or a more complete parser) for robustness.
  • Add proper routing so uploads require a dedicated /upload endpoint and static serving is clearly separated.
  • Add tests for the handlers (unit tests for parsing and endpoints).
  • Add graceful shutdown and active-request draining on server stop.

If you'd like, I can:

  • Run the server and exercise the endpoints (download a zip, POST a JSON) and paste the responses/logs here.
  • Add an example script in examples/ that performs the common curl calls automatically.

What would you like me to do next?

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages