!/usr/bin/env python
-- coding: utf-8 --
Author: Dily
Email:312797697@qq.com
"""实现API代理服务"""
import logging
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
import tornado.httpclient
from tornado.web import HTTPError, asynchronous
from tornado.httpclient import HTTPRequest
from tornado.options import define, options
try:
from tornado.curl_httpclient import CurlAsyncHTTPClient as AsyncHTTPClient
except ImportError:
from tornado.simple_httpclient import SimpleAsyncHTTPClient as AsyncHTTPClient
define("port", default=38888, help="run on the given port", type=int)
define("api_protocol", default="https")
define("api_host", default="DOMAIN")
define("api_port", default="443")
define("api_url", default="URI")
define("debug", default=True, type=bool)
class ProxyHandler(tornado.web.RequestHandler):
@asynchronous
def get(self):
# enable API GET request when debugging
if options.debug:
return self.post()
else:
raise HTTPError(405)
@asynchronous
def post(self):
protocol = options.api_protocol
host = options.api_host
port = options.api_port
murl = options.api_url
# port suffix
port = "" if port == "443" else ":%s" % port
uri = self.request.uri
url = "%s://%s%s%s%s" % (protocol, host, port, uri, murl)
# update host to destination host
headers = dict(self.request.headers)
headers["Host"] = host
try:
AsyncHTTPClient().fetch(
HTTPRequest(url=url,
method="POST",
body=self.request.body,
headers=headers,
follow_redirects=False),
self._on_proxy)
except tornado.httpclient.HTTPError, x:
if hasattr(x, "response") and x.response:
self._on_proxy(x.response)
else:
logging.error("Tornado signalled HTTPError %s", x)
def _on_proxy(self, response):
if response.error and not isinstance(response.error,
tornado.httpclient.HTTPError):
raise HTTPError(500)
else:
self.set_status(response.code)
for header in ("Date", "Cache-Control", "Server", "Content-Type", "Location"):
v = response.headers.get(header)
if v:
self.set_header(header, v)
if response.body:
self.write(response.body)
self.finish()
def main():
tornado.options.parse_command_line()
application = tornado.web.Application([
(r"/.*", ProxyHandler),
])
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
if name == "main":
main()
网友评论