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   httpP   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 $$
