tornado http proxy 二級代理注意事項
1、二級代理remote_stream不是連接的remote_host而是PROXY_HOST
2、http的代理驗証需要在header裡增加 Proxy-authorization: Basic bGs6MjAwMg== , 用戶、密碼是用base64編碼的
本文是在https://gist.github.com/1241783/807624b686a734be61278e899dcf4721a20389c2基礎上改的增加了二級代理功能,
修改了其中的一個post的問題, 增加發送post數據的代碼
if self.request.body:
data += self.request.body
#!/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
import base64
PROXY_HOST = "172.17.5.53"
PROXY_PORT = 80
PROXY_USER = "lk"
PROXY_PWD = "2002"
BASE64_USER_PWD = 'Basic ' + base64.encodestring('%s:%s' % (PROXY_USER, PROXY_PWD))[:-1]
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
self.connect_remote()
def connect_remote(self):
scheme, netloc, path, params, query, fragment = urlparse.urlparse(self.request.uri, 'http')
try:
self.remote_host, _, self.remote_port = netloc.rpartition(':')
self.remote_port = int(self.remote_port)
except ValueError:
self.remote_host = netloc
self.remote_port = 80
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_connect_remote)
self.remote_stream.connect((PROXY_HOST, PROXY_PORT), self._on_connect_remote)
def _on_connect_remote(self):
logging.info('remote addrest (%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['Proxy-authorization'] = BASE64_USER_PWD
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'
if self.request.body:
data += self.request.body
self.remote_stream.write(data, self._on_write_remote)
def _on_write_remote(self):
logging.info('remote addrest (%r, %r) send data end.', self.remote_host, self.remote_port)
self.remote_stream.read_until('\r\n\r\n', self._on_read_remote_headers)
def _on_read_remote_headers(self, data):
logging.info('remote addrest (%r, %r) read headers data 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_write_local_headers)
def _on_write_local_headers(self):
logging.info('remote headers, %s', self.remote_headers)
logging.info('remote addrest (%r, %r) read remote header data end.', self.remote_host, self.remote_port)
if self.remote_headers.get('connection') == 'close':
self.remote_stream.read_until_close(self._on_read_remote_body)
elif 'content-length' in self.remote_headers:
self.remote_stream.read_bytes(int(self.remote_headers['content-length']), self._on_read_remote_body)
else:
self.remote_stream.read_until_close(self._on_read_remote_body)
def _on_read_remote_body(self, data):
logging.info('remote addrest (%r, %r) read data end.', self.remote_host, self.remote_port)
self.request.write(data)
self.request.finish()
def main():
http_server = HTTPServer(LocalProxyHandler)
http_server.listen(8080)
ioloop.IOLoop.instance().start()
if __name__ == '__main__':
main()