Ë
    úmxiœ6  ã                  óR  — U d dl m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
Zd dlmZ d dl
mZ d dlmZ d dl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 d dl m!Z!m"Z"m#Z#m$Z$ erd dl%m&Z&m'Z'm(Z( d dl)m*Z* d dl+m,Z,  ee-«      Z.de/d<    G d„ de«      Z0 G d„ dee«      Z1y)é    )ÚannotationsN)ÚTYPE_CHECKINGÚAnyÚFinal)Úurlparse)Úutf8)ÚWebSocketHandler)Úconfig)Úget_cookie_with_chunksÚget_expose_tokens_config)Ú
get_logger)ÚBackMsg)ÚRuntimeÚSessionClientÚSessionClientDisconnectedError)Úserialize_forward_msg)ÚClientContext)ÚAUTH_COOKIE_NAMEÚTOKENS_COOKIE_NAMEÚis_url_from_allowed_originsÚis_xsrf_enabled)Ú	AwaitableÚIterableÚMapping)ÚHTTPServerRequest)Ú
ForwardMsgr   Ú_LOGGERc                  óN   — e Zd ZdZdd„Zedd„«       Zed	d„«       Zed
d„«       Zy)ÚTornadoClientContexta"  Tornado-specific implementation of ClientContext.

    Captures headers, cookies, and client info from the initial WebSocket handshake.
    Values are cached at construction time since they represent the initial request
    context and should not change during the connection lifetime.
    c                óü   — t        |j                  j                  «       «      | _        |j                  j                  «       D ��ci c]  \  }}||j                  “Œ c}}| _        |j                  | _	        y c c}}w ©N)
ÚlistÚheadersÚget_allÚ_headersÚcookiesÚitemsÚvalueÚ_cookiesÚ	remote_ipÚ
_remote_ip)ÚselfÚtornado_requestÚkÚms       úe/home/htdocs/ttos/venv/lib/python3.12/site-packages/streamlit/web/server/browser_websocket_handler.pyÚ__init__zTornadoClientContext.__init__:   sc   € Ü/3°O×4KÑ4K×4SÑ4SÓ4UÓ/VˆŒà#2×#:Ñ#:×#@Ñ#@Ó#B÷)
Ù˜1˜aˆAˆq�w‰w‰Jó)
ˆŒð '6×&?Ñ&?ˆ�ùó)
s   ÁA8c                ó   — | j                   S )z$All headers as (name, value) tuples.)r%   ©r,   s    r0   r#   zTornadoClientContext.headersA   ó   € ð �}‰}Ðó    c                ó   — | j                   S )z#Cookies as a name-to-value mapping.)r)   r3   s    r0   r&   zTornadoClientContext.cookiesF   r4   r5   c                ó   — | j                   S )zThe client's remote IP address.)r+   r3   s    r0   r*   zTornadoClientContext.remote_ipK   s   € ð �‰Ðr5   N)r-   r   ÚreturnÚNone)r8   zIterable[tuple[str, str]])r8   zMapping[str, str])r8   ú
str | None)	Ú__name__Ú
__module__Ú__qualname__Ú__doc__r1   Úpropertyr#   r&   r*   © r5   r0   r   r   2   sI   „ ñó@ð òó ðð òó ðð òó ñr5   r   c                  ó¤   ‡ — e Zd ZdZdd„Z	 	 	 d	 	 	 	 	 	 	 	 	 dˆ fd„Zdˆ fd„Zdd„Zdd„Zdd„Z	e
dd„«       Zdd	„Zdd
„Zdd„Zdd„Zdd„Zˆ xZS )ÚBrowserWebSocketHandlerz0Handles a WebSocket connection from the browser.c                ój   — || _         d | _        t        «       r| j                  }t	        «       | _        y r!   )Ú_runtimeÚ_session_idr   Ú
xsrf_tokenr   Úexpose_tokens)r,   ÚruntimeÚ_s      r0   Ú
initializez"BrowserWebSocketHandler.initializeT   s/   € ØˆŒØ'+ˆÔô ÔØ—‘ˆAô 6Ó7ˆÕr5   c                ó8   •‡ ‡‡‡— dˆˆˆˆ ˆfd„}t        ||«      S )a)  Get a signed cookie from the request, reconstructing from chunks if needed.

        Added for compatibility with Tornado < 6.3.0. Also handles chunked cookies
        automatically.

        See release notes: https://www.tornadoweb.org/en/stable/releases/v6.3.0.html#deprecation-notices
        c                ó|   •— 	 t         t        ‰�  | ‰‰‰«      S # t        $ r t         t        ‰�  | ‰‰‰«      cY S w xY wr!   )ÚsuperrB   Úget_signed_cookieÚAttributeErrorÚget_secure_cookie)Úcookie_nameÚ	__class__Úmax_age_daysÚmin_versionr,   r(   s    €€€€€r0   Úget_single_cookiezDBrowserWebSocketHandler.get_signed_cookie.<locals>.get_single_cookieq   sU   ø€ ðÜÔ4°dÑMØ ¨°kóð øô "ò ÜÔ4°dÑMØ ¨°kóò ðús   ƒ ™;º;)rQ   Ústrr8   úbytes | None)r   )r,   Únamer(   rS   rT   rU   rR   s   ` ``` €r0   rN   z)BrowserWebSocketHandler.get_signed_cookieb   s   ü€ ÷	ñ 	ô &Ð&7¸Ó>Ð>r5   c                ó<   •— t         ‰| �  |«      xs t        |«      S )zSet up CORS.)rM   Úcheck_originr   )r,   ÚoriginrR   s     €r0   rZ   z$BrowserWebSocketHandler.check_origin}   s   ø€ ä‰wÑ# FÓ+ÒRÔ/JÈ6Ó/RÐRr5   c                ó¶   — | j                  |«      \  }}}| j                  «       \  }}}t        |«      }t        |«      }|r|syt        j                  ||«      S )z�Inspired by tornado.web.RequestHandler.check_xsrf_cookie method,
        to check the XSRF token passed in Websocket connection header.
        F)Ú_decode_xsrf_tokenÚ_get_raw_xsrf_tokenr   ÚhmacÚcompare_digest)r,   Úsupplied_tokenrI   ÚtokenÚexpected_tokenÚdecoded_tokenÚdecoded_expected_tokens          r0   Ú_validate_xsrf_tokenz,BrowserWebSocketHandler._validate_xsrf_token�   s`   € ð ×-Ñ-¨nÓ=‰ˆˆ5�!Ø#×7Ñ7Ó9Ñˆˆ>˜1ä˜U›ˆÜ!% nÓ!5ÐáÑ$:ØÜ×"Ñ" =Ð2HÓIÐIr5   c                ód  — t        j                  |«      }i }|j                  dd«      }t        | j                  j
                  d   «      }|j                  dz   |j                  z   }||k(  r.|j                  dd«      |d<   |d= |d= |j                  |«       |S t        j                  d«       |S )z‰Process the user cookie and extract the user info after
        validating the origin. Origin is validated for security reasons.
        r[   NÚOriginz://Úis_logged_inFzgOrigin mismatch, the origin of websocket request is not the same origin of redirect_uri in secrets.toml)ÚjsonÚloadsÚgetr   Úrequestr#   ÚschemeÚnetlocÚupdater   Úerror)r,   Úraw_cookie_valueÚcookie_valueÚ	user_infoÚcookie_value_originÚparsed_origin_from_headerÚexpected_origin_values          r0   Ú_parse_user_cookiez*BrowserWebSocketHandler._parse_user_cookie�   sÇ   € ô —z‘zÐ"2Ó3ˆØˆ	à*×.Ñ.¨x¸Ó>ÐÜ$,¨T¯\©\×-AÑ-AÀ(Ñ-KÓ$LÐ!à%×,Ñ,¨uÑ4Ð7P×7WÑ7WÑWð 	ð Ð"7Ò7Ø(4×(8Ñ(8¸ÈÓ(OˆI�nÑ%Ø˜XÐ&Ø˜^Ð,Ø×Ñ˜\Ô*ð Ðô �M‰Mð>ôð
 Ðr5   c                ó–   — 	 | j                  t        |«      d¬«       y# t        j                  j                  $ r}t
        |‚d}~ww xY w)z!Send a ForwardMsg to the browser.T)ÚbinaryN)Úwrite_messager   ÚtornadoÚ	websocketÚWebSocketClosedErrorr   )r,   ÚmsgÚes      r0   Úwrite_forward_msgz)BrowserWebSocketHandler.write_forward_msg©   sD   € ð	8Ø×ÑÔ4°SÓ9À$ÐÕGøÜ× Ñ ×5Ñ5ò 	8Ü0°aÐ7ûð	8ús   ‚ ŸA¼AÁAc                ó\   — t        | dd«      }|€t        | j                  «      }|| _        |S )z­Return the client's connection context.

        The context is cached on first access to avoid repeatedly
        constructing a new TornadoClientContext instance.
        Ú_client_contextN)Úgetattrr   rm   rƒ   )r,   Úcontexts     r0   Úclient_contextz&BrowserWebSocketHandler.client_context°   s3   € ô ˜$Ð 1°4Ó8ˆØˆ?Ü*¨4¯<©<Ó8ˆGØ#*ˆDÔ Øˆr5   c                ó   — |r|d   S y)a±  Return the first subprotocol in the given list.

        This method is used by Tornado to select a protocol when the
        Sec-WebSocket-Protocol header is set in an HTTP Upgrade request.

        NOTE: We repurpose the Sec-WebSocket-Protocol header here in a slightly
        unfortunate (but necessary) way. The browser WebSocket API doesn't allow us to
        set arbitrary HTTP headers, and this header is the only one where we have the
        ability to set it to arbitrary values, so we use it to pass tokens (in this
        case, the previous session ID to allow us to reconnect to it) from client to
        server as the *third* value in the list.

        The reason why the auth token is set as the third value is that:
          - when Sec-WebSocket-Protocol is set, many clients expect the server to
            respond with a selected subprotocol to use. We don't want that reply to be
            the session token, so we by convention have the client always set the first
            protocol to "streamlit" and select that.
          - the second protocol in the list is reserved in some deployment environments
            for an auth token that we currently don't use
        r   Nr@   )r,   Úsubprotocolss     r0   Úselect_subprotocolz*BrowserWebSocketHandler.select_subprotocol½   s   € ñ* Ø ‘?Ð"àr5   c                óf  — i }d }	 | j                   j                  d   j                  d«      D �cg c]  }|j                  «       ‘Œ }}| j	                  t
        «      }t        «       rŽ|rŒ|d   }| j                  |«      rv|j                  | j                  |«      «       | j	                  t        «      }	|	r?t        j                  |	«      }
i }| j                  D ]  }|› d�}||
v sŒ|
|   ||<   Œ ||d<   t        |«      dk\  r|d   }t#        j$                  d«      }|j'                  «       D ]:  \  }}| j                   j                  j)                  |«      }|r	|d	   ||<   Œ6d ||<   Œ< | j*                  j-                  | ||¬
«      | _        y c c}w # t        t        j                   f$ r Y Œ¦w xY w)NzSec-Websocket-Protocolú,é   Ú_tokenÚtokensé   é   zserver.trustedUserHeadersr   )Úclientrt   Úexisting_session_id)rm   r#   ÚsplitÚstriprN   r   r   rf   rp   rx   r   rj   rk   rG   ÚlenÚKeyErrorÚJSONDecodeErrorr
   Ú
get_optionr'   Úget_listrD   Úconnect_sessionrE   )r,   ÚargsÚkwargsrt   r’   ÚpÚws_protocolsrr   Úcsrf_protocol_valueÚraw_token_cookie_valueÚ
all_tokensÚfiltered_tokensÚ
token_typeÚ	token_keyÚmapping_configÚheader_nameÚuser_info_keyÚheader_valuess                     r0   ÚopenzBrowserWebSocketHandler.open×   së  € ØCEˆ	à"Ðð"	ð Ÿ™×-Ñ-Ð.FÑG×MÑMÈcÓRöàð —‘•	ðˆLð ð
  $×5Ñ5Ô6FÓGÐÜÔ Ñ%5Ø&2°1¡oÐ#à×,Ñ,Ð-@ÔAØ×$Ñ$ T×%<Ñ%<Ð=MÓ%NÔOð .2×-CÑ-CÔDVÓ-WÐ*Ù-Ü%)§Z¡ZÐ0FÓ%G˜
ð ;=˜Ø*.×*<Ñ*<ò T˜JØ+5¨,°fÐ(=˜IØ(¨JÒ6Ø>HÈÑ>S °
Ò ;ðTð
 />˜	 (Ñ+ä�<Ó  AÒ%ð '3°1¡oÐ#ô  ×*Ñ*Ð+FÓGˆØ*8×*>Ñ*>Ó*@ò 
	0Ñ&ˆK˜Ø ŸL™L×0Ñ0×9Ñ9¸+ÓFˆMÙð
 ,9¸Ñ+;�	˜-Ò(ð ,0�	˜-Ò(ð
	0ð  Ÿ=™=×8Ñ8ØØØ 3ð 9ó 
ˆÔð
 ùòoøô< œ$×.Ñ.Ð/ò 	ñ ð	ús)   †*F °FÁBF Ã'"F ÆF ÆF0Æ/F0c                óv   — | j                   sy | j                  j                  | j                   «       d | _         y r!   )rE   rD   Údisconnect_sessionr3   s    r0   Úon_closez BrowserWebSocketHandler.on_close  s.   € Ø×ÒØØ�‰×(Ñ(¨×)9Ñ)9Ô:ØˆÕr5   c                ó2   — t        j                  d«      ri S y)z¼Enable WebSocket compression.

        Returning an empty dict enables websocket compression. Returning
        None disables it.

        (See the docstring in the parent class.)
        z!server.enableWebsocketCompressionN)r
   r˜   r3   s    r0   Úget_compression_optionsz/BrowserWebSocketHandler.get_compression_options  s   € ô ×ÑÐ@ÔAØˆIØr5   c                óN  — | j                   sy 	 t        |t        «      rt        d«      ‚t	        «       }|j                  |«       t        j                  d|«       |j                  d«      dk(  rQt        j                  d«      st        j                  d«      r| j                  «        y t        j!                  d«       y |j                  d«      d	k(  r[t        j                  d«      st        j                  d«      r| j                  j#                  «        y t        j!                  d
«       y | j                  j%                  | j                   |«       y # t        $ rE}t        j                  d«       | j                  j                  | j                   |«       Y d }~y d }~ww xY w)NzIWebSocket received an unexpected `str` message. (We expect `bytes` only.)z'Received the following back message:
%sz Error deserializing back messageÚtypeÚdebug_disconnect_websocketzglobal.developmentModezglobal.e2eTestzQClient tried to disconnect websocket when not in development mode or e2e testing.Údebug_shutdown_runtimezNClient tried to shut down runtime when not in development mode or e2e testing.)rE   Ú
isinstancerV   Ú	TypeErrorr   ÚParseFromStringr   ÚdebugÚ	ExceptionÚ	exceptionrD   Ú(handle_backmsg_deserialization_exceptionÚ
WhichOneofr
   r˜   ÚcloseÚwarningÚstopÚhandle_backmsg)r,   Úmessager   Úexs       r0   Ú
on_messagez"BrowserWebSocketHandler.on_message'  sn  € Ø×ÒØð	Ü˜'¤3Ô'ô  ð0óð ô
 “)ˆCØ×Ñ Ô(Ü�M‰MÐDÀcÔJð �>‰>˜&Ó!Ð%AÒAÜ× Ñ Ð!9Ô:¼f×>OÑ>OØ ô?ð —
‘
”ð" 	ô —‘Øgôð 	ð �^‰^˜FÓ#Ð'?Ò?Ü× Ñ Ð!9Ô:¼f×>OÑ>OØ ô?ð —‘×"Ñ"Ô$ð 	ô —‘Ødôð 	ð �M‰M×(Ñ(¨×)9Ñ)9¸3Ô?Øøô; ò 	Ü×ÑÐ@ÔAØ�M‰M×BÑBÀ4×CSÑCSÐUWÔXÜûð	ús   �AE Å	F$Å;FÆF$)rH   r   r8   r9   )Né   N)
rX   rV   r(   r:   rS   ÚfloatrT   z
int | Noner8   rW   )r[   rV   r8   Úbool)ra   rV   r8   rÄ   )rr   Úbytesr8   zdict[str, Any])r   r   r8   r9   )r8   r   )rˆ   z	list[str]r8   r:   )r›   r   rœ   r   r8   zAwaitable[None] | None)r8   r9   )r8   zdict[Any, Any] | None)r¿   zstr | bytesr8   r9   )r;   r<   r=   r>   rJ   rN   rZ   rf   rx   r�   r?   r†   r‰   r©   r¬   r®   rÁ   Ú__classcell__)rR   s   @r0   rB   rB   Q   s�   ø„ Ù:ó8ð" !Ø Ø"&ð?àð?ð ð?ð ð	?ð
  ð?ð 
õ?õ6SóJóó48ð ò
ó ð
óó4<ó| ó
÷.r5   rB   )2Ú
__future__r   r_   rj   Útypingr   r   r   Úurllib.parser   Útornado.websocketr|   Útornado.escaper   r	   Ú	streamlitr
   Ústreamlit.auth_utilr   r   Ústreamlit.loggerr   Ústreamlit.proto.BackMsg_pb2r   Ústreamlit.runtimer   r   r   Ústreamlit.runtime.runtime_utilr   Ú!streamlit.runtime.session_managerr   Ú streamlit.web.server.server_utilr   r   r   r   Úcollections.abcr   r   r   Útornado.httputilr   Ústreamlit.proto.ForwardMsg_pb2r   r;   r   Ú__annotations__r   rB   r@   r5   r0   ú<module>rØ      s�   ðö #ã Û ß ,Ñ ,Ý !ã Ý Ý .å ß PÝ 'Ý /ß TÑ TÝ @Ý ;÷ó ñ ß<Ñ<å2å9á˜HÓ%€ˆÓ %ô˜=ô ô>DÐ.°õ Dr5   