Skip to content

Instantly share code, notes, and snippets.

@lepture
Created February 3, 2012 02:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lepture/1727348 to your computer and use it in GitHub Desktop.
Save lepture/1727348 to your computer and use it in GitHub Desktop.
tornado http proxy
#!/usr/bin/env python
#coding:utf-8
import sys, os, re
import logging
import socket
import urlparse
from tornado import iostream, ioloop
from tornado.httpserver import HTTPServer
from tornado import httputil
logging.basicConfig(level=logging.INFO, format='%(levelname)s - - %(asctime)s %(message)s', datefmt='[%d/%b/%Y %H:%M:%S]')
class LocalProxyHandler(object):
def __init__(self, request):
self.request = request
scheme, netloc, path, params, query, fragment = urlparse.urlparse(self.request.uri, 'http')
self.remote_host, self.remote_port = self.resolve_netloc(netloc)
self.remote_path = urlparse.urlunparse((scheme, self.remote_host + ('' if self.remote_host == 80 else ':%d' % self.remote_port), path, params, query, ''))
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
self.remote_stream = iostream.IOStream(sock)
self.remote_stream.connect((self.remote_host, self.remote_port), self._on_remote_connect)
def resolve_netloc(self, netloc):
try:
host, _, port = netloc.rpartition(':')
return host, int(port)
except ValueError:
return netloc, 80
def _on_remote_connect(self):
logging.info('remote address (%r, %r) connected.', self.remote_host, self.remote_port)
data ='%s %s %s\r\n' % (self.request.method, self.remote_path, self.request.version)
self.request.headers['Connection'] = 'close'
self.request.headers['Proxy-Connection'] = 'close'
data += ''.join('%s: %s\r\n' % (k, v) for k,v in self.request.headers.get_all())
data += '\r\n'
self.remote_stream.write(data, self._on_remote_write)
def _on_remote_write(self):
logging.info('remote address (%r, %r) send data end.', self.remote_host, self.remote_port)
self.remote_stream.read_until('\r\n\r\n', self._on_remote_read_headers)
def _on_remote_read_headers(self, data):
logging.info('remote address (%r, %r) read headers end.', self.remote_host, self.remote_port)
eol = data.find('\r\n')
self.remote_headers = httputil.HTTPHeaders.parse(data[eol:])
self.request.connection.write(data, self._on_local_write_headers)
def _on_local_write_headers(self):
logging.info('remote address (%r, %r) to local write headers end.', self.remote_host, self.remote_port)
if self.remote_headers.get('connection') == 'close':
self.remote_stream.read_until_close(self._on_remote_read_body)
elif 'content-length' in self.remote_headers:
self.remote_stream.read_bytes(int(self.remote_headers['content-length']), self._on_remote_read_body)
else:
self.remote_stream.read_until_close(self._on_remote_read_body)
def _on_remote_read_body(self, data):
logging.info('remote address (%r, %r) read finish.', self.remote_host, self.remote_port)
self.request.write(data)
self.request.finish()
def main():
http_server = HTTPServer(LocalProxyHandler, no_keep_alive=True)
http_server.listen(8888)
ioloop.IOLoop.instance().start()
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment