Simple HTTP Proxy
This guide demonstrates how to build a basic multi-threaded HTTP proxy server using Python's socket module. This proxy intercepts HTTP requests, forwards them to the destination server, and relays the response back to the client.
Modules Used:
- socket: To create network connections.
threading: To handle multiple client connections simultaneously.- argparse: To handle command-line arguments.
The Code
Save this as proxy.py.
import socket
import threading
import argparse
import sys
def handle_client(client_socket):
try:
# Receive request from client
request = client_socket.recv(4096)
if not request:
client_socket.close()
return
# Parse the first line to extract the URL
# Request line format: METHOD URL VERSION
first_line = request.split(b'\n')[0]
url = first_line.split(b' ')[1]
# Parse URL to find the destination host and port
http_pos = url.find(b"://")
if http_pos == -1:
temp = url
else:
temp = url[(http_pos+3):]
port_pos = temp.find(b":")
webserver_pos = temp.find(b"/")
if webserver_pos == -1:
webserver_pos = len(temp)
webserver = b""
port = -1
if port_pos == -1 or webserver_pos < port_pos:
port = 80
webserver = temp[:webserver_pos]
else:
# Extract port if specified
port = int((temp[(port_pos+1):])[:webserver_pos-port_pos-1])
webserver = temp[:port_pos]
print(f"Forwarding request to {webserver.decode()}:{port}")
proxy_server(webserver.decode(), port, client_socket, request)
except Exception as e:
client_socket.close()
def proxy_server(webserver, port, client_socket, request_data):
try:
# Connect to the destination server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(10)
s.connect((webserver, port))
s.send(request_data)
while True:
# Receive data from web server
data = s.recv(4096)
if len(data) > 0:
# Send data back to client
client_socket.send(data)
else:
break
s.close()
client_socket.close()
except Exception as e:
if 's' in locals(): s.close()
client_socket.close()
def start_proxy(port):
try:
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('0.0.0.0', port))
server.listen(50)
print(f"Proxy server listening on port {port}...")
while True:
client_sock, addr = server.accept()
client_handler = threading.Thread(target=handle_client, args=(client_sock,))
client_handler.daemon = True
client_handler.start()
except Exception as e:
print(f"Server error: {e}")
sys.exit(1)
except KeyboardInterrupt:
print("\nShutting down proxy.")
sys.exit(0)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Simple HTTP Proxy")
parser.add_argument("--port", type=int, default=8888, help="Port to listen on (default: 8888)")
args = parser.parse_args()
start_proxy(args.port)
Usage
-
Run the proxy:
python proxy.py --port 8888 -
Configure your browser or tool:
- Set your browser's HTTP proxy settings to
localhost(or127.0.0.1) and port8888. - Or test with
curl:curl -x http://localhost:8888 http://httpbin.org/ip
- Set your browser's HTTP proxy settings to
Note: This simple proxy handles standard HTTP requests. It does not implement the CONNECT method required for HTTPS tunneling, so it will likely fail with https:// URLs unless extended.