U
    ˆj“&  ã                   @   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|k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   ú5/tmp/pip-unpacked-wheel-j5h_c8_q/twisted/web/proxy.pyÚ__init__)   s    zProxyClient.__init__c                 C   sJ   |   | j| j¡ | j ¡ D ]\}}|  ||¡ q|  ¡  | j | j	¡ d S ©N)
ZsendCommandr   r   r   ÚitemsZ
sendHeaderZ
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   s4   |  ¡ dkr | jj ||g¡ n| 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 )z�
        Finish the original request, indicating that the response has been
        completely written to it, and disconnect the outgoing transport.
        TN)Ú	_finishedr   Úfinishr   ZloseConnection)r   r   r   r   ÚhandleResponseEndK   s    
zProxyClient.handleResponseEndN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r.   r   r    r%   r+   r-   r0   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   r/   )r   Z	connectorÚreasonr   r   r   ÚclientConnectionFailedk   s    z)ProxyClientFactory.clientConnectionFailedN)	r1   r2   r3   r4   r   r6   r   r8   r:   r   r   r   r   r5   V   s
   r5   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   s   t  | ||¡ || _d S r   ©r
   r   r   ©r   ZchannelZqueuedr   r   r   r   r   �   s    zProxyRequest.__init__c           
      C   sÖ   t | jƒ}|d }|d  d¡}| j| }d|krH| d¡\}}t|ƒ}td|dd …  ƒ}|sh|d }| j| }|  ¡  	¡ }d|kr”| 
d¡|d< | j dd¡ | j ¡ }|| j|| j||| ƒ}	| j |||	¡ d S )	Nr   é   Úasciiú:)ó    rB   é   ó   /ó   host)r   ÚuriÚdecodeÚportsÚsplitr"   r   Ú	protocolsÚgetAllHeadersÚcopyÚencodeÚcontentÚseekÚreadÚmethodÚclientprotor   Ú
connectTCP)
r   Úparsedr6   ÚhostÚportr   Úclass_r   ÚsÚclientFactoryr   r   r   Úprocess…   s$    



zProxyRequest.processN)r1   r2   r3   r4   r5   rJ   rH   r   r   r   rZ   r   r   r   r   r;   v   s
   r;   c                   @   s   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)r1   r2   r3   r4   r;   ÚrequestFactoryr   r   r   r   r[   š   s   r[   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   s   t  | ||¡ || _d S r   r=   r>   r   r   r   r   º   s    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.
        rE   r@   N)ÚrequestHeadersr(   ÚfactoryrU   rM   ÚproxyClientFactoryClassrQ   rF   rR   rK   rN   rP   r   rS   rV   )r   rY   r   r   r   rZ   ¾   s    úzReverseProxyRequest.processN)
r1   r2   r3   r4   r5   r`   r   r   r   rZ   r   r   r   r   r]   ¬   s   r]   c                   @   s   e Zd ZdZeZdS )ÚReverseProxyzo
    Implements a simple reverse proxy.

    For details of usage, see the file examples/reverse-proxy.py.
    N)r1   r2   r3   r4   r]   r\   r   r   r   r   ra   Ð   s   ra   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   rU   rV   Úpathr   )r   rU   rV   rc   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.
        rD   rB   )Úsafezutf-8)rb   rU   rV   rc   ÚurlquoterM   r   )r   rc   Ú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 }|rh| j	d | }n| j	}|  
|j||j| ¡ |j ¡ |¡}| j | j| j |¡ tS )zJ
        Render a request by forwarding it to the proxied server.
        r<   z%s:%drE   r@   r   é   ó   ?)rV   rU   r^   r(   rM   rN   rO   r   rF   rc   r`   rQ   rR   rK   rP   r   rS   r   )r   rf   rU   Úqsr   rY   r   r   r   Úrender  s&    
úzReverseProxyResource.renderN)
r1   r2   r3   r4   r5   r`   r   r   rg   rk   r   r   r   r   rb   Ú   s
   rb   N)r4   Úurllib.parser   re   r   r   Ztwisted.internetr   Ztwisted.internet.protocolr   Ztwisted.web.httpr   r   r	   r
   Ztwisted.web.resourcer   Ztwisted.web.serverr   r   r5   r;   r[   r]   ra   rb   r   r   r   r   Ú<module>   s   7 $$
