U
    c6{iv@  ã                   @  sP  d Z ddlmZ ddlZddlmZm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 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mZ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*m+Z+m,Z,m-Z-m.Z. ddl/m0Z1 ddl2m3Z3 ddl4m5Z5 ddl6m7Z7 ddl8m9Z9m:Z:m;Z;m<Z< ddl=m>Z> ddl?m@Z@mAZA ddlBmCZC ddlDmEZEm Z  G dd„ dejFƒZGeG dd„ deHƒƒZIG dd„ dejFƒZJedd eJd!�ZKe	eeef e.gdf ZLe3ƒ ZMG d"d#„ d#ejFeK ƒZNG d$d%„ d%ejFeK ƒZOed d&�G d'd(„ d(ƒƒZPed)d*d+d,œd-d.„ƒZQee+ƒeG d/d0„ d0e
eK ƒƒƒZReReJ ZSeQjTd1d*d+d,œd2d3„ƒZUeQjTd4d*d+d,œd5d6„ƒZVeQjTd7d*d+d,œd8d9„ƒZWeQjTd:d*d+d,œd;d<„ƒZXeQjTd=d*d+d,œd>d?„ƒZYeQjTd@d*d+d,œdAdB„ƒZZeQjTdCd*d+d,œdDdE„ƒZ[eQjTdFd*d+d,œdGdH„ƒZ\dIdJdKœdLdM„Z]G dNdO„ dOeCƒZ^dPdQd+dRœdSdT„Z_dS )UzD
Private implementation module for public L{twisted.web.websocket}.
é    )ÚannotationsN)Ú	dataclassÚfield)Úsingledispatch)ÚCallableÚGenericÚTypeVarÚUnion)Úimplementer)ÚURL)Ú
ConnectionÚConnectionTypeÚWSConnection)ÚConnectionState)
ÚAcceptConnectionÚBytesMessageÚCloseConnectionÚEventÚPingÚPongÚRejectConnectionÚ
RejectDataÚRequestÚTextMessage)ÚH11Handshake)ÚRemoteProtocolError)ÚDeferred)Ú	IConsumerÚ	IProtocolÚIPushProducerÚIReactorTCPÚ
ITransport)ÚFactory)ÚLogger)ÚFailure)ÚBAD_REQUEST)ÚURIÚBrowserLikePolicyForHTTPSÚResponseÚ_StandardEndpointFactory)ÚHeaders)ÚIAgentEndpointFactoryÚIPolicyForHTTPS)ÚResource)ÚNOT_DONE_YETr   c                   @  sr   e Zd ZdZdddœdd„Zdddœd	d
„Zddddœdd„Zddddœdd„Zdddœdd„Zddœdd„Z	dS )ÚWebSocketTransportz9
    The transport that can send websocket messages.
    ÚstrÚNone©ÚtextÚreturnc                 C  s   dS )z&
        Send a text message.
        N© )Úselfr3   r5   r5   ú?/tmp/pip-unpacked-wheel-hfbvu0bz/twisted/web/_websocket_impl.pyÚsendTextMessageA   s    z"WebSocketTransport.sendTextMessageÚbytes©Údatar4   c                 C  s   dS )z'
        Send a bytes message.
        Nr5   ©r6   r;   r5   r5   r7   ÚsendBytesMessageF   s    z#WebSocketTransport.sendBytesMessageéè  Úint)Úcoder4   c                 C  s   dS )z0
        Drop the websocket connection.
        Nr5   )r6   r@   r5   r5   r7   ÚloseConnectionK   s    z!WebSocketTransport.loseConnectionó    ©Úpayloadr4   c                 C  s   dS )a  
        Send a websocket Ping request to measure latency.

        @note: Per U{Mozilla's documentation
            <https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers#pings_and_pongs_the_heartbeat_of_websockets>},
            multiple 'ping' requests may be coalesced into a single 'pong', and
            unsolicited 'pong' requests must be ignored, so we do not return a
            L{deferred <twisted.internet.defer.Deferred>} here; pongs are
            delivered separately.
        Nr5   ©r6   rD   r5   r5   r7   ÚpingP   s    zWebSocketTransport.pingr   ©Úproducerr4   c                 C  s   dS )zF
        Attach the given L{IPushProducer} to this transport.
        Nr5   ©r6   rH   r5   r5   r7   ÚattachProducer\   s    z!WebSocketTransport.attachProducer©r4   c                 C  s   dS )zT
        Detach a previously attached L{IPushProducer} from this transport.
        Nr5   ©r6   r5   r5   r7   ÚdetachProducera   s    z!WebSocketTransport.detachProducerN)r>   )rB   )
Ú__name__Ú
__module__Ú__qualname__Ú__doc__r8   r=   rA   rF   rJ   rM   r5   r5   r5   r7   r/   <   s   r/   c                   @  s   e Zd ZU dZded< dS )ÚConnectionRejectedz‡
    A websocket connection was rejected by an HTTP response.

    @ivar response: The HTTP response that describes the rejection.
    r(   ÚresponseN)rN   rO   rP   rQ   Ú__annotations__r5   r5   r5   r7   rR   g   s   
rR   c                   @  sn   e Zd ZdZ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S )ÚWebSocketProtocolac  
    An object that conforms to L{WebSocketProtocol} can receive all the events
    from a websocket connection.

    @note: While this is I{sort of} like a L{byte-stream protocol
        <twisted.internet.interfaces.IProtocol>}, the interface is distinct in
        a few ways; in particular, we have discrete C{negotiationStarted} and
        C{negotiationFinished} methods, representing those events in the
        websocket handshaking process, and no C{connectionMade}; similarly,
        since websockets can natively support both text and bytes messages,
        rather than fragmentable segments of a byte stream, we have
        C{textMessageReceived} and C{bytesMessageReceived} but no
        C{dataReceived}.  Finally, this is a L{typing.Protocol} and not a
        L{zope.interface.Interface}, since it does not predate the L{typing}
        module.
    r/   r1   ©Ú	transportr4   c                 C  s   dS )z’
        An underlying transport (e.g.: a TCP connection) has been established;
        negotiation of the websocket transport has begun.
        Nr5   ©r6   rW   r5   r5   r7   ÚnegotiationStarted„   s    z$WebSocketProtocol.negotiationStartedrK   c                 C  s   dS )zn
        Negotiation is complete: a bidirectional websocket channel is now fully
        established.
        Nr5   rL   r5   r5   r7   ÚnegotiationFinishedŠ   s    z%WebSocketProtocol.negotiationFinishedr9   rC   c                 C  s   dS )a¨  
        A Pong message was received.

        @note: Per U{the standard
            <https://www.rfc-editor.org/rfc/rfc6455#section-5.5.2>}::

                A Pong frame sent in response to a Ping frame must have identical
                "Application data" as found in the message body of the Ping frame
                being replied to.

                If an endpoint receives a Ping frame and has not yet sent Pong
                frame(s) in response to previous Ping frame(s), the endpoint MAY
                elect to send a Pong frame for only the most recently processed
                Ping frame.

            Given that some Pong frames may be dropped, this event should only
            be used in concert with the transport's L{.ping
            <WebSocketTransport.ping>} method for its intended purpose, to
            measure latency and connection durability, not to transport
            application data.
        Nr5   rE   r5   r5   r7   ÚpongReceived�   s    zWebSocketProtocol.pongReceivedr0   )Úmessager4   c                 C  s   dS )z<
        A text message was received from the peer.
        Nr5   )r6   r\   r5   r5   r7   ÚtextMessageReceived§   s    z%WebSocketProtocol.textMessageReceivedr:   c                 C  s   dS )z=
        A bytes message was received from the peer.
        Nr5   r<   r5   r5   r7   ÚbytesMessageReceived¬   s    z&WebSocketProtocol.bytesMessageReceivedr$   ©Úreasonr4   c                 C  s   dS )z4
        The websocket connection was lost.
        Nr5   ©r6   r`   r5   r5   r7   ÚconnectionLost±   s    z WebSocketProtocol.connectionLostN)
rN   rO   rP   rQ   rY   rZ   r[   r]   r^   rb   r5   r5   r5   r7   rU   r   s   rU   Ú_WSPT)Ú	covariantÚboundc                   @  s    e Zd ZdZdddœdd„ZdS )ÚWebSocketServerFactoryz²
    A L{WebSocketServerFactory} is a factory for a particular kind of
    L{WebSocketProtocol} that implements server-side websocket listeners via
    L{WebSocketResource}.
    r   rc   ©Úrequestr4   c                 C  s   dS )a/  
        To conform to L{WebSocketServerFactory}, you must implement a
        C{buildProtocol} method which takes a L{Request
        <twisted.web.server.Request>} and returns a L{WebSocketProtocol}.

        @return: a L{WebSocketProtocol} that will handle the inbound
            connection.
        Nr5   )r6   rh   r5   r5   r7   ÚbuildProtocolÃ   s    z$WebSocketServerFactory.buildProtocolN©rN   rO   rP   rQ   ri   r5   r5   r5   r7   rf   ¼   s   rf   c                   @  s    e Zd ZdZdddœdd„ZdS )ÚWebSocketClientFactoryz¸
    A L{WebSocketClientFactory} is a factory for a particular kind of
    L{WebSocketProtocol} that implements client-side websocket listeners via
    L{WebSocketClientEndpoint}.
    r0   rc   )Úurlr4   c                 C  s   dS )a#  
        To conform to L{WebSocketServerFactory}, you must implement a
        C{buildProtocol} method which takes a string representing an URL and
        returns a L{WebSocketProtocol}.

        @return: a L{WebSocketProtocol} that will handle the outgoing
            connection.
        Nr5   )r6   rl   r5   r5   r7   ri   Õ   s    z$WebSocketClientFactory.buildProtocolNrj   r5   r5   r5   r7   rk   Î   s   rk   )Úfrozenc                	   @  sX   e Zd ZU dZded< ded< eeƒ ddfdddd	d
d dœdd„ƒZdddœdd„ZdS )ÚWebSocketClientEndpointz¬
    A L{WebSocketClientEndpoint} describes an URL to connect to and a way of
    connecting to that URL, that can connect a L{WebSocketClientFactory} to
    that URL.
    r+   ÚendpointFactoryr0   rl   Nr    r,   z
int | Nonezbytes | None)Úreactorrl   Ú	tlsPolicyÚconnectTimeoutÚbindAddressr4   c                 C  s   t ||||ƒ}t||ƒS )a)  
        Construct a L{WebSocketClientEndpoint} from a reactor and a URL.

        @param reactor: The reactor to use for the TCP connection.

        @param url: a string describing an URL where a websocket server lives.

        @param tlsPolicy: The TLS policy to use for HTTPS connections.

        @param connectTimeout: The number of seconds for the TCP-level
            connection timeout.

        @param bindAddress: The bind address to use for the TCP client
            connections.

        @return: the newly constructed endpoint.
        )r)   rn   )Úclsrp   rl   rq   rr   rs   ro   r5   r5   r7   Únewò   s       ÿzWebSocketClientEndpoint.newzWebSocketClientFactory[_WSP]rc   )ÚprotocolFactoryr4   c                 ƒ  s^   ˆj  t ˆj d¡¡¡}ddddœ‡fdd„‰ | t ‡ ‡‡fdd	„¡¡I d
H }|j	I d
H S )ae  
        Make an outgoing connection to this L{WebSocketClientEndpoint}'s HTTPS
        connection.

        @param protocolFactory: The constructor for the protocol.

        @return: A coroutine (that yields L{Deferred}s) that completes with the
            connected L{WebSocketProtocol} once the websocket connection is
            established.
        zutf-8úWSConnection | Connectionr!   r1   ©ÚwscÚtr4   c                   s<   t  ˆ j¡}t|jddd d�ƒ}| |  t|j|ƒ¡¡ d S )NÚ )ÚschemeÚhostÚport)	r   ZfromTextrl   r0   ÚreplaceÚwriteÚsendÚ	WSRequestr}   )ry   rz   ÚhÚtargetrL   r5   r7   ÚclientBootstrap   s    z8WebSocketClientEndpoint.connect.<locals>.clientBootstrapc                     s   t ttjƒˆ ˆ ˆj¡ƒS ©N)Ú_WebSocketWireProtocolr   r   ZCLIENTri   rl   r5   ©r…   rv   r6   r5   r7   Ú<lambda>'  s   
ýz1WebSocketClientEndpoint.connect.<locals>.<lambda>N)
ro   ZendpointForURIr&   Z	fromBytesrl   ÚencodeÚconnectÚProtocolFactoryZforProtocolÚ_done)r6   rv   ZendpointÚ	connectedr5   rˆ   r7   r‹     s    ÿÿÿ
	zWebSocketClientEndpoint.connect)	rN   rO   rP   rQ   rT   Úclassmethodr'   ru   r‹   r5   r5   r5   r7   rn   à   s   
úrn   r   ÚAnyWSWPr1   )ÚeventÚprotor4   c                 C  s   dS )z,
    Handle a websocket protocol event.
    Nr5   ©r‘   r’   r5   r5   r7   Ú_handleEvent1  s    r”   c                   @  s  e Zd ZU ded< ded< ded< edd�Zd	ed
< ed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d9ddd&œd'd(„Zd:d+ddd,œd-d.„Zd/dd0œd1d2„Zddœd3d4„Zddœd5d6„Zddœd7d8„ZdS );r‡   rw   Ú_wsconnÚ
_BootstrapÚ
_bootstraprc   Ú_wspF)Úinitr!   rW   zDeferred[_WSP]r�   NzResponse | NoneÚ_rejectResponser1   rV   c                 C  s   || _ tƒ | _|  ¡  d S r†   )rW   r   r�   ÚconnectionMaderX   r5   r5   r7   ÚmakeConnectionG  s    z%_WebSocketWireProtocol.makeConnectionrK   c                 C  s    | j  | ¡ |  | j| j¡ d S r†   )r˜   rY   r—   r•   rW   rL   r5   r5   r7   r›   L  s    z%_WebSocketWireProtocol.connectionMader9   r:   c                 C  s*   | j  |¡ | j  ¡ D ]}t|| ƒ qd S r†   )r•   Zreceive_dataÚeventsr”   )r6   r;   r‘   r5   r5   r7   ÚdataReceivedQ  s    z#_WebSocketWireProtocol.dataReceivedr$   r_   c                 C  s,   | j  |¡ | jd k	r(| j |¡ d | _d S r†   )r˜   rb   rš   Z_bodyDataFinishedra   r5   r5   r7   rb   V  s    
z%_WebSocketWireProtocol.connectionLostr0   r2   c                 C  s,   | j }|d k	st‚| | j t|ƒ¡¡ d S r†   )rW   ÚAssertionErrorr€   r•   r�   r   )r6   r3   rz   r5   r5   r7   r8   ]  s    z&_WebSocketWireProtocol.sendTextMessagec                 C  s,   | j }|d k	st‚| | j t|ƒ¡¡ d S r†   )rW   rŸ   r€   r•   r�   r   )r6   r;   rz   r5   r5   r7   r=   b  s    z'_WebSocketWireProtocol.sendBytesMessagerB   rC   c                 C  s,   | j }|d k	st‚| | j t|ƒ¡¡ d S r†   )rW   rŸ   r€   r•   r�   r   )r6   rD   rz   r5   r5   r7   rF   g  s    z_WebSocketWireProtocol.pingr>   r{   r?   )r@   r`   r4   c                 C  s6   | j }|d k	st‚| | j t||ƒ¡¡ | ¡  d S r†   )rW   rŸ   r€   r•   r�   r   rA   )r6   r@   r`   rz   r5   r5   r7   rA   l  s    z%_WebSocketWireProtocol.loseConnectionr   rG   c                 C  s   t | jƒ |d¡ d S )NT)r   rW   ZregisterProducerrI   r5   r5   r7   rJ   r  s    z%_WebSocketWireProtocol.attachProducerc                 C  s   t | jƒ ¡  d S r†   )r   rW   ZunregisterProducerrL   r5   r5   r7   rM   u  s    z%_WebSocketWireProtocol.detachProducerc                 C  s$   | j }| ` | | j¡ | j ¡  d S r†   )r�   Úcallbackr˜   rZ   ©r6   Údoner5   r5   r7   Ú_completeConnectionx  s    z*_WebSocketWireProtocol._completeConnectionc                 C  s,   | j d k	st‚| j}| `| t| j ƒ¡ d S r†   )rš   rŸ   r�   ZerrbackrR   r¡   r5   r5   r7   Ú_rejectConnection~  s    z(_WebSocketWireProtocol._rejectConnection)rB   )r>   r{   )rN   rO   rP   rT   r   rW   r�   rš   rœ   r›   rž   rb   r8   r=   rF   rA   rJ   rM   r£   r¤   r5   r5   r5   r7   r‡   8  s$   
r‡   r   c                 C  s   |  ¡  d S r†   )r£   r“   r5   r5   r7   Ú_handle_acceptConnectionˆ  s    r¥   r   c                 C  sD   t ƒ }| jD ]\}}| ||¡ qtd| jd||jƒ|_| ¡  d S )Nz1.1r{   )r*   ÚheadersZaddRawHeaderr(   Ústatus_coderW   rš   r¤   )r‘   r’   ÚhdrÚkÚvr5   r5   r7   Ú_handle_rejectConnection�  s
    r«   r   c                 C  s4   |j d k	stdƒ‚|j  | j¡ | jr0|j ¡  d S )Nz7response should never be None when receiving RejectData)rš   rŸ   Z_bodyDataReceivedr;   Zbody_finishedrW   rA   r“   r5   r5   r7   Ú_handle_rejectData–  s    ÿþr¬   r   c                 C  s   |j  | j¡ d S r†   )r˜   r]   r;   r“   r5   r5   r7   Ú_handle_textMessage   s    r­   r   c                 C  s   |j  | j¡ d S r†   )r˜   r^   r;   r“   r5   r5   r7   Ú_handle_bytesMessage¥  s    r®   r   c                 C  s   |j  |j |  ¡ ¡¡ d S r†   )rW   r€   r•   r�   rS   r“   r5   r5   r7   Ú_handle_pingª  s    r¯   r   c                 C  s   |j  | j¡ d S r†   )r˜   r[   rD   r“   r5   r5   r7   Ú_handle_pong¯  s    r°   r   c                 C  sB   |j d k	st‚|jjtjkr4|j  |j |  ¡ ¡¡ |j  	¡  d S r†   )
rW   rŸ   r•   Ústater   ZCLOSEDr€   r�   rS   rA   r“   r5   r5   r7   Ú_handle_closeConnection´  s    r²   r   r9   rg   c                 C  s   |   t¡ |  dd¡ dS )Nzcontent-typez
text/plains$   websocket protocol negotiation error)ZsetResponseCoder%   Z	setHeader)rh   r5   r5   r7   Ú_negotiationError¼  s    
r³   c                      s8   e Zd ZdZdddœ‡ fdd„Zddd	œd
d„Z‡  ZS )ÚWebSocketResourcezœ
    A L{WebSocketResource} is a L{Resource} that presents a websocket listener.
    You can install it into any twisted web server resource hierarchy.
    z)WebSocketServerFactory[WebSocketProtocol]r1   )Úfactoryr4   c                   s   t ƒ  ¡  || _dS )a#  
        Create a L{WebSocketResource} that will respond to incoming connections
        with the given L{WebSocketServerFactory}.

        @param factory: The factory that will be used to respond to inbound
            websocket connections on appropriately formatted GET requests.
        N)ÚsuperÚ__init__rµ   )r6   rµ   ©Ú	__class__r5   r7   r·   È  s    
zWebSocketResource.__init__r   zbytes | intrg   c              
   C  sø   t tjƒ}|j ¡ }dd„ |D ƒ}z| ||j¡ W n> tk
rr } z tj	d||d� t
|ƒ W Y ¢S d}~X Y nX | j |¡}|dk	s�tdƒ‚| tƒ ¡}|j}|jj}	|	dk	sºtdƒ‚|dk	sÊtdƒ‚t|t|ƒ}
|j |
¡ |	 |¡ | ¡  tS )	zv
        This implementation of the C{GET} HTTP method will respond to inbound
        websocket connections.
        c                 S  s"   g | ]\}}|D ]}||f‘qqS r5   r5   )Ú.0ÚhkeyZhvalsÚvalr5   r5   r7   Ú
<listcomp>Ú  s       z0WebSocketResource.render_GET.<locals>.<listcomp>z{request} failed with {rpe})rh   ÚrpeNz"connection not accepted by twistedzchannel transport not connectedz"connection not accepted by wsproto)r   r   ZSERVERZrequestHeadersZgetAllRawHeadersZinitiate_upgrade_connectionÚpathr   Ú_logÚerrorr³   rµ   ri   rŸ   r�   r   Ú
connectionZchannelrW   r‡   ÚserverBootstrapZ_protocolUpgradeForWebsocketsr€   rZ   r.   )r6   rh   Z	handshakeÚrawZsimpleHeadersr¾   ZwsprotZtoSendZwsconrz   Z	wireProtor5   r5   r7   Ú
render_GETÓ  s(    


zWebSocketResource.render_GET)rN   rO   rP   rQ   r·   rÅ   Ú__classcell__r5   r5   r¸   r7   r´   Â  s   r´   rw   r!   rx   c                 C  s   dS )zC
    The server requires no bootstrapping, so this is a no-op.
    Nr5   )ry   rz   r5   r5   r7   rÃ   î  s    rÃ   )`rQ   Ú
__future__r   ÚtypingZdataclassesr   r   Ú	functoolsr   r   r   r   r	   Zzope.interfacer
   Z	hyperlinkr   Zwsprotor   r   r   Zwsproto.connectionr   Zwsproto.eventsr   r   r   r   r   r   r   r   r   r‚   r   Zwsproto.handshaker   Zwsproto.utilitiesr   Ztwisted.internet.deferr   Ztwisted.internet.interfacesr   r   r   r    r!   Ztwisted.internet.protocolr"   rŒ   Ztwisted.loggerr#   Ztwisted.python.failurer$   Ztwisted.web._responsesr%   Ztwisted.web.clientr&   r'   r(   r)   Ztwisted.web.http_headersr*   Ztwisted.web.iwebr+   r,   Ztwisted.web.resourcer-   Ztwisted.web.serverr.   ÚProtocolr/   Ú	ExceptionrR   rU   rc   r–   rÀ   rf   rk   rn   r”   r‡   r�   Úregisterr¥   r«   r¬   r­   r®   r¯   r°   r²   r³   r´   rÃ   r5   r5   r5   r7   Ú<module>   sv   0+
EPK	,