U
    )–€htF  ã                   @   sþ   d 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 ddlZddlmZmZmZ ddl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mZmZm Z m!Z! dZ"G dd„ dƒZ#ee$ e	e e
e% dœdd„Z&ee$ ee e	e dœdd„Z'dS )zR
wsproto/handshake
~~~~~~~~~~~~~~~~~~

An implementation of WebSocket handshakes.
é    )Údeque)	ÚcastÚDequeÚDictÚ	GeneratorÚIterableÚListÚOptionalÚSequenceÚUnionNé   )Ú
ConnectionÚConnectionStateÚConnectionType)ÚAcceptConnectionÚEventÚRejectConnectionÚ
RejectDataÚRequest)Ú	Extension)ÚHeaders)Úgenerate_accept_tokenÚgenerate_nonceÚLocalProtocolErrorÚnormed_header_dictÚRemoteProtocolErrorÚsplit_comma_headers   13c                   @   s  e Zd ZdZeddœdd„Zeedœdd„ƒZee	e
 dœd	d
„ƒZeeeef ddœdd„Zeedœdd„Ze	e ddœdd„Zeeddf dœdd„Zejedœdd„Zeedœdd„Zeedœdd„Zeedœdd„Zeedœdd „Zej edœd!d"„Z!edœd#d$„Z"dS )%ÚH11Handshakez4A Handshake implementation for HTTP/1.1 connections.N)Úconnection_typeÚreturnc                 C   sV   |t jk| _tj| _| jr*t tj¡| _nt tj	¡| _d | _
tƒ | _d | _d | _d S ©N)r   ÚCLIENTÚclientr   Ú
CONNECTINGÚ_stateÚh11r   Ú_h11_connectionÚSERVERÚ_connectionr   Ú_eventsÚ_initiating_requestÚ_nonce)Úselfr   © r-   ú5/tmp/pip-unpacked-wheel-apvau60e/wsproto/handshake.pyÚ__init__*   s    zH11Handshake.__init__)r   c                 C   s   | j S r    )r$   ©r,   r-   r-   r.   Ústate8   s    zH11Handshake.statec                 C   s   | j S )zÙReturn the established connection.

        This will either return the connection or raise a
        LocalProtocolError if the connection has not yet been
        established.

        :rtype: h11.Connection
        )r(   r0   r-   r-   r.   Ú
connection<   s    
zH11Handshake.connection)ÚheadersÚpathr   c                 C   s>   | j rtdƒ‚tjd||d�}t tj¡}|  | |¡¡ dS )zóInitiate an upgrade connection.

        This should be used if the request has already be received and
        parsed.

        :param list headers: HTTP headers represented as a list of 2-tuples.
        :param str path: A URL path.
        z?Cannot initiate an upgrade connection when acting as the clientó   GET©ÚmethodÚtargetr3   N)r"   r   r%   r   r   r!   Úreceive_dataÚsend)r,   r3   r4   Zupgrade_requestZ
h11_clientr-   r-   r.   Úinitiate_upgrade_connectionH   s    ÿz(H11Handshake.initiate_upgrade_connection)Úeventr   c                 C   s€   d}t |tƒr||  |¡7 }n^t |tƒr8||  |¡7 }nDt |tƒrR||  |¡7 }n*t |tƒrl||  |¡7 }nt	d|› d�ƒ‚|S )a
  Send an event to the remote.

        This will return the bytes to send based on the event or raise
        a LocalProtocolError if the event is not valid given the
        state.

        :returns: Data to send to the WebSocket peer.
        :rtype: bytes
        ó    zEvent z$ cannot be sent during the handshake)
Ú
isinstancer   Ú_initiate_connectionr   Ú_acceptr   Ú_rejectr   Ú_send_reject_datar   ©r,   r<   Údatar-   r-   r.   r:   [   s    





ÿzH11Handshake.send)rD   r   c                 C   sl  | j  |pd¡ z| j  ¡ }W n$ tjk
rB   tdtƒ d�‚Y nX t|tjƒsd|tjksd|tj	krh�qh| j
�rHt|tjƒrÂ|jdkrš| j |  |¡¡ n&| j tt|jƒ|jdd�¡ tj| _n„t|tjƒrötj| _| j tt|jƒ|jdd�¡ nPt|tjƒ�r| j t|jdd�¡ n*t|tjƒ�rf| j tddd�¡ tj| _qt|tjƒr| j |  |¡¡ qd	S )
zåReceive data from the remote.

        A list of events that the remote peer triggered by sending
        this data can be retrieved with :meth:`events`.

        :param bytes data: Data received from the WebSocket peer.
        r=   zBad HTTP message©Z
event_hintée   F)r3   Ústatus_codeÚhas_bodyT)rD   Úbody_finishedN)r&   r9   Z
next_eventr%   r   r   r>   ZConnectionClosedZ	NEED_DATAZPAUSEDr"   ÚInformationalResponserG   r)   ÚappendÚ_establish_client_connectionÚlistr3   r   ÚCLOSEDr$   ÚResponseÚ	REJECTINGÚDatar   rD   ÚEndOfMessager   Ú_process_connection_request)r,   rD   r<   r-   r-   r.   r9   t   sZ     ÿ
ÿþý
ýÿ
ýÿÿ
zH11Handshake.receive_datac                 c   s   | j r| j  ¡ V  q dS )z¢Return a generator that provides any events that have been generated
        by protocol activity.

        :returns: a generator that yields H11 events.
        N)r)   Úpopleftr0   r-   r-   r.   Úevents¬   s    zH11Handshake.eventsc                 C   s¨  |j dkrtdtƒ d�‚d }g }d }d }g }d}d }g }	|jD ]¢\}
}|
 ¡ }
|
dkr`t|ƒ}nr|
dkrv| d¡}q>n\|
dkr�| t|ƒ¡ q>nB|
d	krž|}n4|
d
kr¸| t|ƒ¡ q>n|
dkrÆ|}n|
dkrÒ|}|	 |
|f¡ q>|d ksþt	dd„ |D ƒƒ�stdtƒ d�‚|t
k�r:tdtdt
fg|�r.dndd�d�‚|d k�rRtdtƒ d�‚| ¡ dk�rntdtƒ d�‚|d k�r†tdtƒ d�‚t||	|||j d¡d�| _| jS )Nr5   zRequest method must be GETrE   r=   ó
   connections   hostÚidnaó   sec-websocket-extensionsó   sec-websocket-keyó   sec-websocket-protocols   sec-websocket-versionó   upgradec                 s   s   | ]}|  ¡ d kV  qdS ©ÚupgradeN©Úlower©Ú.0Útokenr-   r-   r.   Ú	<genexpr>Ú   s    z;H11Handshake._process_connection_request.<locals>.<genexpr>ú%Missing header, 'Connection: Upgrade'z'Missing header, 'Sec-WebSocket-Version'ó   Sec-WebSocket-Versioniª  i�  )r3   rG   z#Missing header, 'Sec-WebSocket-Key'ó	   websocketú$Missing header, 'Upgrade: WebSocket'zMissing header, 'Host'Úascii)Ú
extensionsÚextra_headersÚhostÚsubprotocolsr8   )r7   r   r   r3   r_   r   ÚdecodeÚextendrK   ÚanyÚWEBSOCKET_VERSIONr   r8   r*   )r,   r<   Úconnection_tokensri   rk   Úkeyrl   r]   Úversionr3   ÚnameÚvaluer-   r-   r.   rS   ·   sŽ    
 ÿ

ÿ
 ÿ
þþ
 ÿ ÿ
 ÿ
ûz(H11Handshake._process_connection_requestc                 C   sð   | j d k	st‚t| j jƒ}|d }t|ƒ}ddd|fg}|jd k	rv|j| j jkr`td|j› �ƒ‚| d|j 	d¡f¡ |j
r¨tttt | j j
ƒ|j
ƒ}|r¨| d|f¡ tjd	||j d
�}t| jrÊtjntj|j
ƒ| _tj| _| j |¡pîdS )NrY   ©ó   Upgrades	   WebSocket©s
   Connectionrw   s   Sec-WebSocket-Acceptzunexpected subprotocol ó   Sec-WebSocket-Protocolrh   ó   Sec-WebSocket-ExtensionsrF   ©rG   r3   r=   )r*   ÚAssertionErrorr   rj   r   Úsubprotocolrl   r   rK   Úencoderi   Úserver_extensions_handshaker   r
   Ústrr%   rJ   r   r"   r   r!   r'   r(   r   ÚOPENr$   r&   r:   )r,   r<   Zrequest_headersÚnonceÚaccept_tokenr3   ÚacceptsÚresponser-   r-   r.   r@   þ   s>    ý
ÿþ ÿþzH11Handshake._acceptc                 C   s†   | j tjkrtd| j  ƒ‚t|jƒ}|js4| d¡ tj	|j
|d�}| j |¡pRd}tj| _|js‚|| j t ¡ ¡pvd7 }tj| _|S )Nz)Connection cannot be rejected in state %s)s   content-lengthó   0r{   r=   )r1   r   r#   r   rM   r3   rH   rK   r%   rO   rG   r&   r:   rP   r$   rR   rN   )r,   r<   r3   r…   rD   r-   r-   r.   rA   %  s    ÿ

zH11Handshake._rejectc                 C   s`   | j tjkrtd| j › �ƒ‚| j tj|jd�¡p4d}|j	r\|| j t 
¡ ¡pPd7 }tj| _|S )Nz$Cannot send rejection data in state )rD   r=   )r1   r   rP   r   r&   r:   r%   rQ   rD   rI   rR   rN   r$   rC   r-   r-   r.   rB   6  s    
ÿzH11Handshake._send_reject_data)Úrequestr   c           
      C   s   || _ tƒ | _d|j d¡fddd| jfdtfg}|jrT| dd |j¡ d	¡f¡ |j	rði }|j	D ] }t
|tƒsvt‚| ¡ ||j< qdg }| ¡ D ]D\}}| d	¡}t
|tƒr¾|rÖ| |¡ q’| d
|| d	¡f ¡ q’|rð| dd |¡f¡ tjd|j d	¡||j d�}	| j |	¡�pdS )Ns   HostrW   rv   rx   s   Sec-WebSocket-Keyre   ry   z, rh   ó   %s; %srz   ó   , r5   r6   r=   )r*   r   r+   rk   r~   rp   rl   rK   Újoinri   r>   r   r|   Úofferrt   ÚitemsÚboolr%   r   r8   rj   r&   r:   )
r,   r‡   r3   ZoffersÚeri   rt   ÚparamsÚbnamer]   r-   r-   r.   r?   D  sD    ûþÿ



ýz!H11Handshake._initiate_connectionc                 C   sš  | j d k	st‚| jd k	st‚d }d }g }d }d}g }|jD ]z\}}	| ¡ }|dkr^t|	ƒ}q:nH|dkrrt|	ƒ}q:n4|dkr‚|	}q:n$|dkr˜|	 d¡}q:n|dkr¦|	}q:| ||	f¡ q:|d ksÐtdd	„ |D ƒƒsÞt	d
t
ƒ d�‚| ¡ dkrøt	dt
ƒ d�‚t| jƒ}
||
k�rt	dt
ƒ d�‚|d k	�rF|| j jk�rFt	d|› �t
ƒ d�‚t|ttt | j jƒƒ}t| j�rntjntj|| jjd ƒ| _tj| _t|||d�S )Nr=   rV   rX   s   sec-websocket-acceptrZ   rh   r[   c                 s   s   | ]}|  ¡ d kV  qdS r\   r^   r`   r-   r-   r.   rc   �  s    z<H11Handshake._establish_client_connection.<locals>.<genexpr>rd   rE   rf   rg   zBad accept tokenzunrecognized subprotocol r   )ri   rj   r}   )r*   r|   r+   r3   r_   r   rm   rK   ro   r   r   r   rl   Úclient_extensions_handshaker   r
   r   ri   r   r"   r   r!   r'   r&   Ztrailing_datar(   r   r�   r$   r   )r,   r<   Úacceptrq   r„   r}   r]   r3   rt   ru   rƒ   ri   r-   r-   r.   rL   o  s|    
ÿ ÿ ÿ


þ ÿ
ý  ÿz)H11Handshake._establish_client_connectionc                 C   s   d  | jj| j| j¡S )Nz{}(client={}, state={}))ÚformatÚ	__class__Ú__name__r"   r1   r0   r-   r-   r.   Ú__repr__°  s
      ÿzH11Handshake.__repr__)#r•   Ú
__module__Ú__qualname__Ú__doc__r   r/   Úpropertyr   r1   r	   r   r2   r   r   Úbytesr€   r;   r   r:   r9   r   rU   r%   r   rS   r   r@   r   rA   r   rB   r?   rJ   rL   r–   r-   r-   r-   r.   r   '   s0    
þ8þG',þAr   )Ú	requestedÚ	supportedr   c           
      C   sì   i }| D ]h}|  dd¡d  ¡ }|D ]J}|j|kr$| |¡}t|tƒrV|rnd||j< q$|dk	r$| d¡||j< q$q|règ }| ¡ D ]Z\}}| d¡}	t|tƒr²|s¦t‚| 	|	¡ q‚|dkrÊ| 	d|	 ¡ q‚| 	d	|	|f ¡ q‚d
 
|¡S dS )zƒAgree on the extensions to use returning an appropriate header value.

    This returns None if there are no agreed extensions
    ú;r   r   TNrh   r=   s   %srˆ   r‰   )ÚsplitÚstriprt   r’   r>   r�   r~   rŒ   r|   rK   rŠ   )
rœ   r�   r„   r‹   rt   Ú	extensionr’   ri   r�   Z
name_bytesr-   r-   r.   r   ¶  s.    





r   )Úacceptedr�   r   c                 C   sf   g }| D ]X}|  dd¡d  ¡ }|D ]&}|j|kr$| |¡ | |¡  qq$td|› �tƒ d�‚q|S )Nrž   r   r   zunrecognized extension rE   )rŸ   r    rt   ÚfinalizerK   r   r   )r¢   r�   ri   r’   rt   r¡   r-   r-   r.   r‘   Ú  s    


 ÿr‘   )(r™   Úcollectionsr   Útypingr   r   r   r   r   r   r	   r
   r   r%   r2   r   r   r   rU   r   r   r   r   r   ri   r   r   Z	utilitiesr   r   r   r   r   r   rp   r   r€   r›   r   r‘   r-   r-   r-   r.   Ú<module>   s*   , 
    þ% þ