# 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:**
*   [[programming/python/modules/socket-module|socket]]: To create network connections.
*   `threading`: To handle multiple client connections simultaneously.
*   [[programming/python/modules/argparse-module|argparse]]: To handle command-line arguments.

## The Code

Save this as `proxy.py`.

```python
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

1.  **Run the proxy:**
    ```bash
    python proxy.py --port 8888
    ```

2.  **Configure your browser or tool:**
    *   Set your browser's HTTP proxy settings to `localhost` (or `127.0.0.1`) and port `8888`.
    *   Or test with `curl`:
        ```bash
        curl -x http://localhost:8888 http://httpbin.org/ip
        ```

**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.

[[programming/python/python]]