U
    ¹~Hj5  ã                   @  sê  d Z ddlmZ ddlmZm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 ddlmZ dd	lmZ dd
lmZmZ ddlmZ ddlmZmZ ddlmZ ddlmZ ddl m!Z!m"Z" ddl#m$Z$ ddl%m&Z& ddl'm(Z(m)Z)m*Z* ddl+m,Z, e	ddd�Z-dZ.G dd„ de&ƒZ/G dd„ de&ƒZ0ze1dƒ W n e2k
�rR   dZ.Y nbX ddl3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z: eG dd „ d e7ƒƒZ;G d!d"„ d"e9e; ƒZ<G d#d$„ d$e6e; ƒZ=eG d%d&„ d&ee- ƒƒZ>ee.d'ƒG d(d)„ d)eƒƒZ?d*S )+z%
Tests for L{twisted.web.websocket}.
é    )Úannotations)Ú	dataclassÚfield)ÚAnyÚGenericÚTypeVar)ÚskipIf)Úimplementer)ÚDeferred)ÚConnectionDone)ÚIPushProducer)ÚAccumulatingProtocolÚMemoryReactorClock)ÚFailure)ÚConnectionCompleterÚIOPump)ÚSynchronousTestCase)ÚBAD_REQUEST)ÚAgentÚreadBody)ÚIRequest)ÚResource)ÚNOT_DONE_YETÚRequestÚSite)ÚDataÚWSPÚWebSocketProtocol)ÚboundFc                   @  s   e Zd Zdddœdd„ZdS )ÚWeirdResourcer   Úbytes©ÚrequestÚreturnc                 C  s   |  d¡ dS )a¯  
        Per U{the wsproto documentation
        <https://python-hyper.org/projects/wsproto/en/latest/api.html#wsproto.events.RejectConnection.has_body>}:

            - The only scenario in which the caller receives a RejectConnection
              with C{has_body == False} is if the peer violates sends an
              informational status code (1xx) other than 101

        This is a weird edge case so we provoke it.
        éf   ó    )ZsetResponseCode©Úselfr"   © r(   úC/tmp/pip-unpacked-wheel-ewod1tgb/twisted/web/test/test_websocket.pyÚ
render_GET#   s    
zWeirdResource.render_GETN)Ú__name__Ú
__module__Ú__qualname__r*   r(   r(   r(   r)   r   "   s   r   c                   @  s    e Zd ZdZdddœdd„ZdS )ÚDelayedResponsez¾
    A resource that will not respond to a C{GET} request right away.  You will
    need to use the C{request.write(b'RESPONSE BODY')} and C{request.finish()}
    to trigger a response.
    r   Úintr!   c                 C  s
   || _ tS ©N)r"   r   r&   r(   r(   r)   r*   9   s    zDelayedResponse.render_GETN)r+   r,   r-   Ú__doc__r*   r(   r(   r(   r)   r.   2   s   r.   ZwsprotoT)ÚConnectionRejectedÚWebSocketClientEndpointÚWebSocketClientFactoryr   ÚWebSocketResourceÚWebSocketServerFactoryÚWebSocketTransportc                   @  sª   e Zd ZU dZeed�Zded< dZded< dd	d
œdd„Z	d	dœdd„Z
dd	dœdd„Zdd	dœdd„Zdd	dœdd„Zdd	dœdd„Zddœdd „Zd!dœd"d#„ZdS )$ÚMyWSPz
        Used to implement both client-side and server-side WebSocket
        application that will help with testing.
        ©Údefault_factoryzlist[bytes]ÚpongsNzFailure | NoneÚwasLostr7   ÚNone)Ú	transportr#   c                 C  s
   || _ d S r0   )r>   )r'   r>   r(   r(   r)   ÚnegotiationStartedW   s    zMyWSP.negotiationStarted©r#   c                 C  s   d S r0   r(   ©r'   r(   r(   r)   ÚnegotiationFinishedZ   s    zMyWSP.negotiationFinishedr   )Úreasonr#   c                 C  s
   || _ d S r0   )r<   )r'   rC   r(   r(   r)   ÚconnectionLost]   s    zMyWSP.connectionLostr    )Údatar#   c                 C  s&   |dkr| j  d¡ n| j |¡ d S )Nó   requestó    responseÿ)r>   ÚsendBytesMessageÚ	bDeferredÚcallback©r'   rE   r(   r(   r)   ÚbytesMessageReceived`   s    zMyWSP.bytesMessageReceivedÚstrc                 C  s&   |dkr| j  d¡ n| j |¡ d S )Nr"   Úresponse)r>   ÚsendTextMessageÚdeferredrJ   rK   r(   r(   r)   ÚtextMessageReceivedf   s    zMyWSP.textMessageReceived)Úpayloadr#   c                 C  s   | j  |¡ d S r0   )r;   Úappend)r'   rR   r(   r(   r)   ÚpongReceivedl   s    zMyWSP.pongReceivedzDeferred[str]c                 C  s   t ƒ | _| j d¡ | jS )zR
            Send a text message to the server and expect a response.
            r"   )r
   rP   r>   rO   rA   r(   r(   r)   ÚsendRequesto   s    zMyWSP.sendRequestzDeferred[bytes]c                 C  s   t ƒ | _| j d¡ | jS )zS
            Send a bytes message to the server and expect a response.
            rF   )r
   rI   r>   rH   rA   r(   r(   r)   ÚbytesRequestw   s    zMyWSP.bytesRequest)r+   r,   r-   r1   r   Úlistr;   Ú__annotations__r<   r?   rB   rD   rL   rQ   rT   rU   rV   r(   r(   r(   r)   r8   M   s   
r8   c                   @  s&   e Zd ZU ded< dddœdd„ZdS )	Ú	MyFactoryzWebSocketFixture[Any]Úfixturer   r8   r!   c                 C  s   t ƒ }| jj |¡ |S r0   )r8   rZ   ÚserversrS   )r'   r"   Únewr(   r(   r)   ÚbuildProtocol‚   s    zMyFactory.buildProtocolN)r+   r,   r-   rX   r]   r(   r(   r(   r)   rY      s   
rY   c                   @  s   e Zd Zdddœdd„ZdS )ÚMyClientFactoryrM   r8   ©Úurir#   c                 C  s   t ƒ S r0   )r8   )r'   r`   r(   r(   r)   r]   ˆ   s    zMyClientFactory.buildProtocolN)r+   r,   r-   r]   r(   r(   r(   r)   r^   ‡   s   r^   c                   @  s¨   e Zd ZU eƒ Zded< eed�Zded< eed�Z	ded< dZ
d	ed
< eed�Zded< eed�Zded< edddœdd„ƒZd dddœdd„Zd!dddœdd„ZdS )"ÚWebSocketFixturezWebSocketClientFactory[WSP]ÚclientFactoryr9   r   Úreactorr   ÚresourceéP   r/   Ú
portNumberz	list[WSP]r[   r.   ÚslowResourcezWebSocketFixture[WSP])rb   r#   c                 C  sz   | |ƒ}t ƒ }||_|j dt|ƒ¡ |j dtddƒ¡ |j dtƒ ¡ |j d|j¡ |j 	|j
t|j|jd�¡ |S )Ns   connects   resources	   some-datazapplication/octet-streams
   processings   slow)rc   )rY   rZ   rd   ZputChildr5   r   r   rg   rc   Z	listenTCPrf   r   )Úclsrb   r'   ZserverFactoryr(   r(   r)   r\   •   s     ÿ ÿzWebSocketFixture.newúhttp://localhost:80/connectrM   r   r_   c                 Ã  s    t  | j|¡}| | j¡I d H S r0   )r3   r\   rc   Úconnectrb   )r'   r`   Úclientr(   r(   r)   rj   ¥   s    zWebSocketFixture.connectTÚboolr   )Úgreetr#   c                 C  s*   t | jƒ}|j|d�}|dk	s&tdƒ‚|S )aP  
        There should be a single websocket connection in progress; complete it.

        @param greet: Should we immediately issue a greeting, i.e. deliver any
            pending buffered TCP data, upon connection?  If C{False}, the
            caller must call C{flush} on the result to deliver any pending
            data.
        ©rm   NzConnection not in progress.)r   rc   ZsucceedOnceÚAssertionError)r'   rm   Z	completerZ	succeededr(   r(   r)   Úcomplete©   s    	
zWebSocketFixture.completeN)ri   )T)r+   r,   r-   r   rb   rX   r   rc   r   rd   rf   rW   r[   r.   rg   Úclassmethodr\   rj   rp   r(   r(   r(   r)   ra   Œ   s   
ra   z'wsproto library required for websocketsc                   @  sŠ   e Zd Zddœdd„Zddœdd„Zddœdd„Zddœd	d
„Zddœdd„Zddœdd„Zddœdd„Z	ddœdd„Z
ddœdd„ZdS )ÚWebSocketTestsr=   r@   c                 C  sŽ   t  tƒ ¡}t | ¡ ¡}|  |¡ |  t|j	j
ƒd¡ |  t|j	jƒd¡ | ¡ }|  |¡}| ¡ }|  |¡ | ¡  |  |  |¡d¡ dS )zÏ
        Connecting to a websocket server (installed with L{WebSocketResource})
        from a websocket client (connected with L{WebSocketClientEndpoint})
        results in a websocket connection.
        é   rN   N)ra   r\   r^   r
   ÚfromCoroutinerj   ÚassertNoResultÚassertEqualÚlenrc   Z
tcpServersZ
tcpClientsrp   ÚsuccessResultOfrU   Úflush)r'   rZ   Ú	connectedÚpumpÚwsClientÚ	requestedr(   r(   r)   Útest_websocketº   s    


zWebSocketTests.test_websocketc                 C  s\   t  tƒ ¡}t | ¡ ¡}| ¡ }|  |¡}| ¡ }|  	|¡ | 
¡  |  |  |¡d¡ dS )zŠ
        Connecting to a websocket server and sending it a bytes message results
        in C{bytesMessageReceived} being called.
        rG   N)ra   r\   r^   r
   rt   rj   rp   rx   rV   ru   ry   rv   )r'   rZ   rz   r{   r|   Z
bRequestedr(   r(   r)   Útest_bytesMessageÌ   s    

z WebSocketTests.test_bytesMessagec                   sì   t  tƒ ¡}t | ¡ ¡ | ¡ }g ‰ ttƒG ‡ fdd„dƒƒ}|ƒ }|j	d j
 |¡ |  ˆ g ¡ |jj ¡  |  ˆ dg¡ |jj ¡  |  ˆ ddg¡ |jj ¡  |  ˆ dddg¡ |  |jj|¡ |j	d j
 ¡  |  |jjd¡ dS )zo
        Websocket transports can notify a producer of backpressure events via
        attachProducer.
        c                      sB   e Zd Zddœ‡ fdd„Zddœ‡ fdd„Zddœ‡ fdd„Zd	S )
z6WebSocketTests.test_backpressure.<locals>.TestProducerr=   r@   c                   s   ˆ   d¡ d S )NÚpaused©rS   rA   ©Úeventsr(   r)   ÚpauseProducingæ   s    zEWebSocketTests.test_backpressure.<locals>.TestProducer.pauseProducingc                   s   ˆ   d¡ d S )NÚresumedr�   rA   r‚   r(   r)   ÚresumeProducingé   s    zFWebSocketTests.test_backpressure.<locals>.TestProducer.resumeProducingc                   s   ˆ   d¡ d S )NÚstoppedr�   rA   r‚   r(   r)   ÚstopProducingì   s    zDWebSocketTests.test_backpressure.<locals>.TestProducer.stopProducingN)r+   r,   r-   r„   r†   rˆ   r(   r‚   r(   r)   ÚTestProducerä   s   r‰   r   r€   r…   r‡   N)ra   r\   r^   r
   rt   rj   rp   r	   r   r[   r>   ZattachProducerrv   ZserverIOZproducerr„   r†   rˆ   ÚassertIsZdetachProducer)r'   rZ   r{   r‰   ZtestProducerr(   r‚   r)   Útest_backpressureÚ   s$    
z WebSocketTests.test_backpressurec                 C  sb   t  tƒ ¡}t | ¡ ¡}| ¡ }|  |¡}|j 	d¡ |  
|jg ¡ | ¡  |  
|jdg¡ dS )a6  
        Internally, Twisted's websocket resource responds to all ping requests
        with a pong as required by the spec, so peers can issue a C{ping} and
        receive a C{pong} message with the same payload; our websocket
        transport also implements a C{ping} method to send that message.
        s   123N)ra   r\   r^   r
   rt   rj   rp   rx   r>   Zpingrv   r;   ry   ©r'   rZ   rz   r{   r|   r(   r(   r)   Útest_pingPongü   s    
zWebSocketTests.test_pingPongc                 C  s¨   t  tƒ ¡}t | ¡ ¡}| ¡ }|  |¡}|  |j	d j
d¡ |  |j
d¡ |j ¡  |  |j	d j
d¡ |  |j
d¡ | ¡  |  |j	d j
d¡ |  |j
d¡ dS )zu
        When the underlying TCP connection is lost,
        L{WebSocketProtocol.connectionLost} is invoked.
        r   N)ra   r\   r^   r
   rt   rj   rp   rx   rŠ   r[   r<   r>   ZloseConnectionry   ZassertIsNotrŒ   r(   r(   r)   Útest_serverConnectionLost  s    

z(WebSocketTests.test_serverConnectionLostc                 C  sj   t  tƒ ¡}t|jƒ}| dd¡}|  |¡ | ¡  |  |¡}|  	|j
t¡ t|ƒ}|  	|  |¡d¡ dS )z«
        Attempting to issue an C{HTTP GET} against a websocket server
        (installed with L{WebSocketResource}) results in a C{BAD_REQUEST}
        response.
        s   GETs   http://localhost/connects$   websocket protocol negotiation errorN)ra   r\   r^   r   rc   r"   ru   rp   rx   rv   Úcoder   r   )r'   rZ   ZagentrN   ÚrÚbodyr(   r(   r)   Útest_bad  s    


 ÿzWebSocketTests.test_badc                 C  sJ   t  tƒ ¡}t | d¡¡}|jdd�}|  |¡ | ¡  |  	|t
¡ dS )úÁ
        Attempting to connect to a regular HTTP resource that does not support
        websockets will result in the Deferred returned from
        L{WebSocketClientEndpoint} failing.
        zhttp://localhost/emptyFrn   N©ra   r\   r^   r
   rt   rj   rp   ru   ry   ÚfailureResultOfr2   ©r'   rZ   rz   r{   r(   r(   r)   Útest_connectionRefused0  s    
z%WebSocketTests.test_connectionRefusedc                 C  sJ   t  tƒ ¡}t | d¡¡}|jdd�}|  |¡ | ¡  |  	|t
¡ dS )r“   zhttp://localhost/processingFrn   Nr”   r–   r(   r(   r)   Útest_connectionRefusedWeird=  s    ÿ
z*WebSocketTests.test_connectionRefusedWeirdc                 C  s  t  tƒ ¡}t | d¡¡}|jdd�}|  |¡ |jj	 
d¡ | ¡  |  |t¡}|jj}| tƒ  }¡ |  |jd¡ |jj	}| 
d¡ | ¡  |  |jd¡ | 
d¡ | ¡  |  |jd¡ | ¡  |  |jd¡ | ¡  |jdk	sòtd	ƒ‚|  |jjt¡ dS )
z§
        When the client connection is refused by an asynchronous HTTP response,
        the websocket client will not be notified until the response arrives.
        zhttp://localhost/slowTrn   r%   s   hellos   worlds
   helloworldNzshould be closed now)ra   r\   r^   r
   rt   rj   rp   ru   rg   r"   Úwritery   r•   r2   ÚvaluerN   ZdeliverBodyr   rv   rE   ÚfinishrŠ   ZclosedReasonro   Útyper   )r'   rZ   rz   r{   ZrejectedÚrespÚpÚreqr(   r(   r)   Útest_connectionRefusedSlowL  s,    


z)WebSocketTests.test_connectionRefusedSlowN)r+   r,   r-   r~   r   r‹   r�   rŽ   r’   r—   r˜   r    r(   r(   r(   r)   rr   ¸   s   "rr   N)@r1   Ú
__future__r   Zdataclassesr   r   Útypingr   r   r   Zunittestr   Zzope.interfacer	   Ztwisted.internet.deferr
   Ztwisted.internet.errorr   Ztwisted.internet.interfacesr   Ztwisted.internet.testingr   r   Ztwisted.python.failurer   Ztwisted.test.iosimr   r   Ztwisted.trial.unittestr   Ztwisted.web._responsesr   Ztwisted.web.clientr   r   Ztwisted.web.iwebr   Ztwisted.web.resourcer   Ztwisted.web.serverr   r   r   Ztwisted.web.staticr   r   Z
shouldSkipr   r.   Ú
__import__ÚImportErrorZtwisted.web.websocketr2   r3   r4   r   r5   r6   r7   r8   rY   r^   ra   rr   r(   r(   r(   r)   Ú<module>   sF   
$
1+