U
    
W[k&                     @   s   d Z ddlmZmZ ddlmZmZ ddlmZ ddl	m
Z
 ddlmZ ddlmZ ddlmZmZmZ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.
    )absolute_importdivision)urllib_parseurlquote)reactor)ClientFactory)Resource)NOT_DONE_YET)
HTTPClientRequestHTTPChannel_QUEUED_SENTINELc                   @   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   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)
ZsendCommandr   r   r   itemsZ
sendHeaderZ
endHeaders	transportwriter   )r   headervaluer   r   r   connectionMade5   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   handleHeaderA   s    zProxyClient.handleHeaderc                 C   s   | j | d S r   )r   r   )r   bufferr   r   r   handleResponsePartL   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   handleResponseEndP   s    
zProxyClient.handleResponseEndN)__name__
__module____qualname____doc__r/   r   r!   r&   r,   r.   r1   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   d   s    zProxyClientFactory.__init__c                 C   s    |  | j| j| j| j| j| jS r   )protocolr   r   r   r   r   r   )r   Zaddrr   r   r   buildProtocolm   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   r0   )r   Z	connectorreasonr   r   r   clientConnectionFailedr   s    z)ProxyClientFactory.clientConnectionFailedN)	r2   r3   r4   r5   r   r7   r   r8   r:   r   r   r   r   r6   \   s
   	r6   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   httpP   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rJ|d\}}t|}t d|dd   }|sl|d }| j| }| 	 
 }d|kr|d|d< | jdd | j }|| j|| j||| }	| j|||	 d S )	Nr      ascii:)    rB         /   host)r   urlparseuridecodeportssplitr#   Z
urlunparse	protocolsgetAllHeaderscopyencodecontentseekreadmethodclientprotor   
connectTCP)
r   Zparsedr7   hostportr   Zclass_r   sclientFactoryr   r   r   process   s*    


 zProxyRequest.processN)r2   r3   r4   r5   r6   rK   rI   r   r   r   rY   r   r   r   r   r;   ~   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)r2   r3   r4   r5   r;   requestFactoryr   r   r   r   rZ      s   rZ   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   rN   proxyClientFactoryClassrR   rG   rS   rL   rO   rQ   r   rT   rV   )r   rX   r   r   r   rY      s        zReverseProxyRequest.processN)
r2   r3   r4   r5   r6   r_   r   r   r   rY   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)r2   r3   r4   r5   r\   r[   r   r   r   r   r`      s   r`   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 )aS  
        @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{str}
        N)r   r   rU   rV   pathr   )r   rU   rV   rb   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   )Zsafezutf-8)ra   rU   rV   rb   r   rN   r   )r   rb   requestr   r   r   getChild  s      zReverseProxyResource.getChildc                 C   s   | j dkr| j}n| jd t| j  }|jd|dg |jdd t	|j
d }|rn| jd | }n| j}| |j||j| |j |}| j| j| j | tS )zJ
        Render a request by forwarding it to the proxied server.
        r<   rA   rE   r@   r         ?)rV   rU   strr]   r)   rN   rO   rP   r   rF   rG   rb   r_   rR   rS   rL   rQ   r   rT   r	   )r   rc   rU   Zqsr   rX   r   r   r   render  s&    
    zReverseProxyResource.renderN)
r2   r3   r4   r5   r6   r_   r   r   rd   rh   r   r   r   r   ra      s
   ra   N)r5   Z
__future__r   r   Ztwisted.python.compatr   r   Ztwisted.internetr   Ztwisted.internet.protocolr   Ztwisted.web.resourcer   Ztwisted.web.serverr	   Ztwisted.web.httpr
   r   r   r   r   r6   r;   rZ   r\   r`   ra   r   r   r   r   <module>   s   <"'#