Skip to content

ShivaGupta-14/python-multi-threaded-http-server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 

Repository files navigation

🌐 My Multi-threaded HTTP Server

This is my project for a multi-threaded HTTP server, built from scratch in Python.
The goal was to understand how HTTP, sockets, and threading work together at a low level.
I built it using only Python's standard libraries, so no external packages are needed.

The server can serve static files for a simple website (HTML, images, text) and also handle JSON uploads through a POST request.


⚡ Features

  • Handles GET and POST requests for basic web functionality.
  • Serves static files like .html pages, .jpg and .png images, and .txt files.
  • Uses a thread pool to manage multiple client connections at the same time without crashing.
  • Supports Keep-Alive connections with an idle timeout to manage resources efficiently.
  • Includes important security checks to prevent common attacks like path traversal.

🚀 How to Run It

📝 What You Need

  • Python 3.7 or newer ✅

🛠 Steps

  1. Clone or download the project files.

  2. Make sure you have the resources folder with all the website files inside (index.html, Image1.jpg, jokes.txt, etc.).

  3. Run the server from your terminal:

    # This runs the server with the default settings
    # (Host: 127.0.0.1, Port: 8080, Threads: 10)
    python3 server.py

    You can also provide your own settings for the port, host, and thread count:

    # Example: run on port 9000 with 5 threads
    python3 server.py 9000 127.0.0.1 5
  4. Open your browser and go to http://127.0.0.1:8080 to see the home page.


📥 Testing File Downloads

To test the binary file download feature, navigate to the following URLs in your browser:

  • To download a text file: http://127.0.0.1:8080/jokes.txt
  • To download an image: http://127.0.0.1:8080/Image1.jpg

In both cases, your browser should not display the file directly but will instead open a "Save As" dialog.
This behavior is triggered by the Content-Disposition: attachment header sent by the server.

📝 Testing JSON Uploads (POST Request)

You can test POST requests using curl or Postman.

Using curl (from your terminal):

curl -X POST \
  [http://127.0.0.1:8080/upload](http://127.0.0.1:8080/upload) \
  -H "Content-Type: application/json" \
  -d '{"username": "shiva", "message": "Testing POST request!"}'

📝 Using Postman

  1. Set the method to POST.
  2. Set the URL to http://127.0.0.1:8080/upload.
  3. Go to the Body tab, select raw, and choose JSON from the dropdown.
  4. Paste your JSON content in the text area.

After sending the request, the server should respond with a 201 Created status and a JSON body confirming success.
You can then check the resources/uploads directory to see the newly created file.


🧩 How the Code Works: A Deeper Dive

This server is built around a few key functions that handle everything from listening for connections to sending back the final response.


1️⃣ Server Startup and Listening

Everything starts in the run_server function.

Socket Creation:

  • A TCP socket is created using socket.socket(socket.AF_INET, socket.SOCK_STREAM).
  • AF_INET specifies IPv4 networking, and SOCK_STREAM means a TCP socket, guaranteeing reliable, in-order data delivery.

Binding:

  • The socket is bound to the specified host and port with server.bind((host, port)).
  • Like assigning a specific phone number to a phone so it can receive calls.

Listening:

  • server.listen(LISTEN_BACKLOG) puts the socket in listening mode, ready to accept incoming client connections.

Main Loop:

  • The server enters an infinite while True: loop.
  • server.accept() is a blocking call—it waits for a client to connect.

2️⃣ Handling Concurrent Clients with a Thread Pool

  • To avoid being stuck handling one client at a time, the server uses a ThreadPoolExecutor.
  • When server.accept() receives a new connection, it submits the client-handling task to the thread pool:
pool.submit(client_wrapper, conn, addr)

3️⃣ The client_wrapper Function

The client_wrapper function:

  • Sets a descriptive name for the thread.
  • Calls serve_client, which handles a single client’s requests.
  • If the thread pool is full, new connections are placed in a connection_queue.
    When a thread finishes, it picks up the next waiting connection.

4️⃣ Serving a Client Connection

The serve_client function manages the entire lifecycle of a client connection.

🌀 Keep-Alive Loop

  • Handles multiple requests from the same client (up to MAX_PERSISTENT_REQUESTS).
  • Core of Keep-Alive functionality.

📥 Receiving Data

  • Uses conn.recv(8192).
  • Blocking call; waits until data arrives.

⏱️ Timeout Handling

  • conn.settimeout(KEEP_ALIVE_TIMEOUT) (usually 30s) prevents indefinite connections.
  • Raises socket.timeout if no data is received, then closes the connection.

5️⃣ Parsing the HTTP Request

The parse_request_bytes function:

  • Decodes bytes into UTF-8 string.
  • Separates headers & body by \r\n\r\n.
  • Extracts request line (method, path, HTTP version).
    • Example: GET /index.html HTTP/1.1
  • Parses headers into a Python dictionary.

6️⃣ Routing and Handling the Request

🔹 GET Requests

  • Passed to handle_get.
  • Locates the file, sets correct Content-Type, reads content in binary mode.

🔹 POST Requests

  • Passed to handle_post.
  • Validates Content-Type: application/json, parses JSON, saves to resources/uploads/, returns 201 Created.

🚫 Other Methods

  • Responds with 405 Method Not Allowed for unsupported methods like PUT or DELETE.

7️⃣ Building and Sending the Response

The build_response function:

  • Status Line: e.g., HTTP/1.1 200 OK

  • Headers: Date, Server, Content-Type, Connection, plus any custom headers

  • Formatting: Headers joined with \r\n

  • Send Response: Encoded to bytes and sent via conn.sendall()

  • Keep-Alive continues loop; otherwise, conn.close() ensures safe closure.


⚠️ Known Limitations

  • Large Files: Reads entire file into memory; inefficient for huge files.
  • Basic HTTP Support: Only supports a subset of HTTP/1.1; no HTTP/2, chunked encoding, or caching.
  • Single resources Folder: All files must reside inside it.

🧠 Summary

This project demonstrates:

  • The core mechanics of HTTP communication.
  • Using sockets for low-level networking.
  • Using thread pools for handling concurrent client connections efficiently.

✨ Thanks for Checking Out My Project!

Author: Shiva Gupta
Feel free to explore, test, and improve it! 🚀

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published