
    -e5                    v   U d Z ddlmZ ddlZ ej        e          ZddlZddlZ	ddl
mZmZmZ ddlmZ ddl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l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+ erddl,m-Z- dZ. G d de+e          Z/e' G d d                      Z0dZ1de2d<   dS )zA Provide a web socket handler for the Bokeh Server application.

    )annotationsN)TYPE_CHECKINGAnycast)urlparse)locksweb)WebSocketClosedErrorWebSocketHandler)settings)check_token_signatureget_session_idget_token_payload   )Protocol)MessageErrorProtocolErrorValidationError)Message)Receiver)	dataclass   )ProtocolHandler   )AuthRequestHandler)ServerConnection)	WSHandlerc                       e Zd ZU dZded<   d. fdZd Zd/dZej	        d.d            Z
d0dZd1dZd2dZd3dZd4dZd5dZ	 d6d7 fd#Zd.d$Zd8d&Zd9d(Zd:d+Zd;d,Zd;d-Z xZS )<r   zI Implements a custom Tornado WebSocketHandler for the Bokeh Server.

    zServerConnection | None
connectionreturnNonec                >   d | _         d | _        d | _        |d         | _        d| _        t          j                    | _        d | _        |	                    dd           | _
        |	                    dd           | _         t                      j        |g|R i | d S )Napplication_contextcompression_level	mem_level)receiverhandlerr   r#   latest_pongr   Lock
write_lock_tokenpop_compression_level
_mem_levelsuper__init__)selftornado_appargskw	__class__s       5lib/python3.11/site-packages/bokeh/server/views/ws.pyr1   zWSHandler.__init__H   s    #%&;#<   *,,"$&&)<d"C"C&&d33 	2t222r22222    c                    d S N )r2   r#   bokeh_websocket_paths      r7   
initializezWSHandler.initializeZ   s    r8   originstrboolc                <   ddl m} t          |          }|j                                        }| j        j        }t          j                    r t          t          j                              } |||          }|rdS t                              d||||           dS )a   Implement a check_origin policy for Tornado to call.

        The supplied origin will be compared to the Bokeh server allowlist. If the
        origin is not allow, an error will be logged and ``False`` will be returned.

        Args:
            origin (str) :
                The URL of the connection origin

        Returns:
            bool, True if the connection is allowed, False otherwise

        r   )check_allowlistTzRefusing websocket connection from Origin '%s';                       use --allow-websocket-origin=%s or set BOKEH_ALLOW_WS_ORIGIN=%s to permit this; currently we allow origins %rF)utilrB   r   netloclowerapplicationwebsocket_originsr   allowed_ws_originsetlogerror)r2   r>   rB   parsed_originorigin_hostallowed_hostsalloweds          r7   check_originzWSHandler.check_origin]   s     	+***** ((#*0022(:%'' 	> : < <==M!/+}== 	4II Ek;G G G 5r8   c                   t                               d           | j        }| j        dk    r#|                                  t          d          |#|                                  t          d          t          j        t          j	        
                    t          j        j                                                            }t          |          }d|vr#|                                  t          d          ||d         k    r#|                                  t          d	          t          || j        j        | j        j        
          s9t'          |          }t                               d|           t          d          	 | j        j                            | j        | j                   dS # t0          $ r&}t                               d|           Y d}~dS d}~ww xY w)zR Initialize a connection to a client.

        Returns:
            None

        zWebSocket connection openedbokehz!Subprotocol header is not 'bokeh'Nz'No token received in subprotocol header)tzsession_expiryz$Session expiry has not been providedzToken is expired.)signed
secret_keyz*Token for session %r had invalid signaturezInvalid token signaturez"Failed to fully open connection %r)rJ   infor,   selected_subprotocolcloser   calendartimegmdtdatetimenowtimezoneutc	timetupler   r   rF   sign_sessionsrV   r   rK   io_loopadd_callback_async_open	Exceptiondebug)r2   tokenr^   payload
session_ides         r7   openzWSHandler.open|   s    	.///$//JJLLL CDDD]JJLLL IJJJobkoooAAKKMMNN#E**7**JJLLL FGGGG,---JJLLL 3444&u.2.>.L262B2MO O O 	; (..JIIBJOOO 9:::	?$11$2BDKPPPPP 	? 	? 	? II:A>>>>>>>>>		?s   *F9 9
G)G$$G)subprotocols	list[str]
str | Nonec                    t                               d           t                               d|           t          |          dk    sd S |d         | _        |d         S )NzSubprotocol header receivedz Supplied subprotocol headers: %rr   r   r   )rJ   rg   tracelenr,   )r2   rm   s     r7   select_subprotocolzWSHandler.select_subprotocol   sW    		/000		4lCCC<  A%%4"1oAr8   dict[str, Any] | Nonec                L    | j         d S d| j         i}| j        
| j        |d<   |S )Nr%   r&   )r.   r/   )r2   optionss     r7   get_compression_optionsz!WSHandler.get_compression_options   s6    "*4&(?@?&#'?GK r8   rh   c                   K   	 t          |          }| j                            || j        |           d{V  | j                            |          }t                      }t          |          | _        t          	                    d|           t                      | _        t          	                    d|           | j                            || | j        |          | _        t                              d           nC# t           $ r6}t                              d|           |                                  |d}~ww xY w| j        j                            d          }|                     |           d{V  dS )a   Perform the specific steps needed to open a connection to a Bokeh session

        Specifically, this method coordinates:

        * Getting a session for a session ID (creating a new one if needed)
        * Creating a protocol receiver and handler
        * Opening a new ServerConnection and sending it an ACK

        Args:
            session_id (str) :
                A session ID to for a session to connect to

                If no session exists with the given ID, a new session is made

        Returns:
            None

        NzReceiver created for %rzProtocolHandler created for %rzServerConnection createdz/Could not create new server session, reason: %sACK)r   r#   create_session_if_neededrequestget_sessionr   r   r'   rJ   rg   r   r(   rF   new_connectionr   rW   r   rK   rY   protocolcreatesend_message)r2   rh   rj   sessionr~   rk   msgs          r7   re   zWSHandler._async_open   sr     &	'..J*CCJPTP\^cddddddddd.:::FFGzzH$X..DMII/:::*,,DLII6AAA".==hdNfhoppDOHH/0000 	 	 	IIGKKKJJLLLG	
 o&--e44$$$$$$$$$ts   C<D 
E1D<<Efragmentstr | bytesc                4  K   	 |                      |           d{V }nL# t          $ r?}t                              d||d           |                     d           d}Y d}~nd}~ww xY w	 |r^t
          t
          j                            |           |                     |           d{V }|r| 	                    |           d{V  nJ# t          $ r=}t                              d||d           |                     d           Y d}~nd}~ww xY wdS )a   Process an individual wire protocol fragment.

        The websocket RFC specifies opcodes for distinguishing text frames
        from binary frames. Tornado passes us either a text or binary string
        depending on that opcode, we have to look at the type of the fragment
        to see what we got.

        Args:
            fragment (unicode or bytes) : wire fragment to process

        Nz/Unhandled exception receiving a message: %r: %rTexc_infoz server failed to parse a messagez.Handler or its work threw an exception: %r: %rz!server failed to handle a message)
_receiverf   rJ   rK   _internal_error_message_test_portreceivedappend_handle	_schedule)r2   r   messagerk   works        r7   
on_messagezWSHandler.on_message   sv     "	 MM(33333333GG 	 	 	 IIGH_cIddd  !CDDDGGGGGG			F /%1&/66w???!\\'22222222 /........... 	F 	F 	FIIF7]aIbbb  !DEEEEEEEE	F ts-     
A)5A$$A)-A C 
D3DDdatabytesc                   	 t          |                    d                    | _        d S # t          $ r! t                              d|d           Y d S t          $ r! t                              d|d           Y d S w xY w)Nzutf-8z#received invalid unicode in pong %rTr   z#received invalid integer in pong %r)intdecoder)   UnicodeDecodeErrorrJ   rq   
ValueError)r2   r   s     r7   on_pongzWSHandler.on_pong  s    	R"4;;w#7#788D! 	R 	R 	RII;TDIQQQQQQ 	R 	R 	RII;TDIQQQQQQ	Rs   '+ 'A?&A?>A?r   Message[Any]c                   K   	 t           t           j                            |           |                    |            d{V  n*# t          $ r t
                              d           Y nw xY wdS )z Send a Bokeh Server protocol message to the connected client.

        Args:
            message (Message) : a message to send

        Nz/Failed sending message as connection was closed)r   sentr   sendr
   rJ   warningr2   r   s     r7   r   zWSHandler.send_message  s      	K!-"'..w777,,t$$$$$$$$$$# 	K 	K 	KKKIJJJJJ	K ts   AA $A-,A-FTbytes | str | dict[str, Any]binarylockedc                $  K   |rb| j                                          d{V 5  t                                          ||           d{V  ddd           dS # 1 swxY w Y   dS t                                          ||           d{V  dS )zj Override parent write_message with a version that acquires a
        write lock before writing.

        N)r+   acquirer0   write_message)r2   r   r   r   r6   s       r7   r   zWSHandler.write_message"  s        	9..00000000 = =gg++GV<<<<<<<<<= = = = = = = = = = = = = = = = = = ''''88888888888s   )AA"Ac                    t                               d| j        | j                   | j        ?| j        j                                         | j                            | j                   dS dS )z2 Clean up when the connection is closed.

        z/WebSocket connection closed: code=%s, reason=%rN)	rJ   rW   
close_codeclose_reasonr   r   notify_connection_lostrF   client_lost)r2   s    r7   on_closezWSHandler.on_close.  sg     	BDOUYUfggg?&O#::<<<((99999 '&r8   Message[Any] | Nonec                   K   	 | j                             |           d {V }|S # t          t          t          f$ r-}|                     t          |                     Y d }~d S d }~ww xY wr:   )r'   consumer   r   r   _protocol_errorr?   )r2   r   r   rk   s       r7   r   zWSHandler._receive7  s      	 M11(;;;;;;;;GNm_= 	 	 	  Q(((44444	s   !& A*"A%%A*
Any | Nonec                   K   	 | j                             || j                   d {V }|S # t          t          t
          f$ r-}|                     t          |                     Y d }~d S d }~ww xY wr:   )r(   handler   r   r   r   r   r?   )r2   r   r   rk   s       r7   r   zWSHandler._handle@  s      	,,WdoFFFFFFFFDKm_= 	 	 	  Q(((44444	s   ', A0"A++A0r   r   c                   K   t          |t                    r:|                     t          t          t                   |                     d {V  n|                     d|           d S )Nzexpected a Message not )
isinstancer   r   r   r   r   )r2   r   s     r7   r   zWSHandler._scheduleI  sr      dG$$ 	E##Dt$<$<==========  !C4!C!CDDDtr8   c                h    t                               d|           |                     d|           d S )Nz3Bokeh Server internal error: %s, closing connectioni'  rJ   rK   rY   r   s     r7   r   zWSHandler._internal_errorQ  1    		GQQQ

5'"""""r8   c                h    t                               d|           |                     d|           d S )Nz3Bokeh Server protocol error: %s, closing connectioni'  r   r   s     r7   r   zWSHandler._protocol_errorU  r   r8   )r    r!   )r>   r?   r    r@   )rm   rn   r    ro   )r    rt   )rh   r?   r    r!   )r   r   r    r!   )r   r   r    r!   )r   r   r    r!   )FT)r   r   r   r@   r   r@   r    r!   )r   r   r    r   )r   r   r    r   )r   r   r    r!   )r   r?   r    r!   )__name__
__module____qualname____doc____annotations__r1   r=   rP   r	   authenticatedrl   rs   rw   re   r   r   r   r   r   r   r   r   r   r   __classcell__)r6   s   @r7   r   r   A   s          ('''3 3 3 3 3 3$     > 	&? &? &? &?P      * * * *X% % % %NR R R R   " 26
9 
9 
9 
9 
9 
9 
9: : : :         # # # ## # # # # # # #r8   r   c                  $    e Zd ZU ded<   ded<   dS )MessageTestPortzlist[Message[Any]]r   r   N)r   r   r   r   r;   r8   r7   r   r   `  s*               r8   r   zMessageTestPort | Noner   )3r   
__future__r   logging	getLoggerr   rJ   rZ   r]   r\   typingr   r   r   urllib.parser   tornador   r	   tornado.websocketr
   r   bokeh.settingsr   bokeh.util.tokenr   r   r   r~   r   protocol.exceptionsr   r   r   protocol.messager   protocol.receiverr   util.dataclassesr   protocol_handlerr   auth_request_handlerr   r   r   __all__r   r   r   r   r;   r8   r7   <module>r      s      # " " " " " g!!      + + + + + + + + + + ! ! ! ! ! !         D D D D D D D D $ # # # # # U U U U U U U U U U !           O O O O O O O O O O ' ' ' ' ' ' ) ) ) ) ) ) ) ) ) ) ) ) . . . . . . 4 4 4 4 4 4 .------V# V# V# V# V#"$4 V# V# V#~ ! ! ! ! ! ! ! ! .2  1 1 1 1 1 1r8   