U
    9ÜŸj{.  ã                   @   s~   d dl 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 e  e¡ZG dd„ deƒZG d	d
„ d
eƒZdS )é    N)Úunquote)ÚConnectionDenyÚWebSocketServerFactoryÚWebSocketServerProtocol)Údeferé   )Úparse_x_forwarded_forc                   @   s¦   e Zd ZdZdZdZdd„ Zdd„ Zdd	„ Zd
d„ Z	dd„ Z
dd„ Zdd„ Zdd„ Zd'dd„Zdd„ Zd(dd„Zd)dd„Zdd„ Zdd „ Zd!d"„ Zd#d$„ Zd%d&„ ZdS )*ÚWebSocketProtocolzj
    Protocol which supports WebSockets and forwards incoming messages to
    the websocket channels.
    Ú	websocketFc                 C   s"  | j j| _| j | ¡ || _d | _| jj| _t ¡ | _t ¡ | _	�z¨g | _
|j ¡ D ]N\}}| d¡}d|krpqT| ¡ dkrˆt|ƒ| _qT| j
 | ¡ | d¡f¡ qT| j ¡ }| j ¡ }t|dƒròt|dƒròt|jƒ|jg| _t|jƒ|jg| _nd | _d | _| jj�r4tt| j
ƒ| jj| jj| jj| jƒ\| _| _g }| j
D ]2\}}|dk�r>dd	„ t|  d¡ƒ !d
¡D ƒ}�q>|j" d¡| _"t# $| jj%| dt| j"  d¡ƒ| j"| j| j
| j&| j| j|dœ	¡| _'| j'd k	�rè| j' (| j)¡ | j' *| j+¡ W n& t,k
�r   t- .t/ 0¡ ¡ ‚ Y nX t# 1¡ | _2| j2S )NÚasciió   _s   daphne-root-pathÚlatin1ÚhostÚports   sec-websocket-protocolc                 S   s   g | ]}|  ¡ ‘qS © )Ústrip)Ú.0Úxr   r   ú6/tmp/pip-unpacked-wheel-tk6c4rm9/daphne/ws_protocol.pyÚ
<listcomp>G   s    z/WebSocketProtocol.onConnect.<locals>.<listcomp>ú,r
   )	ÚtypeÚpathÚraw_pathÚ	root_pathÚheadersZquery_stringÚclientÚserverÚsubprotocols)3ÚfactoryÚserver_classr   Zprotocol_connectedÚrequestZprotocol_to_acceptr   ÚtimeÚsocket_openedÚ	last_pingZclean_headersr   ÚitemsÚencodeÚlowerr   ÚappendÚ	transportZgetPeerZgetHostÚhasattrÚstrr   r   Úclient_addrZserver_addrZproxy_forwarded_address_headerr   ÚdictZproxy_forwarded_port_headerZproxy_forwarded_proto_headerZclient_schemeÚdecodeÚsplitr   r   ZmaybeDeferredZcreate_applicationZ_raw_query_stringZapplication_deferredZaddCallbackÚapplicationCreateWorkedZ
addErrbackÚapplicationCreateFailedÚ	ExceptionÚloggerÚerrorÚ	tracebackÚ
format_excZDeferredÚhandshake_deferred)Úselfr!   ÚnameÚvalueZpeerr   r   Úheaderr   r   r   Ú	onConnect   sx    







û
ÿ
÷ý
zWebSocketProtocol.onConnectc                 C   sH   || _ | j  ddi¡ | j dd| jj| jr:dt| jƒ nddœ¡ dS )zk
        Called when the background thread has successfully made the application
        instance.
        r   zwebsocket.connectr
   Z
connectingú%s:%sN©r   r   )Úapplication_queueÚ
put_nowaitr   Ú
log_actionr!   r   r,   Útuple)r8   r?   r   r   r   r0   h   s    ýýz)WebSocketProtocol.applicationCreateWorkedc                 C   s   t  |¡ |S )z9
        Called when application creation fails.
        )r3   r4   )r8   Zfailurer   r   r   r1   |   s    
z)WebSocketProtocol.applicationCreateFailedc                 C   s@   t  d| j¡ | j dd| jj| jr2dt| jƒ nd dœ¡ d S )Nz!WebSocket %s open and establishedr
   Ú	connectedr=   r>   )r3   Údebugr,   r   rA   r!   r   rB   ©r8   r   r   r   ÚonOpen…   s    ýýzWebSocketProtocol.onOpenc                 C   sd   | j rt d| j¡ d S t d| j¡ t ¡ | _|rH| j d|dœ¡ n| j d| d¡dœ¡ d S )NzMuting incoming frame on %szWebSocket incoming frame on %szwebsocket.receive)r   ÚbytesÚutf8)r   Útext)	Úmutedr3   rD   r,   r"   r$   r?   r@   r.   )r8   ÚpayloadZisBinaryr   r   r   Ú	onMessage“   s    
ÿÿzWebSocketProtocol.onMessagec                 C   sn   | j  | ¡ t d| j¡ | js<t| dƒr<| j d|dœ¡ | j  	dd| j
j| jr`dt| jƒ ndd	œ¡ dS )
z8
        Called when Twisted closes the socket.
        zWebSocket closed for %sr?   zwebsocket.disconnect)r   Úcoder
   Zdisconnectedr=   Nr>   )r   Úprotocol_disconnectedr3   rD   r,   rJ   r*   r?   r@   rA   r!   r   rB   )r8   ZwasCleanrM   Úreasonr   r   r   ÚonClose£   s    ÿýýzWebSocketProtocol.onClosec                 C   sê   d|krt dƒ‚|d dkr0|  | dd ¡¡ n¶|d dkrh| j| jkrR|  ¡  qæ| j| dd ¡d� n~|d dkræ| j| jkrˆt d	ƒ‚| d
d ¡r®| dd ¡r®t d|f ƒ‚| d
d ¡rÊ|  |d
 d¡ | dd ¡ræ|  |d d¡ d S )Nr   zMessage has no type definedzwebsocket.acceptÚsubprotocolzwebsocket.closerM   ©rM   zwebsocket.sendz4Socket has not been accepted, so cannot send over itrG   rI   zMGot invalid WebSocket reply message on %s - contains both bytes and text keysTF)Ú
ValueErrorÚserverAcceptÚgetÚstateÚSTATE_CONNECTINGÚserverRejectÚserverCloseÚ
serverSend)r8   Úmessager   r   r   Úhandle_replyº   s*    
ÿÿzWebSocketProtocol.handle_replyc                 C   s0   t | dƒr | j tddd�¡ n| jdd� dS )zF
        Called by the server when our application tracebacks
        r7   iô  zInternal server error©rM   rO   ió  rR   N)r*   r7   Úerrbackr   ZsendCloseFrame)r8   Ú	exceptionr   r   r   Úhandle_exceptionÑ   s
    

ÿz"WebSocketProtocol.handle_exceptionNc                 C   s"   | j  |¡ | ` t d| j¡ dS )zO
        Called when we get a message saying to accept the connection.
        z$WebSocket %s accepted by applicationN)r7   Úcallbackr3   rD   r,   )r8   rQ   r   r   r   rT   Þ   s    zWebSocketProtocol.serverAcceptc                 C   sd   | j  tddd�¡ | ` | j | ¡ t d| j¡ | j dd| j	j
| jrVdt| jƒ ndd	œ¡ dS )
zO
        Called when we get a message saying to reject the connection.
        i“  zAccess deniedr]   z$WebSocket %s rejected by applicationr
   Zrejectedr=   Nr>   )r7   r^   r   r   rN   r3   rD   r,   rA   r!   r   rB   rE   r   r   r   rX   æ   s    
ÿýýzWebSocketProtocol.serverRejectc                 C   sJ   | j | jkr|  ¡  t d| j¡ |r4|  ||¡ n|  | d¡|¡ dS )z@
        Server-side channel message to send a message.
        z&Sent WebSocket packet to client for %srH   N)rV   rW   rT   r3   rD   r,   ZsendMessager&   )r8   ÚcontentÚbinaryr   r   r   rZ   û   s    zWebSocketProtocol.serverSendc                 C   s    |dkrdn|}| j |d� dS )zA
        Server-side channel message to close the socket
        Niè  rR   )Z	sendClose)r8   rM   r   r   r   rY     s    zWebSocketProtocol.serverClosec                 C   s   t   ¡ | j S )z>
        Returns the time since the socket was opened
        )r"   r#   rE   r   r   r   Úduration  s    zWebSocketProtocol.durationc                 C   s‚   |   ¡ | jjkr$| jjdkr$|  ¡  | j| jkrJ|   ¡ | jjkr~|  ¡  n4| j| jkr~t	 	¡ | j
 | jjkr~|  ¡  t	 	¡ | _
dS )zK
        Called periodically to see if we should timeout something
        r   N)rd   r   Zwebsocket_timeoutrY   rV   rW   Zwebsocket_connect_timeoutrX   Z
STATE_OPENr"   r$   Zping_intervalZ_sendAutoPingrE   r   r   r   Úcheck_timeouts  s    ÿ
þ
z WebSocketProtocol.check_timeoutsc                 C   s   t t| ƒƒS ©N)ÚhashÚidrE   r   r   r   Ú__hash__*  s    zWebSocketProtocol.__hash__c                 C   s   t | ƒt |ƒkS rf   )rh   )r8   Úotherr   r   r   Ú__eq__-  s    zWebSocketProtocol.__eq__c                 C   s   d| j ›d| j›d�S )Nz<WebSocketProtocol client=z path=ú>)r,   r   rE   r   r   r   Ú__repr__0  s    zWebSocketProtocol.__repr__)N)F)N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Zapplication_typerJ   r<   r0   r1   rF   rL   rP   r\   r`   rT   rX   rZ   rY   rd   re   ri   rk   rm   r   r   r   r   r	      s(   K	


	r	   c                       s,   e Zd ZdZeZdd„ Z‡ fdd„Z‡  ZS )ÚWebSocketFactoryzˆ
    Factory subclass that remembers what the "main"
    factory is, so WebSocket protocols can access it
    to get reply ID info.
    c                 O   s   || _ tj| f|ž|Ž d S rf   )r    r   Ú__init__)r8   r    ÚargsÚkwargsr   r   r   rs   =  s    zWebSocketFactory.__init__c                    sF   zt ƒ  |¡}| |_|W S  tk
r@   t dt ¡  ¡ ‚ Y nX dS )zh
        Builds protocol instances. We use this to inject the factory object into the protocol.
        zCannot build protocol: %sN)ÚsuperÚbuildProtocolr   r2   r3   r4   r5   r6   )r8   ÚaddrÚprotocol©Ú	__class__r   r   rw   A  s    zWebSocketFactory.buildProtocol)	rn   ro   rp   rq   r	   ry   rs   rw   Ú__classcell__r   r   rz   r   rr   4  s   rr   )Úloggingr"   r5   Úurllib.parser   Zautobahn.twisted.websocketr   r   r   Ztwisted.internetr   Úutilsr   Ú	getLoggerrn   r3   r	   rr   r   r   r   r   Ú<module>   s   
  $