python - 有人可以解释这条扭曲的事吗?

标签 python linux python-2.7 twisted http-proxy

 class ConnectProxy(Proxy):

    requestFactory = ConnectProxyRequest
    connectedRemote = None

   def requestDone(self, request):   
       if request.method == 'CONNECT' and self.connectedRemote is not None:  
           self.connectedRemote.connectedClient = self
       else:
           Proxy.requestDone(self, request)

self.connectedRemote.connectedClient = self做什么?

最佳答案

因此,这个代码片段的原始源代码是mygithub repositories中的一个,它包装了twisted http代理服务器协议,也支持connect方法。
简而言之,这会将self(下游协议实例——在客户端和这个扭曲服务器之间)分配给上游连接的协议实例(远程https服务器)的一个成员,这样从上游连接接收到的任何数据都可以很容易地写回下游客户端的传输。
我对代码有一个较长的解释,但这将有助于对http代理协议有一个基本的了解,所以我将尝试设置一些上下文,但如果您已经知道如何工作,请随意跳过。
http代理get和connect概述
除了作为用于与web服务器通信的请求/响应传输,http协议还可用于通过“转发”代理(通过协议的一些小扩展)与其他服务器通信。
普通的http请求可以通过建立直接到服务器的tcp连接来实现,例如,由www.example.com:80指定。此http请求如下所示:

> GET /foo HTTP/1.1
< HTTP/1.1 200 OK

如果您需要通过http代理进行通信,那么您将建立到该代理服务器(例如,localhost:8080)的tcp连接,并向该http服务器发送以下消息:
> GET http://www.example.com/foo http/1.1
< HTTP/1.1 200 OK

代理将为www.example.com执行dns查找,建立tcp连接,并代表您发送http请求。然后它会将响应体流回到您的客户机。将浏览器配置为使用特定代理将导致它隐式重写所有http url以通过该代理服务器。
把这一点与问题联系起来:twisted发布了一个specially formatted HTTP request来理解这些http代理get请求。对于使用http的普通浏览器来说,这非常有效。
现在,在图片中有了TLS,我们想阻止代理嗅探我们本应安全的流量。这就是为什么浏览器,而不是像这样通过代理发送一个https请求:
> GET https://www.example.com/foo http/1.1
< HTTP/1.1 200 OK

而是使用Proxy protocol。如果代理支持此方法,则此方法会将连接置于“隧道”或直通模式。这些请求看起来像这样:
> CONNECT www.example.com:443 http/1.1
< HTTP/1.1 200 CONNECT OK

在这种模式下,代理不代表客户机处理dns、tcp(tls)和http的所有舞蹈,而只处理前两个舞蹈,dns和tcp。如果代理成功地建立到example.com IP的TCP连接,那么它将开始将客户端发送的所有字节转发到服务器,并按原样将从服务器接收的所有字节转发回客户端。这允许客户机和服务器执行后续的tls握手和http请求,而不会意识到(或关心)两者之间存在代理服务器。
实际上,twisted.web.proxy模块没有实现connect方法。相反,对于使用此方法的请求,它将返回http501 Not Implemented错误,导致任何连接的浏览器无法通过https加载资产。
CONNECT HTTP proxy extension method试图通过将现有扭曲类从twisted.web.proxy中分类,但实现对连接方法的支持,从而填补了这一空白。
代码的说明
代理可能有点毛茸茸的原因,但诀窍是记住,对于每一个请求,有2个连接在玩:连接到扭曲Web代理服务器的客户端(例如浏览器)和“上游”连接之间的“下游”连接,从扭曲的Web代理服务器到远程HTTP(S)服务器。
下面是问题代码:
class ConnectProxy(Proxy):

    requestFactory = ConnectProxyRequest
    connectedRemote = None

    def requestDone(self, request):   
        if request.method == 'CONNECT' and self.connectedRemote is not None:  
            self.connectedRemote.connectedClient = self
        else:
            Proxy.requestDone(self, request)

我们将分节进行:
class ConnectProxy(Proxy):

Proxy这里是twisted.web.proxy.Proxy子类,它为http服务器实现http请求处理程序。我们将其子类化为一个新的twisted.internet.Protocol,称为Protocol
requestFactory = ConnectProxyRequest
connectedRemote = None

父类ConnectProxy是http请求处理程序协议twisted.web.proxy.Proxy的一个基本子类。它通常将twisted.web.http.HTTPChannel属性定义为requestFactory类。但由于该请求处理程序不支持connect方法,因此我们使用稍后在文件中定义的子类,称为twisted.web.proxy.ProxyRequest。一个更好的名字可能是ConnectProxyRequest,但哦,好吧。
ConnectOrGetProxyRequest只是将此服务器协议的所有实例上的成员访问默认为“无”的一种简捷方法。对于针对此协议实例发出的连接请求,将在成功的上游连接上为该变量分配connectedRemote = None协议的实例(稍后在源中定义)。ConnectProxyClient负责通过此协议实例将ConnectProxyClient从上游连接(与远程服务器)转发回连接到此服务器的下游客户端。
def requestDone(self, request):   

dataReceivedrequestDone的guts调用,此时来自此服务器的所有http响应(头和正文)都已发送到下游客户端。对于get请求,这将结束来自上游http服务器的响应。对于connect请求,这将结束上游tcp连接握手的成功或失败。
if request.method == 'CONNECT' and self.connectedRemote is not None:  
    self.connectedRemote.connectedClient = self

根据twisted-connect-proxy,当(代理)服务器响应连接完成其200成功响应/正文时,连接切换到直通模式。
在成功的下游(到远程服务器)连接上,HTTPChannel将被设置为该连接的直通协议,而不是无。在这种情况下,我们给它一个对该协议的引用,这样它就可以轻松地将数据发送回上游客户端(例如浏览器)。
如果上游连接失败,或者这是一个get proxy请求,我们完成了对响应体的流式处理,我们就陷入self.connectedRemote的情况
else:
    Proxy.requestDone(self, request)

这调用父类的else:。这对于http服务器正确实现http对于正确关闭或维护与下游客户机的持久“keepalive”连接非常重要。

关于python - 有人可以解释这条扭曲的事吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30450199/

相关文章:

python - 如何在 pandas groupby 中正确使用变量?

c - 内核领域中的错误处理/检查

c++ - 错误 : Compiling simple PjSIP program under ubuntu

Python:安装 pip 时出现权限被拒绝错误

python float对象不支持项赋值

python - 使用条件计算 pandas 数据框中出现的总数

python - __init__ 的正确类型注释

linux - 为什么 docker0 桥在带有法兰绒的 kubernetes 集群中出现?

python - 使用pygame旋转图像

Python 字典计数