- Name: LI Jianxi
- Student ID: 24109859d
- Course: COMP2322 Computer Networking
- Date: April 2026
This project implements a multi-threaded web server in Python that handles HTTP requests from web browsers or other client programs. The server supports concurrent connections, various HTTP methods, multiple response status codes, and features like persistent connections and conditional requests.
- ✅ Multi-threaded architecture – each request handled in a separate thread
- ✅ GET method support for text and image files
- ✅ HEAD method support
- ✅ HTTP persistent connections (keep-alive) and non-persistent connections (close)
- ✅ Last-Modified and If-Modified-Since header handling
| Status Code | Description | Status |
|---|---|---|
| 200 OK | Request successful | ✅ |
| 304 Not Modified | File not modified since last request | ✅ |
| 400 Bad Request | Malformed request syntax | ✅ |
| 403 Forbidden | Access denied (directory listing, path traversal) | ✅ |
| 404 Not Found | Requested file does not exist | ✅ |
- Path traversal attack prevention
- File permission checking
- Directory listing disabled
- Python 3.12.8 or higher
- No additional packages required (uses only standard library)
- Windows
- Linux
- macOS
- Clone or download the project files
project/
├── MyWebServer.py
├── MyHTTPRequest.py
├── MyHTTPResponse.py
├── server_main.py
├── www/
│ ├── empty_dir (using to test 403 forbidden)
│ ├── index.html
│ ├── test.txt
│ └── test.jpg
└── server.log (auto-generated)
- No compilation needed – Python is an interpreted language
Basic usage (default settings):
python server_main.pyDefault: http://127.0.0.1:8080, serving files from ./www
Custom host and port:
python server_main.py --host 0.0.0.0 --port 8888Custom root directory:
python web_server.py --root /path/to/your/files(Supposing that the host and port of the server is 127.0.0.1 and 8080) 1. Using a Web Browser Open your browser and navigate to:
-
http://127.0.0.1:8080/ – Home page with test links
-
http://127.0.0.1:8080/test.txt – Text file
-
http://127.0.0.1:8080/test.jpg – Image file
2. Using curl (Recommended for testing)
GET requests:
# Basic GET
curl http://127.0.0.1:8080/test.txt
# Verbose output (shows headers)
curl -v http://127.0.0.1:8080/test.txt
# Download and save file
curl -o downloaded.txt http://127.0.0.1:8080/test.txtHEAD requests:
# Get headers only
curl -I http://127.0.0.1:8080/test.txtTest 304 Not Modified:
# Get file info first to see Last-Modified time
curl -I http://127.0.0.1:8080/test.txt
# Use future date to get 304
curl -v -H "If-Modified-Since: Tue, 01 Jan 2030 00:00:00 GMT" http://127.0.0.1:8080/test.txtTest 404 Not Found:
curl -v http://127.0.0.1:8080/nonexistent.htmlTest 403 Forbidden:
curl -v http://127.0.0.1:8080/empty_dir/Test 400 Bad Request:
# Send malformed request
curl -v -X "" http://127.0.0.1:8080/When running, the server displays detailed information:
Server started on 127.0.0.1:8080
Serving files from: C:\project\www
Press Ctrl+C to stop the server
🔌 New connection from 127.0.0.1:63070
================================================================================
📥 NEW REQUEST
================================================================================
⏰ Time: 2026-03-21 19:55:30
🌐 Client: 127.0.0.1:63070
📋 Method: GET
📁 Path: /test.txt
🔧 Version: HTTP/1.1
📎 Headers:
Host: 127.0.0.1:8080
User-Agent: curl/8.18.0
Connection: keep-alive
Serving file: C:\project\www\test.txt
📤 RESPONSE:
Status: 200 OK
Size: 49 bytes
Type: text/plain
================================================================================
✅ Response: 200 OK
🔌 Connection closed from 127.0.0.1:63070
The server maintains a log file server.log with the following format:
2026-03-21 19:55:30 - 127.0.0.1/127.0.0.1 - 2026-03-21 19:55:30 - GET /test.txt - Request Received
2026-03-21 19:55:30 - 127.0.0.1/127.0.0.1 - 2026-03-21 19:55:30 - GET /test.txt - 200 OK
| Class | Purpose |
|---|---|
| HTTPRequest | Parses incoming HTTP requests, extracts method, path, headers |
| HTTPResponse | Builds HTTP responses with proper status codes and headers |
| WebServer | Main server class handling connections, threading, and file serving |
-
Client connects → Server accepts in main thread
-
New thread created →
handle_client()processes the connection -
receive_request()reads HTTP request -
HTTPRequest parses the request
-
process_request()routes to appropriate handler (GET/HEAD) -
serve_file()locates file, checks permissions, builds response -
Response sent back to client
-
Connection handled based on
Connectionheader (keep-alive/close)
| Problem | Solution |
|---|---|
Address already in use |
Change port with --port 8888 or stop other services using port 8080 |
Permission denied |
Use port > 1024 (e.g., 8080) or run as administrator |
| 403 Forbidden | Check file permissions; ensure files are readable |
| 404 Not Found | Verify file exists in www directory |
| Slow responses | Check if server is running; verify no firewall blocking |
This server uses port 8080 by default instead of port 80 because:
-
Port 80 is often occupied by other web servers (IIS, Apache, etc.)
-
Ports below 1024 require administrator privileges on most systems
-
Python socket programming documentation
-
HTTP/1.1 RFC 2616 specification