Python 如何在不中断流的情况下安全地从asyncio读取ReaderStream
我正在尝试构建一个中间人代理服务器,将客户端请求转发到我的应用程序中预定义的各种代理服务。因此,为了做到这一点,我需要区分客户对服务的请求。Python 如何在不中断流的情况下安全地从asyncio读取ReaderStream,python,tcp,proxy,python-asyncio,Python,Tcp,Proxy,Python Asyncio,我正在尝试构建一个中间人代理服务器,将客户端请求转发到我的应用程序中预定义的各种代理服务。因此,为了做到这一点,我需要区分客户对服务的请求。 只要我不取消注释#data=wait client\u reader.read(2048),下面的代码就可以工作,我可以从中解析标题。i、 e.如果我执行了该代码, 如果我使用未注释的代码行执行此操作: r = requests.get('http://api.ipify.org/', headers = {'Proxy-Type':'custom'},
只要我不取消注释
#data=wait client\u reader.read(2048)
,下面的代码就可以工作,我可以从中解析标题。i、 e.如果我执行了该代码,如果我使用未注释的代码行执行此操作:
r = requests.get('http://api.ipify.org/', headers = {'Proxy-Type':'custom'}, proxies={'http':'http://127.0.0.1:9911'})
在r.content
async def proxy_data(reader, writer, connection_string):
try:
while True:
data = await reader.read(2048)
if not data:
break
writer.write(data)
await writer.drain()
except Exception as e:
raise
finally:
writer.close()
async def accept_client(client_reader, client_writer):
try:
# Get proxy service - [Proxy-Type] from header via client_reader
# Set remote_address and remote_port based on it
# data = await client_reader.read(2048)
(remote_reader, remote_writer) = await asyncio.wait_for(
asyncio.open_connection(host = remote_address, port = remote_port),
timeout = 30)
except asyncio.TimeoutError:
client_writer.close()
except Exception as e:
client_writer.close()
else:
# Pipe the streams
asyncio.ensure_future(proxy_data(client_reader, remote_writer))
asyncio.ensure_future(proxy_data(remote_reader, client_writer))
def main():
def handle_client(client_reader, client_writer):
asyncio.ensure_future(
accept_client(
client_reader = client_reader,
client_writer = client_writer
)
)
loop = asyncio.get_event_loop()
try:
server = loop.run_until_complete(
asyncio.start_server(
handle_client, host = '127.0.0.1', port = 9911))
except Exception as e:
logger.error('Bind error: {}'.format(e))
sys.exit(1)
for s in server.sockets:
logger.debug('Proxy broker listening on {}'.format(s.getsockname()))
try:
loop.run_forever()
except KeyboardInterrupt:
pass
if __name__ == '__main__':
main()
有人能指出这里的问题或如何有条件地打开连接吗?通过重新输入客户端读取器() 感谢Vincent的评论,指出了请求篡改的情况,并将请求重建回其原始形式
async def accept_client(client_reader, client_writer):
try:
# Get proxy service - [Proxy-Type] from header via client_reader
# Set remote_address and remote_port based on it
data = await client_reader.read(2048)
# -------- Edited --------
# perform operations based on data and obtain remote_address, remote_port
(remote_reader, remote_writer) = await asyncio.wait_for(
asyncio.open_connection(host = remote_address, port = remote_port),
timeout = 30)
except asyncio.TimeoutError:
client_writer.close()
except Exception as e:
client_writer.close()
else:
# Write the data to remote
remote_writer.write(data)
await remote_writer.drain()
# Pipe the streams
asyncio.ensure_future(proxy_data(client_reader, remote_writer))
asyncio.ensure_future(proxy_data(remote_reader, client_writer))
也许您忘记了在管道化流之前在远程写入程序中写入头数据?但是远程写入程序不应该依赖于打开的连接吗?i、 e.远程_writer不应该基于客户端头中请求的自定义代理服务吗?是的,但您不希望通过提取代理信息来破坏请求格式。您必须找到一种方法来重建可由远程服务处理的有效请求。确实如此,但由于我不希望以任何方式篡改该请求,因此只要在
accept\u client
中有一个本地\u reader流的tmp\u reader副本,并针对该条件进行处理就可以了。这似乎不工作,也只是一个复制,我想这与它是一个科罗?!通过使用client\u reader.feed\u data(data)
修复实际上,在保存数据之后,feed\u data
是由底层流协议调用的,我认为这样使用是不安全的。例如,该协议可能会从客户端接收更多数据,并在您反馈报头之前对其进行反馈,从而破坏请求。我会使用remote\u writer.write(data)
(在管道传输流之前)。我不确定是否可以使用remote\u writer
作为实际定义remote\u地址的条件,而remote\u port
将取决于从本地\u reader
中的头获取的数据。比如说,如果客户端头包含'Proxy-Type':'tor'
,那么我的远程地址将是tor ip
的地址。当然可以,但这应该不是问题。我将使用以下工作流:从客户端读取头,获取远程地址,创建远程连接,将头写入远程,通过管道连接客户端和远程。太棒了!。再次感谢