o
    ¯b;  ã                   @   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))
zkimport cgi
fs = cgi.FieldStorage()
param = fs.getvalue("param")
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   ú;/usr/lib/python3/dist-packages/twisted/web/test/test_cgi.pyr   c   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
   ÚsibpathÚ__file__ÚputChildr   r   ÚSiter   Ú	listenTCPÚpÚgetHostÚport)ÚselfÚcgiÚrootÚcgipathÚsiter   r   r   ÚstartServerh   s   
z(_StartServerAndTearDownMixin.startServerc                 C   s   t | dd ƒr| j ¡ S d S )Nr'   )Úgetattrr'   ÚstopListening©r*   r   r   r   ÚtearDownp   s   
ÿz%_StartServerAndTearDownMixin.tearDownc                 C   sJ   t j |  ¡ ¡}t|dƒ}| |¡ W d   ƒ |S 1 sw   Y  |S )NÚwt)ÚosÚpathÚabspathÚmktempÚopenÚwrite)r*   ÚsourceÚcgiFilenameÚcgiFiler   r   r   ÚwriteCGIt   s   
ÿþz%_StartServerAndTearDownMixin.writeCGIN)r   r   r   r/   r3   r>   r   r   r   r   r    g   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)r>   Ú	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 outputrA   )ÚassertEqualr5   ÚlineseprD   )r*   Úresr   r   r   rI   Ž   ó   zCGITests._testCGI_1c                    ób   ˆ   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@   rA   rB   c                    s,   ˆ   d| j d¡¡ ˆ   d| j d¡¡ d S )NÚmonkeysr   z	last yearÚdate)ÚassertNotInÚheadersÚgetRawHeaders©Úresponser2   r   r   ÚcheckResponseŸ   s   z;CGITests.test_protectedServerAndDate.<locals>.checkResponse)
r>   ÚSPECIAL_HEADER_CGIr/   rD   r   rE   r   rF   rG   ÚdiscardBody©r*   r<   rJ   rK   ÚagentrL   rZ   r   r2   r   Útest_protectedServerAndDate‘   s   






z$CGITests.test_protectedServerAndDatec                    rR   )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@   rA   rB   c                    s   ˆ   | j d¡dg¡ | S )Nzcontent-typeztext/cgi-duplicate-test©rN   rV   rW   rX   r2   r   r   rZ   ´   s
   
þzBCGITests.test_noDuplicateContentTypeHeaders.<locals>.checkResponse)
r>   Ú$NO_DUPLICATE_CONTENT_TYPE_HEADER_CGIr/   rD   r   rE   r   rF   rG   r\   r]   r   r2   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@   rA   s   foos   bar)s   Proxys   X-Innocent-HeaderrB   )rV   c                    s,   t  |  d¡¡}ˆ  t| ¡ ƒh d£¡ d S )NrA   >   Ú	HTTP_HOSTÚHTTP_CONNECTIONÚHTTP_X_INNOCENT_HEADER)ÚjsonÚloadsÚdecoderN   ÚsetÚkeys)rY   rV   r2   r   r   rZ   Ï   s
   
þz7CGITests.test_noProxyPassthrough.<locals>.checkResponse)r>   ÚHEADER_OUTPUT_CGIr/   rD   r   rE   r   r   ÚHeadersrF   rG   rH   )r*   r<   rJ   rK   r^   rV   rL   rZ   r   r2   r   Útest_noProxyPassthrough¾   s   




ÿ
z CGITests.test_noProxyPassthroughc                    rR   )zp
        If a CGI script emits two instances of the same header, both are sent
        in the response.
        r@   rA   rB   c                    s   ˆ   | j d¡ddg¡ d S )NÚheaderÚspamÚeggsr`   rX   r2   r   r   rZ   è   rQ   z7CGITests.test_duplicateHeaderCGI.<locals>.checkResponse)
r>   ÚDUAL_HEADER_CGIr/   rD   r   rE   r   rF   rG   r\   r]   r   r2   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@   rA   rB   c                    s   ˆ   t | ¡¡ d S ©N)Úappendr	   ÚtextFromEventDict)Ú	eventDict)ÚloggedMessagesr   r   Ú
addMessageü   s   z4CGITests.test_malformedHeaderCGI.<locals>.addMessagec                    s   ˆ  dtdƒ ˆ ¡ d S )Nzignoring malformed CGI header: s   XYZ)ÚassertInÚrepr©Úignored©rw   r*   r   r   rZ     s   ÿz7CGITests.test_malformedHeaderCGI.<locals>.checkResponse)r>   ÚBROKEN_HEADER_CGIr/   rD   r   rE   r   rF   rG   r\   r	   ÚaddObserverÚ
addCleanupÚremoveObserver)r*   r<   rJ   rK   r^   rL   rx   rZ   r   r}   r   Útest_malformedHeaderCGIî   s   







z CGITests.test_malformedHeaderCGIc                 C   s”   t j |  ¡ ¡}t|dƒ}| t¡ W d   ƒ n1 sw   Y  |  |¡}t 	t
¡}d|f }| d¡}| d|¡}| tj¡ | | j¡ |S )Nr4   r@   rA   rB   )r5   r6   r7   r8   r9   r:   ÚREADINPUT_CGIr/   r   rE   r   rD   rF   rG   rH   Ú_test_ReadEmptyInput_1©r*   r<   r=   rJ   r^   rK   rL   r   r   r   Útest_ReadEmptyInput
  s   ÿ



zCGITests.test_ReadEmptyInputé   c                 C   ó&   dt j› }| d¡}|  ||¡ d S ©Nzreadinput okrA   ©r5   rO   rD   rN   ©r*   rP   Úexpectedr   r   r   r„     ó   
zCGITests._test_ReadEmptyInput_1c                 C   s¢   t j |  ¡ ¡}t|dƒ}| t¡ W d   ƒ n1 sw   Y  |  |¡}t 	t
¡}d|f }| d¡}|j|dt tdƒ¡d}| tj¡ | | j¡ |S ©Nr4   r@   rA   s   POSTs   Here is your stdin)ÚuriÚmethodÚbodyProducer)r5   r6   r7   r8   r9   r:   rƒ   r/   r   rE   r   rD   rF   ÚFileBodyProducerr   rG   rH   Ú_test_ReadInput_1r…   r   r   r   Útest_ReadInput  s    ÿ



ýzCGITests.test_ReadInputc                 C   rˆ   r‰   rŠ   r‹   r   r   r   r“   3  r   zCGITests._test_ReadInput_1c                 C   sž   t j |  ¡ ¡}t|dƒ}| t¡ W d   ƒ n1 sw   Y  |  |¡}d|f }| d¡}t	 
t¡j|dt	 tdƒ¡d}| t	j¡ | | j¡ |S rŽ   )r5   r6   r7   r8   r9   r:   ÚREADALLINPUT_CGIr/   rD   r   rE   r   rF   r’   r   rG   rH   Ú_test_ReadAllInput_1)r*   r<   r=   rJ   rK   rL   r   r   r   Útest_ReadAllInput8  s   ÿ



ýzCGITests.test_ReadAllInputc                 C   rˆ   )Nzreadallinput okrA   rŠ   r‹   r   r   r   r–   K  r   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   ÚFakeReactorV  s    r   ÚaÚbÚTCPú	127.0.0.1é90  z
dummy-file©r   N)	r   r   ÚIPv4Addressr   r   ÚFilteredScriptr   Ú
assertTruer˜   )r*   r   ÚfakeReactorrF   r   r   r   r   Útest_useReactorArgumentP  s   
z CGITests.test_useReactorArgumentN)r   r   r   rœ   r   ÚIReactorProcessÚ
providedByr   ÚskiprM   rI   r_   rb   rm   rr   r‚   r†   Útimeoutr„   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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=1234rB   )
r>   ÚURL_PARAMETER_CGIr/   r   rE   r   rF   rG   rH   Ú_test_urlParameters_1)r*   r<   rJ   rK   r^   rL   r   r   r   Útest_urlParameterst  s   



z!CGIScriptTests.test_urlParametersc                 C   rˆ   )NÚ1234rA   rŠ   r‹   r   r   r   r¯   ‚  r   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™   ÚenvÚ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¢   Ú	PATH_INFOz/a/bN)
r   Ú	CGIScriptr8   r   r   r¤   r   r   rN   r²   )r*   r   Ú_reactorr   rF   r   r   r   Útest_pathInfo‡  s   
zCGIScriptTests.test_pathInfoN)r   r   r   rœ   r°   r¯   rº   r   r   r   r   r­   o  s
    r­   c                   @   ó    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                    ó   ˆ  ˆ jt¡ d S rs   ©rN   ÚresponseCoder   r{   ©rF   r*   r   r   Ú
cbRenderedµ  ó   z1CGIDirectoryTests.test_render.<locals>.cbRendered)r   ÚCGIDirectoryr8   r   r   rG   )r*   r   rL   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}.
        Úfooc                    r¾   rs   r¿   r{   rÁ   r   r   rÂ   É  rÃ   z8CGIDirectoryTests.test_notFoundChild.<locals>.cbRendered)	r8   r5   Úmakedirsr   rÄ   r   ÚgetChildr   rG   )r*   r6   r   ÚchildrL   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                   @   r»   )Ú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   ÚProcessTerminatedrN   rÀ   r   )r*   rF   Ú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Ì   ÚconnectionLostr   rÎ   r   rÍ   r   rÏ   )r*   rL   rF   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 rs   r   )Ú_rX   r   r   Ú<lambda>ô  s    zdiscardBody.<locals>.<lambda>)r   rH   rG   rX   r   rX   r   r\   ì  s   r\   )4rœ   rf   r5   r   Úior   Útwisted.internetr   r   r   r   Útwisted.internet.errorr   Útwisted.pythonr   r	   r
   Útwisted.trialr   Útwisted.webr   r   r   r   r   r   Útwisted.web.httpr   r   Útwisted.web.test._utilr   Útwisted.web.test.requesthelperr   r   rC   rq   r~   r[   rƒ   r•   ra   rk   r®   r¥   r   r    ÚTestCaser?   r­   r¼   rË   r\   r   r   r   r   Ú<module>   s<    	
 u8)