U
    R¹Öh‚<  ã                   @  sF  d dl m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
 d dlm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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!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z( d dl)m*Z* d dl+m,Z, d dl-m.Z.m/Z/m0Z0m1Z1m2Z2 d dl3m4Z4 G dd„ dƒZ5G dd„ deƒZ6dS )é    )ÚannotationsN)ÚAnyÚLiteralÚOptionalÚSequenceÚcast)Úunquote)ÚHeaders)ÚConnectionClosed)ÚServerExtensionFactory)ÚServerPerMessageDeflateFactory)ÚHTTPResponse)ÚWebSocketServerProtocol)ÚSubprotocol)ÚASGI3ApplicationÚASGISendEventÚWebSocketAcceptEventÚWebSocketCloseEventÚWebSocketConnectEventÚWebSocketDisconnectEventÚWebSocketReceiveEventÚWebSocketResponseBodyEventÚWebSocketResponseStartEventÚWebSocketScopeÚWebSocketSendEvent)ÚConfig)ÚTRACE_LOG_LEVEL)ÚClientDisconnectedÚget_local_addrÚget_path_with_query_stringÚget_remote_addrÚis_ssl)ÚServerStatec                   @  s>   e Zd ZdZdddœdd„Zdddœdd„Zd	d
œdd„ZdS )ÚServerFr   ÚNone)ÚwsÚreturnc                 C  s   d S ©N© ©Úselfr%   r(   r(   úR./venv/lib/python3.8/site-packages/uvicorn/protocols/websockets/websockets_impl.pyÚregister/   s    zServer.registerc                 C  s   d S r'   r(   r)   r(   r(   r+   Ú
unregister2   s    zServer.unregisterÚbool©r&   c                 C  s   | j  S r'   )Úclosing©r*   r(   r(   r+   Ú
is_serving5   s    zServer.is_servingN)Ú__name__Ú
__module__Ú__qualname__r0   r,   r-   r2   r(   r(   r(   r+   r#   ,   s   r#   c                      sò   e Zd ZU ded< ded< d8dddd	d
œ‡ fdd„Zdddœ‡ fdd„Zdddœ‡ fdd„Zddœdd„Zdddœdd„Zdddd œd!d"„Z	dd#d$d%œd&d'„Z
ddœd(d)„Zd*dd+d,œd-d.„Zddœd/d0„Zd1dd2œd3d4„Zd5dœd6d7„Z‡  ZS )9ÚWebSocketProtocolzlist[tuple[str, str]]Úextra_headersz+logging.Logger | logging.LoggerAdapter[Any]ÚloggerNr   r"   zdict[str, Any]z asyncio.AbstractEventLoop | None)ÚconfigÚserver_stateÚ	app_stateÚ_loopc                   s  |j s| ¡  || _tt|jƒ| _|p,t ¡ | _	|j
| _
|| _|j| _|j| _d | _d | _d | _d | _|  t ¡ | _t ¡ | _t ¡ | _d | _d| _d| _d | _tƒ | _g }| jjrÀ| tƒ ¡ tƒ j | j!| 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_serverZmax_sizeZ	max_queueZping_intervalZping_timeoutÚ
extensionsr8   c                 S  s$   g | ]\}}|  d ¡|  d ¡f‘qS ©úlatin-1©Údecode©Ú.0ÚnameÚvaluer(   r(   r+   Ú
<listcomp>r   s    z.WebSocketProtocol.__init__.<locals>.<listcomp>)+ZloadedÚloadr9   r   r   Z
loaded_appÚappÚasyncioZget_event_loopÚloopÚ	root_pathr;   ÚconnectionsÚtasksÚ	transportÚserverÚclientÚschemeÚEventÚhandshake_started_eventÚhandshake_completed_eventÚclosed_eventÚinitial_responseÚconnect_sentÚ lost_connection_before_handshakeÚaccepted_subprotocolr#   r>   Zws_per_message_deflateÚappendr   ÚsuperÚ__init__r=   Zws_max_sizeZws_max_queueZws_ping_intervalZws_ping_timeoutÚloggingZ	getLoggerZserver_headerZdefault_headersr7   )r*   r9   r:   r;   r<   r?   ©Ú	__class__r(   r+   r^   =   sN    


ø
ÿzWebSocketProtocol.__init__zasyncio.Transportr$   )rP   r&   c                   sx   | j  | ¡ || _t|ƒ| _t|ƒ| _t|ƒr2dnd| _| j	 
t¡rh| jrTd| j nd}| j	 td|¡ tƒ  |¡ d S )NZwssr%   ú%s:%d - Ú z%sWebSocket connection made)rN   ÚaddrP   r   rQ   r    rR   r!   rS   r8   ÚisEnabledForr   Úlogr]   Úconnection_made)r*   rP   Úprefixr`   r(   r+   rg   v   s    

z!WebSocketProtocol.connection_madezException | None)Úexcr&   c                   sv   | j  | ¡ | j t¡r<| jr(d| j nd}| j td|¡ | j ¡  | _	| j 
¡  tƒ  |¡ |d krr| j ¡  d S )Nrb   rc   z%sWebSocket connection lost)rN   Úremover8   re   r   rR   rf   rV   Úis_setrZ   Úsetr]   Úconnection_lostrP   Úclose)r*   ri   rh   r`   r(   r+   rm   …   s    
z!WebSocketProtocol.connection_lostr/   c                 C  s4   d| j _| j ¡ r|  d¡ n|  ¡  | j ¡  d S )NTéô  )r>   r0   rV   rk   Zfail_connectionÚsend_500_responserP   rn   r1   r(   r(   r+   Úshutdown’   s
    
zWebSocketProtocol.shutdownzasyncio.Task[None])Útaskr&   c                 C  s   | j  |¡ d S r'   )rO   Údiscard)r*   rr   r(   r(   r+   Úon_task_completeš   s    z"WebSocketProtocol.on_task_completeÚstrr	   zHTTPResponse | None)ÚpathÚrequest_headersr&   c                 Ã  s
  |  d¡\}}}tjj |¡ g }| d¡D ]}| dd„ | d¡D ƒ¡ q,dd„ | ¡ D ƒ}t	|ƒ}| j
| }	| j
 d¡| d¡ }
d| jjd	d
œd| j| j| j| j
|	|
| d¡||| j ¡ di i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)rE   Útokenr(   r(   r+   rH   ¬   s     z5WebSocketProtocol.process_request.<locals>.<listcomp>ú,c                 S  s(   g | ] \}}|  d ¡|j d ddf‘qS )ÚasciiÚsurrogateescape)Úerrors)ÚencoderD   r(   r(   r+   rH   ®   s   ÿr|   Z	websocketz2.4)ÚversionZspec_versionz1.1zwebsocket.http.response)ÚtypeZasgiZhttp_versionrS   rQ   rR   rM   rv   Zraw_pathÚquery_stringÚheadersÚsubprotocolsÚstater?   N)Ú	partitionÚ
websocketsÚlegacyZ	handshakeZcheck_requestZget_allÚextendÚsplitZ	raw_itemsr   rM   r   r9   Zasgi_versionrS   rQ   rR   r;   ÚcopyÚscoperL   Zcreate_taskÚrun_asgiZadd_done_callbackrt   rO   rd   rU   ÚwaitrX   )r*   rv   rw   Zpath_portionÚ_r‚   r„   ÚheaderZasgi_headersÚ	full_pathZfull_raw_pathrr   r(   r(   r+   Úprocess_request   s>    	þ
òz!WebSocketProtocol.process_requestzSequence[Subprotocol] | NonezSubprotocol | None)rƒ   Úavailable_subprotocolsr&   c                 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.
        )r[   )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
ó    )ru   Úlenr   rP   ÚwriteÚjoinrU   rl   )r*   ÚmsgZcontentr(   r(   r+   rp   Õ   s    ûz#WebSocketProtocol.send_500_responser   r   )Úprotocolrv   r&   c                 Ã  s   | 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)rV   rl   Zwait_closed)r*   rš   rv   r(   r(   r+   r=   ã   s    
zWebSocketProtocol.ws_handlerc                 Ã  s  z|   | j| j| j¡I dH }W n~ tk
rF   | j ¡  | j ¡  Y n¾ t	k
rœ   | j ¡  | j
 d¡ | j ¡ s~|  ¡  n| j ¡ I dH  | j ¡  Y nhX | j ¡  | j ¡ sÒ| j
 d¡ |  ¡  | j ¡  n2|dk	r| j
 d|¡ | j ¡ I dH  | j ¡  dS )zr
        Wrapper around the ASGI callable, handling exceptions and unexpected
        termination states.
        NzException in ASGI application
z1ASGI callable returned without sending handshake.z4ASGI callable should return None, but returned '%s'.)rJ   rŒ   Úasgi_receiveÚ	asgi_sendr   rW   rl   rP   rn   ÚBaseExceptionr8   Z	exceptionrU   rk   rp   rV   rŽ   Úerror)r*   Úresultr(   r(   r+   r   ì   s*    






zWebSocketProtocol.run_asgir   )Úmessager&   c              
   Ã  sô  |d }| j  ¡ sf|dkrŒtd|ƒ}| j d| jd t| jƒ¡ d | _ttt	 | 
d¡ƒ| _d|kr€| j dd	„ |d D ƒ¡ | j  ¡  nÖ|d
kràtd|ƒ}| j d| jd t| jƒ¡ tjjg df| _| j  ¡  | j ¡  n‚|dkrRtd|ƒ}| j d| jd t| jƒ|d ¡ t |d ¡}dd„ | 
dg ¡D ƒ}||df| _| j  ¡  nd}t|| ƒ‚nŠ| j ¡ sl| jd krl| j ¡ I d H  z°|dkrÜtd|ƒ}| 
d¡}| 
d¡}|d krÆ|n|}|  |¡I d H  n`|d
kr,td|ƒ}| 
dd¡}	| 
dd¡pd}
|  |	|
¡I d H  | j ¡  nd}t|| ƒ‚W n* tk
rh } z
t|‚W 5 d }~X Y nX n„| jd k	rà|dkrÎtd|ƒ}| jd  |d!  }| jd d … |f | _| 
d"d#¡sÞ| j ¡  nd$}t|| ƒ‚nd%}t|| ƒ‚d S )&Nr   zwebsocket.acceptr   z%s - "WebSocket %s" [accepted]rR   Zsubprotocolrƒ   c                 s  s&   | ]\}}|  d ¡|  d ¡fV  qdS )rA   NrB   rD   r(   r(   r+   Ú	<genexpr>  s   ÿz.WebSocketProtocol.asgi_send.<locals>.<genexpr>zwebsocket.closer   z%s - "WebSocket %s" 403r•   zwebsocket.http.response.startr   z%s - "WebSocket %s" %dÚstatusc                 S  s$   g | ]\}}|  d ¡|  d ¡f‘qS r@   rB   rD   r(   r(   r+   rH   4  s    z/WebSocketProtocol.asgi_send.<locals>.<listcomp>zmExpected ASGI message 'websocket.accept', 'websocket.close', or 'websocket.http.response.start' but got '%s'.zwebsocket.sendr   ÚbytesÚtextÚcodeiè  Úreasonrc   zJExpected ASGI message 'websocket.send' or 'websocket.close', but got '%s'.zwebsocket.http.response.bodyr   é   ÚbodyZ	more_bodyFzBExpected ASGI message 'websocket.http.response.body' but got '%s'.z\Unexpected ASGI message '%s', after sending 'websocket.close' or response already completed.)rU   rk   r   r8   ÚinforŒ   r   rX   r   r   Úgetr[   r7   r‰   rl   ÚhttpZ
HTTPStatusZ	FORBIDDENrW   ÚRuntimeErrorrV   rŽ   Úsendrn   r
   r   )r*   r    Zmessage_typer¢   rƒ   r™   Ú
bytes_dataZ	text_dataÚdatar¥   r¦   ri   r¨   r(   r(   r+   rœ   	  s’    
ýü
ý


ü
ÿÿ







zWebSocketProtocol.asgi_sendzHWebSocketDisconnectEvent | WebSocketConnectEvent | WebSocketReceiveEventc                 Ã  sÂ   | j sd| _ ddiS | j ¡ I d H  | jr4dddœS | j ¡ rHdddœS z|  ¡ I d H }W nH tk
r¢   | j ¡  | j	j
rŠdddœ Y S d| jp”d| jd	œ Y S X t|tƒr¸d
|dœS d
|dœS )NTr   zwebsocket.connectzwebsocket.disconnectiî  )r   r¥   ií  ro   )r   r¥   r¦   zwebsocket.receive)r   r¤   )r   r£   )rY   rV   rŽ   rZ   rW   rk   Zrecvr
   rl   r>   r0   Z
close_codeZclose_reasonÚ
isinstanceru   )r*   r¯   r(   r(   r+   r›   h  s$    





zWebSocketProtocol.asgi_receive)N)r3   r4   r5   Ú__annotations__r^   rg   rm   rq   rt   r’   r”   rp   r=   r   rœ   r›   Ú__classcell__r(   r(   r`   r+   r6   9   s   
 û9/		_r6   )7Z
__future__r   rK   r«   r_   Útypingr   r   r   r   r   Zurllib.parser   r‡   Zwebsockets.legacy.handshakeZwebsockets.datastructuresr	   Zwebsockets.exceptionsr
   Zwebsockets.extensions.baser   Z(websockets.extensions.permessage_deflater   Zwebsockets.legacy.serverr   Zwebsockets.serverr   Zwebsockets.typingr   Zuvicorn._typesr   r   r   r   r   r   r   r   r   r   r   Zuvicorn.configr   Zuvicorn.loggingr   Zuvicorn.protocols.utilsr   r   r   r    r!   Zuvicorn.serverr"   r#   r6   r(   r(   r(   r+   Ú<module>   s*   4