| 62 | |
| 63 | @web.asynchronous |
| 64 | def connect(self): |
| 65 | def read_from_client(data): |
| 66 | upstream.write(data) |
| 67 | |
| 68 | def read_from_upstream(data): |
| 69 | client.write(data) |
| 70 | |
| 71 | def client_close(data=None): |
| 72 | if upstream.closed(): |
| 73 | return |
| 74 | if data: |
| 75 | upstream.write(data) |
| 76 | upstream.close() |
| 77 | |
| 78 | def upstream_close(data=None): |
| 79 | if client.closed(): |
| 80 | return |
| 81 | if data: |
| 82 | client.write(data) |
| 83 | client.close() |
| 84 | |
| 85 | def start_tunnel(): |
| 86 | client.read_until_close(client_close, read_from_client) |
| 87 | upstream.read_until_close(upstream_close, read_from_upstream) |
| 88 | client.write(b'HTTP/1.1 200 Connection established\r\n\r\n') |
| 89 | |
| 90 | def on_connect(data=None): |
| 91 | if data: |
| 92 | first_line = data.splitlines()[0] |
| 93 | http_v, status, text = first_line.split(None, 2) |
| 94 | if 200 == int(status): |
| 95 | start_tunnel() |
| 96 | return |
| 97 | self.set_status(500) |
| 98 | self.finish() |
| 99 | |
| 100 | def start_proxy_tunnel(): |
| 101 | upstream.write(b'CONNECT %b HTTP/1.1\r\n' % bytes(self.request.uri, 'utf8')) |
| 102 | upstream.write(b'Host: %b\r\n' % bytes(self.request.uri, 'utf8')) |
| 103 | upstream.write(b'Proxy-Connection: Keep-Alive\r\n\r\n') |
| 104 | upstream.read_until(b'\r\n\r\n', on_connect) |
| 105 | |
| 106 | try: |
| 107 | proxy = get_proxy(True) |
| 108 | client = self.request.connection.stream |
| 109 | upstream = iostream.IOStream(socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)) |
| 110 | upstream.connect((proxy.ip, proxy.port), start_proxy_tunnel) |
| 111 | except: |
| 112 | self.set_status(500) |
| 113 | self.write("Internal server error:\n" + |
| 114 | ''.join(traceback.format_exception(*sys.exc_info()))) |
| 115 | self.finish() |
| 116 | |
| 117 | def handle_response(self, response: HTTPResponse): |
| 118 | |