Python Web Proxy
Here is another simple proxy server written in Python, this time a regular web proxy. I tried to make it as simple as possible; using only common Python modules. This means it connects directly to a socket instead of using the more sophisticated HTTP modules and so on.
It works on most pages, but there are some "bugs" on some pages. Most notably, I have seen that the CSS stylesheets are not always transferred, meaning the layout will look strange. I have not tested it against any "rich" web-pages using AJAX and the like, so I have no idea how that will work. HTTPS does not work, since it relies on some more advanced mechanisms in the proxy, and support for the "CONNECT" request, which is not present here.
Then again, this is meant as an emergency solution and/or a way to observe the basic requirements of a web proxy server.
Enjoy:
#!/usr/bin/python
from threading import Thread
import socket
import re
import urlparse
import time
class ClientConnection(Thread):
def __init__(self, client_socket):
Thread.__init__(self)
self.client_socket = client_socket
def _extract_host(self, data):
match = re.match("^(?:GET|POST|HEAD) (.*?) (HTTP\/[.0-9]*)", data)
if match:
url = urlparse.urlparse(match.group(1))
# NOTE: Alternate port numbers not handled.
return url.netloc
else:
return None
def _try_recv(self, sock):
try:
return sock.recv(4096, socket.MSG_DONTWAIT)
except:
return None
def run(self):
try:
data = self.client_socket.recv(4096)
except:
self.client_socket.close()
return
if len(data) == 0:
self.client_socket.close()
return
host = self._extract_host(data)
port = 80
if host == None:
self.client_socket.close()
return
# A hack, but it works.
data = data.replace("HTTP/1.1", "HTTP/1.1\r\nConnection: close")
print "Open: %s" % (host)
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.connect((host, port))
self.server_socket.sendall(data)
timeout = 0
while True:
data = self._try_recv(self.server_socket)
if data != None:
try:
self.client_socket.sendall(data)
except:
break
data = self._try_recv(self.client_socket)
if data != None:
try:
self.server_socket.sendall(data)
except:
break
if (timeout > 200):
break
time.sleep(0.1)
timeout += 1
print "Close: %s" % (host)
self.server_socket.close()
self.client_socket.close()
class ProxyServer(object):
def __init__(self, port):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.bind(('', port))
self.sock.listen(64)
def loop(self):
while True:
(client_socket, client_address) = self.sock.accept()
connection = ClientConnection(client_socket)
connection.start()
if __name__ == "__main__":
ps = ProxyServer(8080)
ps.loop()