o
    4ήc4                     @   sR  d dl Z d dlZd dlZd dlZd dlmZmZmZmZm	Z	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 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!m"Z"m#Z#m$Z$ d dl%m&Z& ej'dk r|d dl(m)Z) nd dlm)Z) erd dl*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2 G dd dZ3G dd deZ4dS )    N)TYPE_CHECKINGAnyListOptionalSequenceTupleUnioncast)unquote)Headers)ConnectionClosed)ServerPerMessageDeflateFactory)HTTPResponse)WebSocketServerProtocol)Subprotocol)Config)TRACE_LOG_LEVEL)get_local_addrget_path_with_query_stringget_remote_addris_ssl)ServerState)      )Literal)ASGISendEventWebSocketAcceptEventWebSocketCloseEventWebSocketConnectEventWebSocketDisconnectEventWebSocketReceiveEventWebSocketScopeWebSocketSendEventc                   @   sB   e Zd ZdZdeddfddZdeddfddZdefd	d
ZdS )ServerFwsreturnNc                 C      d S N selfr$   r(   r(   S/tmp/pip-target-vg8gfxp4/lib/python/uvicorn/protocols/websockets/websockets_impl.pyregister/      zServer.registerc                 C   r&   r'   r(   r)   r(   r(   r+   
unregister2   r-   zServer.unregisterc                 C   s   | j  S r'   )closingr*   r(   r(   r+   
is_serving5   s   zServer.is_serving)	__name__
__module____qualname__r/   r   r,   r.   boolr1   r(   r(   r(   r+   r#   ,   s
    r#   c                       s  e Zd ZU eeeef  ed< 	d)dedede	e
j f fddZde
jd	df fd
dZde	e d	df fddZd*ddZde
jd	dfddZdeded	e	e fddZdede	ee  d	e	e fddZd*ddZdeded	efddZd*d d!Zd+d$d%Zd	e d& fd'd(Z!  Z"S ),WebSocketProtocolextra_headersNconfigserver_state_loopc              
      s  |j s|  || _|j| _|pt | _|j| _|j	| _	|j
| _
d | _d | _d | _d | _d | _t | _t | _t | _d | _d| _d| _d | _d | _t | _g }| jjr^|t  t j| j | j| jj!| jj"| jj#|t$%dd d | _&dd |j'D | _(d S )NFzuvicorn.error)
ws_handler	ws_servermax_sizeping_intervalping_timeout
extensionsloggerc                 S   $   g | ]\}}| d | d fqS )latin-1decode.0namevaluer(   r(   r+   
<listcomp>o       z.WebSocketProtocol.__init__.<locals>.<listcomp>))loadedloadr8   
loaded_appappasyncioget_event_looploop	root_pathconnectionstasks	transportserverclientschemescopeEventhandshake_started_eventhandshake_completed_eventclosed_eventinitial_responseconnect_sent lost_connection_before_handshakeaccepted_subprotocoltransfer_data_taskr#   r<   ws_per_message_deflateappendr   super__init__r;   ws_max_sizews_ping_intervalws_ping_timeoutlogging	getLoggerserver_headerdefault_headersr7   )r*   r8   r9   r:   r@   	__class__r(   r+   rg   <   sL   


	zWebSocketProtocol.__init__rV   r%   c                    sx   | j |  || _t|| _t|| _t|rdnd| _| j	
tr4| jr*d| j nd}| j	td| t | d S )Nwssr$   %s:%d -  z%sWebSocket connection made)rT   addrV   r   rW   r   rX   r   rY   rA   isEnabledForr   logrf   connection_made)r*   rV   prefixro   r(   r+   rw   t   s   

z!WebSocketProtocol.connection_madeexcc                    sz   | j |  | jtr| jrd| j nd}| jtd| | j  | _	| j
  t | |d u r;| j  d S d S )Nrr   rs   z%sWebSocket connection lost)rT   removerA   ru   r   rX   rv   r]   is_setra   setrf   connection_lostrV   close)r*   ry   rx   ro   r(   r+   r}      s   

z!WebSocketProtocol.connection_lostc                 C   s   d| j _| j  d S )NT)r<   r/   rV   r~   r0   r(   r(   r+   shutdown   s   zWebSocketProtocol.shutdowntaskc                 C   s   | j | d S r'   )rU   discard)r*   r   r(   r(   r+   on_task_complete   s   z"WebSocketProtocol.on_task_completepathheadersc           
         s   | d\}}}tjj| g }|dD ]}|dd |dD  qdd | D }d| j	j
dd	d
| j| j| j| jt||d|d||d| _| j|  }	|	| j | j|	 | j I dH  | jS )a(  
        This hook is called to determine if the websocket should return
        an HTTP response and close.

        Our behavior here is to start the ASGI application, and then wait
        for either `accept` or `close` in order to determine if we should
        close the connection.
        ?zSec-WebSocket-Protocolc                 S   s   g | ]}|  qS r(   )strip)rG   tokenr(   r(   r+   rJ      s    z5WebSocketProtocol.process_request.<locals>.<listcomp>,c                 S   rB   )ascii)encoderF   r(   r(   r+   rJ      rK   	websocketz2.3)versionspec_versionz1.1r   )typeasgihttp_versionrY   rW   rX   rS   r   raw_pathquery_stringr   subprotocolsN)	partition
websocketslegacy	handshakecheck_requestget_allextendsplit	raw_itemsr8   asgi_versionrY   rW   rX   rS   r
   r   rZ   rR   create_taskrun_asgiadd_done_callbackr   rU   rt   r\   waitr_   )
r*   r   r   path_portion_r   r   headerasgi_headersr   r(   r(   r+   process_request   s6   z!WebSocketProtocol.process_requestavailable_subprotocolsc                 C   s   | j S )z
        We override the standard 'process_subprotocol' behavior here so that
        we return whatever subprotocol is sent in the 'accept' message.
        )rb   )r*   r   r   r(   r(   r+   process_subprotocol   s   z%WebSocketProtocol.process_subprotocolc                 C   sH   d}ddt t|d d dd|g}| jd| | j  d S )Ns   Internal Server ErrorsM   HTTP/1.1 500 Internal Server Error
content-type: text/plain; charset=utf-8
s   content-length: r   s   
s   connection: close
    )strlenr   rV   writejoinr\   r|   )r*   msgcontentr(   r(   r+   send_500_response   s   z#WebSocketProtocol.send_500_responseprotocolc                    s    | j   | j I dH  dS )z
        This is the main handler function for the 'websockets' implementation
        to call into. We just wait for close then return, and instead allow
        'send' and 'receive' events to drive the flow.
        N)r]   r|   r^   r   )r*   r   r   r(   r(   r+   r;      s   
zWebSocketProtocol.ws_handlerc              
      s
  z|  | j| j| jI dH }W n9 tyI } z-| j  d}| jj||d | j	
 s1|   n| j I dH  | j  W Y d}~dS d}~ww | j  | j	
 sgd}| j| |   | j  dS |durd}| j|| | j I dH  | j  dS dS )zr
        Wrapper around the ASGI callable, handling exceptions and unexpected
        termination states.
        NzException in ASGI application
)exc_infoz1ASGI callable returned without sending handshake.z4ASGI callable should return None, but returned '%s'.)rO   rZ   asgi_receive	asgi_sendBaseExceptionr^   r|   rA   errorr\   r{   r   r]   r   rV   r~   )r*   resultry   r   r(   r(   r+   r      s2   





zWebSocketProtocol.run_asgimessager   c           	         s  |d }| j  sz|dkrGtd|}| jd| jd t| j d | _ttt	 |
d| _d|v r@| jdd	 |d D  | j   d S |d
krrtd|}| jd| jd t| j tjjg df| _| j   | j  d S d}t|| | j s| j I d H  |dkrtd|}|
d}|
d}|d u r|n|}| |I d H  d S |d
krtd|}|
dd}|
ddpd}| ||I d H  | j  d S d}t|| d}t|| )Nr   zwebsocket.acceptr   z%s - "WebSocket %s" [accepted]rX   subprotocolr   c                 s   s(    | ]\}}| d | d fV  qdS )rC   NrD   rF   r(   r(   r+   	<genexpr>  s
    
z.WebSocketProtocol.asgi_send.<locals>.<genexpr>zwebsocket.closer   z%s - "WebSocket %s" 403r   zLExpected ASGI message 'websocket.accept' or 'websocket.close', but got '%s'.zwebsocket.sendr"   bytestextcodei  reasonrs   zJExpected ASGI message 'websocket.send' or 'websocket.close', but got '%s'.z>Unexpected ASGI message '%s', after sending 'websocket.close'.)r\   r{   r	   rA   inforZ   r   r_   r   r   getrb   r7   r   r|   http
HTTPStatus	FORBIDDENr^   RuntimeErrorr]   r   sendr~   )	r*   r   message_typer   
bytes_data	text_datadatar   r   r(   r(   r+   r     sf   








zWebSocketProtocol.asgi_send)r   r   r    c              
      s   | j sd| _ ddiS | j I d H  | jrdddS | j r%dddS z	|  I d H }W n, tyZ } z | j  | j	j
rJdddW  Y d }~S d|jdW  Y d }~S d }~ww dd	i}t|trj||d
< |S ||d< |S )NTr   zwebsocket.connectzwebsocket.disconnecti  )r   r   i  i  zwebsocket.receiver   r   )r`   r]   r   ra   r^   r{   recvr   r|   r<   r/   r   
isinstancer   )r*   r   ry   r   r(   r(   r+   r   K  s2   




zWebSocketProtocol.asgi_receiver'   )r%   N)r   r   r%   N)#r2   r3   r4   r   r   r   __annotations__r   r   r   rP   AbstractEventLooprg   	Transportrw   	Exceptionr}   r   Taskr   r   r   r   r   r   r   r   r   r   r;   r   r   r   r   __classcell__r(   r(   ro   r+   r6   9   s^   
 8

,


	


Fr6   )5rP   r   rk   systypingr   r   r   r   r   r   r   r	   urllib.parser
   r   websockets.datastructuresr   websockets.exceptionsr   (websockets.extensions.permessage_deflater   websockets.legacy.serverr   websockets.serverr   websockets.typingr   uvicorn.configr   uvicorn.loggingr   uvicorn.protocols.utilsr   r   r   r   uvicorn.serverr   version_infotyping_extensionsr   asgiref.typingr   r   r   r   r   r    r!   r"   r#   r6   r(   r(   r(   r+   <module>   s0    (
(