Skip to content

Instantly share code, notes, and snippets.

@zhuzhuor
Created June 17, 2012 06:01
Show Gist options
  • Save zhuzhuor/2943603 to your computer and use it in GitHub Desktop.
Save zhuzhuor/2943603 to your computer and use it in GitHub Desktop.
A (Lame) Python WSGI HTTP Proxy based on Tornado
#!/usr/bin/env python
'''
A blocking HTTP proxy based on non-blocking Tornado...
-- for the sake of WSGI compatibility --
also without HTTPS support...
'''
from tornado import web, wsgi, httpclient, escape
import httplib
# from pprint import pprint
disallowed_response_headers = set([
'connection',
'keep-alive',
'proxy-authenticate',
'proxy-authorization',
'te',
'trailers',
'transfer-encoding',
'upgrade',
# all above are hop-by-hop headers
'content-encoding', # will cause errors
])
class MainHandler(web.RequestHandler):
SUPPORTED_METHODS = ['GET', 'POST']
def handle_response(self, response):
self.set_status(response.code)
# pprint(response.headers)
# check the last comment of http://goo.gl/4w5yj
for h in response.headers.keys():
if h.lower() not in disallowed_response_headers:
list_values = response.headers.get_list(h)
for v in list_values:
# print h, v
self.add_header(h, v)
if response.body:
self.write(response.body)
def get(self):
# tornado-proxy by senko works without this
# wsgiref's handling is a little different from tornado
if self.request.uri.startswith('http%3A'):
url = 'http:' + self.request.uri[7:]
else:
url = self.request.uri
# pprint(self.request.headers)
headers = {h: v for (h, v) in self.request.headers.items() \
if not h.lower().startswith('proxy')
}
http_req = httpclient.HTTPRequest(
url=url,
method=self.request.method,
body=self.request.body,
headers=headers,
follow_redirects=False,
allow_nonstandard_methods=True
)
client = httpclient.HTTPClient()
try:
response = client.fetch(http_req)
self.handle_response(response)
except httpclient.HTTPError, err:
self.handle_response(err.response)
except Exception, err:
self.set_status(500)
self.write('Internal Server Error: ' + str(err))
finally:
self.finish()
# def post as get
post = get
# for fixing a small bug in tornado; please check http://goo.gl/zR4Pq
class MyWSGIApplication(wsgi.WSGIApplication):
def __call__(self, environ, start_response):
handler = web.Application.__call__(self, wsgi.HTTPRequest(environ))
assert handler._finished
status = str(handler._status_code) + " " + \
httplib.responses[handler._status_code]
headers = handler._headers.items() + handler._list_headers
if hasattr(handler, "_new_cookie"):
for cookie in handler._new_cookie.values():
headers.append(("Set-Cookie", cookie.OutputString(None)))
start_response(status,
[(escape.native_str(k), escape.native_str(v))
for (k, v) in headers])
return handler._write_buffer
app = MyWSGIApplication([
(r'.*', MainHandler),
])
if __name__ == "__main__":
import wsgiref.simple_server
server = wsgiref.simple_server.make_server('', 8888, app)
server.serve_forever()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment