U
    gc                     @  s8  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
mZ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mZ dd	lm Z  dd
lm!Z!m"Z"m#Z# ddddgZ$eeeef Z%G dd dej&Z'e'j(Z(e'j)Z)G dd dej&Z*e*j+Z+e*j,Z,e*j-Z-e*j.Z.dZ/G dd dZ0dS )    )annotationsN)	GeneratorUnion   )ConnectionClosedConnectionClosedErrorConnectionClosedOKInvalidStatePayloadTooBigProtocolError)	Extension)
OK_CLOSE_CODES	OP_BINARYOP_CLOSEOP_CONTOP_PINGOP_PONGOP_TEXTClose	CloseCodeFrame)RequestResponse)StreamReader)
LoggerLikeOriginSubprotocolProtocolSideStateSEND_EOFc                   @  s   e Zd ZdZed\ZZdS )r   z6A WebSocket connection is either a server or a client.   N)__name__
__module____qualname____doc__rangeSERVERCLIENT r)   r)   7/tmp/pip-unpacked-wheel-dx_q7dq3/websockets/protocol.pyr   .   s   c                   @  s    e Zd ZdZed\ZZZZdS )r   z6A WebSocket connection is in one of these four states.   N)	r"   r#   r$   r%   r&   
CONNECTINGOPENCLOSINGCLOSEDr)   r)   r)   r*   r   8   s       c                   @  s  e Zd ZdZedddddddd	d
ddZeddddZejdd	dddZeddddZ	eddddZ
eddddZdd	dddZd	dddZdd d	d!d"d#ZdJdd d	d!d%d&ZdKdd d	d!d'd(ZdLdd*d	d+d,d-Zdd	dd.d/Zdd	dd0d1ZdMd2d*d	d+d3d4Zd5dd6d7Zd8dd9d:Zd dd;d<Zd=dd>d?Zd=dd@dAZdBd	dCdDdEZdBd	dCdFdGZd	ddHdIZdS )Nr   a6  
    Sans-I/O implementation of a WebSocket connection.

    Args:
        side: :attr:`~Side.CLIENT` or :attr:`~Side.SERVER`.
        state: Initial state of the WebSocket connection.
        max_size: Maximum size of incoming messages in bytes;
            :obj:`None` disables the limit.
        logger: Logger for this connection; depending on ``side``,
            defaults to ``logging.getLogger("websockets.client")``
            or ``logging.getLogger("websockets.server")``;
            see the :doc:`logging guide <../../topics/logging>` for details.

    i   N)statemax_sizeloggerr   r   z
int | NonezLoggerLike | NoneNone)sider1   r2   r3   returnc                C  s   t  | _|d kr(td|j  }|| _|tj	| _
|| _|| _|| _d | _d| _d | _g | _d | _d | _d | _d | _d | _d| _t | _g | _g | _|  | _t| j d | _d S )Nzwebsockets.F) uuidZuuid4idlogging	getLoggernamelowerr3   isEnabledForDEBUGdebugr5   r1   r2   cur_sizeexpect_continuation_frameorigin
extensionsZsubprotocol
close_rcvd
close_sentclose_rcvd_then_senthandshake_exceof_sentr   readereventswritesparseparsernext
parser_exc)selfr5   r1   r2   r3   r)   r)   r*   __init__X   s0    	
	

zProtocol.__init__)r6   c                 C  s   | j S )zt
        State of the WebSocket connection.

        Defined in 4.1, 4.2, 7.1.3, and 7.1.4 of :rfc:`6455`.

        )_staterP   r)   r)   r*   r1      s    zProtocol.state)r1   r6   c                 C  s    | j r| j d|j || _d S )Nz= connection is %s)r?   r3   r;   rR   )rP   r1   r)   r)   r*   r1      s    c                 C  s*   | j tk	rdS | jdkrtjS | jjS dS )z
        `WebSocket close code`_.

        .. _WebSocket close code:
            https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.5

        :obj:`None` if the connection isn't closed yet.

        N)r1   r/   rD   r   ABNORMAL_CLOSUREcoderS   r)   r)   r*   
close_code   s
    

zProtocol.close_codez
str | Nonec                 C  s(   | j tk	rdS | jdkrdS | jjS dS )z
        `WebSocket close reason`_.

        .. _WebSocket close reason:
            https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.6

        :obj:`None` if the connection isn't closed yet.

        N )r1   r/   rD   reasonrS   r)   r)   r*   close_reason   s
    

zProtocol.close_reasonr   c                 C  sf   | j tkstd| jdk	rD| jdk	rD| jjtkrD| jjtkrDt}nt}|| j| j| j	}| j
|_|S )a  
        Exception to raise when trying to interact with a closed connection.

        Don't raise this exception while the connection :attr:`state`
        is :attr:`~websockets.protocol.State.CLOSING`; wait until
        it's :attr:`~websockets.protocol.State.CLOSED`.

        Indeed, the exception includes the close code and reason, which are
        known only once the connection is closed.

        Raises:
            AssertionError: If the connection isn't closed yet.

        zconnection isn't closed yetN)r1   r/   AssertionErrorrD   rE   rU   r   r   r   rF   rO   	__cause__)rP   exc_typeexcr)   r)   r*   	close_exc   s$    

zProtocol.close_excbytes)datar6   c                 C  s   | j | t| j dS )aH  
        Receive data from the network.

        After calling this method:

        - You must call :meth:`data_to_send` and send this data to the network.
        - You should call :meth:`events_received` and process resulting events.

        Raises:
            EOFError: If :meth:`receive_eof` was called earlier.

        N)rI   Z	feed_datarN   rM   rP   r`   r)   r)   r*   receive_data   s    zProtocol.receive_datac                 C  s$   | j jrdS | j   t| j dS )a  
        Receive the end of the data stream from the network.

        After calling this method:

        - You must call :meth:`data_to_send` and send this data to the network;
          it will return ``[b""]``, signaling the end of the stream, or ``[]``.
        - You aren't expected to call :meth:`events_received`; it won't return
          any new events.

        :meth:`receive_eof` is idempotent.

        N)rI   eofZfeed_eofrN   rM   rS   r)   r)   r*   receive_eof  s    
zProtocol.receive_eofbool)r`   finr6   c                 C  sL   | j std| jtk	r.td| jj  | | _ | t	t
|| dS )a  
        Send a `Continuation frame`_.

        .. _Continuation frame:
            https://datatracker.ietf.org/doc/html/rfc6455#section-5.6

        Parameters:
            data: payload containing the same kind of data
                as the initial frame.
            fin: FIN bit; set it to :obj:`True` if this is the last frame
                of a fragmented message and to :obj:`False` otherwise.

        Raises:
            ProtocolError: If a fragmented message isn't in progress.

        unexpected continuation frameconnection is N)rA   r   rR   r-   r	   r1   r;   r<   
send_framer   r   rP   r`   rf   r)   r)   r*   send_continuation  s    
zProtocol.send_continuationTc                 C  sL   | j rtd| jtk	r.td| jj  | | _ | t	t
|| dS )a  
        Send a `Text frame`_.

        .. _Text frame:
            https://datatracker.ietf.org/doc/html/rfc6455#section-5.6

        Parameters:
            data: payload containing text encoded with UTF-8.
            fin: FIN bit; set it to :obj:`False` if this is the first frame of
                a fragmented message.

        Raises:
            ProtocolError: If a fragmented message is in progress.

        expected a continuation framerh   N)rA   r   rR   r-   r	   r1   r;   r<   ri   r   r   rj   r)   r)   r*   	send_text3  s    
zProtocol.send_textc                 C  sL   | j rtd| jtk	r.td| jj  | | _ | t	t
|| dS )a  
        Send a `Binary frame`_.

        .. _Binary frame:
            https://datatracker.ietf.org/doc/html/rfc6455#section-5.6

        Parameters:
            data: payload containing arbitrary binary data.
            fin: FIN bit; set it to :obj:`False` if this is the first frame of
                a fragmented message.

        Raises:
            ProtocolError: If a fragmented message is in progress.

        rl   rh   N)rA   r   rR   r-   r	   r1   r;   r<   ri   r   r   rj   r)   r)   r*   send_binaryJ  s    
zProtocol.send_binaryrW   str)rU   rX   r6   c                 C  s   | j tk	r td| jj  |dkrJ|dkr8tdttj	d}d}nt||}|
 }| tt| | jdkszt|| _t| _dS )a_  
        Send a `Close frame`_.

        .. _Close frame:
            https://datatracker.ietf.org/doc/html/rfc6455#section-5.5.1

        Parameters:
            code: close code.
            reason: close reason.

        Raises:
            ProtocolError: If the code isn't valid or if a reason is provided
                without a code.

        rh   NrW   z#cannot send a reason without a coder0   )rR   r-   r	   r1   r;   r<   r   r   r   ZNO_STATUS_RCVD	serializeri   r   r   rD   rZ   rE   r.   rP   rU   rX   closer`   r)   r)   r*   
send_closea  s    

zProtocol.send_closec                 C  s>   | j tk	r*| j tk	r*td| jj  | tt	| dS )z
        Send a `Ping frame`_.

        .. _Ping frame:
            https://datatracker.ietf.org/doc/html/rfc6455#section-5.5.2

        Parameters:
            data: payload containing arbitrary binary data.

        rh   N)
rR   r-   r.   r	   r1   r;   r<   ri   r   r   ra   r)   r)   r*   	send_ping  s    zProtocol.send_pingc                 C  s>   | j tk	r*| j tk	r*td| jj  | tt	| dS )z
        Send a `Pong frame`_.

        .. _Pong frame:
            https://datatracker.ietf.org/doc/html/rfc6455#section-5.5.3

        Parameters:
            data: payload containing arbitrary binary data.

        rh   N)
rR   r-   r.   r	   r1   r;   r<   ri   r   r   ra   r)   r)   r*   	send_pong  s    zProtocol.send_pongintc                 C  s   | j tkrR|tjkrRt||}| }| tt| || _	| j
dk	rLd| _t| _ | jtkrj| jsj|   |  | _t| j dS )a?  
        `Fail the WebSocket connection`_.

        .. _Fail the WebSocket connection:
            https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.7

        Parameters:
            code: close code
            reason: close reason

        Raises:
            ProtocolError: If the code isn't valid.
        NT)r1   r-   r   rT   r   rp   ri   r   r   rE   rD   rF   r.   r5   r'   rH   send_eofdiscardrM   rN   rq   r)   r)   r*   fail  s    




zProtocol.failzlist[Event]c                 C  s   | j g  }| _ |S )a*  
        Fetch events generated from data received from the network.

        Call this method immediately after any of the ``receive_*()`` methods.

        Process resulting events, likely by passing them to the application.

        Returns:
            Events read from the connection.
        )rJ   )rP   rJ   r)   r)   r*   events_received  s    zProtocol.events_receivedzlist[bytes]c                 C  s   | j g  }| _ |S )a  
        Obtain data to send to the network.

        Call this method immediately after any of the ``receive_*()``,
        ``send_*()``, or :meth:`fail` methods.

        Write resulting data to the connection.

        The empty bytestring :data:`~websockets.protocol.SEND_EOF` signals
        the end of the data stream. When you receive it, half-close the TCP
        connection.

        Returns:
            Data to write to the connection.

        )rK   )rP   rK   r)   r)   r*   data_to_send  s    zProtocol.data_to_sendc                 C  s   | j tkp| jdk	S )a  
        Tell if the TCP connection is expected to close soon.

        Call this method immediately after any of the ``receive_*()``,
        ``send_close()``, or :meth:`fail` methods.

        If it returns :obj:`True`, schedule closing the TCP connection after a
        short timeout if the other side hasn't already closed it.

        Returns:
            Whether the TCP connection is expected to close soon.

        N)r1   r.   rG   rS   r)   r)   r*   close_expected  s    zProtocol.close_expectedzGenerator[(None, None, None)]c              
   c  s  z| j  E dH r,| jr$| jd td| jdkr<d}n| jdkrN| j}n| j| j }tj| j j	| j
tk|| jdE dH }| jr| jd| | | qW n6 tk
r } z| tjt| || _W 5 d}~X Y n tk
r } z| tjt| || _W 5 d}~X Y n tk
rZ } z&| tj|j d|j  || _W 5 d}~X Y n tk
r } z| tjt| || _W 5 d}~X Y nF tk
r } z&| jjddd	 | tj || _W 5 d}~X Y nX dV  td
dS )a-  
        Parse incoming data into frames.

        :meth:`receive_data` and :meth:`receive_eof` run this generator
        coroutine until it needs more data or reaches EOF.

        :meth:`parse` never raises an exception. Instead, it sets the
        :attr:`parser_exc` and yields control.

        N< EOFzunexpected end of stream)maskr2   rC   z< %sz at position zparser failedT)exc_infoz"parse() shouldn't step after error)rI   at_eofr?   r3   EOFErrorr2   r@   r   rL   Z
read_exactr5   r'   rC   
recv_framer   ry   r   ZPROTOCOL_ERRORro   rO   rT   UnicodeDecodeErrorZINVALID_DATArX   startr
   ZMESSAGE_TOO_BIG	ExceptionerrorINTERNAL_ERRORrZ   )rP   r2   framer]   r)   r)   r*   rL     sJ    

zProtocol.parsec                 c  s   | j tkp| jtk| jkst| j E dH s:| j  q| j	rL| j
	d | j tkrh| jtkrh|   t| _ dV  tddS )z
        Discard incoming data.

        This coroutine replaces :meth:`parse`:

        - after receiving a close frame, during a normal closure (1.4);
        - after sending a close frame, during an abnormal closure (7.1.7).

        Nr}   z"discard() shouldn't step after EOF)r1   r,   r5   r'   rH   rZ   rI   r   rx   r?   r3   r(   rw   r/   rS   r)   r)   r*   rx   [  s    zProtocol.discardr   )r   r6   c                 C  sz  |j tks|j tkrD| jdk	r&td|jr4d| _nt|j| _n&|j tkr| jdkr`td|jrnd| _n|  jt|j7  _n|j t	krt
t|j}| | n|j tkrn|j tkrXt|j| _| jtkr| jdk	std| _| jdk	rtd| jtkr.| t
t|j | j| _d| _t| _| jtkrB|   |  | _t| j ntd|j d| j| dS )	z-
        Process an incoming frame.

        Nrl   rg   Fzincomplete fragmented messageTzunexpected opcode: Z02x)opcoder   r   r@   r   rf   lenr`   r   r   r   r   ri   r   r   rL   rD   r1   r.   rE   rZ   rF   r-   r5   r'   rw   rx   rM   rN   rJ   append)rP   r   Z
pong_framer)   r)   r*   r   y  sF    







zProtocol.recv_framec                 C  s6   | j r| j d| | j|j| jtk| jd d S )Nz> %s)r~   rC   )r?   r3   rK   r   rp   r5   r(   rC   )rP   r   r)   r)   r*   ri     s    zProtocol.send_framec                 C  s2   | j r
td| _ | jr"| jd | jt d S )NTz> EOF)rH   rZ   r?   r3   rK   r   r    rS   r)   r)   r*   rw     s
    
zProtocol.send_eof)T)T)NrW   )rW   )r"   r#   r$   r%   r-   rQ   propertyr1   setterrV   rY   r^   rb   rd   rk   rm   rn   rs   rt   ru   ry   rz   r{   r|   rL   rx   r   ri   rw   r)   r)   r)   r*   r   H   s@   D	%$1GT
)1
__future__r   enumr9   r7   typingr   r   
exceptionsr   r   r   r	   r
   r   rC   r   framesr   r   r   r   r   r   r   r   r   r   Zhttp11r   r   Zstreamsr   r   r   r   __all__EventIntEnumr   r'   r(   r   r,   r-   r.   r/   r    r   r)   r)   r)   r*   <module>   s4    0