U
    
W[Á5  ã                   @   s*  d Z ddlZddlZddl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mZmZ ddlmZmZ ddlmZmZmZmZmZ dd	lmZ dd
lm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ej(ƒZ)G dd„ dej(ƒZ*G dd„ dej(ƒZ+G dd„ dej(ƒZ,dd„ Z-dS )z!
Tests for L{twisted.web.twcgi}.
é    N)ÚBytesIO)Úunittest)ÚaddressÚreactorÚ
interfacesÚerror)ÚutilÚfailureÚlog)Ú	NOT_FOUNDÚINTERNAL_SERVER_ERROR)ÚclientÚtwcgiÚserverÚresourceÚhttp_headers)Ú_render)Ú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))
c                   @   s   e Zd ZejZdS )ÚPythonScriptN)Ú__name__Ú
__module__Ú__qualname__ÚsysÚ
executableÚfilter© r   r   ú;/usr/lib/python3/dist-packages/twisted/web/test/test_cgi.pyr   X   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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   sH   t  ¡ }t t|¡}| dt|ƒ¡ t |¡}t	 
d|¡| _| j ¡ jS )Ns   cgir   )r   ZResourcer   ZsibpathÚ__file__ZputChildr   r   ZSiter   Z	listenTCPÚpZgetHostZport)ÚselfZcgiÚrootZcgipathZsiter   r   r   ÚstartServerf   s    
zCGITests.startServerc                 C   s   t | dd ƒr| j ¡ S d S )Nr   )Úgetattrr   ZstopListening©r    r   r   r   ÚtearDowno   s    zCGITests.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   ÚwriteCGIt   s    zCGITests.writeCGIc                 C   sV   |   t¡}|  |¡}d|f }| d¡}t t¡ d|¡}| tj	¡ | | j
¡ |S )Núhttp://localhost:%d/cgiÚasciió   GET)r0   Ú	DUMMY_CGIr"   Úencoder   ÚAgentr   ÚrequestÚaddCallbackÚreadBodyÚ
_testCGI_1)r    r.   ÚportnumÚurlÚdr   r   r   Útest_CGI{   s    



zCGITests.test_CGIc                 C   s   |   |dtj d¡ ¡ d S )Ns
   cgi outputr2   )ÚassertEqualr'   Úlinesepr5   )r    Úresr   r   r   r:   ‡   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.
        r1   r2   r3   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)
r0   ÚSPECIAL_HEADER_CGIr"   r5   r   r6   r   r7   r8   ÚdiscardBody©r    r.   r;   r<   Úagentr=   rG   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.
        r1   r2   r3   c                    s   ˆ   | j d¡dg¡ | S )Nzcontent-typeztext/cgi-duplicate-test©r?   rC   rD   rE   r$   r   r   rG   ®   s
    
þzBCGITests.test_noDuplicateContentTypeHeaders.<locals>.checkResponse)
r0   Ú$NO_DUPLICATE_CONTENT_TYPE_HEADER_CGIr"   r5   r   r6   r   r7   r8   rI   rJ   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.
        r1   r2   s   foos   bar)s   Proxys   X-Innocent-Headerr3   )rC   c                    s.   t  |  d¡¡}ˆ  t| ¡ ƒdddh¡ d S )Nr2   Z	HTTP_HOSTZHTTP_CONNECTIONZHTTP_X_INNOCENT_HEADER)ÚjsonÚloadsÚdecoder?   ÚsetÚkeys)rF   rC   r$   r   r   rG   Ç   s
    
þz7CGITests.test_noProxyPassthrough.<locals>.checkResponse)r0   ÚHEADER_OUTPUT_CGIr"   r5   r   r6   r   r   ZHeadersr7   r8   r9   )r    r.   r;   r<   rK   rC   r=   rG   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.
        r1   r2   r3   c                    s   ˆ   | j d¡ddg¡ d S )NÚheaderZspamZeggsrM   rE   r$   r   r   rG   ß   s    
 ÿz7CGITests.test_duplicateHeaderCGI.<locals>.checkResponse)
r0   ÚDUAL_HEADER_CGIr"   r5   r   r6   r   r7   r8   rI   rJ   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
        r1   r2   r3   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©r\   r    r   r   rG   ú   s    ÿz7CGITests.test_malformedHeaderCGI.<locals>.checkResponse)r0   ÚBROKEN_HEADER_CGIr"   r5   r   r6   r   r7   r8   rI   r
   ZaddObserverZ
addCleanupZremoveObserver)r    r.   r;   r<   rK   r=   r]   rG   r   r`   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&   r1   r2   r3   )r'   r(   r)   r*   r+   r,   ÚREADINPUT_CGIr"   r   r6   r   r5   r7   r8   r9   Ú_test_ReadEmptyInput_1©r    r.   r/   r;   rK   r<   r=   r   r   r   Útest_ReadEmptyInput  s    



zCGITests.test_ReadEmptyInputé   c                 C   s&   d  tj¡}| d¡}|  ||¡ d S ©Nzreadinput ok{}r2   ©Úformatr'   r@   r5   r?   ©r    rA   Zexpectedr   r   r   rd     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&   r1   r2   s   POSTs   Here is your stdin)ZuriÚmethodZbodyProducer)r'   r(   r)   r*   r+   r,   rc   r"   r   r6   r   r5   r7   ÚFileBodyProducerr   r8   r9   Ú_test_ReadInput_1re   r   r   r   Útest_ReadInput  s"    



ÿýzCGITests.test_ReadInputc                 C   s&   d  tj¡}| d¡}|  ||¡ d S rh   ri   rk   r   r   r   ro   -  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 rl   )r'   r(   r)   r*   r+   r,   ÚREADALLINPUT_CGIr"   r5   r   r6   r   r7   rn   r   r8   r9   Ú_test_ReadAllInput_1)r    r.   r/   r;   r<   r=   r   r   r   Útest_ReadAllInput3  s     



ÿýzCGITests.test_ReadAllInputc                 C   s&   d  tj¡}| d¡}|  ||¡ d S )Nzreadallinput ok{}r2   ri   rk   r   r   r   rr   G  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   ÚspawnProcessW  s    zBCGITests.test_useReactorArgument.<locals>.FakeReactor.spawnProcessN)r   r   r   Ú__doc__rt   rw   r   r   r   r   ÚFakeReactorR  s   ry   ÚaÚbÚTCPú	127.0.0.1é90  z
dummy-file©r   N)	r   r   ÚIPv4Addressr   r   ÚFilteredScriptr   Z
assertTruert   )r    ry   ZfakeReactorr7   r   r   r   r   Útest_useReactorArgumentM  s    
z CGITests.test_useReactorArgumentN)r   r   r   rx   r   ZIReactorProcessZ
providedByr   Úskipr"   r%   r0   r>   r:   rL   rO   rV   rY   rb   rf   Ztimeoutrd   rp   ro   rs   rr   r‚   r   r   r   r   r   ]   s.   	r   c                   @   s   e Zd ZdZdd„ ZdS )ÚCGIScriptTestsz'
    Tests for L{twcgi.CGIScript}.
    c                 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    ZprocessÚfilenameru   ÚenvZwdirr   r   r   rw   x  s    
z>CGIScriptTests.test_pathInfo.<locals>.FakeReactor.spawnProcessN)r   r   r   rx   rw   r   r   r   r   ry   t  s   ry   r   rz   r{   r|   r}   r~   Z	PATH_INFOz/a/bN)
r   Z	CGIScriptr*   r   r   r€   r   r   r?   r…   )r    ry   Z_reactorr   r7   r   r   r   Útest_pathInfoo  s    
ÿzCGIScriptTests.test_pathInfoN)r   r   r   rx   rˆ   r   r   r   r   r„   j  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 rZ   ©r?   ÚresponseCoder   r_   ©r7   r    r   r   Ú
cbRendered›  s    z1CGIDirectoryTests.test_render.<locals>.cbRendered)r   ÚCGIDirectoryr*   r   r   r8   )r    r   r=   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 rZ   r‹   r_   r   r   r   rŽ   ®  s    z8CGIDirectoryTests.test_notFoundChild.<locals>.cbRendered)	r*   r'   Úmakedirsr   r   r   ZgetChildr   r8   )r    r(   r   Zchildr=   rŽ   r   r   r   Útest_notFoundChild¡  s    




z$CGIDirectoryTests.test_notFoundChildN)r   r   r   rx   r   r’   r   r   r   r   r‰     s   r‰   c                   @   s   e Zd Z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   ZCGIProcessProtocolZprocessEndedr	   ZFailurer   ZProcessTerminatedr?   rŒ   r   )r    r7   Zprotocolr   r   r   Útest_prematureEndOfHeaders¹  s    

z2CGIProcessProtocolTests.test_prematureEndOfHeadersN)r   r   r   rx   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 rZ   r   )Ú_rE   r   r   Ú<lambda>Î  ó    zdiscardBody.<locals>.<lambda>)r   r9   r8   rE   r   rE   r   rI   Æ  s    rI   ).rx   r   r'   rP   Úior   Ztwisted.trialr   Ztwisted.internetr   r   r   r   Ztwisted.pythonr   r	   r
   Ztwisted.web.httpr   r   Ztwisted.webr   r   r   r   r   Ztwisted.web.test._utilr   Ztwisted.web.test.test_webr   r4   rX   ra   rH   rc   rq   rN   rU   r   r   ZTestCaser   r„   r‰   r“   rI   r   r   r   r   Ú<module>   s6   	  %&