a
    )(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   0lib/python3.9/site-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   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v 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   Z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   r7   r9   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   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|v rH|d\}}t|}td|dd   }|sh|d }| j| }|  	 }d|vr|
d|d< | jdd | j }|| j|| j||| }	| j|||	 d S )	Nr      ascii:)    rA         /   host)r   uridecodeportssplitr"   r   	protocolsgetAllHeaderscopyencodecontentseekreadmethodclientprotor   
connectTCP)
r   Zparsedr6   hostportr   Zclass_r   sclientFactoryr   r   r   process   s$    



zProxyRequest.processN)r1   r2   r3   r4   r5   rI   rG   r   r   r   rW   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   rX      s   rX   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.
        rD   r?   N)requestHeadersr(   factoryrS   rL   proxyClientFactoryClassrP   rE   rQ   rJ   rM   rO   r   rR   rT   )r   rV   r   r   r   rW      s    zReverseProxyRequest.processN)
r1   r2   r3   r4   r5   r]   r   r   r   rW   r   r   r   r   rZ      s   rZ   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   rZ   rY   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 )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   rS   rT   pathr   )r   rS   rT   r`   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.
        rC   rA   )Zsafezutf-8)r_   rS   rT   r`   urlquoterL   r   )r   r`   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:%drD   r?   r         ?)rT   rS   r[   r(   rL   rM   rN   r   rE   r`   r]   rP   rQ   rJ   rO   r   rR   r   )r   rb   rS   Zqsr   rV   r   r   r   render  s&    
zReverseProxyResource.renderN)
r1   r2   r3   r4   r5   r]   r   r   rc   rf   r   r   r   r   r_      s
   r_   N)r4   Zurllib.parser   ra   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:   rX   rZ   r^   r_   r   r   r   r   <module>   s   7 $$
