o
    ¯b“&  ã                   @   sÔ   d Z ddlmZmZmZ ddlmZ ddlm	Z	 ddl
mZmZmZmZ ddlmZ ddlmZ G dd	„ d	eƒZG d
d„ de	ƒZG dd„ deƒZG dd„ deƒZG dd„ deƒZG dd„ deƒZG dd„ deƒZdS )aT  
Simplistic HTTP proxy support.

This comes in two main variants - the Proxy and the ReverseProxy.

When a Proxy is in use, a browser trying to connect to a server (say,
www.yahoo.com) will be intercepted by the Proxy, and the proxy will covertly
connect to the server, and return the result.

When a ReverseProxy is in use, the client connects directly to the ReverseProxy
(say, www.yahoo.com) which farms off the request to one of a pool of servers,
and returns the result.

Normally, a Proxy is used on the client end of an Internet connection, while a
ReverseProxy is used on the server end.
é    )ÚquoteÚurlparseÚ
urlunparse)Úreactor)ÚClientFactory)Ú_QUEUED_SENTINELÚHTTPChannelÚ
HTTPClientÚRequest)ÚResource)ÚNOT_DONE_YETc                   @   sD   e Zd ZdZdZdd„ Zdd„ Zdd„ Zd	d
„ Zdd„ Z	dd„ Z
dS )ÚProxyClientzµ
    Used by ProxyClientFactory to implement a simple web proxy.

    @ivar _finished: A flag which indicates whether or not the original request
        has been finished yet.
    Fc                 C   sD   || _ || _|| _d|v r|d= d|d< | dd ¡ || _|| _d S )Ns   proxy-connections   closes
   connections
   keep-alive)ÚfatherÚcommandÚrestÚpopÚheadersÚdata©Úselfr   r   Úversionr   r   r   © r   ú3/usr/lib/python3/dist-packages/twisted/web/proxy.pyÚ__init__)   s   
zProxyClient.__init__c                 C   sJ   |   | j| j¡ | j ¡ D ]
\}}|  ||¡ q|  ¡  | j | j	¡ d S ©N)
ÚsendCommandr   r   r   ÚitemsÚ
sendHeaderÚ
endHeadersÚ	transportÚwriter   )r   ÚheaderÚvaluer   r   r   ÚconnectionMade4   s
   zProxyClient.connectionMadec                 C   s   | j  t|ƒ|¡ d S r   )r   ÚsetResponseCodeÚint)r   r   ÚcodeÚmessager   r   r   ÚhandleStatus;   s   zProxyClient.handleStatusc                 C   s6   |  ¡ dv r| jj ||g¡ d S | jj ||¡ d S )N)s   servers   dates   content-type)Úlowerr   ÚresponseHeadersÚsetRawHeadersÚaddRawHeader)r   Úkeyr"   r   r   r   ÚhandleHeader>   s   zProxyClient.handleHeaderc                 C   s   | j  |¡ d S r   )r   r    )r   Úbufferr   r   r   ÚhandleResponsePartH   s   zProxyClient.handleResponsePartc                 C   s(   | j sd| _ | j ¡  | j ¡  dS dS )z�
        Finish the original request, indicating that the response has been
        completely written to it, and disconnect the outgoing transport.
        TN)Ú	_finishedr   Úfinishr   ÚloseConnection)r   r   r   r   ÚhandleResponseEndK   s
   
ýzProxyClient.handleResponseEndN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r1   r   r#   r(   r.   r0   r4   r   r   r   r   r      s    
r   c                   @   s,   e Zd ZdZeZdd„ Zdd„ Zdd„ ZdS )	ÚProxyClientFactoryz?
    Used by ProxyRequest to implement a simple web proxy.
    c                 C   s(   || _ || _|| _|| _|| _|| _d S r   )r   r   r   r   r   r   r   r   r   r   r   ^   s   
zProxyClientFactory.__init__c                 C   s    |   | j| j| j| j| j| j¡S r   )Úprotocolr   r   r   r   r   r   )r   Úaddrr   r   r   ÚbuildProtocolf   s   ÿz ProxyClientFactory.buildProtocolc                 C   s8   | j  dd¡ | j j dd¡ | j  d¡ | j  ¡  dS )zh
        Report a connection failure in a response to the incoming request as
        an error.
        iõ  s   Gateway errors   Content-Types	   text/htmls   <H1>Could not connect</H1>N)r   r$   r*   r,   r    r2   )r   Ú	connectorÚreasonr   r   r   ÚclientConnectionFailedk   s   z)ProxyClientFactory.clientConnectionFailedN)	r5   r6   r7   r8   r   r:   r   r<   r?   r   r   r   r   r9   V   s    r9   c                   @   s6   e Zd ZdZdeiZddiZeefdd„Z	dd„ Z
dS )	ÚProxyRequestzÃ
    Used by Proxy to implement a simple web proxy.

    @ivar reactor: the reactor used to create connections.
    @type reactor: object providing L{twisted.internet.interfaces.IReactorTCP}
    s   httpéP   c                 C   ó   t  | ||¡ || _d S r   ©r
   r   r   ©r   ÚchannelÚqueuedr   r   r   r   r   �   ó   
zProxyRequest.__init__c           
      C   sÖ   t | jƒ}|d }|d  d¡}| j| }d|v r$| d¡\}}t|ƒ}td|dd …  ƒ}|s4|d }| j| }|  ¡  	¡ }d|vrJ| 
d¡|d< | j dd¡ | j ¡ }|| j|| j||| ƒ}	| j |||	¡ d S )	Nr   é   Úasciiú:)ó    rK   é   ó   /ó   host)r   ÚuriÚdecodeÚportsÚsplitr%   r   Ú	protocolsÚgetAllHeadersÚcopyÚencodeÚcontentÚseekÚreadÚmethodÚclientprotor   Ú
connectTCP)
r   Úparsedr:   ÚhostÚportr   Úclass_r   ÚsÚclientFactoryr   r   r   Úprocess…   s$   



zProxyRequest.processN)r5   r6   r7   r8   r9   rS   rQ   r   r   r   rc   r   r   r   r   r@   v   s    r@   c                   @   ó   e Zd ZdZeZdS )ÚProxyao  
    This class implements a simple web proxy.

    Since it inherits from L{twisted.web.http.HTTPChannel}, to use it you
    should do something like this::

        from twisted.web import http
        f = http.HTTPFactory()
        f.protocol = Proxy

    Make the HTTPFactory a listener on a port as per usual, and you have
    a fully-functioning web proxy!
    N)r5   r6   r7   r8   r@   ÚrequestFactoryr   r   r   r   re   š   s    re   c                   @   s*   e Zd ZdZeZeefdd„Zdd„ Z	dS )ÚReverseProxyRequestal  
    Used by ReverseProxy to implement a simple reverse proxy.

    @ivar proxyClientFactoryClass: a proxy client factory class, used to create
        new connections.
    @type proxyClientFactoryClass: L{ClientFactory}

    @ivar reactor: the reactor used to create connections.
    @type reactor: object providing L{twisted.internet.interfaces.IReactorTCP}
    c                 C   rB   r   rC   rD   r   r   r   r   º   rG   zReverseProxyRequest.__init__c                 C   sZ   | j  d| jj d¡g¡ |  | j| j| j|  	¡ | j
 ¡ | ¡}| j | jj| jj|¡ dS )zµ
        Handle this request by connecting to the proxied server and forwarding
        it there, then forwarding the response back as the response to this
        request.
        rN   rI   N)ÚrequestHeadersr+   Úfactoryr^   rV   ÚproxyClientFactoryClassrZ   rO   r[   rT   rW   rY   r   r\   r_   )r   rb   r   r   r   rc   ¾   s   úzReverseProxyRequest.processN)
r5   r6   r7   r8   r9   rj   r   r   r   rc   r   r   r   r   rg   ¬   s
    rg   c                   @   rd   )ÚReverseProxyzo
    Implements a simple reverse proxy.

    For details of usage, see the file examples/reverse-proxy.py.
    N)r5   r6   r7   r8   rg   rf   r   r   r   r   rk   Ð   s    rk   c                   @   s0   e Zd ZdZeZefdd„Zdd„ Zdd„ Z	dS )	ÚReverseProxyResourceaØ  
    Resource that renders the results gotten from another server

    Put this resource in the tree to cause everything below it to be relayed
    to a different server.

    @ivar proxyClientFactoryClass: a proxy client factory class, used to create
        new connections.
    @type proxyClientFactoryClass: L{ClientFactory}

    @ivar reactor: the reactor used to create connections.
    @type reactor: object providing L{twisted.internet.interfaces.IReactorTCP}
    c                 C   s&   t  | ¡ || _|| _|| _|| _dS )aU  
        @param host: the host of the web server to proxy.
        @type host: C{str}

        @param port: the port of the web server to proxy.
        @type port: C{port}

        @param path: the base path to fetch data from. Note that you shouldn't
            put any trailing slashes in it, it will be added automatically in
            request. For example, if you put B{/foo}, a request on B{/bar} will
            be proxied to B{/foo/bar}.  Any required encoding of special
            characters (such as " " or "/") should have been done already.

        @type path: C{bytes}
        N)r   r   r^   r_   Úpathr   )r   r^   r_   rm   r   r   r   r   r   ë   s
   

zReverseProxyResource.__init__c                 C   s,   t | j| j| jd t|dd� d¡ | jƒS )z¿
        Create and return a proxy resource with the same proxy configuration
        as this one, except that its path also contains the segment given by
        C{path} at the end.
        rM   rK   )Úsafezutf-8)rl   r^   r_   rm   ÚurlquoterV   r   )r   rm   Úrequestr   r   r   ÚgetChild  s   üzReverseProxyResource.getChildc                 C   s¨   | j dkr	| j}nd| j| j f }|j d| d¡g¡ |j dd¡ t|jƒd }|r4| j	d | }n| j	}|  
|j||j| ¡ |j ¡ |¡}| j | j| j |¡ tS )zJ
        Render a request by forwarding it to the proxied server.
        rA   z%s:%drN   rI   r   é   ó   ?)r_   r^   rh   r+   rV   rW   rX   r   rO   rm   rj   rZ   r[   rT   rY   r   r\   r   )r   rp   r^   Úqsr   rb   r   r   r   Úrender  s&   
úzReverseProxyResource.renderN)
r5   r6   r7   r8   r9   rj   r   r   rq   ru   r   r   r   r   rl   Ú   s    rl   N)r8   Úurllib.parser   ro   r   r   Útwisted.internetr   Útwisted.internet.protocolr   Útwisted.web.httpr   r   r	   r
   Útwisted.web.resourcer   Útwisted.web.serverr   r   r9   r@   re   rg   rk   rl   r   r   r   r   Ú<module>   s   7 $$
