U
    T‚g;  ã                   @   sT  d Z ddlZddlZddl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mZmZ ddlmZ ddlmZmZmZmZmZmZ dd	lmZmZ dd
lmZ ddlm Z m!Z! dZ"dZ#dZ$dZ%dZ&dZ'dZ(dZ)dZ*G dd„ dej+ƒZ,G dd„ dƒZ-G dd„ de-ej.ƒZ/G dd„ de-ej.ƒZ0G dd„ dej.ƒZ1G dd „ d ej.ƒZ2d!d"„ Z3dS )#z!
Tests for L{twisted.web.twcgi}.
é    N)ÚBytesIO)ÚaddressÚerrorÚ
interfacesÚreactor)ÚConnectionLost)ÚfailureÚlogÚutil)Úunittest)ÚclientÚhttpÚhttp_headersÚresourceÚserverÚtwcgi)ÚINTERNAL_SERVER_ERRORÚ	NOT_FOUND)Ú_render)ÚDummyChannelÚDummyRequestz2print("Header: OK")
print("")
print("cgi output")
zJprint("Header: spam")
print("Header: eggs")
print("")
print("cgi output")
z+print("XYZ")
print("")
print("cgi output")
zPprint("Server: monkeys")
print("Date: last year")
print("")
print("cgi output")
a&  # This is an example of a correctly-written CGI script which reads a body
# from stdin, which only reads env['CONTENT_LENGTH'] bytes.

import os, sys

body_length = int(os.environ.get('CONTENT_LENGTH',0))
indata = sys.stdin.read(body_length)
print("Header: OK")
print("")
print("readinput ok")
a+  # This is an example of the typical (incorrect) CGI script which expects
# the server to close stdin when the body of the request is complete.
# A correct CGI should only read env['CONTENT_LENGTH'] bytes.

import sys

indata = sys.stdin.read()
print("Header: OK")
print("")
print("readallinput ok")
zMprint("content-type: text/cgi-duplicate-test")
print("")
print("cgi output")
z†import json
import os
print("")
print("")
vals = {x:y for x,y in os.environ.items() if x.startswith("HTTP_")}
print(json.dumps(vals))
z]import os
param = str(os.environ['QUERY_STRING'])
print("Header: OK")
print("")
print(param)
c                   @   s   e Zd ZejZdS )ÚPythonScriptN)Ú__name__Ú
__module__Ú__qualname__ÚsysÚ
executableÚfilter© r   r   ú=/tmp/pip-unpacked-wheel-1_7di8ic/twisted/web/test/test_cgi.pyr   b   s   r   c                   @   s$   e Zd Zdd„ Zdd„ Zdd„ ZdS )Ú_StartServerAndTearDownMixinc                 C   sH   t  ¡ }t t|¡}| dt|ƒ¡ t |¡}t	 
d|¡| _| j ¡ jS )Ns   cgir   )r   ÚResourcer
   ZsibpathÚ__file__ZputChildr   r   ZSiter   Z	listenTCPÚpZgetHostÚport)ÚselfÚcgiÚrootZcgipathÚsiter   r   r   ÚstartServerg   s    
z(_StartServerAndTearDownMixin.startServerc                 C   s   t | dd ƒr| j ¡ S d S )Nr#   )Úgetattrr#   ÚstopListening©r%   r   r   r   ÚtearDowno   s    z%_StartServerAndTearDownMixin.tearDownc              	   C   s4   t j |  ¡ ¡}t|dƒ�}| |¡ W 5 Q R X |S )NÚwt)ÚosÚpathÚabspathÚmktempÚopenÚwrite)r%   ÚsourceÚcgiFilenameÚcgiFiler   r   r   ÚwriteCGIs   s    z%_StartServerAndTearDownMixin.writeCGIN)r   r   r   r)   r-   r8   r   r   r   r   r    f   s   r    c                   @   s¢   e Zd ZdZej e¡sdZdd„ Z	dd„ Z
dd„ Zd	d
„ Zdd„ Zdd„ Zdd„ Zdd„ Zde_dd„ Zdd„ Zde_dd„ Zdd„ Zde_dd„ Zdd„ Zd S )!ÚCGITestsz,
    Tests for L{twcgi.FilteredScript}.
    z5CGI tests require a functional reactor.spawnProcess()c                 C   sV   |   t¡}|  |¡}d|f }| d¡}t t¡ d|¡}| tj	¡ | | j
¡ |S )Núhttp://localhost:%d/cgiÚasciió   GET)r8   Ú	DUMMY_CGIr)   Úencoder   ÚAgentr   ÚrequestÚaddCallbackÚreadBodyÚ
_testCGI_1)r%   r6   ÚportnumÚurlÚdr   r   r   Útest_CGI‚   s    



zCGITests.test_CGIc                 C   s   |   |dtj d¡ ¡ d S )Ns
   cgi outputr;   )ÚassertEqualr/   Úlinesepr>   )r%   Úresr   r   r   rC   �   s    zCGITests._testCGI_1c                    sb   ˆ   t¡}ˆ  |¡}d|f }| d¡}t t¡}| d|¡}| t	¡ ‡ fdd„}| |¡ |S )zc
        If the CGI script emits a I{Server} or I{Date} header, these are
        ignored.
        r:   r;   r<   c                    s,   ˆ   d| j d¡¡ ˆ   d| j d¡¡ d S )NZmonkeysr   z	last yearÚdate)ZassertNotInÚheadersÚgetRawHeaders©Úresponser,   r   r   ÚcheckResponsež   s    z;CGITests.test_protectedServerAndDate.<locals>.checkResponse)
r8   ÚSPECIAL_HEADER_CGIr)   r>   r   r?   r   r@   rA   ÚdiscardBody©r%   r6   rD   rE   ÚagentrF   rP   r   r,   r   Útest_protectedServerAndDate�   s    






z$CGITests.test_protectedServerAndDatec                    sb   ˆ   t¡}ˆ  |¡}d|f }| d¡}t t¡}| d|¡}| t	¡ ‡ fdd„}| |¡ |S )z¤
        If the CGI script emits a I{content-type} header, make sure that the
        server doesn't add an additional (duplicate) one, as per ticket 4786.
        r:   r;   r<   c                    s   ˆ   | j d¡dg¡ | S )Nzcontent-typeztext/cgi-duplicate-test©rH   rL   rM   rN   r,   r   r   rP   ³   s
    
þzBCGITests.test_noDuplicateContentTypeHeaders.<locals>.checkResponse)
r8   Ú$NO_DUPLICATE_CONTENT_TYPE_HEADER_CGIr)   r>   r   r?   r   r@   rA   rR   rS   r   r,   r   Ú"test_noDuplicateContentTypeHeaders¥   s    






z+CGITests.test_noDuplicateContentTypeHeadersc                    s|   ˆ   t¡}ˆ  |¡}d|f }| d¡}t t¡}t dgdgdœ¡}|j	d||d�}‡ fdd	„}| 
tj¡ | 
|¡ |S )
zV
        The CGI script is never called with the Proxy header passed through.
        r:   r;   s   foos   bar)s   Proxys   X-Innocent-Headerr<   )rL   c                    s.   t  |  d¡¡}ˆ  t| ¡ ƒdddh¡ d S )Nr;   Z	HTTP_HOSTZHTTP_CONNECTIONZHTTP_X_INNOCENT_HEADER)ÚjsonÚloadsÚdecoderH   ÚsetÚkeys)rO   rL   r,   r   r   rP   Î   s
    
þz7CGITests.test_noProxyPassthrough.<locals>.checkResponse)r8   ÚHEADER_OUTPUT_CGIr)   r>   r   r?   r   r   ZHeadersr@   rA   rB   )r%   r6   rD   rE   rT   rL   rF   rP   r   r,   r   Útest_noProxyPassthrough½   s    




ÿ
z CGITests.test_noProxyPassthroughc                    sb   ˆ   t¡}ˆ  |¡}d|f }| d¡}t t¡}| d|¡}| t	¡ ‡ fdd„}| |¡ |S )zp
        If a CGI script emits two instances of the same header, both are sent
        in the response.
        r:   r;   r<   c                    s   ˆ   | j d¡ddg¡ d S )NÚheaderZspamÚeggsrV   rN   r,   r   r   rP   ç   s    z7CGITests.test_duplicateHeaderCGI.<locals>.checkResponse)
r8   ÚDUAL_HEADER_CGIr)   r>   r   r?   r   r@   rA   rR   rS   r   r,   r   Útest_duplicateHeaderCGIÙ   s    






z CGITests.test_duplicateHeaderCGIc                    sŒ   ˆ  t¡}ˆ |¡}d|f }| d¡}t t¡}| d|¡}| t	¡ g ‰ ‡ fdd„}t
 |¡ ˆ t
j|¡ ‡ ‡fdd„}| |¡ |S )zF
        Check for the error message in the duplicated header
        r:   r;   r<   c                    s   ˆ   t | ¡¡ d S ©N)Úappendr	   ZtextFromEventDict)Z	eventDict)ÚloggedMessagesr   r   Ú
addMessageû   s    z4CGITests.test_malformedHeaderCGI.<locals>.addMessagec                    s   ˆ  dtdƒ ˆ ¡ d S )Nzignoring malformed CGI header: s   XYZ)ZassertInÚrepr©Zignored©rf   r%   r   r   rP     s    
 ÿz7CGITests.test_malformedHeaderCGI.<locals>.checkResponse)r8   ÚBROKEN_HEADER_CGIr)   r>   r   r?   r   r@   rA   rR   r	   ZaddObserverZ
addCleanupZremoveObserver)r%   r6   rD   rE   rT   rF   rg   rP   r   rj   r   Útest_malformedHeaderCGIí   s    







z CGITests.test_malformedHeaderCGIc              	   C   s€   t j |  ¡ ¡}t|dƒ�}| t¡ W 5 Q R X |  |¡}t 	t
¡}d|f }| d¡}| d|¡}| tj¡ | | j¡ |S )Nr.   r:   r;   r<   )r/   r0   r1   r2   r3   r4   ÚREADINPUT_CGIr)   r   r?   r   r>   r@   rA   rB   Ú_test_ReadEmptyInput_1©r%   r6   r7   rD   rT   rE   rF   r   r   r   Útest_ReadEmptyInput	  s    



zCGITests.test_ReadEmptyInputé   c                 C   s&   dt j› �}| d¡}|  ||¡ d S ©Nzreadinput okr;   ©r/   rI   r>   rH   ©r%   rJ   Úexpectedr   r   r   rn     s    
zCGITests._test_ReadEmptyInput_1c              	   C   sŽ   t j |  ¡ ¡}t|dƒ�}| t¡ W 5 Q R X |  |¡}t 	t
¡}d|f }| d¡}|j|dt tdƒ¡d�}| tj¡ | | j¡ |S ©Nr.   r:   r;   s   POSTs   Here is your stdin)ÚuriÚmethodZbodyProducer)r/   r0   r1   r2   r3   r4   rm   r)   r   r?   r   r>   r@   ÚFileBodyProducerr   rA   rB   Ú_test_ReadInput_1ro   r   r   r   Útest_ReadInput  s    



ýzCGITests.test_ReadInputc                 C   s&   dt j› �}| d¡}|  ||¡ d S rr   rs   rt   r   r   r   rz   2  s    
zCGITests._test_ReadInput_1c              	   C   sŠ   t j |  ¡ ¡}t|dƒ�}| t¡ W 5 Q R X |  |¡}d|f }| d¡}t	 
t¡j|dt	 tdƒ¡d�}| t	j¡ | | j¡ |S rv   )r/   r0   r1   r2   r3   r4   ÚREADALLINPUT_CGIr)   r>   r   r?   r   r@   ry   r   rA   rB   Ú_test_ReadAllInput_1)r%   r6   r7   rD   rE   rF   r   r   r   Útest_ReadAllInput7  s    



ýzCGITests.test_ReadAllInputc                 C   s&   dt j› �}| d¡}|  ||¡ d S )Nzreadallinput okr;   rs   rt   r   r   r   r}   J  s    
zCGITests._test_ReadAllInput_1c                 C   sX   G dd„ dƒ}|ƒ }t ddgƒ}t ddd¡|_tjd|d	�}t||ƒ |  |j¡ d
S )zw
        L{twcgi.FilteredScript.runProcess} uses the reactor passed as an
        argument to the constructor.
        c                   @   s   e Zd ZdZdZdd„ ZdS )z5CGITests.test_useReactorArgument.<locals>.FakeReactorzR
            A fake reactor recording whether spawnProcess is called.
            Fc                 _   s
   d| _ dS )zÇ
                Set the C{called} flag to C{True} if C{spawnProcess} is called.

                @param args: Positional arguments.
                @param kwargs: Keyword arguments.
                TN)Úcalled)r%   ÚargsÚkwargsr   r   r   ÚspawnProcess\  s    zBCGITests.test_useReactorArgument.<locals>.FakeReactor.spawnProcessN)r   r   r   Ú__doc__r   r‚   r   r   r   r   ÚFakeReactorU  s   r„   ÚaÚbÚTCPú	127.0.0.1é90  z
dummy-file©r   N)	r   r   ÚIPv4Addressr   r   ÚFilteredScriptr   Ú
assertTruer   )r%   r„   ZfakeReactorr@   r   r   r   r   Útest_useReactorArgumentO  s    
z CGITests.test_useReactorArgumentN)r   r   r   rƒ   r   ZIReactorProcessZ
providedByr   ÚskiprG   rC   rU   rX   r_   rc   rl   rp   Útimeoutrn   r{   rz   r~   r}   rŽ   r   r   r   r   r9   z   s(   r9   c                   @   s(   e Zd ZdZdd„ Zdd„ Zdd„ ZdS )	ÚCGIScriptTestsz'
    Tests for L{twcgi.CGIScript}.
    c                 C   sP   |   t¡}|  |¡}d|f }t t¡}| d|¡}| tj¡ | | j	¡ |S )zk
        If the CGI script is passed URL parameters, do not fall over,
        as per ticket 9887.
        s"   http://localhost:%d/cgi?param=1234r<   )
r8   ÚURL_PARAMETER_CGIr)   r   r?   r   r@   rA   rB   Ú_test_urlParameters_1)r%   r6   rD   rE   rT   rF   r   r   r   Útest_urlParameterss  s    



z!CGIScriptTests.test_urlParametersc                 C   s&   dt j› �}| d¡}|  ||¡ d S )Nz
param=1234r;   rs   rt   r   r   r   r“   �  s    
z$CGIScriptTests._test_urlParameters_1c                 C   sb   G dd„ dƒ}|ƒ }t j|  ¡ |d�}tddgƒ}t ddd¡|_t||ƒ |  |j	d	 d
¡ dS )zt
        L{twcgi.CGIScript.render} sets the process environment
        I{PATH_INFO} from the request path.
        c                   @   s   e Zd ZdZdd„ ZdS )z1CGIScriptTests.test_pathInfo.<locals>.FakeReactorzZ
            A fake reactor recording the environment passed to spawnProcess.
            c                 S   s
   || _ dS )a9  
                Store the C{env} L{dict} to an instance attribute.

                @param process: Ignored
                @param filename: Ignored
                @param args: Ignored
                @param env: The environment L{dict} which will be stored
                @param wdir: Ignored
                N)Úprocess_env)r%   ÚprocessÚfilenamer€   ÚenvZwdirr   r   r   r‚   ‘  s    
z>CGIScriptTests.test_pathInfo.<locals>.FakeReactor.spawnProcessN)r   r   r   rƒ   r‚   r   r   r   r   r„   Œ  s   r„   rŠ   r…   r†   r‡   rˆ   r‰   Z	PATH_INFOz/a/bN)
r   Z	CGIScriptr2   r   r   r‹   r   r   rH   r•   )r%   r„   Z_reactorr   r@   r   r   r   Útest_pathInfo†  s    
zCGIScriptTests.test_pathInfoN)r   r   r   rƒ   r”   r“   r™   r   r   r   r   r‘   n  s   r‘   c                   @   s    e Zd ZdZdd„ Zdd„ ZdS )ÚCGIDirectoryTestsz*
    Tests for L{twcgi.CGIDirectory}.
    c                    s>   t  ˆ ¡ ¡}tdgƒ‰ t|ˆ ƒ}‡ ‡fdd„}| |¡ |S )zc
        L{twcgi.CGIDirectory.render} sets the HTTP response code to I{NOT
        FOUND}.
        Ú c                    s   ˆ  ˆ jt¡ d S rd   ©rH   ÚresponseCoder   ri   ©r@   r%   r   r   Ú
cbRendered´  s    z1CGIDirectoryTests.test_render.<locals>.cbRendered)r   ÚCGIDirectoryr2   r   r   rA   )r%   r   rF   rŸ   r   rž   r   Útest_render«  s    


zCGIDirectoryTests.test_renderc                    sX   ˆ  ¡ }t |¡ t |¡}tdgƒ‰ | dˆ ¡}t|ˆ ƒ}‡ ‡fdd„}| |¡ |S )a  
        L{twcgi.CGIDirectory.getChild} returns a resource which renders an
        response with the HTTP I{NOT FOUND} status code if the indicated child
        does not exist as an entry in the directory used to initialized the
        L{twcgi.CGIDirectory}.
        Zfooc                    s   ˆ  ˆ jt¡ d S rd   rœ   ri   rž   r   r   rŸ   È  s    z8CGIDirectoryTests.test_notFoundChild.<locals>.cbRendered)	r2   r/   Úmakedirsr   r    r   ÚgetChildr   rA   )r%   r0   r   ÚchildrF   rŸ   r   rž   r   Útest_notFoundChildº  s    




z$CGIDirectoryTests.test_notFoundChildN)r   r   r   rƒ   r¡   r¥   r   r   r   r   rš   ¦  s   rš   c                   @   s    e Zd ZdZdd„ Zdd„ ZdS )ÚCGIProcessProtocolTestsz0
    Tests for L{twcgi.CGIProcessProtocol}.
    c                 C   s:   t dgƒ}t |¡}| t t ¡ ¡¡ |  |j	t
¡ dS )zÂ
        If the process communicating with L{CGIProcessProtocol} ends before
        finishing writing out headers, the response has I{INTERNAL SERVER
        ERROR} as its status code.
        r›   N)r   r   ÚCGIProcessProtocolÚprocessEndedr   ÚFailurer   ÚProcessTerminatedrH   r�   r   )r%   r@   Úprotocolr   r   r   Útest_prematureEndOfHeadersÔ  s    

z2CGIProcessProtocolTests.test_prematureEndOfHeadersc                 C   sH   t ƒ }t |d¡}t |¡}| t tdƒ¡¡ | 	t t
 ¡ ¡¡ dS )zg
        Ensure that the CGI process ends cleanly when the request connection
        is lost.
        TzConnection doneN)r   r   ÚRequestr   r§   ZconnectionLostr   r©   r   r¨   r   rª   )r%   rF   r@   r«   r   r   r   Útest_connectionLostß  s
    
z+CGIProcessProtocolTests.test_connectionLostN)r   r   r   rƒ   r¬   r®   r   r   r   r   r¦   Ï  s   r¦   c                    s   t  ˆ ¡ ‡ fdd„¡S )zn
    Discard the body of a HTTP response.

    @param response: The response.

    @return: The response.
    c                    s   ˆ S rd   r   )Ú_rN   r   r   Ú<lambda>ó  ó    zdiscardBody.<locals>.<lambda>)r   rB   rA   rN   r   rN   r   rR   ë  s    rR   )4rƒ   rY   r/   r   Úior   Ztwisted.internetr   r   r   r   Ztwisted.internet.errorr   Ztwisted.pythonr   r	   r
   Ztwisted.trialr   Ztwisted.webr   r   r   r   r   r   Ztwisted.web.httpr   r   Ztwisted.web.test._utilr   Ztwisted.web.test.requesthelperr   r   r=   rb   rk   rQ   rm   r|   rW   r^   r’   rŒ   r   r    ZTestCaser9   r‘   rš   r¦   rR   r   r   r   r   Ú<module>   s:    		 u8)