a
    m¬zf‘Ð  ã                   @   sÆ  d Z ddlZddlmZ ddlZddlZddlZddlZddl	Z
ddlmZ ddlZddlZddlZddlmZmZ ddlmZmZ ddlmZmZmZmZ ddlZejdd… d	kZ ep¼eZ!d
Z"dZ#G dd„ dej$ƒZ$G dd„ dƒZ%ej&dd„ ƒZ'ej&dd„ ƒZ(ej&dd„ ƒZ)dd„ Z*dd„ Z+dd„ Z,ej- .dd¡dd„ ƒZ/ej- .dd¡d d!„ ƒZ0ej- .d"d#ej1d$ej-j2eored%d&d'd(f¡d)d*„ ƒZ3d+d,„ Z4ej- .d-ej1ej5ej6d&d.d/ej1ej5ej7d&d0d/ej1ej5ej8d&d1d/ej1dej8d&d2ej-j2ed3d4d5ej1ej5ej9d&d6d/ej1e:d7d8d9d/ej1ej5d:d8d;d/fej1e;ej6d&d<d/ej1e<ej7d&d=d/ej1e<ej9d&d>d/f ¡d?d@„ ƒZ=dAdB„ Z>dCdD„ Z?ej-j2eo¢eo¢e o¢e! dEd&d'dFdG„ ƒZ@ej-j2eoÐeoÐe oÐe! dEd&d'dHdI„ ƒZAej- .dJdK¡dLdM„ ƒZBdNdO„ ZCdPdQ„ ZDdRdS„ ZEej- .dTdU¡dVdW„ ƒZFdXdY„ ZGej-j2eedZƒƒd4d[d\„ ƒZHd]d^„ ZId_d`„ ZJej- .dadb¡dcdd„ ƒZKej-j2ded4dfdg„ ƒZLej- .dhdi¡djdk„ ƒZMG dldm„ dmƒZNG dndo„ doƒZOdpdq„ ZPdS )rzETests for TCP connection handling, including proper and timely close.é    N)Úmatch)Ú
namedtuple)ÚtrimÚunwrap)ÚhelperÚwebtest)ÚIS_CIÚIS_MACOSÚIS_PYPYÚ
IS_WINDOWSé   )é   é   é   z(pPeErRsSiIsStTeEnNcCeE oOfF vViIsSiIoOnNc                   @   sˆ   e Zd Z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eeeeeeeee	e
eeedœZdS )Ú
Controllerz!Controller for serving WSGI apps.c                 C   s   dS )zRender Hello world.zHello, world!© ©ÚreqÚrespr   r   úD/var/www/media/lib/python3.9/site-packages/cheroot/test/test_conn.pyÚhello!   s    zController.helloc                 C   s   t S )zRender ``pov`` value.)Úpovr   r   r   r   r   %   s    zController.povc                 C   s*   d| j d v rtdƒ|jd< dd„ }|ƒ S )zRender streaming response.Úset_clÚQUERY_STRINGé
   úContent-Lengthc                  s   s   t dƒD ]} t| ƒV  qd S )Nr   )ÚrangeÚstr)Úxr   r   r   Úcontent.   s    z"Controller.stream.<locals>.content)Úenvironr   Úheaders)r   r   r   r   r   r   Ústream)   s    zController.streamc                 C   s@   | j d dks td| j d  ƒ‚| j d  ¡  d¡}d|›dS )z%Process file upload and render thank.ÚREQUEST_METHODÚPOSTz'POST' != request.method %rz
wsgi.inputúutf-8úthanks for 'ú')r    ÚAssertionErrorÚreadÚdecode)r   r   Zinput_contentsr   r   r   Úupload4   s    ÿÿzController.uploadc                 C   s
   d|_ dS )z Render response with status 204.Z204z
Code = 204©Ústatusr   r   r   r   Ú
custom_204>   s    zController.custom_204c                 C   s
   d|_ dS )z Render response with status 304.Z304z
Code = 304r,   r   r   r   r   Ú
custom_304C   s    zController.custom_304c                 C   s
   d|_ dS )z Render response with status 500.z500 Internal Server ErrorÚokr,   r   r   r   r   Úerr_before_readH   s    zController.err_before_readc                 C   s
   dgd S )zRender 1MB response.A   aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaé   r   r   r   r   r   Úone_megabyte_of_aM   s    zController.one_megabyte_of_ac                 C   s   d|j d< dS )z3Render buffered response with invalid length value.Ú5r   zI have too many bytes©r!   r   r   r   r   Úwrong_cl_bufferedQ   s    
zController.wrong_cl_bufferedc                 C   s   d|j d< ddgS )z5Render unbuffered response with invalid length value.r4   r   zI tooz have too many bytesr5   r   r   r   r   Úwrong_cl_unbufferedV   s    
zController.wrong_cl_unbufferedc                 C   s   |   d¡ d¡S )z°Encode PATH_INFO correctly depending on Python version.

        WSGI 1.0 is a mess around unicode. Create endpoints
        that match the PATH_INFO that it produces.
        r%   zlatin-1)Úencoder*   )Ústringr   r   r   Ú_munge[   s    zController._munge)ú/helloú/povú/page1ú/page2ú/page3ú/streamú/uploadú/custom/204ú/custom/304ú/err_before_readz/one_megabyte_of_aú/wrong_cl_bufferedú/wrong_cl_unbufferedN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   r"   r+   r.   r/   r1   r3   r6   r7   r:   Úhandlersr   r   r   r   r      s4   
	ór   c                   @   s8   e Zd ZdZedg d¢ƒZdd„ Zdejdfdd	„Z	d
S )ÚErrorLogMonitorzCMock class to access the server error_log calls made by the server.ÚErrorLogCall)ÚmsgÚlevelÚ	tracebackc                 C   s   g | _ g | _dS )z×Initialize the server error log monitor/interceptor.

        If you need to ignore a particular error message use the property
        ``ignored_msgs`` by appending to the list the expected error messages.
        N)ÚcallsÚignored_msgs©Úselfr   r   r   Ú__init__y   s    zErrorLogMonitor.__init__Ú Fc                 C   s,   |rt  ¡ }nd}| j t |||¡¡ dS )z2Intercept the call to the server error_log method.rV   N)Ú
traceback_Ú
format_excrQ   ÚappendrL   rM   )rT   rN   rO   rP   Ztblinesr   r   r   Ú__call__ƒ   s    
zErrorLogMonitor.__call__N)
rG   rH   rI   rJ   r   rM   rU   ÚloggingÚINFOrZ   r   r   r   r   rL   t   s   
rL   c                    sD   t ƒ }‡ fdd„}||jd< | j‰ |ˆ _dˆ _tˆ _| ˆ _dˆ _ˆ S )z:Attach a WSGI app to the given server and preconfigure it.c                    s
   t ˆ jƒS ©N)r   Útimeoutr   ©Zwsgi_serverr   r   Ú_timeout‘   s    z$raw_testing_server.<locals>._timeoutz/timeoutéé  r   )r   rK   Úserver_instanceÚwsgi_appÚmax_request_body_sizer^   Úserver_clientZkeep_alive_conn_limit)Zwsgi_server_clientZappr`   r   r_   r   Úraw_testing_serverŒ   s    
rf   c                 c   s^   |  | dtƒ ¡ | V  | jjD ]:\}}}|tjkr4q|| jjv sJ djf i tƒ ¤Žfƒ‚qdS )zóModify the "raw" base server to monitor the error_log messages.

    If you need to ignore a particular error message use the property
    ``testing_server.error_log.ignored_msgs`` by appending to the list
    the expected error messages.
    Ú	error_logzTFound error in the error log: message = '{c_msg}', level = '{c_level}'
{c_traceback}N)	ÚsetattrrL   rg   rQ   r[   ÚWARNINGrR   ÚformatÚlocals)rf   ÚmonkeypatchZc_msgZc_levelZc_tracebackr   r   r   Útesting_serverž   s    	
þÿrm   c                 C   s   | j S )z5Get and return a test client out of the given server.)re   )rm   r   r   r   Útest_client¹   s    rn   c                 C   s   |   ¡ dd„ |D ƒv S )zCheck that a header is present.c                 s   s   | ]\}}|  ¡ V  qd S r]   ©Úlower)Ú.0ÚkÚ_r   r   r   Ú	<genexpr>Á   ó    z header_exists.<locals>.<genexpr>ro   )Úheader_namer!   r   r   r   Úheader_exists¿   s    rw   c                    s   |   ¡ ‡ fdd„|D ƒv S )z2Check that a header with a given value is present.c                 3   s"   | ]\}}|ˆ kr|  ¡ V  qd S r]   ro   )rq   rr   Úv©Úheader_valuer   r   rt   Æ   s   ÿz#header_has_value.<locals>.<genexpr>ro   )rv   rz   r!   r   ry   r   Úheader_has_valueÄ   s    ÿr{   c                 C   sŒ  |   ¡ }d|_| ¡  | jd|d\}}}t|dd… ƒ}|dksFJ ‚|dd… dksZJ ‚|t ¡ ksjJ ‚td	|ƒrxJ ‚| jd
|d\}}}t|dd… ƒ}|dks¨J ‚|dd… dks¼J ‚|t ¡ ksÌJ ‚td	|ƒrÚJ ‚| jd|dgd\}}}t|dd… ƒ}|dksJ ‚|dd… dks&J ‚|t ¡ ks8J ‚td	d|ƒsJJ ‚t	 
tjj¡ | jd|d W d  ƒ n1 s~0    Y  dS )z%Test persistent HTTP/1.1 connections.Fr<   ©Ú	http_connNr   éÈ   é   ÚOKÚ
Connectionr=   r>   )r   Úclose)r}   r!   r‚   )Úget_connectionÚ	auto_openÚconnectÚgetÚintr   r8   rw   r{   ÚpytestÚraisesÚhttpÚclientÚNotConnected©rn   Úhttp_connectionÚstatus_lineÚactual_headersÚactual_resp_bodyÚactual_statusr   r   r   Ú"test_HTTP11_persistent_connectionsÌ   s<    ÿÿþr“   r   )FTc           
      C   sB  |   ¡ }d|_| ¡  | jd|d\}}}t|dd… ƒ}|dksFJ ‚|dd… dksZJ ‚|t ¡ ksjJ ‚td	|ƒrxJ ‚|rì| jd
|d\}}}td|ƒsžJ ‚td	d|ƒr®J ‚td|ƒr¼J ‚|dksÈJ ‚|dd… dksÜJ ‚|dksèJ ‚nJ| jd|d\}}}td|ƒrJ ‚|dksJ ‚|dd… dks4J ‚|dksBJ ‚d}|D ]*\}}	| 	¡ dkrJt
|	ƒdkrJd}qJ|rtd	d|ƒràJ ‚nPtd	d|ƒs¢J ‚t tjj¡ | jd|d W d  ƒ n1 sÖ0    Y  | jd|d\}}}|dksJ ‚|dd… dksJ ‚|dks&J ‚td|ƒr6J ‚| ¡  dS )z;Test serving of streaming responses with HTTP/1.1 protocol.Fr<   r|   Nr   r~   r   r€   r   ú/stream?set_cl=Yesr   r‚   úTransfer-Encodingó
   0123456789r@   ztransfer-encodingÚchunkedTru   )rƒ   r„   r…   r†   r‡   r   r8   rw   r{   rp   r   rˆ   r‰   rŠ   r‹   rŒ   Úheadr‚   )
rn   r   rŽ   r   r   r‘   r’   Zchunked_responserr   rx   r   r   r   Útest_streaming_11÷   s\    
ÿÿÿ.ÿr™   c                 C   s   | j j}d| j _|  ¡ }d|_| ¡  | jd|dgdd\}}}t|dd… ƒ}|dks\J ‚|d	d… d
kspJ ‚|t ¡ ks€J ‚t	dd|ƒsJ ‚|r| jd|dgdd\}}}t|dd… ƒ}|dksÌJ ‚|d	d… d
ksàJ ‚|dksìJ ‚t
d|ƒsúJ ‚t	dd|ƒsJ ‚t
d|ƒrìJ ‚nÎ| jd|dgdd\}}}t|dd… ƒ}|dksVJ ‚|d	d… d
kslJ ‚|dkszJ ‚t
d|ƒrŠJ ‚t	dd|ƒrœJ ‚t
d|ƒr¬J ‚t tjj¡  | jd|dd W d  ƒ n1 sâ0    Y  || j _| ¡  dS )z;Test serving of streaming responses with HTTP/1.0 protocol.úHTTP/1.0Fr<   ©r   ú
Keep-Alive)r}   r!   ÚprotocolNr   r~   r   r€   r   rœ   r”   r–   r   r•   r@   ©r}   r   )rb   r   rƒ   r„   r…   r†   r‡   r   r8   r{   rw   rˆ   r‰   rŠ   r‹   rŒ   r‚   )rn   r   Úoriginal_server_protocolrŽ   r   r   r‘   r’   r   r   r   Útest_streaming_10I  s^    	ýýýþ&r    Úhttp_server_protocolrš   zHTTP/1.1z)Fails under PyPy in CI for unknown reasonF)ÚreasonÚstrict)Úmarksc           	      C   s¦  | j j}|| j _d}|  ¡ }d|_| ¡  | jd|d\}}}t|dd… ƒ}|dksZJ ‚|dd… d	ksnJ ‚|t ¡ ks~J ‚t	d
|ƒrŒJ ‚| jddg||d\}}}t|dd… ƒ}|dksÂJ ‚|dd… d	ksÖJ ‚|t ¡ ksæJ ‚t
d
d|ƒsöJ ‚t
ddjf i tƒ ¤Ž|ƒsJ ‚| jd||d\}}}t|dd… ƒ}|dksJJ ‚|dd… d	ks`J ‚|t ¡ ksrJ ‚t	d
|ƒr‚J ‚t	d|ƒr’J ‚|| j _| ¡  dS )z$Test Keep-Alive enabled connections.rš   Fr>   )r   Nr   r~   r   r€   r   r?   r›   ©r!   r}   r   rœ   ú-timeout={test_client.server_instance.timeout}rž   )rb   r   rƒ   r„   r…   r†   r‡   r   r8   rw   r{   rj   rk   r‚   )	rn   r¡   rŸ   Zhttp_client_protocolrŽ   r   r   r‘   r’   r   r   r   Útest_keepalive•  sR    þþý
þr§   c                    sr  dˆ j _‡ fdd„}d‡ fdd„	}d‡ fdd	„	}tjjtjjtjjf}|ƒ }||ƒ |d
ƒ |ƒ }||ƒ |dƒ ||ƒ |dƒ |ƒ }||dd |dƒ t |¡ ||ƒ W d  ƒ n1 sÄ0    Y  |dƒ t	 
d¡ ||ƒ |dƒ t	 
d¡ |d
ƒ t |¡ ||ƒ W d  ƒ n1 s,0    Y  |d
ƒ ||ƒ |d
ƒ tˆ j _| ¡  | ¡  | ¡  dS )z*Test management of Keep-Alive connections.r   c                     s   ˆ   ¡ } d| _|  ¡  | S )NF)rƒ   r„   r…   )rŽ   ©rn   r   r   Ú
connectioná  s    z2test_keepalive_conn_management.<locals>.connectionTc                    s®   ˆ j ddg| dd\}}}t|d d… ƒ}|dks6J ‚|dd … dksJJ ‚|t ¡ ksZJ ‚|rŽtd	d
|ƒsnJ ‚td
djf i tƒ ¤Ž|ƒsªJ ‚ntd	|ƒrœJ ‚td
|ƒrªJ ‚d S )Nr?   r›   rš   r¥   r   r~   r   r€   r   rœ   r¦   )r†   r‡   r   r8   r{   rj   rk   rw   )ÚconnÚ	keepaliver   r   r‘   r’   r¨   r   r   Úrequestè  s&    þÿü
z/test_keepalive_conn_management.<locals>.requestç      ð?c                    sL   t   ¡ | }ˆ jjj}|| kr"d S t   ¡ |ksJ djf i tƒ ¤Žfƒ‚qd S )Nz1idle conn count mismatch, wanted {count}, got {n})Útimerb   Ú_connectionsZ_num_connectionsrj   rk   )Úcountr^   ÚdeadlineÚnr¨   r   r   Úcheck_server_idle_conn_countý  s    
ÿÿzDtest_keepalive_conn_management.<locals>.check_server_idle_conn_countr   F)r«   Ng333333ó?)T)r­   )rb   r^   rŠ   r‹   ÚBadStatusLineÚCannotSendRequestrŒ   rˆ   r‰   r®   Úsleepr‚   )rn   r©   r¬   r³   Zdisconnect_errorsZc1Úc2Úc3r   r¨   r   Útest_keepalive_conn_managementÝ  sH    ý&

(r¹   )Úsimulated_exceptionÚerror_numberÚexception_leakszsocket.error(ECONNRESET))Úidzsocket.error(EPIPE)z simulated socket.error(ENOTCONN)zreal socket.error(ENOTCONN)z$Now reproducible this way on Windows)r¢   )r½   r¤   zsocket.error(ESHUTDOWN)éš  TzRuntimeError(666)éÿÿÿÿzsocket.error(-1)z ConnectionResetError(ECONNRESET)zBrokenPipeError(EPIPE)zBrokenPipeError(ESHUTDOWN)c                    s  ˆdu rdnˆ| dƒ‰|j jj‰‡ ‡‡‡‡‡fdd„‰ ˆ |j jdˆ ¡ | ¡ }d|_| ¡  | d¡ | d|j  	d	¡¡ | 
¡  td
tr’dnd ƒD ]}t d¡ tˆ dƒrš q¸qšˆdurÒˆ jjˆu søJ ‚n&tˆ jjtjƒsæJ ‚ˆ jjj| ksøJ ‚ˆ j|u sJ ‚dS )a  Test there's no traceback on broken connection during close.

    It artificially causes :py:data:`~errno.ECONNRESET` /
    :py:data:`~errno.EPIPE` / :py:data:`~errno.ESHUTDOWN` /
    :py:data:`~errno.ENOTCONN` as well as unrelated :py:exc:`RuntimeError`
    and :py:exc:`socket.error(-1) <socket.error>` on the server socket when
    :py:meth:`socket.shutdown() <socket.socket.shutdown>` is called. It's
    triggered by closing the client socket before the server had a chance
    to respond.

    The expectation is that only :py:exc:`RuntimeError` and a
    :py:exc:`socket.error` with an unusual error code would leak.

    With the :py:data:`None`-parameter, a real non-simulated
    :py:exc:`OSError(107, 'Transport endpoint is not connected')
    <OSError>` happens.
    NzSimulated socket errorc                    s|   ˆ  | dˆjj| jd¡ ˆd ur<ˆ  | jdˆjjˆd¡ ˆ | jd¡ˆ _zˆ| ƒ W n ˆyp   dˆ _Y n0 dˆ _d S )NÚsocket)ÚwrapsÚshutdown)Zside_effectTF)rh   Zmock_moduleZMockrÀ   ÚspyÚfin_spyÚexception_leakedrS   ©Ú_close_kernel_socketZexc_instanceÚmockerrl   Zold_close_kernel_socketrº   r   r   rÇ   ‘  s    þþzCtest_broken_connection_during_tcp_fin.<locals>._close_kernel_socketrÇ   Fó   GET /hello HTTP/1.1úHost: %sÚasciir   r   r   gš™™™™™¹?rÅ   )rb   ÚConnectionClassrÇ   rh   rƒ   r„   r…   ÚsendÚhostr8   r‚   r   ÚIS_SLOW_ENVr®   r¶   ÚhasattrrÄ   Zspy_exceptionÚ
isinstancerÀ   ÚerrorÚerrnorÅ   )r»   r¼   rÈ   rl   rº   rn   rª   rs   r   rÆ   r   Ú%test_broken_connection_during_tcp_finE  s8    Dþÿý



ÿrÔ   c                    sÚ   dd„ ‰ ‡ ‡fdd„}ˆ  |jjjd|¡ | ¡  d¡ | ¡  |jjdd… }|jj 	¡  t
jdft
jd	ft
jd
ff}t|ƒt|ƒksŒJ ‚t||ƒD ]>\\}}\}	}
}||
ks´J ‚t||	ƒdus–J |	›d|›ƒ‚q–dS )z:Test that unhandled internal error cascades into shutdown.c                  _   s   t dƒ‚d S ©Nr¾   )ÚConnectionResetError)Ú_argsÚ_kwargsr   r   r   Ú_raise_connection_resetÉ  s    zZtest_broken_connection_during_http_communication_fallback.<locals>._raise_connection_resetc                    s.   ˆ  | jjdˆ ¡ ˆ  | jjdˆ ¡ ˆ ƒ  d S )Nr‚   Úwrite)rh   rª   ÚrfileÚwfilerS   ©rÙ   rl   r   r   Ú_read_request_lineÌ  s    zUtest_broken_connection_during_http_communication_fallback.<locals>._read_request_lineÚread_request_lineó   GET / HTTP/1.1Nz^socket\.error 666$zK^Got a connection error while handling a connection from .*:\d{1,5} \(666\)a&  A fatal exception happened\. Setting the server interrupt flag to ConnectionResetError\(666,?\) and giving up\.\n\nPlease, report this on the Cheroot tracker at <https://github\.com/cherrypy/cheroot/issues/new/choose>, providing a full reproducer with as much context and details as possible\.$ú does not match )rh   rb   rÌ   ÚRequestHandlerClassrƒ   rÍ   Újoinrg   rQ   Úclearr[   ri   r\   ÚCRITICALÚlenÚzipÚ_matches_pattern)rl   rn   rm   Úwsgi_server_threadrÞ   Úactual_log_entriesÚexpected_log_entriesÚexpected_log_levelÚexpected_msg_regexÚ
actual_msgÚactual_log_levelÚ_tbr   rÝ   r   Ú9test_broken_connection_during_http_communication_fallbackÂ  s8    ýþþùýÿrñ   c                 C   sä   dd„ }||j jd< |  ¡ }|jdddd | d|j¡ | ¡  | ¡  |jj	dd… }|jj	 
¡  tjd	ftjd
ftjdff}t|ƒt|ƒks–J ‚t||ƒD ]>\\}}\}	}
}||
ks¾J ‚t||	ƒdus J |	›d|›ƒ‚q dS )zATest that a keyboard interrupt from HTTP handler causes shutdown.c                 S   s   t dƒ‚d S )Nz)simulated test handler keyboard interrupt)ÚKeyboardInterrupt©Z_reqZ_respr   r   r   Ú_trigger_kb_intr  s    z7test_kb_int_from_http_handler.<locals>._trigger_kb_intrz/kb_intrÚGETT©Ú	skip_hostÚHostNzy^Got a server shutdown request while handling a connection from .*:\d{1,5} \(simulated test handler keyboard interrupt\)$zi^Setting the server interrupt flag to KeyboardInterrupt\('simulated test handler keyboard interrupt',?\)$z#^Keyboard Interrupt: shutting down$rá   )rc   rK   rƒ   Ú
putrequestÚ	putheaderrÎ   Ú
endheadersrã   rg   rQ   rä   r[   ÚDEBUGr\   ræ   rç   rè   )rn   rm   ré   rô   r}   rê   rë   rì   rí   rî   rï   rð   r   r   r   Útest_kb_int_from_http_handlerû  s8    þþþõýÿrý   z@Fails under PyPy 3.6 under Ubuntu 20.04 in CI for unknown reasonc                    s\  G dd„ dt ƒ‰ ‡ fdd„}||jjd< |  |jjd¡}| ¡ }|jdddd	 | d
|j	¡ | 
¡  |jsnqft|jjƒdks‚J ‚|jjdk rq‚t|jjƒdks¤J ‚tdƒ|_|jjrºJ ‚| ¡  |jjdd… }|jj ¡  tjdftjdff}	t|ƒt|	ƒksJ ‚t|	|ƒD ]D\\}
}\}}}|
|ks2J ‚t||ƒdusJ |›d|›ƒ‚qdS )z=Ensure worker threads are resilient to in-handler exceptions.c                   @   s   e Zd ZdZdS )zAtest_unhandled_exception_in_request_handler.<locals>.SillyMistakez)A simulated crash within an HTTP handler.N©rG   rH   rI   rJ   r   r   r   r   ÚSillyMistake:  s   rÿ   c                    s   ˆ dƒ‚d S )Nu2   simulated unhandled exception ðŸ’£ in test handlerr   ró   ©rÿ   r   r   Ú_trigger_scary_exc=  s    zGtest_unhandled_exception_in_request_handler.<locals>._trigger_scary_excz
/scary_excr‚   rõ   Trö   rø   r   útest requesting shutdownNu€   ^Unhandled error while processing an incoming connection SillyMistake\('simulated unhandled exception ðŸ’£ in test handler',?\)$ú"^SystemExit raised: shutting down$rá   )ÚBaseExceptionrc   rK   rÃ   rb   rÌ   rƒ   rù   rú   rÎ   rû   Úcalledræ   ÚrequestsÚ_threadsÚidleÚ
SystemExitÚ	interruptrã   rg   rQ   rä   r[   ÚERRORr\   rç   rè   )rÈ   rl   rn   rm   ré   r  Úserver_connection_close_spyr}   rê   rë   rì   rí   rî   rï   rð   r   r   r   Ú+test_unhandled_exception_in_request_handler+  sL    þ
þþùýÿr  c                    sl  G dd„ dt ƒ‰ |jjjj‰‡ ‡fdd„}| |jjjd|¡ |  |jjd¡}t|jj	ƒdksbJ ‚| 
¡  d¡ |jsxqp|jjdk r†qxt|jj	ƒdksšJ ‚td	d
„ |jj	D ƒƒs´J ‚tdƒ|_|jj	rÊJ ‚| ¡  |jjdd… }|jj ¡  tjdftjdff}t|ƒt|ƒksJ ‚t||ƒD ]D\\}	}
\}}}|	|ksBJ ‚t|
|ƒdus"J |›d|
›ƒ‚q"dS )z<Ensure worker threads are resilient to unhandled exceptions.c                   @   s   e Zd ZdZdS )z?test_remains_alive_post_unhandled_exception.<locals>.ScaryCrashz&A simulated crash during HTTP parsing.Nrþ   r   r   r   r   Ú
ScaryCrash…  s   r  c                    s   ˆ| ƒ ˆ dƒ‚d S rÕ   r   rS   ©r  Z_orig_read_request_liner   r   rÞ   Ž  s    zGtest_remains_alive_post_unhandled_exception.<locals>._read_request_linerß   r‚   r   rà   c                 s   s   | ]}|  ¡ V  qd S r]   )Úis_alive)rq   Zworker_threadr   r   r   rt   ¬  s   ÿz>test_remains_alive_post_unhandled_exception.<locals>.<genexpr>r  NzM^Unhandled error while processing an incoming connection ScaryCrash\(666,?\)$r  rá   )r  rb   rÌ   râ   rß   rh   rÃ   ræ   r  r  rƒ   rÍ   r  r  Úallr	  r
  rã   rg   rQ   rä   r[   r  r\   rç   rè   )rÈ   rl   rn   rm   ré   rÞ   r  rê   rë   rì   rí   rî   rï   rð   r   r  r   Ú+test_remains_alive_post_unhandled_exceptionv  sX    
ÿýþþ
þþúýÿr  Útimeout_before_headers)TFc                 C   sz   |   ¡ }d|_| ¡  |s:| d¡ | d|j  d¡¡ t td ¡ |j	|j
dd}| ¡  |jdksnJ ‚| ¡  d	S )
zbCheck timeout without sending any data.

    The server will close the connection with a 408.
    FrÉ   rÊ   rË   r   rõ   ©Úmethodé˜  N)rƒ   r„   r…   rÍ   rÎ   r8   r®   r¶   r^   Úresponse_classÚsockÚbeginr-   r‚   )rn   r  rª   Úresponser   r   r   Útest_HTTP11_TimeoutÏ  s    
r  c              
   C   sL  d}|   ¡ }|jddt dd | d|j¡ | ¡  |j|jdd}| ¡  |j	dks\J ‚| 
¡ }ttƒ ¡ }||ks|J ‚| d	¡ | d
|j  d¡¡ | ¡  |j|jdd}| ¡  |j	dksÊJ ‚| 
¡ }d}||ksâJ ‚t td ¡ | d	¡ | d
|j  d¡¡ | ¡  |j|jdd}z| ¡  W nP tjtjjfyR   Y nR ty„ } zt || ¡ W Y d}~n(d}~0 0 |j	dkr¤t || 
¡  ¡ | ¡  |   ¡ }|jdddd | d|j¡ | ¡  |j|jdd}| ¡  |j	dksJ ‚| 
¡ }t ¡ }||ks J ‚| d	¡ t td ¡ |j|jdd}z| ¡  W nP tjtjjfyr   Y nR ty¤ } zt || ¡ W Y d}~n(d}~0 0 |j	dkrÄt || 
¡  ¡ | ¡  |   ¡ }|jdddd | d|j¡ | ¡  |j|jdd}| ¡  |j	dks"J ‚| 
¡ }t ¡ }||ks@J ‚| ¡  dS )zuCheck timeout after at least one request has succeeded.

    The server should close the connection without 408.
    z=Writing to timed out socket didn't fail as it should have: %srõ   z/timeout?t=%sTrö   rø   r  r~   rÉ   rÊ   rË   ó   Hello, world!r   Nr  r<   )rƒ   rù   r^   rú   rÎ   rû   r  r  r  r-   r)   r   r8   Ú_outputÚ_send_outputr®   r¶   rÀ   rÒ   rŠ   r‹   r´   Ú	Exceptionrˆ   Úfailr‚   r   rÍ   )rn   Úfail_msgrª   r  Zactual_bodyZexpected_bodyÚexr   r   r   Ú!test_HTTP11_Timeout_after_requestï  s†    

$
$r#  c                 C   s   |   ¡ }|jdddd | d|j¡ | ¡  tdƒD ]‚}| d|  d¡¡ | d	|j  d
¡¡ | ¡  |j	|j
dd}|j
 dd¡|_| ¡  | d¡}|jdks¬J ‚|dks6J ‚q6|j	|j
dd}| ¡  | ¡ }|jdksèJ ‚|dksôJ ‚| ¡  dS )zXTest HTTP/1.1 pipelining.

    :py:mod:`http.client` doesn't support this directly.
    rõ   r;   Trö   rø   é   zGET /hello?%s HTTP/1.1z
iso-8859-1rÊ   rË   r  Úrbr   é   r~   r  N)rƒ   rù   rú   rÎ   rû   r   r  r8   r  r  r  ÚmakefileÚfpr  r)   r-   r‚   )rn   rª   Ztrialr  Úbodyr   r   r   Útest_HTTP11_pipeliningM  s,    ÿ
r*  c                 C   sš  |   ¡ }|jdddd | d|j¡ | dd¡ | dd	¡ | ¡  | d
¡ |j|jdd}| ¡ \}}}|dkszJ ‚| 	¡  | 
¡  |jdddd | d|j¡ | dd¡ | dd¡ | dd¡ | ¡  |j|jdd}| ¡ \}}}|dksþJ ‚|j ¡  ¡ }|r(t d| ¡ qþq(qþd}	| |	¡ | ¡  t |¡\}
}}t|
dd… ƒ}|dkslJ ‚d|	 ¡ ›d ¡ }||ksŽJ ‚| 	¡  dS )z$Test 100-continue header processing.r$   rA   Trö   rø   úContent-Typeú
text/plainr   Ú4s   d'ohr  éd   Z17ÚExpectú100-continuez2100 Continue should not output any headers. Got %ró   I am a small fileNr   r~   r&   r'   )rƒ   rù   rú   rÎ   rû   rÍ   r  r  Ú_read_statusr‚   r…   r(  ÚreadlineÚstriprˆ   r   r  r   Úshbr‡   r*   r8   )rn   rª   r  Ú_versionr-   Ú_reasonÚversionr¢   Úliner)  r   Ú_actual_headersr‘   r’   Úexpected_resp_bodyr   r   r   Útest_100_Continuew  sL    
ÿÿ
r<  rd   )r   ra   c                 C   sê  | j j}|| j _|  ¡ }|jdddd | d|j¡ | dd¡ | dd	¡ | d
d¡ | ¡  |j|jdd}| 	¡ \}}}|dksŒJ ‚d}|r¤|j
 ¡  ¡ }q| d¡ | ¡  t |¡\}	}
}t|	dd… ƒ}|dksâJ ‚| d¡ | d|j  d¡¡ | d¡ | d¡ | d¡ | ¡  |j|jdd}| 	¡ \}}}|dksTJ ‚d}|rp|j
 ¡  ¡ }qXd}| |¡ | ¡  t |¡\}	}}t|	dd… ƒ}|dks´J ‚d| ¡ ›d ¡ }||ksÖJ ‚| ¡  || j _dS )z9Test a max_request_body_size of 0 (the default) and 1001.r$   rD   Trö   rø   r+  r,  r   Z1000r/  r0  r  r.  sè  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxNr   éô  s   POST /upload HTTP/1.1rÊ   rË   s   Content-Type: text/plains   Content-Length: 17s   Expect: 100-continuer1  r~   r&   r'   )rb   rd   rƒ   rù   rú   rÎ   rû   r  r  r2  r(  r3  r4  rÍ   r  r   r5  r‡   r  r8   r  r*   r‚   )rn   rd   Zold_maxrª   r  r6  r-   r7  Úskipr   r:  r‘   r’   r8  r¢   r)  r   r;  r   r   r   Útest_readall_or_close®  sT    	





r?  c                 C   s<  |   ¡ }d|_| ¡  | jd|d\}}}t|dd… ƒ}|dksFJ ‚|dd… dksZJ ‚|t ¡ ksjJ ‚td	|ƒrxJ ‚| jd
|d\}}}t|dd… ƒ}|dks¨J ‚td|ƒr¶J ‚|dksÂJ ‚td	|ƒrÐJ ‚| jd|d\}}}t|dd… ƒ}|dksJ ‚td|ƒrJ ‚|dks J ‚td	|ƒr0J ‚| ¡  dS )z.Test HTTP queries with an empty response body.Fr<   r|   Nr   r~   r   r€   r   rB   éÌ   r   ru   rC   i0  )	rƒ   r„   r…   r†   r‡   r   r8   rw   r‚   r   r   r   r   Útest_No_Message_Bodyö  s8    ÿÿÿrA  z¹
        Headers from earlier request leak into the request
        line for a subsequent request, resulting in 400
        instead of 413. See cherrypy/cheroot#69 for details.
        c           
      C   sT  |   ¡ }d}|jdddd | d|j¡ | dd¡ | d	d
¡ | dd¡ | ¡  | |¡ | ¡ }t |¡\}}}t	|dd… ƒ}|dks”J ‚|dd… dks¨J ‚dd  
¡ }||ksÀJ ‚d d¡}|jdddd | d|j¡ | dd¡ | d
d¡ | ¡  | |¡ | ¡ }t |¡\}}	}t	|dd… ƒ}|dksHJ ‚| ¡  dS )z1Test HTTP uploads with chunked transfer-encoding.sF   8;key=value
xx
xxxx
5
yyyyy
0
Content-Type: application/json

r$   rA   Trö   rø   r•   r—   ZTrailerr+  r   Ú3Nr   r~   r   r€   zthanks for '%s's   xx
xxxxyyyyys   
)s   3e3sã  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxó   0ru   ru   r,  é  )rƒ   rù   rú   rÎ   rû   rÍ   Úgetresponser   r5  r‡   r8   rã   r‚   )
rn   rª   r)  r  r   r:  r‘   r’   r;  r   r   r   r   Útest_Chunked_Encoding  s:    ÿ


rF  c                 C   s–   |   ¡ }|jdddd | d|j¡ | dd¡ | dd	¡ | ¡  | ¡ }t |¡\}}}t|d
d… ƒ}|dkszJ ‚d}||ksŠJ ‚| 	¡  d
S )zŠTry a non-chunked request where Content-Length exceeds limit.

    (server.max_request_body_size).
    Assert error before body send.
    r$   rA   Trö   rø   r+  r,  r   Z9999Nr   rD  sC   The entity sent with the request exceeds the maximum allowed bytes.)
rƒ   rù   rú   rÎ   rû   rE  r   r5  r‡   r‚   )rn   rª   r  r   r:  r‘   r’   r;  r   r   r   Útest_Content_Length_inW  s    ÿrG  c                 C   sD   | j dddgd\}}}t|dd… ƒ}|dks4J ‚|dks@J ‚dS )	z6Test that malicious Content-Length header returns 400.rA   )r+  r,  )r   znot-an-integerr5   Nr   i  s    Malformed Content-Length Header.)Úpostr‡   )rn   r   r:  r‘   r’   r   r   r   Útest_Content_Length_not_intq  s    þþrI  )ÚuriÚexpected_resp_statusr;  ))rE   r=  sL   The requested resource returned more bytes than the declared Content-Length.)rF   r~   s   I tooc           
      C   sŠ   |   ¡ }|jd|dd | d|j¡ | ¡  | ¡ }t |¡\}}}t|dd… ƒ}	|	|ksbJ ‚||ksnJ ‚| 	¡  | j
jj d¡ dS )z_Test response with Content-Length less than the response body.

    (non-chunked response)
    rõ   Trö   rø   Nr   )z@ValueError('Response body exceeds the declared Content-Length.')zAValueError('Response body exceeds the declared Content-Length.',))rƒ   rù   rú   rÎ   rû   rE  r   r5  r‡   r‚   rb   rg   rR   Úextend)
rn   rJ  rK  r;  rª   r  r   r:  r‘   r’   r   r   r   Útest_Content_Length_out€  s    rM  zbSometimes this test fails due to low timeout. Ref: https://github.com/cherrypy/cherrypy/issues/598c                 C   s    |   ¡ }tj dd|j|jf ¡}| d¡}t t	d ¡ d}|rh| |¡}|sRqh||7 }|t
|ƒ8 }q>t
|ƒdksxJ ‚|dd ksˆJ ‚|d	ks”J ‚| ¡  d
S )z5Test serving large file with a read timeout in place.z%s://%s:%s/one_megabyte_of_arŠ   i   g333333ã?i þ i   s   aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar2   r   N)rƒ   Úurllibr¬   ÚurlopenrÎ   Úportr)   r®   r¶   r^   ræ   r‚   )rn   rª   Zremote_data_connÚbufÚ	remainingÚdatar   r   r   Útest_598®  s&    ÿÿ

rT  Úinvalid_terminator)s   

s   

c                 C   sR   |   ¡ }| d| ¡ |j|jdd}| ¡  | ¡ }d}||ksFJ ‚| ¡  dS )z1Test HTTP queries with no valid CRLF terminators.s   GET /hello HTTP/1.1%srõ   r  s   HTTP requires CRLF terminatorsN)rƒ   rÍ   r  r  r  r)   r‚   )rn   rU  rª   r  r‘   r;  r   r   r   Útest_No_CRLFÊ  s    
rV  c                   @   s    e Zd ZdZdd„ Zdd„ ZdS )ÚFaultySelectz:Mock class to insert errors in the selector.select method.c                 C   s   || _ d| _d| _dS )z:Initilize helper class to wrap the selector.select method.FN)Úoriginal_selectÚrequest_servedÚos_error_triggered)rT   rX  r   r   r   rU   â  s    zFaultySelect.__init__c                 C   s   | j rd| _tdƒ‚|  |¡S )z'Intercept the calls to selector.select.Tz(Error while selecting the client socket.)rY  rZ  ÚOSErrorrX  )rT   r^   r   r   r   rZ   è  s    zFaultySelect.__call__N©rG   rH   rI   rJ   rU   rZ   r   r   r   r   rW  ß  s   rW  c                   @   s    e Zd ZdZdd„ Zdd„ ZdS )ÚFaultyGetMapz;Mock class to insert errors in the selector.get_map method.c                 C   s   || _ d| _d| _dS )z;Initilize helper class to wrap the selector.get_map method.FN)Úoriginal_get_mapÚsabotage_connÚconn_closed)rT   r^  r   r   r   rU   ô  s    zFaultyGetMap.__init__c                 C   sF   | j r"| js"dd„ |  ¡  ¡ D ƒnd}|D ]}| ¡  d| _q*|  ¡ S )z(Intercept the calls to selector.get_map.c                 s   s,   | ]$\}\}}}}t |tjjƒr|V  qd S r]   )rÑ   ÚcherootÚserverÚHTTPConnection)rq   rs   rª   r   r   r   rt   ü  s   ÿz(FaultyGetMap.__call__.<locals>.<genexpr>r   T)r_  r`  r^  Úitemsr‚   )rT   Zsabotage_targetsrª   r   r   r   rZ   ú  s    ýý
ÿýzFaultyGetMap.__call__Nr\  r   r   r   r   r]  ñ  s   r]  c                 C   s¤   t | jjjjƒ}| | jjjd|¡ t| jjjjjƒ}| | jjjjd|¡ | jddgd\}}}|dksnJ ‚d |_	|_
t | jjd ¡ |js–J ‚|js J ‚d	S )
z†Test the error handling segment of HTTP connection selection.

    See :py:meth:`cheroot.connections.ConnectionManager.get_conn`.
    ÚselectÚget_mapr=   r›   r5   z200 OKTr   N)rW  rb   r¯   Ú	_selectorre  rh   r]  rf  r¬   r_  rY  r®   r¶   Zexpiration_intervalrZ  r`  )rn   rl   Zfaux_selectZfaux_get_mapZresp_statusZ_resp_headersZ
_resp_bodyr   r   r   Ú test_invalid_selected_connection	  s0    
ÿýÿ
ýÿ
rh  )QrJ   rÓ   Úrer   rè   rÀ   Úsysr®   r[   rP   rW   Úcollectionsr   Úhttp.clientrŠ   Úurllib.requestrN  rˆ   Zjaraco.textr   r   Zcheroot.testr   r   Zcheroot._compatr   r	   r
   r   Zcheroot.serverra  Úversion_infoZIS_PY36rÏ   r^   r   r   rL   Zfixturerf   rm   rn   rw   r{   r“   ÚmarkZparametrizer™   r    ÚparamZxfailr§   r¹   rÒ   Ú
ECONNRESETÚEPIPEÚENOTCONNÚ	ESHUTDOWNÚRuntimeErrorrÖ   ÚBrokenPipeErrorrÔ   rñ   rý   r  r  r  r#  r*  r<  r?  rA  rF  rG  rI  rM  rT  rV  rW  r]  rh  r   r   r   r   Ú<module>   s4  V


+þ
Kþ
Eýþþþ
:h
þ
þ
þþü	
þåþþþ÷äþ-
P90ü
Eü
Sþ
^*7þ
A)ÿÿ	
/þ
!ÿ
þ
