o
    &æÑgôr  ã                   @   sÔ   d Z ddlZddlZddl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mZ ddlmZ zddlZW n eyN   ddlZe d¡ dZY nw G dd„ dejƒZG d	d
„ d
ejƒZG dd„ dƒZdS )al  
Python WebSocket library
Copyright 2011 Joel Martin
Copyright 2016 Pierre Ossman
Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3)

Supports following protocol versions:
    - http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-07
    - http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10
    - http://tools.ietf.org/html/rfc6455
é    N)Ú	b64encode)Úsha1)Úurlparsez/no 'numpy' module, HyBi protocol will be slowerc                   @   ó   e Zd ZdS )ÚWebSocketWantReadErrorN©Ú__name__Ú
__module__Ú__qualname__© r   r   úS/root/parts/websockify/install/lib/python3.10/site-packages/websockify/websocket.pyr   "   ó    r   c                   @   r   )ÚWebSocketWantWriteErrorNr   r   r   r   r   r   $   r   r   c                   @   s$  e Zd ZdZdZdd„ Zdd„ Zdg f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dd„ Zd d!„ Zd"d#„ ZdGd%d&„ZdGd'd(„ZdHd*d+„ZdHd,d-„Zd.d/„ Zd0d1„ Zd2d3„ Zd4d5„ Zd6d7„ Zd8d9„ Zd:d;„ Zd<d=„ Z d>d?„ Z!d@dA„ Z"dIdCdD„Z#dEdF„ Z$dS )JÚ	WebSocketao  WebSocket protocol socket like class.

    This provides access to the WebSocket protocol by behaving much
    like a real socket would. It shares many similarities with
    ssl.SSLSocket.

    The WebSocket protocols requires extra data to be sent and received
    compared to the application level data. This means that a socket
    that is ready to be read may not hold enough data to decode any
    application data, and a socket that is ready to be written to may
    not have enough space for an entire WebSocket frame. This is
    handled by the exceptions WebSocketWantReadError and
    WebSocketWantWriteError. When these are raised the caller must wait
    for the socket to become ready again and call the relevant function
    again.

    A connection is established by using either connect() or accept(),
    depending on if a client or server session is desired. See the
    respective functions for details.

    The following methods are passed on to the underlying socket:

        - fileno
        - getpeername, getsockname
        - getsockopt, setsockopt
        - gettimeout, settimeout
        - setblocking
    z$258EAFA5-E914-47DA-95CA-C5AB0DC85B11c                 C   sF   d| _ d| _d| _g | _d| _d| _d| _d| _d| _d| _	d| _
dS )z Creates an unconnected WebSocketÚnewó    NF)Ú_stateÚ_partial_msgÚ_recv_bufferÚ_recv_queueÚ_send_bufferÚ_previous_sendmsgÚ_sent_closeÚ_received_closeÚ
close_codeÚclose_reasonÚsocket©Úselfr   r   r   Ú__init__G   s   
zWebSocket.__init__c                 C   s6   |dv r| j d usJ ‚t| j |ƒS td| jj|f ƒ‚)N)ÚfilenoÚgetpeernameÚgetsocknameÚ
getsockoptÚ
setsockoptÚ
gettimeoutÚ
settimeoutÚsetblockingz!%s instance has no attribute '%s')r   ÚgetattrÚAttributeErrorÚ	__class__r   )r   Únamer   r   r   Ú__getattr__\   s   
ÿzWebSocket.__getattr__Nc                 C   s\  d| _ t|ƒ}|j}|jdv r|sd}n|jdv r|sd}ntd|j ƒ‚| jdkrMt |j|f¡| _|jdv rJt	 
¡ }|j| j|jd| _d	| _nd
| _| jd	krZ| j ¡  d
| _| jd
krÎd| _tdƒD ]}|  jtt d¡ƒ7  _qft| j d¡ƒ d¡| _|j}|sˆd}|  d|¡ |  d|j¡ |  dd¡ |  dd¡ |  d| j¡ |  dd¡ |dur¸|  d|¡ t|ƒdkrÇ|  dd |¡¡ |  ¡  d| _| jdkrÚ|  ¡  d | _| jd krª|  ¡ sètd!ƒ‚| j d"¡d#kròt‚| j  d$d%¡\}| _| d¡}|  ¡ }	t|	ƒd&k s|	d d'krtd(ƒ‚|	d% d)kr+td*d+ |	d%d… ¡ ƒ‚| j  d"d%¡\}
| _|
 d¡d, }
t! "|
¡}
|
 #dd¡ $¡ dkrVt%t&|
ƒƒ td-ƒ‚|
 #d.¡}|du rdtd/ƒ‚t'| j| j(  d¡ƒ )¡ }t|ƒ d¡}| `||krƒtd0ƒ‚|
 #d¡| _*t|ƒdkr›| j*durštd1ƒ‚n
| j*|vr¥td2ƒ‚d3| _dS td4ƒ‚)5az  Establishes a new connection to a WebSocket server.

        This method connects to the host specified by uri and
        negotiates a WebSocket connection. origin should be specified
        in accordance with RFC 6454 if known. A list of valid
        sub-protocols can be specified in the protocols argument.

        The data will be sent in the clear if the "ws" scheme is used,
        and encrypted if the "wss" scheme is used.

        Both WebSocketWantReadError and WebSocketWantWriteError can be
        raised whilst negotiating the connection. Repeated calls to
        connect() must retain the same arguments.
        T)ÚwsÚhttpéP   )ÚwssÚhttpsi»  zUnknown scheme '%s'r   )Úserver_hostnameÚssl_handshakeÚheadersÚ é   é   úlatin-1Úasciiú/ÚGETÚHostÚUpgradeÚ	websocketÚ
ConnectionÚupgradeúSec-WebSocket-KeyúSec-WebSocket-Versioné   NÚOriginr   úSec-WebSocket-Protocolz, Úsend_headersÚresponsezSocket closed unexpectedlys   

éÿÿÿÿs   
é   é   zHTTP/1.1zInvalid responseÚ101zWebSocket request denied: %sú ú
ú#Missing or incorrect upgrade headerúSec-WebSocket-Acceptz#Missing Sec-WebSocket-Accept headerz#Invalid Sec-WebSocket-Accept headerz(Unexpected Sec-WebSocket-Protocol headerz!Invalid protocol chosen by serverÚdoneú WebSocket is in an invalid state)+Úclientr   ÚportÚschemeÚ	Exceptionr   r   Úcreate_connectionÚhostnameÚsslÚcreate_default_contextÚwrap_socketÚdo_handshakeÚ_keyÚrangeÚchrÚrandomÚ	randranger   ÚencodeÚdecodeÚpathÚsend_requestÚsend_headerÚlenÚjoinÚend_headersÚ_flushÚ_recvr   Úfindr   ÚsplitÚemailÚmessage_from_stringÚgetÚlowerÚprintÚtyper   ÚGUIDÚdigestÚprotocol)r   ÚuriÚoriginÚ	protocolsrS   ÚcontextÚirc   ÚrequestÚwordsr4   ÚacceptÚexpectedr   r   r   Úconnecti   s¦   
€
€

ÿ








ÿzWebSocket.connectc                 C   s`  | j dkržd| _|| _| dd¡ ¡ dkrtdƒ‚| d¡}|du r&td	ƒ‚|d
v r2dt|ƒ | _ntd| ƒ‚| d¡}|du rEtdƒ‚t|| j	  
d¡ƒ ¡ }t|ƒ d¡}d| _| dd¡ d¡}|ru|  |¡| _| j|vrutdƒ‚|  dd¡ |  dd¡ |  dd¡ |  d|¡ | jr—|  d| j¡ |  ¡  d| _ | j dkr¬|  ¡  d| _ dS tdƒ‚)af  Establishes a new WebSocket session with a client.

        This method negotiates a WebSocket connection with an incoming
        client. The caller must provide the client socket and the
        headers from the HTTP request.

        A server can identify that a client is requesting a WebSocket
        connection by looking at the "Upgrade" header. It will include
        the value "websocket" in such cases.

        WebSocketWantWriteError can be raised if the response cannot be
        sent right away. accept() must be called again once more space
        is available using the same arguments.
        r   Fr@   r5   r>   rN   rB   Nz$Missing Sec-WebSocket-Version header)Ú7Ú8Ú13z	hybi-%02dzUnsupported protocol version %srA   z Missing Sec-WebSocket-Key headerr9   rE   ú,zInvalid protocol selectedée   zSwitching Protocolsr=   r?   rO   ÚflushrP   rQ   )r   rR   r   ro   rp   rU   ÚintÚversionr   rs   ra   rt   r   rb   ru   rl   Úselect_subprotocolÚsend_responsere   rh   ri   )r   r   r4   ÚverÚkeyr}   rx   r   r   r   r}   é   sF   




zWebSocket.acceptc                 C   ó   dS )a  Returns which sub-protocol should be used.

        This method does not select any sub-protocol by default and is
        meant to be overridden by an implementation that wishes to make
        use of sub-protocols. It will be called during handling of
        accept().
        r5   r   )r   rx   r   r   r   rˆ   4  s   zWebSocket.select_subprotocolc                 C   s   |   |¡ dS )z®Called when a WebSocket ping message is received.

        This will be called whilst processing recv()/recvmsg(). The
        default implementation sends a pong reply back.N)Úpong©r   Údatar   r   r   Úhandle_ping>  s   zWebSocket.handle_pingc                 C   rŒ   )z£Called when a WebSocket pong message is received.

        This will be called whilst processing recv()/recvmsg(). The
        default implementation does nothing.Nr   rŽ   r   r   r   Úhandle_pongE  s   zWebSocket.handle_pongc                 C   s   |   ¡ S )a¹  Read data from the WebSocket.

        This will return any available data on the socket (which may
        be the empty string if the peer sent an empty message or
        messages). If the socket is closed then None will be
        returned. The reason for the close is found in the
        'close_code' and 'close_reason' properties.

        Unlike recvmsg() this method may return data from more than one
        WebSocket message. It is however not guaranteed to return all
        buffered data. Callers should continue calling recv() whilst
        pending() returns True.

        Both WebSocketWantReadError and WebSocketWantWriteError can be
        raised when calling recv().
        )Úrecvmsgr   r   r   r   ÚrecvL  s   zWebSocket.recvc                 C   s6   | j r	|  ¡  dS |  ¡ r|  ¡ S |  ¡ sdS |  ¡ S )aŠ  Read a single message from the WebSocket.

        This will return a single WebSocket message from the socket
        (which will be the empty string if the peer sent an empty
        message). If the socket is closed then None will be
        returned. The reason for the close is found in the
        'close_code' and 'close_reason' properties.

        Unlike recv() this method will not return data from more than
        one WebSocket message. Callers should continue calling
        recvmsg() whilst pending() returns True.

        Both WebSocketWantReadError and WebSocketWantWriteError can be
        raised when calling recvmsg().
        N)r   ri   ÚpendingÚ_recvmsgÚ_recv_framesr   r   r   r   r’   _  s   zWebSocket.recvmsgc                 C   s   t | jƒdkS )a  Check if any WebSocket data is pending.

        This method will return True as long as there are WebSocket
        frames that have yet been processed. A single recv() from the
        underlying socket may return multiple WebSocket frames and it
        is therefore important that a caller continues calling recv()
        or recvmsg() as long as pending() returns True.

        Note that this function merely tells if there are raw WebSocket
        frames pending. Those frames may not contain any application
        data.
        r   )rf   r   r   r   r   r   r”   ƒ  s   zWebSocket.pendingc                 C   s   t |ƒdkrdS |  |¡S )aÀ  Write data to the WebSocket

        This will queue the given data and attempt to send it to the
        peer. Unlike sendmsg() this method might coalesce the data with
        data from other calls, or split it over multiple messages.

        WebSocketWantWriteError can be raised if there is insufficient
        space in the underlying socket. send() must be called again
        once more space is available using the same arguments.
        r   )rf   Úsendmsg)r   Úbytesr   r   r   Úsend’  s   
zWebSocket.sendc                 C   st   t |tƒst‚| jrdS | jdur#| j|krt‚|  ¡  d| _t|ƒS z|  d|¡ W t|ƒS  t	y9   || _‚ w )a­  Write a single message to the WebSocket

        This will queue the given message and attempt to send it to the
        peer. Unlike send() this method will preserve the data as a
        single WebSocket message.

        WebSocketWantWriteError can be raised if there is insufficient
        space in the underlying socket. sendmsg() must be called again
        once more space is available using the same arguments.
        r   NrJ   )
Ú
isinstancer˜   Ú	TypeErrorr   r   Ú
ValueErrorri   rf   Ú_sendmsgr   )r   Úmsgr   r   r   r—   ¢  s"   


üþzWebSocket.sendmsgc                 C   ó   |   d||f ¡ d S )NzHTTP/1.1 %d %s
©Ú
_queue_str)r   ÚcodeÚmessager   r   r   r‰   Ä  ó   zWebSocket.send_responsec                 C   rŸ   )Nz%s: %s
r    )r   ÚkeywordÚvaluer   r   r   re   Ç  r¤   zWebSocket.send_headerc                 C   s   |   d¡ d S )NrM   r    r   r   r   r   rh   Ê  s   zWebSocket.end_headersc                 C   s   |   d| ¡ |f ¡ d S )Nz%s %s HTTP/1.1
)r¡   Úupper)r   rr   rc   r   r   r   rd   Í  s   zWebSocket.send_requestr   c                 C   ób   t |tƒst‚| jdur| j|krt‚|  ¡  d| _dS z	|  d|¡ W dS  ty0   || _‚ w )zùWrite a ping message to the WebSocket

        WebSocketWantWriteError can be raised if there is insufficient
        space in the underlying socket. ping() must be called again once
        more space is available using the same arguments.
        Né	   ©rš   r˜   r›   r   rœ   ri   r   r   rŽ   r   r   r   ÚpingÐ  ó   


þzWebSocket.pingc                 C   r¨   )zùWrite a pong message to the WebSocket

        WebSocketWantWriteError can be raised if there is insufficient
        space in the underlying socket. pong() must be called again once
        more space is available using the same arguments.
        Né
   rª   rŽ   r   r   r   r   é  r¬   zWebSocket.pongéè  c                 C   sl   | j r	|  ¡  dS | jsd| _d| _d| _ d}|dur.|t d|¡7 }|dur.|| d¡7 }|  d|¡ dS )	as  Gracefully terminate the WebSocket connection.

        This will start the process to terminate the WebSocket
        connection. The caller must continue to calling recv() or
        recvmsg() after this function in order to wait for the peer to
        acknowledge the close. Calls to send() and sendmsg() will be
        ignored.

        WebSocketWantWriteError can be raised if there is insufficient
        space in the underlying socket for the close message. shutdown()
        must be called again once more space is available using the same
        arguments.

        The how argument is currently ignored.
        Nr®   zLocally initiated closeTr   ú>HúUTF-8é   )	r   ri   r   r   r   ÚstructÚpackra   r   )r   Úhowr¢   Úreasonrž   r   r   r   Úshutdown  s   zWebSocket.shutdownc                 C   s   |   tj||¡ |  ¡  dS )a  Terminate the WebSocket connection immediately.

        This will close the WebSocket connection directly after sending
        a close message to the peer.

        WebSocketWantWriteError can be raised if there is insufficient
        space in the underlying socket for the close message. close()
        must be called again once more space is available using the same
        arguments.
        N)r¶   r   Ú	SHUT_RDWRÚ_close)r   r¢   rµ   r   r   r   Úclose'  s   zWebSocket.closec              
   C   s   | j d usJ ‚	 z| j  d¡}W n ty% } z	|jtjkr t‚‚ d }~ww t|ƒdkr.dS |  j|7  _t| j dƒrD| j  	¡ sC	 dS n	 dS q)NTi   r   Fr”   )
r   r“   ÚOSErrorÚerrnoÚEWOULDBLOCKr   rf   r   Úhasattrr”   )r   r   Úexcr   r   r   rj   5  s*   €ý
ûìzWebSocket._recvc                 C   st   |   ¡ s| jd u rd| _d| _d | _| _|  ¡  dS 	 |  | j¡}|d u r)	 dS | j|d d … | _| j 	|¡ q)Niî  zConnection closed abnormallyTFÚlength)
rj   r   r   r   r   r¸   Ú_decode_hybir   r   Úappend)r   Úframer   r   r   r–   O  s   
ýûzWebSocket._recv_framesc                 C   s¢  | j rO| j  d¡}| js|d s|  tjdd¡ q | jr*|d r*|  tjdd¡ q |d dkrR| js<|  tjdd¡ q |  j|d 7  _|d	 rQ| j}d
| _|S nú|d dkra|  tjdd¡ në|d dkr| jrs|  tjdd¡ q |d	 r{|d S |d | _nË|d dkr| jrŒq d| _| jr˜|  	¡  d S |d	 s¥|  tjdd¡ q d }d }t
|d ƒdkrèt d|d d d… ¡d }t
|d ƒdkrè|d dd … }z| d¡}W n tyç   |  tjdd¡ Y q w |d u ród| _d| _n
|| _|d urý|| _|  d ||¡ d S |d dkr#|d	 s|  tjdd¡ q |  |d ¡ n)|d dkr@|d	 s8|  tjdd¡ q |  |d ¡ n|  tjdd|d  ¡ | j st‚)Nr   Úmaskediê  z Procotol error: Frame not maskedzProcotol error: Frame maskedÚopcodez-Procotol error: Unexpected continuation frameÚpayloadÚfinr   rI   ië  z*Unsupported: Text frames are not supportedrJ   z$Procotol error: Unexpected new framer±   TzUnsupported: Fragmented closer¯   r°   z&Procotol error: Invalid UTF-8 in closeií  z&No close status code specified by peerr©   zUnsupported: Fragmented pingr­   zUnsupported: Fragmented pongz"Unsupported: Unknown opcode 0x%02x)r   ÚpoprR   r¶   r   r·   r   r   r   r¸   rf   r²   Úunpackrb   ÚUnicodeDecodeErrorr   r   r   r‘   r   )r   rÂ   rž   r¢   rµ   r   r   r   r•   b  sŒ   ýþ

¯SzWebSocket._recvmsgc              
   C   s   | j sd S | jd usJ ‚z	| j | j ¡}W n ty* } z	|jtjkr%t‚‚ d }~ww | j |d … | _ | j r8t‚| jrD| jrF|  	¡  d S d S d S ©N)
r   r   r™   rº   r»   r¼   r   r   r   r¸   )r   Úsentr¾   r   r   r   ri   ¹  s"   €ýÿzWebSocket._flushc                 C   s   |  j |7  _ |  ¡  d S rÊ   )r   ri   rŽ   r   r   r   Ú_sendÑ  s   zWebSocket._sendc                 C   s   |  j | d¡7  _ d S )Nr8   )r   ra   )r   Ústringr   r   r   r¡   Ö  s   zWebSocket._queue_strc                 C   sP   | j rd}tdƒD ]}|t d¡ ¡ 7 }q	|  |||¡}n|  ||¡}|  |¡S )Nr   é   r7   )rR   r]   r_   r`   Úto_bytesÚ_encode_hybirÌ   )r   rÄ   rž   Úmaskrz   rÂ   r   r   r   r   Û  s   
zWebSocket._sendmsgc                 C   s   | j  ¡  d | _ d S rÊ   )r   r¹   r   r   r   r   r¸   ç  s   

zWebSocket._closec                 C   s   |   ||¡S rÊ   )Ú_unmask)r   ÚbufrÑ   r   r   r   Ú_maskì  s   zWebSocket._maskc                 C   s0  t rut|ƒ}d}|}d }}|dkr=t  d¡}tjdkr!| d¡}t j||dd}t j||t|d ƒd}	t  |	|¡ 	¡ }|d rqt  d	¡}tjdkrP| d¡}t j|||d d}t j||||d  |d d
}	t  |	|¡ 	¡ }|| S t
 
d	¡}	|	 |¡ tt|	ƒƒD ]}
|	|
  ||
d  N  < q…|	 	¡ S )Nr   r   rÎ   z<u4Úbigú>rI   )ÚcountÚB)Úoffsetr×   )Únumpyrf   ÚdtypeÚsysÚ	byteorderÚnewbyteorderÚ
frombufferr†   Úbitwise_xorÚtobytesÚarrayÚ	frombytesr]   )r   rÓ   rÑ   ÚplenÚpstartÚpendÚbÚcrÛ   r   rz   r   r   r   rÒ   ð  s6   





ÿ

zWebSocket._unmaskTc           	      C   s²   |d@ }|r
|dO }d}|durd}|   ||¡}t|ƒ}|dkr*t d|||B ¡}n!|dkr=|dk r=t d|d	|B |¡}n|dkrKt d
|d|B |¡}|durU|| | S || S )zó Encode a HyBi style WebSocket frame.
        Optional opcode:
            0x0 - continuation
            0x1 - text frame
            0x2 - binary frame
            0x8 - connection close
            0x9 - ping
            0xA - pong
        é   é€   r   Né}   ú>BBi   z>BBHé~   z>BBQé   )rÔ   rf   r²   r³   )	r   rÄ   rÓ   Úmask_keyrÆ   Úb1Úmask_bitÚpayload_lenÚheaderr   r   r   rÐ     s"   zWebSocket._encode_hybic           	      C   sb  ddddddœ}t |ƒ}d}||k rdS t d|dd… ¡\}}|d@ |d< |d	@   |d
< |d	@   |d< |d rD|d7 }||k rDdS |d@ }|dkrb|d7 }||k rVdS t d|dd… ¡\}n|dkr{|d7 }||k rpdS t d|dd… ¡\}|| |d< ||d k r‰dS |d r¥||d |… }|  |||| … |¡|d< |S |||| … |d< |S )a   Decode HyBi style WebSocket packets.
        Returns:
            {'fin'          : boolean,
             'opcode'       : number,
             'masked'       : boolean,
             'length'       : encoded_length,
             'payload'      : decoded_buffer}
        r   FN)rÆ   rÄ   rÃ   r¿   rÅ   rJ   rì   ré   rÄ   rê   rÆ   rÃ   rÎ   rî   rí   r¯   r±   z>Qr­   r¿   rÅ   )rf   r²   rÈ   rÒ   )	r   rÓ   ÚfÚblenÚhlenrð   Úb2r¿   rï   r   r   r   rÀ   2  sL   
üþzWebSocket._decode_hybi)r   )r®   N)NT)%r   r	   r
   Ú__doc__rs   r   r,   r   r}   rˆ   r   r‘   r“   r’   r”   r™   r—   r‰   re   rh   rd   r«   r   r¶   r¹   rj   r–   r•   ri   rÌ   r¡   r   r¸   rÔ   rÒ   rÐ   rÀ   r   r   r   r   r   '   sH     K
$"



%W
!!r   )rø   rÜ   râ   rm   r»   r_   r   rX   r²   Úbase64r   Úhashlibr   Úurllib.parser   rÚ   ÚImportErrorÚwarningsÚwarnÚSSLWantReadErrorr   ÚSSLWantWriteErrorr   r   r   r   r   r   Ú<module>   s,   
ý