U
    gtF                     @   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-u83us8q9/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 )zReturn 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 )zInitiate 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| _nt|tjrt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 )
zReceive 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_hinte   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 )zReturn 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st	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rt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
rtttt | j j
|j
}|r|d|f tjd	||j d
}t| jrtjntj|j
| _tj| _| j|pd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	ri }|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   paramsZ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stdd	 |D st	d
t
 d| dkrt	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|rg }| D ]Z\}}|d}	t|tr|st|	|	 q|dkr|	d|	  q|	d	|	|f  qd

|S dS )zAgree 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*   , 
    % 