
    5iZS                       U d Z ddlmZ ddlZddl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 dd	l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mZ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) ddl*m+Z+ ddl,m-Z- ddl.m/Z/ ddl0m1Z1 ddl2m3Z3  ee4      Z5de6d<   dZ7de6d<   	 	 	 	 d&dZ8d'dZ9d(dZ:d)dZ;d*dZ<	 	 	 	 	 	 d+dZ= G d  d!e      Z> G d" d#e      Z?d,d$Z@d-d%ZAy).z,WebSocket handling for the Starlette server.    )annotationsN)suppress)TYPE_CHECKINGAnyFinal)urlparse)config)get_cookie_with_chunksget_expose_tokens_config)
get_logger)BackMsg)serialize_forward_msg)ClientContextSessionClientSessionClientDisconnectedError)get_cookie_secretis_url_from_allowed_originsis_xsrf_enabled)starlette_app_utils)TOKENS_COOKIE_NAMEUSER_COOKIE_NAMEWEBSOCKET_MAX_SEND_QUEUE_SIZEXSRF_COOKIE_NAME)IterableMapping)Headers)	BaseRoute)	WebSocket)
ForwardMsg)Runtimer   _LOGGERz_stcore/stream_ROUTE_WEBSOCKET_STREAMc                   | j                  d      }|sy|j                  d      D cg c]  }|j                          }}|r
|d   r|d   nd}t        |      dk\  r
|d   r|d   nd}t        |      dk\  r
|d   r|d   nd}|||fS c c}w )	a  Parse the Sec-WebSocket-Protocol header.

    Returns a tuple of (selected_subprotocol, xsrf_token, existing_session_id).

    The subprotocol header is repurposed to pass tokens from client to server:
    - First entry: subprotocol to select (e.g., "streamlit")
    - Second entry: XSRF token for authentication validation
    - Third entry: existing session ID for reconnection

    Positional semantics are preserved: empty/whitespace entries are treated as
    None rather than being filtered out (which would shift positions).
    zsec-websocket-protocol)NNN,r   N         )getsplitstriplen)headersrawvalueentriesselected
xsrf_tokenexisting_sessions          |/home/obispo/Crisostomo_bridge/mision_env/lib/python3.12/site-packages/streamlit/web/server/starlette/starlette_websocket.py_parse_subprotocolsr4   @   s     ++.
/C +.))C.9u{{}9G9$wqzH"7|q0WQZTJ%(\Q%671:wqz4Z!111	 :s   Bc                    i }t        j                  d      }t        |t              s|S |j	                         D ]"  \  }}| j                  |      }|r|d   nd||<   $ |S )z'Extract user info from trusted headers.zserver.trustedUserHeadersr   N)r	   
get_option
isinstancedictitemsgetlist)r,   	user_infomappingheader_nameuser_keyvaluess         r3   _gather_user_infor@   [   sj    .0I ;<Ggt$!( <X-+1fQit	(<     c                X    | yt        |       }|j                  }||k(  ryt        |       S )a  Check if the WebSocket Origin header is allowed.

    This mirrors Tornado's WebSocketHandler.check_origin behavior, which allows
    same-origin connections by default and delegates to is_url_from_allowed_origins
    for cross-origin requests.

    Parameters
    ----------
    origin: str | None
        The origin of the WebSocket connection.

    host: str | None
        The host of the WebSocket connection.

    Returns
    -------
    bool
        True if:
        - The origin is None (browser didn't send Origin header, allowed per spec)
        - The origin matches the host (same-origin request)
        - The origin is in the allowed origins list (is_url_from_allowed_origins)
    T)r   netlocr   )originhostparsed_originorigin_hosts       r3   _is_origin_allowedrH   h   s=    4 ~ V$M&&K d 'v..rA   c                    t               }| }t        |t              r|j                  d      }t	        j
                  |t        |      }|i S t        ||      S )ar  Parse and validate a signed user cookie.

    Note: This only understands cookies signed with itsdangerous (Starlette).
    Cookies signed by Tornado's set_secure_cookie will fail to decode and
    return an empty dict, requiring users to re-authenticate after switching
    backends. This is expected behavior when switching between Tornado and Starlette backends.
    latin-1)r   r7   strencoder   decode_signed_valuer   _parse_decoded_user_cookie)cookie_valuerD   secretsigned_valuedecodeds        r3   _parse_user_cookie_signedrS      s^      FL,$ $**95!55 ,G 	%gv66rA   c                (   	 t        j                  | j                  d            }t        |      }|j                  r|j                  si S |j                   d|j                   }|j                  d      }||k7  rt
        j                  d       i S d|j                  dd      i}|j                  dd       |j                  dd       |j                  |       |S # t        t         j                  f$ r t
        j                  d       i cY S w xY w)	zParse an already-decoded user cookie and validate the origin.

    This is used when the cookie has already been decoded (e.g., from chunked cookie
    retrieval). Validates the origin against the request origin for security.
    zutf-8z"Error decoding auth cookie payloadz://rD   zgOrigin mismatch, the origin of websocket request is not the same origin of redirect_uri in secrets.tomlis_logged_inFN)jsonloadsdecodeUnicodeDecodeErrorJSONDecodeErrorr!   	exceptionr   schemerC   r(   errorpopupdate)decoded_cookierD   payloadrF   expected_origincookie_originr;   s          r3   rN   rN      s   **^227;<
 V$M}';';	&--.c-2F2F1GHOKK)M':	
 	!/^U1S TIKK$KK%W'  4 45 >?	s   $C 0DDc                @     t               d fd}t        ||      S )a  Get a signed cookie value, reconstructing from chunks if necessary.

    Large cookies may be split into multiple chunks (e.g., `_streamlit_user`,
    `_streamlit_user__1`, `_streamlit_user__2`) due to browser cookie size limits.
    This function handles both single and chunked cookies transparently.

    Parameters
    ----------
    cookies
        Dictionary of cookie names to their string values.
    cookie_name
        The base name of the cookie to retrieve.

    Returns
    -------
    bytes | None
        The decoded (unsigned) cookie value, or None if the cookie doesn't exist
        or has an invalid signature.

    Notes
    -----
    Uses itsdangerous signing which is NOT compatible with Tornado's format.
    Cookies signed by Tornado will fail to decode.
    c                |    j                  |       }|y |j                  d      }t        j                  | |      S )NrJ   )r(   rL   r   rM   )name	raw_valuerQ   cookiesrP   s      r3   get_single_cookiez9_get_signed_cookie_with_chunks.<locals>.get_single_cookie   s?    KK%	 ''	2"66vt\RRrA   )rf   rK   returnbytes | None)r   r
   )rh   cookie_nameri   rP   s   `  @r3   _get_signed_cookie_with_chunksrm      s#    6  FS ""3[AArA   c                  N    e Zd ZdZddZedd       Zed	d       Zed
d       Zy)StarletteClientContexta$  Starlette-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                               | _        t	        |j
                        | _        |j                  }|r|j                  | _	        y d | _	        y )N)
listr,   r9   _headersr8   rh   _cookiesclientrE   
_remote_ip)self	websocketrt   s      r3   __init__zStarletteClientContext.__init__   sM    /3I4E4E4K4K4M/N(,Y->->(?!!5;fkkrA   c                    | j                   S )z$All headers as (name, value) tuples.)rr   rv   s    r3   r,   zStarletteClientContext.headers        }}rA   c                    | j                   S )z#Cookies as a name-to-value mapping.)rs   rz   s    r3   rh   zStarletteClientContext.cookies  r{   rA   c                    | j                   S )zThe client's remote IP address.)ru   rz   s    r3   	remote_ipz StarletteClientContext.remote_ip  s     rA   Nrw   r   rj   None)rj   zIterable[tuple[str, str]])rj   zMapping[str, str])rj   
str | None)	__name__
__module____qualname____doc__rx   propertyr,   rh   r~    rA   r3   ro   ro      sI    F      rA   ro   c                  B    e Zd ZdZddZd	dZd
dZedd       Zd	dZ	y)StarletteSessionClienta  WebSocket client for Starlette that implements the SessionClient interface.

    This class bridges the synchronous `write_forward_msg` calls from the Streamlit
    runtime to the asynchronous WebSocket send operations. It uses an internal
    queue and a background sender task to avoid blocking the calling thread.

    Parameters
    ----------
    websocket
        The Starlette WebSocket connection to send messages through.
    c                    || _         t        |      | _        t        j                  t
              | _        t        j                  | j                         d      | _	        t        j                         | _        y )N)maxsizezstarlette-ws-send)rf   )
_websocketro   _client_contextasyncioQueuer   _send_queuecreate_task_sender_sender_taskEvent_closed)rv   rw   s     r3   rx   zStarletteSessionClient.__init__  s\    #5i@ 2912
 $//LLN!4
 }}rA   c                v  K   ddl m} 	 	 | j                  j                          d{   }| j                  j                  |       d{    F7 (7 # |$ r Y n#t        $ r t        j                  d       Y nw xY w| j                  j                          y# | j                  j                          w xY ww)a  Background task that drains the send queue and writes to the WebSocket.

        This task runs continuously, waiting for messages on the queue and sending
        them to the WebSocket. It decouples message generation (sync) from network
        I/O (async), allowing non-blocking sends from the runtime thread.

        The task terminates when the WebSocket disconnects or an error occurs,
        at which point it sets the closed flag to signal the client is no longer
        usable.
        r   WebSocketDisconnectNzError sending websocket payload)starlette.websocketsr   r   r(   r   
send_bytes	Exceptionr!   r[   r   set)rv   r   ra   s      r3   r   zStarletteSessionClient._sender(  s      	=		 $ 0 0 4 4 66oo00999 69" 	 	A?@	A LLDLLs\   B9A A"A AA A A<B A<9B ;A<<B ?B9B66B9c                
   | j                   j                         rt        t        |      }	 | j                  j                  |       y# t        j                  $ r&}| j                   j                          t        |d}~ww xY w)a0  Send a ForwardMsg to the browser via the WebSocket.

        This method is called synchronously from the Streamlit runtime. The message
        is serialized and queued for asynchronous sending by the background sender task.

        Parameters
        ----------
        msg
            The ForwardMsg protobuf to send to the client.

        Raises
        ------
        SessionClientDisconnectedError
            If the client is already closed or the send queue is full (client
            is overwhelmed and not consuming messages fast enough).
        N)	r   is_setr   r   r   
put_nowaitr   	QueueFullr   )rv   msgra   excs       r3   write_forward_msgz(StarletteSessionClient.write_forward_msg@  sk    " << 00',	:''0   	:LL0c9	:s   A	 	B!A==Bc                    | j                   S )z'Return the client's connection context.)r   rz   s    r3   client_contextz%StarletteSessionClient.client_context[  s     ###rA   c                   K   | j                   j                          | j                  j                          t	        t
        j                        5  | j                   d{    ddd       y7 # 1 sw Y   yxY ww)zClose the client and release resources.

        Sets the closed flag to prevent further message sends, cancels the
        background sender task, and waits for it to complete cleanup.
        N)r   r   r   cancelr   r   CancelledErrorrz   s    r3   aclosezStarletteSessionClient.aclose`  sd      	  "g,,- 	$####	$ 	$#	$ 	$s0   AA<A0 A.!A0%	A<.A00A95A<Nr   )rj   r   )r   r   rj   r   )rj   r   )
r   r   r   r   rx   r   r   r   r   r   r   rA   r3   r   r     s/    
'0:6 $ $	$rA   r   c                <     ddl m t               d fd}|S )a
  Create the WebSocket endpoint handler for client-server communication.

    This factory function creates a Starlette WebSocket handler that manages the
    bidirectional communication between the browser and the Streamlit runtime.
    The handler performs:
    - Origin validation (CORS/XSRF protection)
    - Subprotocol negotiation
    - Session management (connect/disconnect)
    - User authentication via cookies and trusted headers
    - BackMsg processing from the client
    - ForwardMsg sending to the client (via StarletteSessionClient)

    Parameters
    ----------
    runtime
        The Streamlit runtime instance that manages sessions and script execution.

    Returns
    -------
    Callable
        An async function that handles WebSocket connections.
    r   r   c                p  K   | j                   j                  d      }| j                   j                  d      }t        ||      s1t        j	                  d|       | j                  d       d {    y t        | j                         \  }}}| j                  |       d {    t        |       }d }	 i }t               r| j                  j                  t              }	| j                   j                  d      }
|
rt        j                  ||	      r	 t        | j                  t              }|rl|j!                  t#        ||
             t        | j                  t$              }|r5t'        j(                  |      }i }D ]  }| d}||v s||   ||<    ||d<   |j!                  t/        | j                                j1                  |||
      }	 	 | j3                          d {   }t9               }	 |j;                  |       |j?                  d      }|dk(  rYtA        jB                  d      stA        jB                  d      r| j                          d {    nt        j	                  d       |dk(  rQtA        jB                  d      stA        jB                  d      rjE                          n*t        j	                  d       jG                  ||       	 |jI                  |       |jK                          d {    y 7 7 q# t*        $ r t        j-                  d	       Y w xY w7 R# $ r Y bt4        $ r% | j                          d {  7   t7        d      w xY w# t*        $ r4}t        j-                  d       |j=                  ||       Y d }~d }~ww xY w7 X# $ r Y w xY w7 # |jK                          d {  7   w xY w# 	 |jI                  |       |jK                          d {  7   w # |jK                          d {  7   w xY wxY ww)NOriginHostz9Rejecting WebSocket connection from disallowed origin: %si  )code)subprotocol_tokentokensz'Error parsing auth cookie for websocket)rt   r;   existing_session_idzVWebSocket text frames are not supported; connection closed. Expected binary protobufs.z 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.)&r,   r(   rH   r!   warningcloser4   acceptr   r   rh   r   r   validate_xsrf_tokenrm   r   r_   rN   r   rV   rW   r   r[   r@   connect_sessionreceive_bytesRuntimeError	TypeErrorr   ParseFromString(handle_backmsg_deserialization_exception
WhichOneofr	   r6   stophandle_backmsgdisconnect_sessionr   )rw   rD   rE   r   r1   r   rt   
session_idr;   xsrf_cookieorigin_headerraw_auth_cookieraw_token_cookie
all_tokensfiltered_tokens
token_type	token_keydataback_msgr   msg_typer   expose_tokensruntimes                        r3   _websocket_endpointz5create_websocket_handler.<locals>._websocket_endpoint  s4     ""&&x0  $$V,!&$/OOKV //t/,,,7J8
4Z!4 ;777'	2!%
t	&(*I '//334DE ) 1 1 5 5h ? !%8%L%L&U*H%--/?+ +%,, :$3]!" 0N ) 1 13E0,  0-1ZZ8H-I
BD2? !*J3=,f0EI'0J'>FP,5G*
(C!* 7F	( 3 .y/@/@AB 00#$7 1 J !*!8!8!::D #9,,T2 $..v6
 ;;(()ABfFWFW(G (oo///OO; 77(()ABfFWFW(G  OO; &&z8<o |&)..z: mmo%% - 	8R % U))*STU ;* # 	
 $//+++#5 	 ! %%&HI!-HH& " 0* # 	 	 &fmmo%%&)..z: mmo%%fmmo%%sZ  A.P61L23P6%L&P68AN; A8L L 9N; M ,L>-M 1
N; <M8 AN;  N8!BN; 'O :P6OP6P6L;7N; :L;;N; >M M5N; M5#M&$M55N; 8	N5)N0*N; 0N55N; ;O O& OO& P6O#OO##P6&P3(P;P3PP3P0)P,*P00P33P6r   )r   r   r   )r   r   r   r   s   ` @@r3   create_websocket_handlerr   l  s    . 9,.MH&T rA   c                ^    ddl m} ddlm}  | ||xs dt              t        |             gS )ab  Create the WebSocket route for client-server communication.

    Creates a route at `/_stcore/stream` (with optional base URL prefix) that handles
    the bidirectional WebSocket connection between the browser and Streamlit runtime.

    Parameters
    ----------
    runtime
        The Streamlit runtime instance that manages sessions and script execution.
    base_url
        Optional base URL path prefix for the route (e.g., "myapp" results in
        "/myapp/_stcore/stream").

    Returns
    -------
    list[BaseRoute]
        A list containing the single WebSocketRoute for the stream endpoint.
    r   )WebSocketRoute)make_url_path )starlette.routingr   streamlit.url_utilr   r"   r   )r   base_urlr   r   s       r3   create_websocket_routesr     s5    & 10 	(.b*AB$W-	
 rA   )r,   r   rj   z)tuple[str | None, str | None, str | None])r,   r   rj   zdict[str, str | bool | None])rD   r   rE   r   rj   bool)rO   zstr | bytesrD   rK   rj   dict[str, Any])r`   bytesrD   rK   rj   r   )rh   zdict[str, str]rl   rK   rj   rk   )r   r    rj   r   )r   r    r   r   rj   zlist[BaseRoute])Br   
__future__r   r   rV   
contextlibr   typingr   r   r   urllib.parser   	streamlitr	   streamlit.auth_utilr
   r   streamlit.loggerr   streamlit.proto.BackMsg_pb2r   streamlit.runtime.runtime_utilr   !streamlit.runtime.session_managerr   r   r    streamlit.web.server.server_utilr   r   r   streamlit.web.server.starletter   6streamlit.web.server.starlette.starlette_server_configr   r   r   r   collections.abcr   r   starlette.datastructuresr   r   r   r   r   streamlit.proto.ForwardMsg_pb2r   streamlit.runtimer    r   r!   __annotations__r"   r4   r@   rH   rS   rN   rm   ro   r   r   r   r   rA   r3   <module>r      s    3 "    , , !  P ' / @ 
 
 ?  10+.9)H% % "2  122.26
&/R72<%B%B*-%B%BP] <[$] [$|ePrA   