
    #&aJq                     &   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 	 ddlZ G d dej&                        Z G d	 d
ej*                        Z G d de      Zy# e$ r ddlZ ej$                  d       dZY Uw xY w)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y)WebSocketWantReadErrorN__name__
__module____qualname__     6/usr/lib/python3/dist-packages/websockify/websocket.pyr   r   "       r   r   c                       e Zd Zy)WebSocketWantWriteErrorNr   r   r   r   r   r   $   r   r   r   c                       e Zd ZdZdZd Zd Zdg fdZd Zd Z	d	 Z
d
 Zd Zd Zd Zd Zd Zd dZd dZd!dZd!dZd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd"dZd Z y)#	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                     d| _         d| _        d| _        g | _        d| _        d| _        d| _        d| _        d| _        d| _	        d| _
        y)z Creates an unconnected WebSocketnewr   NF)_state_partial_msg_recv_buffer_recv_queue_send_buffer_previous_sendmsg_sent_close_received_close
close_codeclose_reasonsocketselfs    r   __init__zWebSocket.__init__G   sY     !% $ r   c                     |dv r$| j                   J t        | j                   |      S t        | j                  j                  d|d      )N)filenogetpeernamegetsockname
getsockopt
setsockopt
gettimeout
settimeoutsetblockingz instance has no attribute '')r    getattrAttributeError	__class__r	   )r"   names     r   __getattr__zWebSocket.__getattr__\   sV     # #
 ;;***4;;-- "&.."9"94"A B Br   Nc                 
   d| _         t        |      }|j                  }|j                  dv r|s.d}n+|j                  dv r|sd}nt	        d|j                  z        | j
                  dk(  rgt        j                  |j                  |f      | _        |j                  dv r,t        j                  | j                        | _        d| _        nd	| _        | j
                  dk(  r!| j                  j                          d	| _        | j
                  d	k(  rrd
| _        t        d      D ]3  }| xj                  t        t        j                   d            z  c_        5 t#        | j                  j%                  d            j'                  d      | _        |j(                  }|sd}| j+                  d|z         | j+                  d|j                  z         | j+                  d       | j+                  d       | j+                  d| j                  z         | j+                  d       || j+                  d|z         t-        |      dkD  r#| j+                  ddj/                  |      z         | j+                  d       d| _        | j
                  dk(  r| j1                          d| _        | j
                  dk(  rA| j3                         st	        d      | j4                  j7                  d      d k(  rt8        | j4                  j;                  d!d"      \  }| _        |j'                  d      }|j;                         }t-        |      d#k  s|d   d$k7  rt	        d%      |d"   d&k7  r t	        d'd(j/                  |d"d       z        | j4                  j;                  dd"      \  }	| _        |	j'                  d      dz   }	t=        j>                  |	      }	|	jA                  d)d
      jC                         d*k7  rtE        tG        |	             t	        d+      |	jA                  d,      }
|
t	        d-      tI        | j                  | jJ                  z   j%                  d            jM                         }t#        |      j'                  d      }| `|
|k7  rt	        d.      |	jA                  d/      | _'        t-        |      dk(  r| jN                  $t	        d0      | jN                  |vrt	        d1      d2| _        yt	        d3      )4az  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httpP   )wsshttpsi  zUnknown scheme '%s'r   ssl_handshakeheaders       latin-1ascii/zGET %s HTTP/1.1
z
Host: %s
Upgrade: websocket
zConnection: upgrade
zSec-WebSocket-Key: %s
zSec-WebSocket-Version: 13
NzOrigin: %s
r   Sec-WebSocket-Protocol: %s
z, 
send_headersresponsezSocket closed unexpectedlys   

s   
      zHTTP/1.1zInvalid response101zWebSocket request denied: %s Upgrade	websocket#Missing or incorrect upgrade headerzSec-WebSocket-Acceptz#Missing Sec-WebSocket-Accept headerz#Invalid Sec-WebSocket-Accept headerSec-WebSocket-Protocolz(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wrap_socketdo_handshake_keyrangechrrandom	randranger   encodedecodepath
_queue_strlenjoin_flush_recvr   findr   splitemailmessage_from_stringgetlowerprinttyper   GUIDdigestprotocol)r"   uriorigin	protocolsrR   ira   requestwordsr:   acceptexpecteds               r   connectzWebSocket.connecti   s>     smxx::'ZZ++1CJJ>??
 ;;% 22CLL$3GHDKzz--!oodkk:-';;/)KK$$&#DK;;)#DI2Y 8		S!1!1#!677	8!$))"2"29"=>EEgNDI88DOO1D89OONS\\9:OO45OO56OO7$))CDOO;<! 06 9:9~! @499YCW WXOOF#(DK;;.(KKM$DK;;*$::< <==  %%k2b8,,+/+<+<+B+B7A+N(Wd'nnY/GMMOEE
QE!H
$: 233Qx5  >%PQPR)AT TUU+/+<+<+B+B;PQ+R(Wd'nnY/&8G//8G{{9b)//1[@d7m$ EFF[[!78F~ EFFTYY2::7CDKKMH *11':H	! EFF#KK(@ADM9~"==,#$NOO==	1#$GHH DK:;;r   c                 $   | j                   dk(  rd| _        || _        |j                  dd      j	                         dk7  rt        d      |j                  d      }|t        d	      |d
v rdt        |      z  | _        nt        d|z        |j                  d      }|t        d      t        || j                  z   j                  d            j                         }t        |      j                  d      }d| _        |j                  dd      j                  d      }|r/| j!                  |      | _        | j                  |vrt        d      | j#                  d       | j#                  d       | j#                  d       | j#                  d|z         | j                  r| j#                  d| j                  z         | j#                  d       d| _         | j                   dk(  r| j%                          d| _         y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   Fupgrader;   rL   rM   zSec-WebSocket-VersionNz$Missing Sec-WebSocket-Version header)7813z	hybi-%02dzUnsupported protocol version %szSec-WebSocket-Keyz Missing Sec-WebSocket-Key headerr?   rN   ,zInvalid protocol selectedz"HTTP/1.1 101 Switching Protocols
rA   zConnection: Upgrade
zSec-WebSocket-Accept: %s
rB   rC   flushrO   rP   )r   rQ   r    rk   rl   rT   intversionr   ro   r_   rp   r   r`   rq   rh   select_subprotocolrb   re   )r"   r    r:   verkeyrx   rt   s          r   rx   zWebSocket.accept   s   & ;;%DK DK{{9b)//1[@ EFF++56C{ FGG
 &&*SX5 AC GHH++12C{ BCC 3?227;<CCEFv&--g6FDM$<bAGGLI $ 7 7	 B ==	1#$?@@OOBCOO45OO56OO:VCD}} @4== PQOOF#!DK;;'!KKM DK:;;r   c                      y)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().
        r;   r   )r"   rt   s     r   r   zWebSocket.select_subprotocol2  s     r   c                 &    | j                  |       y)zCalled 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"   datas     r   handle_pingzWebSocket.handle_ping<  s    
 			$r   c                      y)zCalled when a WebSocket pong message is received.

        This will be called whilst processing recv()/recvmsg(). The
        default implementation does nothing.Nr   r   s     r   handle_pongzWebSocket.handle_pongC  s    
 	r   c                 "    | j                         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!   s    r   recvzWebSocket.recvJ  s    " ||~r   c                     | j                   r| j                          y| j                         r| j                         S | j	                         sy| j                         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   re   pending_recvmsg_recv_framesr!   s    r   r   zWebSocket.recvmsg]  sO    " KKM <<>==?"   " }}r   c                 2    t        | j                        dkD  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   )rc   r   r!   s    r   r   zWebSocket.pending  s     4##$q((r   c                 B    t        |      dk(  ry| j                  |      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   )rc   sendmsg)r"   bytess     r   sendzWebSocket.send  s!     u:?||E""r   c                 4   t        |t              st        | j                  ry| j                  7| j                  |k7  rt
        | j                          d| _        t        |      S 	 | j                  d|       t        |      S # t        $ r	 || _         w xY 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   NrH   )

isinstancer   	TypeErrorr   r   
ValueErrorre   rc   _sendmsgr   )r"   msgs     r   r   zWebSocket.sendmsg  s     #u%O!!-%%,  KKM%)D"s8O	MM#s#
 3x	 ' 	%(D"	s   (B Bc                     t        |t              st        | j                  -| j                  |k7  rt        | j                          d| _        y	 | j                  d|       y# t        $ r	 || _         w xY w)zWrite 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   re   r   r   r   s     r   pingzWebSocket.ping  t     $&O!!-%%-  KKM%)D"	MM#t$& 	%)D"	   A$ $A6c                     t        |t              st        | j                  -| j                  |k7  rt        | j                          d| _        y	 | j                  d|       y# t        $ r	 || _         w xY w)zWrite 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   s     r   r   zWebSocket.pong  r   r   c                 
   | j                   r| j                          y| j                  sd| _        d| _        d| _         d}|/|t        j                  d|      z  }|||j                  d      z  }| j                  d|       y)	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.
        N  zLocally initiated closeTr   >HUTF-8   )	r   re   r   r   r   structpackr_   r   )r"   howcodereasonr   s        r   shutdownzWebSocket.shutdown  s    $ KKM ##"DO 9D6;;tT**C!v}}W--c3r   c                 f    | j                  t        j                  ||       | j                          y)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   s      r   closezWebSocket.close  s#     	f&&f5r   c                 t   | j                   J 	 	 | j                   j                  d      }t        |      dk(  ry| xj                  |z  c_        t        | j                   d      r| j                   j                         s	 y	 yu# t        $ r)}|j                  t        j                  k(  rt
         d }~ww xY w)NTi   r   Fr   )
r    r   OSErrorerrnoEWOULDBLOCKr   rc   r   hasattrr   )r"   r   excs      r   rf   zWebSocket._recv'  s    {{&&&{{''- 4yA~% t{{I.{{**,  )   99 1 1100s   B 	B7$B22B7c                 :   | j                         s9| j                  d| _        d| _        dx| _        | _        | j                          y	 | j                  | j                        }|	 y| j                  |d   d  | _        | j                  j                  |       R)Ni  zConnection closed abnormallyTFlength)
rf   r   r   r   r   r   _decode_hybir   r   append)r"   frames     r   r   zWebSocket._recv_framesA  s    zz|&"&$B!:>> 4#7KKM%%d&7&78E}  !% 1 1%/2B CD##E* r   c                    | j                   r| j                   j                  d      }| j                  s'|d   s"| j                  t        j
                  dd       [| j                  r'|d   r"| j                  t        j
                  dd       |d   dk(  ra| j                  s"| j                  t        j
                  dd       | xj                  |d   z  c_        |d	   r6| j                  }d
| _        |S |d   dk(  r#| j                  t        j
                  dd       n|d   dk(  rE| j                  r#| j                  t        j
                  dd       Y|d	   r|d   S |d   | _        n|d   dk(  r| j                  rd| _        | j                  r| j                          y |d	   s#| j                  t        j
                  dd       d }d }t        |d         dk\  rJt        j                  d|d   d d       d   }t        |d         dkD  r|d   dd  }	 |j                  d      }|dx| _        }d| _        n|| _        ||| _        | j                  d ||       y |d   dk(  r=|d	   s#| j                  t        j
                  dd       | j#                  |d          nl|d   dk(  r=|d	   s#| j                  t        j
                  dd       | j%                  |d          n'| j                  t        j
                  dd|d   z         | j                   rt&        # t        $ r% | j                  t        j
                  dd       Y Yw xY w)Nr   maskedi  z Procotol error: Frame not maskedzProcotol error: Frame maskedopcodez-Procotol error: Unexpected continuation framepayloadfinr   rG   i  z*Unsupported: Text frames are not supportedrH   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   poprQ   r   r    r   r   r   r   r   rc   r   unpackr`   UnicodeDecodeErrorr   r   r   r   r   )r"   r   r   r   r   s        r   r   zWebSocket._recvmsgT  s3   $$((+E;;uXf..6XY{{uXf..6TUX#%((MM&"2"2D:ij!!U9%55!<++C(+D%JxC'f..6bcxC'$$MM&"2"2D:`a< ++(-i(8D%xC''''+$##KKMU|MM&"2"2D:YZuY'(A-!==uY/?/CDQGD5+,q0!&y!1!"!5%%+]]7%;F
 <-11DOd(PD%&*DO),2)dD&1xC'U|MM&"2"2D:XY  y!12xC'U|MM&"2"2D:XY  y!12f..6Z]bck]l6lmc f %$;  2 % MM&*:*:DBjk$%s    L- -*MMc                    | j                   sy | j                  J 	 | j                  j                  | j                         }| j                   |d  | _         | j                   rt        | j                  r| j                  r| j                          y y y # t        $ r)}|j                  t        j
                  k(  rt         d }~ww xY wN)
r   r    r   r   r   r   r   r   r   r   )r"   sentr   s      r   re   zWebSocket._flush  s      {{&&&	;;##D$5$56D !--de4)) D$4$4KKM %5  	yyE-----	s   %B 	C$C  Cc                 N    | xj                   |z  c_         | j                          y r   )r   re   r   s     r   _sendzWebSocket._send  s    T!r   c                 L    | xj                   |j                  d      z  c_         y )Nr>   )r   r_   )r"   strings     r   rb   zWebSocket._queue_str  s     	V]]955r   c                     | j                   r>d}t        d      D ]  }|t        j                  d      z  } | j	                  |||      }n| j	                  ||      }| j                  |      S )Nr      r=   )rQ   r[   r]   r^   _encode_hybir   )r"   r   r   maskru   r   s         r   r   zWebSocket._sendmsg  sk    ;;D1X .((--.%%fc48E%%fc2Ezz%  r   c                 F    | j                   j                          d | _         y r   )r    r   r!   s    r   r   zWebSocket._close  s    r   c                 &    | j                  ||      S r   )_unmask)r"   bufr   s      r   _maskzWebSocket._mask  s    ||C&&r   c                 ~   t         rUt        |      }d}|}dx}}|dk\  rt        j                  d      }t        j                  dk(  r|j                  d      }t        j                  ||d      }t        j                  ||t        |dz              }	t        j                  |	|      j                         }|dz  rt        j                  d	      }t        j                  dk(  r|j                  d      }t        j                  |||dz        }t        j                  ||||dz  z
  |dz  
      }	t        j                  |	|      j                         }||z   S t        j                  d	      }	|	j                  |       t        t        |	            D ]  }
|	|
xx   ||
dz     z  cc<    |	j                         S )Nr   r   r   z<u4big>rG   )countB)offsetr   )numpyrc   dtypesys	byteordernewbyteorder
frombufferr   bitwise_xortobytesarray	frombytesr[   )r"   r   r   plenpstartpendbcr   r   ru   s              r   r   zWebSocket._unmask  s   s8DFDKAqykk%(==E)!..s3E''e1=''U#dQh-H%%dD199;axkk#&==E)!..s3E''eD1HF''U#tax0D%%dD199;q5L ;;s#DNN33t9% 'Q4A;&'<<>!r   c                 J   |dz  }|r|dz  }d}|d}| j                  ||      }t        |      }|dk  rt        j                  d|||z        }nF|dkD  r!|dk  rt        j                  d|d|z  |      }n |dk\  rt        j                  d	|d
|z  |      }||z   |z   S |z   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   }   >BBi   z>BBH~   z>BBQ   )r   rc   r   r   )	r"   r   r   mask_keyr   b1mask_bitpayload_lenheaders	            r   r   zWebSocket._encode_hybi  s     d]$JBH**S(+C#h#[[K(,BCF3;#6[[S8^[IFE![[S8^[IFH$s**C<r   c                    dddddd}t        |      }d}||k  ryt        j                  d|dd       \  }}|dz  |d<   |d	z    |d
<   |d	z    |d<   |d   r|dz  }||k  ry|dz  }|dk(  r'|dz  }||k  ryt        j                  d|dd       \  }n+|dk(  r&|dz  }||k  ryt        j                  d|dd       \  }||z   |d<   ||d   k  ry|d   r%||dz
  | }| j                  ||||z    |      |d<   |S ||||z    |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   rH   r   r   r   r   r   r   r   r   r   r   r   z>Qr   r   r   )rc   r   r   r   )	r"   r   fblenhlenr   b2r   r   s	            r   r   zWebSocket._decode_hybi$  sz     #"	$ 3x$;uc"1g.B4i(I&%!Dy/)(X;AIDd{dS=AIDd{mmD#a(3GFs]AIDd{mmD#a)4GFVm(!H+X;46$'H<<D$v+(?JAiL  tT&[2AiLr   )r   )r   N)NT)!r	   r
   r   __doc__ro   r#   r2   rz   rx   r   r   r   r   r   r   r   r   r   r   r   r   rf   r   r   re   r   rb   r   r   r   r   r   r   r   r   r   r   r   '   s    : 2D*B #'" |<|I<V&"H)#  D22# J4&U%n0
6

!
'"B B9r   r   )r  r   r   ri   r   r]   r    rW   r   base64r   hashlibr   urllib.parser   r   ImportErrorwarningswarnSSLWantReadErrorr   SSLWantWriteErrorr   objectr   r   r   r   <module>r     s   
       
    !	S11 		c33 	v v  HMMCDEs   A0 0BB