我试图在Python中通过龙卷风制作代理服务器。简单的http代理服务器运行良好,但是https代理存在一些问题。我的部分程序可能有问题如下。
import tornado.ioloop
from tornado.web import RequestHandler, Application
from tornado.httpclient import AsyncHTTPClient, HTTPRequest
from tornado.httpserver import HTTPServer
class HTTPSHandler(RequestHandler):
@tornado.web.asynchronous
def get(self):
print self.request.host, self.request.method
def handle_request(response):
if response.error and not isinstance(response.error, tornado.httpclient.HTTPError):
print "Error:", response.error
else:
self.write(response.body)
self.finish(" ")#in case of response.body == None
request = self.request
req = HTTPRequest(url=request.uri, method=request.method,
headers=request.headers, body=request.body,
allow_nonstandard_methods = True, follow_redirects = False,
validate_cert=True)
http_client = AsyncHTTPClient()
try:
http_client.fetch(req, handle_request)
except Exception as e:
print e
@tornado.web.asynchronous
def post(self):
return self.get()
@tornado.web.asynchronous
def head(self):
return self.get()
@tornado.web.asynchronous
def delete(self):
return self.get()
@tornado.web.asynchronous
def patch(self):
return self.get()
@tornado.web.asynchronous
def put(self):
return self.get()
@tornado.web.asynchronous
def options(self):
return self.get()
if __name__ == "__main__":
app2 = Application([(r"https:.*", HTTPSHandler),])
httpsServer = HTTPServer(app2, ssl_options = {
"certfile": "./server.crt",
"keyfile": "./server.key",
})
app2.listen(444)
tornado.ioloop.IOLoop.instance().start()
它输出如下警告(当我访问 https://www.google.com 和 https://github.com 时)
WARNING:tornado.access:405 CONNECT www.google.co.jp:443 (127.0.0.1) 0.69ms
WARNING:tornado.access:405 CONNECT github.com:443 (127.0.0.1) 0.58ms
最后,使用https协议的网页无法显示浏览器错误。
ERR_TUNNEL_CONNECTION_FAILED
我想,这是由龙卷风的请求处理程序引起的,因为它不支持 CONNECT 方法。我的问题是如何使用 CONNECT 方法?
我已经注意到解决此问题的方法。
首先,SUPPORTED_METHOD应该用HTTPSHandler类编写。这可以解决405警告和浏览器错误。
class HTTPSHandler(RequestHandler):
SUPPORTED_METHODS = ("CONNECT", "GET", "HEAD", "POST", "DELETE", "PATCH", "PUT", "OPTIONS")
@tornado.web.asynchronous
def get(self):
这是在官方文件中写的,如下所示。
If you want to support more methods than the standard GET/HEAD/POST, you
should override the class variable ``SUPPORTED_METHODS`` in your
`RequestHandler` subclass.
此外,为了处理和处理 CONNECT 方法请求,HTTPSHandler 类中需要额外的方法。
@tornado.web.asynchronous
def connect(self):
print "some specific processings here"
最后,我在正则表达式和ssl_option中犯了愚蠢的错误。
app2 = Application([(r"https:.*", HTTPSHandler),]) # not correct
app2 = Application([(r".*", HTTPSHandler),]) # correct
httpServer = HTTPServer(app2) # ssl_options is not needed
理论上,您应该能够以与WebSocketHandler相同的方式实现CONNECT方法,即劫持底层连接的IOStream。 但请注意,这是未知的领域;HTTP 代理协议与纯 HTTP 有一些差异,我不知道在普通的应用程序级 HTTP 服务之上实现代理的效果如何。