3
K^|                @   s  d dl Z d dlZd dlZd dlZd dlZd dlZd dl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mZmZ d dlmZmZmZ d dlmZ d d	lmZmZmZmZ d d
lmZ d dlm Z  d dl!m"Z" d dl#m$Z$m%Z% d dl&m'Z' d dl(m)Z) d dl*m+Z+m,Z, d dlm-Z- d dl.Z.d-Z/dd Z0dd Z1G dd de2Z3G dd de2Z4d d! Z5G d"d# d#e2Z6G d$d de Z7ej8e7 ej8e7 ej8e7 G d%d& d&e2Z9G d'd de2Z:d(Z;G d)d de7Z<G d*d de:Z=G d+d de7Z>G d,d de:Z?dS ).    N)pformat)deque)parse)__version__)IWebSocketChannelIWebSocketChannelFrameApiIWebSocketChannelStreamingApi)ConnectionRequestConnectionResponseConnectionDeny)ConnectingRequest)	Stopwatchnewidwildcards2patternsencode_truncate)_LazyHexFormatter)ObservableMixin)Utf8Validator)XorMaskerNullcreate_xor_masker) PERMESSAGE_COMPRESSION_EXTENSION)	parse_url)PayloadExceededErrorDisconnected)_maybe_tls_reasonWebSocketProtocolWebSocketFactoryWebSocketServerProtocolWebSocketServerFactoryWebSocketClientProtocolWebSocketClientFactoryc             C   s   | j  dkrdS tj| }|jj  }|dkr0dS |j}|j}|dkrpyddd| }W n tk
rn   d}Y nX |stdj| |||fS )z
    Given an RFC6455 Origin URL, this returns the (scheme, host, port)
    triple. If there's no port, and the scheme isn't http or https
    then port will be None
    nullfileNi  P   )httpshttpzNo host part in Origin '{}')	lowerr   urlsplitschemehostnameportKeyError
ValueErrorformat)urlresr(   hostr*    r1   ?/tmp/pip-unpacked-wheel-p9ga6z5n/autobahn/websocket/protocol.py_url_to_originG   s     


r3   c       
      C   sl   | dkrdS t | t s&t| dk r.td| \}}}d}|j|||d}x|D ]}	|	j|rRdS qRW dS )a  
    Internal helper. Returns True if the provided websocket_origin
    triple should be considered valid given the provided policy and
    expected host_port.

    Currently, the policy is just the list of allowedOriginsPatterns
    from the WebSocketProtocol instance. Schemes and ports are matched
    first, and only if there is not a mismatch do we compare each
    allowed-origin pattern against the host.
    r!   F   z$'websocket_origin' must be a 3-tuplez{scheme}://{host}:{port})r(   r0   r*   T)
isinstancetuplelenr,   r-   match)
websocket_originZhost_scheme	host_portZhost_policyZorigin_schemeorigin_hostorigin_porttemplateZorigin_headerZorigin_patternr1   r1   r2   _is_same_origind   s    


r>   c               @   s,   e Zd Zdd Zdd Zdd Zdd Zd	S )
TrafficStatsc             C   s   | j   d S )N)reset)selfr1   r1   r2   __init__   s    zTrafficStats.__init__c             C   sL   d| _ d| _d| _d| _d| _d| _d| _d| _d| _d| _	d| _
d| _d S )Nr   )outgoingOctetsWireLeveloutgoingOctetsWebSocketLeveloutgoingOctetsAppLeveloutgoingWebSocketFramesoutgoingWebSocketMessagesincomingOctetsWireLevelincomingOctetsWebSocketLevelincomingOctetsAppLevelincomingWebSocketFramesincomingWebSocketMessagespreopenOutgoingOctetsWireLevelpreopenIncomingOctetsWireLevel)rA   r1   r1   r2   r@      s    zTrafficStats.resetc             C   s   | j dkr t| jt| j  }nd }| jdkrDt| jt| j }nd }| jdkrnt| j| j t| j }nd }| jdkrt| j| j t| j }nd }| j| j| j ||| j| j| j	| j| j| j||| j
| j| jdS )Nr   )rC   rD   rE   outgoingCompressionRatiooutgoingWebSocketOverheadrF   rG   rM   rH   rI   rJ   incomingCompressionRatioincomingWebSocketOverheadrK   rL   rN   )rE   floatrD   rJ   rI   rC   rH   rF   rG   rM   rK   rL   rN   )rA   rO   rQ   rP   rR   r1   r1   r2   __json__   s8    



zTrafficStats.__json__c             C   s   t j| j S )N)jsondumpsrT   )rA   r1   r1   r2   __str__   s    zTrafficStats.__str__N)__name__
__module____qualname__rB   r@   rT   rW   r1   r1   r1   r2   r?      s   *r?   c               @   s   e Zd ZdZdd ZdS )FrameHeaderzX
    Thin-wrapper for storing WebSocket frame metadata.

    FOR INTERNAL USE ONLY!
    c             C   s"   || _ || _|| _|| _|| _dS )a  
        Constructor.

        :param opcode: Frame opcode (0-15).
        :type opcode: int
        :param fin: Frame FIN flag.
        :type fin: bool
        :param rsv: Frame reserved flags (0-7).
        :type rsv: int
        :param length: Frame payload length.
        :type length: int
        :param mask: Frame mask (binary string) or None.
        :type mask: str
        N)opcodefinrsvlengthmask)rA   r\   r]   r^   r_   r`   r1   r1   r2   rB      s
    zFrameHeader.__init__N)rX   rY   rZ   __doc__rB   r1   r1   r1   r2   r[      s   r[   c       	      C   s   | j dj }|d j }i }i }x|dd D ]~}|jd}|dkr0|d| j j }||d d j }||kr||  d| 7  < ||  d7  < q|||< d||< q0q0W |||fS )a|  
    Parses the beginning of a HTTP request header (the data up to the 

 line) into a pair
    of status line and HTTP headers dictionary.
    Header keys are normalized to all-lower-case.

    FOR INTERNAL USE ONLY!

    :param data: The HTTP header data up to the 

 line.
    :type data: bytes

    :returns: tuple -- Tuple of HTTP status line, headers and headers count.
    z
iso-8859-1r      N:z, %s)decode
splitlinesstripfindr&   )	datarawhttp_status_linehttp_headershttp_headers_cnthikeyvaluer1   r1   r2   parseHttpHeader   s     

rq   c               @   sB   e Zd ZdZdd Zdd ZdddZd	d
 Zdd Zdd Z	dS )Timingsz}
    Helper class to track timings by key. This class also supports item access,
    iteration and conversion to string.
    c             C   s   t  | _i | _d S )N)r   
_stopwatch_timings)rA   r1   r1   r2   rB   ,  s    zTimings.__init__c             C   s   | j j | j|< dS )zy
        Track elapsed for key.

        :param key: Key under which to track the timing.
        :type key: str
        N)rs   elapsedrt   )rA   ro   r1   r1   r2   track0  s    zTimings.trackTc             C   s   || j kr|| j kr| j | | j |  }|r|dk rFdt|d  }n@|dk r`dt|d  }n&|dk rzdt|d	  }nd
t| }|jdS |S n|rdjdS dS dS )a  
        Get elapsed difference between two previously tracked keys.

        :param startKey: First key for interval (older timestamp).
        :type startKey: str
        :param endKey: Second key for interval (younger timestamp).
        :type endKey: str
        :param formatted: If ``True``, format computed time period and return string.
        :type formatted: bool

        :returns: float or str -- Computed time period in seconds (or formatted string).
        gh㈵>z%d nsg    eAg{Gz?z%d usg    .A
   z%d msg     @@z%d s   zn.a.N)rt   roundrjust)rA   ZstartKeyZendKey	formatteddsr1   r1   r2   diff9  s    

zTimings.diffc             C   s   | j j|d S )N)rt   get)rA   ro   r1   r1   r2   __getitem__Z  s    zTimings.__getitem__c             C   s
   | j j S )N)rt   __iter__)rA   r1   r1   r2   r   ]  s    zTimings.__iter__c             C   s
   t | jS )N)r   rt   )rA   r1   r1   r2   rW   `  s    zTimings.__str__N)T)
rX   rY   rZ   ra   rB   rv   r~   r   r   rW   r1   r1   r1   r2   rr   &  s   	
!rr   c               @   s  e Zd ZdZdZddddddd	d
dg	ZddgZdddddddddd	ZdddZdZ	dZ
dZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZ d Z!d!Z"d"Z#d#Z$d$Z%d%Z&eeeeeee e!e"e#e$gZ'd&d'd(d)d*d+d,d-d.d/d0d1d2d3d4d5gZ(d6d7d8d9d:d;d<d=d>d?d@dAgZ)dBdCdDdEdFd:gZ*dGdH Z+dIdJ Z,dKdL Z-dMdN Z.dOdP Z/dQdR Z0dSdT Z1dUdV Z2dWdX Z3dYdZ Z4d[d\ Z5d]d^ Z6d_d` Z7dadb Z8dcdd Z9dedf Z:dgdh Z;ddjdkZ<dldm Z=ednfdodpZ>dqdr Z?dsdt Z@dudv ZAdwdx ZBdydz ZCd{d| ZDd}d~ ZEdd ZFdd ZGdd ZHdd ZIdd ZJdd ZKdd ZLdd ZMdddZNdd ZOdd ZPdd ZQdd ZRdd ZSdd ZTdddZUdddZVdd ZWdd ZXdddZYdddZZdddZ[dddZ\dd Z]dddZ^dd Z_dddZ`dddZadddZbdS )r   a   
    Protocol base class for WebSocket.

    This class implements:

      * :class:`autobahn.websocket.interfaces.IWebSocketChannel`
      * :class:`autobahn.websocket.interfaces.IWebSocketChannelFrameApi`
      * :class:`autobahn.websocket.interfaces.IWebSocketChannelStreamingApi`
    z<never connected>rw                           rx   )	rw   r   r   r   r   r   r   r   r   )rx   r   s$   258EAFA5-E914-47DA-95CA-C5AB0DC85B11gh㈵>rb      r   r4      i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  i  	logOctets	logFramestrackTimingsutf8validateIncoming	applyMaskmaxFramePayloadSizemaxMessagePayloadSizeautoFragmentSize
failByDropechoCloseCodeReasonopenHandshakeTimeoutcloseHandshakeTimeout
tcpNoDelayautoPingIntervalautoPingTimeoutautoPingSizeversions	webStatusrequireMaskedClientFramesmaskServerFramesperMessageCompressionAcceptserveFlashSocketPolicyflashSocketPolicyallowedOriginsallowedOriginsPatternsallowNullOriginmaxConnectionstrustXForwardedForversionacceptMaskedServerFramesmaskClientFramesserverConnectionDropTimeoutperMessageCompressionOffersc             C   s$   t j | _t j | _| jdg d S )Nmessage)txaioZcreate_future	is_closedis_openZset_valid_events)rA   r1   r1   r2   rB      s    

zWebSocketProtocol.__init__c             C   s   | j jd dS )z[
        Implements :func:`autobahn.websocket.interfaces.IWebSocketChannel.onOpen`
        zWebSocketProtocol.onOpenN)logdebug)rA   r1   r1   r2   onOpen*  s    zWebSocketProtocol.onOpenc             C   s   || _ g | _d| _dS )zc
        Implements :func:`autobahn.websocket.interfaces.IWebSocketChannel.onMessageBegin`
        r   N)message_is_binarymessage_datamessage_data_total_length)rA   isBinaryr1   r1   r2   onMessageBegin0  s    z WebSocketProtocol.onMessageBeginc             C   s   || _ g | _|  j|7  _| jsd| j  k o6| jk n  rbd| _| j| j| jdj| j| j n:d| j  k ov|k n  rd| _	| j|| jdj|| j dS )zh
        Implements :func:`autobahn.websocket.interfaces.IWebSocketChannel.onMessageFrameBegin`
        r   TzEreceived WebSocket message size {} exceeds payload limit of {} octetszCreceived WebSocket frame size {} exceeds payload limit of {} octetsN)
Zframe_length
frame_datar   
failedByMer    wasMaxMessagePayloadSizeExceeded_max_message_size_exceededr-   r   wasMaxFramePayloadSizeExceeded)rA   r_   r1   r1   r2   onMessageFrameBegin8  s    z%WebSocketProtocol.onMessageFrameBeginc             C   s   | j s|| jdkrp|  jt|7  _d| j  k o8| jk n  rbd| _| j| j| jdj| j| j | jj	| n| j
j	| dS )zg
        Implements :func:`autobahn.websocket.interfaces.IWebSocketChannel.onMessageFrameData`
        r   TzYreceived (partial) WebSocket message size {} (already) exceeds payload limit of {} octetsN)r   websocket_versionr   r7   r   r   r   r-   r   appendr   )rA   payloadr1   r1   r2   onMessageFrameDataK  s    
z$WebSocketProtocol.onMessageFrameDatac             C   s   | j s| j| j d| _dS )zf
        Implements :func:`autobahn.websocket.interfaces.IWebSocketChannel.onMessageFrameEnd`
        N)r   Z_onMessageFramer   )rA   r1   r1   r2   onMessageFrameEnd[  s    z#WebSocketProtocol.onMessageFrameEndc             C   s   | j s| jj| dS )zc
        Implements :func:`autobahn.websocket.interfaces.IWebSocketChannel.onMessageFrame`
        N)r   r   extend)rA   r   r1   r1   r2   onMessageFramed  s    z WebSocketProtocol.onMessageFramec                sh    j s^dj j} jr$ jjd  j| j  jd| jd} fdd}tj	|d| d _dS )za
        Implements :func:`autobahn.websocket.interfaces.IWebSocketChannel.onMessageEnd`
            	onMessager   )Z	is_binaryc                s    j jd| d d S )Nz&Firing signal 'message' failed: {fail})fail)r   error)f)rA   r1   r2   r   y  s    z-WebSocketProtocol.onMessageEnd.<locals>.errorN)
r   joinr   trackedTimingsrv   Z
_onMessager   Zfirer   add_callbacks)rA   r   r   r   r1   )rA   r2   onMessageEndk  s    zWebSocketProtocol.onMessageEndc             C   s"   | j jd|rt|nd|d dS )z^
        Implements :func:`autobahn.websocket.interfaces.IWebSocketChannel.onMessage`
        zOWebSocketProtocol.onMessage(payload=<{payload_len} bytes)>, isBinary={isBinary}r   )payload_lenr   N)r   r   r7   )rA   r   r   r1   r1   r2   r     s    zWebSocketProtocol.onMessagec             C   s6   | j jd|rt|ndd | jtjkr2| j| dS )z[
        Implements :func:`autobahn.websocket.interfaces.IWebSocketChannel.onPing`
        z7WebSocketProtocol.onPing(payload=<{payload_len} bytes>)r   )r   N)r   r   r7   stater   
STATE_OPENsendPong)rA   r   r1   r1   r2   onPing  s
    zWebSocketProtocol.onPingc             C   s    | j jd|rt|ndd dS )z[
        Implements :func:`autobahn.websocket.interfaces.IWebSocketChannel.onPong`
        z7WebSocketProtocol.onPong(payload=<{payload_len} bytes>)r   )r   N)r   r   r7   )rA   r   r1   r1   r2   onPong  s    zWebSocketProtocol.onPongc             C   s   | j jd|||d dS )z\
        Implements :func:`autobahn.websocket.interfaces.IWebSocketChannel.onClose`
        zLWebSocketProtocol.onClose(wasClean={wasClean}, code={code}, reason={reason}))wasCleancodereasonN)r   r   )rA   r   r   r   r1   r1   r2   onClose  s
    zWebSocketProtocol.onClosec             C   s  d| _ d| _|dk	rd|dk sFd|  ko.dkn  r>|tjksF|dkrd| jdj|rZdS tj| _ n|| _ |dk	rt }|j|}|d o|d s| j	d	rdS n|j
d
| _| jtjkr | jdk	r| jjd | jj  d| _d| _| jjr | jdd n| jdkrtj| j| j| _n| jtjkrd| _| jdkrN| jdd n4| jrr| j| j t| jddd n| jtjdd | jjr| jdd n n| jtjkrd| _nt ddS )aQ  
        Callback when a Close frame was received. The default implementation answers by
        sending a Close when no Close was sent before. Otherwise it drops
        the TCP connection either immediately (when we are a server) or after a timeout
        (when we are a client and expect the server to drop the TCP).

        :param code: Close status code, if there was one (:class:`WebSocketProtocol`.CLOSE_STATUS_CODE_*).
        :type code: int
        :param reasonRaw: Close reason (when present, a status code MUST have been also be present).
        :type reasonRaw: bytes
        Ni  i  i  zinvalid close code {}Tr   rb   z'invalid close reason (non-UTF8 payload)utf8z?connection closed properly: canceling closing handshake timeout)abort)isReply{   )r   
reasonUtf8r   )r   r   Fzlogic error)!remoteCloseCoderemoteCloseReasonr   CLOSE_STATUS_CODES_ALLOWED_protocol_violationr-   CLOSE_STATUS_CODE_NORMALr   validate_invalid_payloadrd   r   STATE_CLOSINGcloseHandshakeTimeoutCallr   r   cancelr   factoryisServerdropConnectionr   r   
call_lateronServerConnectionDropTimeoutserverConnectionDropTimeoutCallr   r   sendCloseFramer   r   STATE_CLOSED	Exception)rA   r   	reasonRawuvalr1   r1   r2   onCloseFrame  sN    :






zWebSocketProtocol.onCloseFramec             C   sB   d| _ | jtjkr2d| _d| _d| _| jdd n| jj	d dS )z
        We (a client) expected the peer (a server) to drop the connection,
        but it didn't (in time self.serverConnectionDropTimeout).
        So we drop the connection, but set self.wasClean = False.
        NFzPWebSocket closing handshake timeout (server did not drop TCP connection in time)T)r   zQskipping closing handshake timeout: server did indeed drop the connection in time)
r   r   r   r   r   wasNotCleanReasonwasServerConnectionDropTimeoutr   r   r   )rA   r1   r1   r2   r     s    z/WebSocketProtocol.onServerConnectionDropTimeoutc             C   s   d| _ | jtjtjgkr8d| _d| _d| _| jdd nV| jtj	krR| j
jd n<| jtjkrl| j
jd n"| jtjkr| j
jd ntd	dS )
z
        We expected the peer to complete the opening handshake with to us.
        It didn't do so (in time self.openHandshakeTimeout).
        So we drop the connection, but set self.wasClean = False.
        NFzWWebSocket opening handshake timeout (peer did not finish the opening handshake in time)T)r   zeskipping opening handshake timeout: WebSocket connection is open (opening handshake already finished)zNskipping opening handshake timeout: WebSocket connection is already closing ..zJskipping opening handshake timeout: WebSocket connection is already closedzlogic error)openHandshakeTimeoutCallr   r   STATE_CONNECTINGSTATE_PROXY_CONNECTINGr   r   wasOpenHandshakeTimeoutr   r   r   r   r   r   r   )rA   r1   r1   r2   onOpenHandshakeTimeout  s    z(WebSocketProtocol.onOpenHandshakeTimeoutc             C   sB   d| _ | jtjkr2d| _d| _d| _| jdd n| jj	d dS )z
        We expected the peer to respond to us initiating a close handshake. It didn't
        respond (in time self.closeHandshakeTimeout) with a close response frame though.
        So we drop the connection, but set self.wasClean = False.
        NFzWWebSocket closing handshake timeout (peer did not finish the closing handshake in time)T)r   zJskipping closing handshake timeout: WebSocket connection is already closed)
r   r   r   r   r   r   wasCloseHandshakeTimeoutr   r   r   )rA   r1   r1   r2   onCloseHandshakeTimeout6  s    z)WebSocketProtocol.onCloseHandshakeTimeoutc             C   s"   d| _ d| _d| _| jdd dS )z
        When doing automatic ping/pongs to detect broken connection, the peer
        did not reply in time to our ping. We drop the connection.
        Fz?WebSocket ping timeout (peer did not respond with pong in time)NT)r   )r   r   autoPingTimeoutCallr   )rA   r1   r1   r2   onAutoPingTimeoutF  s    z#WebSocketProtocol.onAutoPingTimeoutFc             C   s   | j   | jtjkrp| jr0| jjd| j|d n| jjd| j|| j	d d| _
tj| _tj| j|  | j| n| jjd| jd dS )	z5
        Drop the underlying TCP connection.
        z5dropping connection to peer {peer} with abort={abort})peerr   z?dropping connection to peer {peer} with abort={abort}: {reason})r   r   r   TzFdropping connection to peer {peer} skipped - connection already closed)r   N)ZunregisterProducerr   r   r   r   r   r   r   warnr   droppedByMer   resolver   Z_closeConnection)rA   r   r1   r1   r2   r   P  s    z WebSocketProtocol.dropConnectionc             C   s   | j tj| d S )N)_fail_connectionr   !CLOSE_STATUS_CODE_MESSAGE_TOO_BIG)rA   Zmsg_sizeZmax_msg_sizer   r1   r1   r2   r   h  s    z,WebSocketProtocol._max_message_size_exceededz
going awayc             C   s   | j tjkr|| jjd||d d| _| jrJd| _dj|| _	| j
dd q| j tjkrn| j|t|ddd q| j
dd n| jjd	 d
S )z1
        Fails the WebSocket connection.
        z6failing WebSocket connection (code={code}): "{reason}")r   r   TFz+I dropped the WebSocket TCP connection: {0})r   r   )r   r   r   z=skip failing of connection since connection is already closedN)r   r   r   r   r  r   r   r   r-   r   r   r   r   r   r   )rA   r   r   r1   r1   r2   r  o  s    z"WebSocketProtocol._fail_connectionc             C   s0   | j jd|d | jtj| | jr(dS dS dS )a
  
        Fired when a WebSocket protocol violation/error occurs.

        :param reason: Protocol violation that was encountered (human readable).
        :type reason: str

        :returns: bool -- True, when any further processing should be discontinued.
        zProtocol violation: {reason})r   TFN)r   r   r  r    CLOSE_STATUS_CODE_PROTOCOL_ERRORr   )rA   r   r1   r1   r2   r     s
    	z%WebSocketProtocol._protocol_violationc             C   s0   | j jd|d | jtj| | jr(dS dS dS )a  
        Fired when invalid payload is encountered. Currently, this only happens
        for text message when payload is invalid UTF-8 or close frames with
        close reason that is invalid UTF-8.

        :param reason: What was invalid for the payload (human readable).
        :type reason: str

        :returns: bool -- True, when any further processing should be discontinued.
        zInvalid payload: {reason})r   TFN)r   r   r  r   !CLOSE_STATUS_CODE_INVALID_PAYLOADr   )rA   r   r1   r1   r2   r     s
    z"WebSocketProtocol._invalid_payloadc             C   s6   t | d s| j|kr2|| _| jr,t | _nd| _dS )z
        Enable/disable tracking of detailed timings.

        :param enable: Turn time tracking on/off.
        :type enable: bool
        r   N)hasattrr   rr   r   )rA   enabler1   r1   r2   setTrackTimings  s
    
z!WebSocketProtocol.setTrackTimingsc             C   s  g }xV| j D ]L}t| |s:t| |t| j| | jjj}n| jj}|j|t| ||f qW | jj	dt
|d d| _d| _| j| j t | _| jj r| jjdk	rtj| _ntj| _tj| _d| _t | _d| _t | _d| _d| _ d| _!d| _"d| _#d| _$d| _%d| _&d| _'d| _(d| _)d| _*d| _+d| _,d| _-| jjsFd| _.d| _/d| _0d| _1d| _2d| _3| j4dkr| jj5j6| j4| j7| _/dS )z
        This is called by network framework when a new TCP connection has been established
        and handed over to a Protocol instance (an instance of this class).
        z
{attrs})attrsNr   Fr   )8CONFIG_ATTRSr  setattrgetattrr   	__class__rX   r   r   r   r   _perMessageCompressr   r
  r   r?   trafficStatsr   proxyr   r   r   r   SEND_STATE_GROUND
send_staterh   r   
send_queue	triggeredr   utf8validatorr   r   
closedByMer   r  r   r   r   r   r   wasServingFlashSocketPolicyFilelocalCloseCodelocalCloseReasonr   r   r   r   r   r   autoPingPendingautoPingPendingCallr   _batched_timerr   r   )rA   ZconfigAttrLogZ
configAttrZconfigAttrSourcer1   r1   r2   _connectionMade  s\    	


z!WebSocketProtocol._connectionMadec             C   sT  | j jd|d | jj r@| jdk	r@| j jd | jj  d| _| jrb| j jd | jj  d| _| jr| j jd | jj  d| _| jdk	r| jj  d| _| j	t
jkrt
j| _	tj| j|  | jr| j jd n|| js<| j o| jdkr"t|dd}|sdnt|}|r|| _nd	| _| j| jt
jd
| j  n| j| j| j| j dS )zc
        This is called by network framework when a transport connection was
        lost.
        z_connectionLost: {reason})r   Nz&serverConnectionDropTimeoutCall.cancelzBAuto ping/pong: canceling autoPingPendingCall upon lost connectionzBAuto ping/pong: canceling autoPingTimeoutCall upon lost connectionz9connection dropped after serving Flash Socket Policy Filerp   zLpeer dropped the TCP connection without previous WebSocket closing handshakez$connection was closed uncleanly (%s))r   r   r   r   r   r   r  r   r   r   r   r   r   r  r   r  r   r  r   r  r   Z_onClose CLOSE_STATUS_CODE_ABNORMAL_CLOSEr   r   )rA   r   Zreason_valueZreason_stringr1   r1   r2   _connectionLost6  s<    




z!WebSocketProtocol._connectionLostc             C   s   | j jd| jt|d dS )zu
        Hook fired right after raw octets have been received, but only when
        self.logOctets == True.
        z)RX Octets from {peer} : octets = {octets})r   octetsN)r   r   r   r   )rA   rh   r1   r1   r2   logRxOctetsk  s    zWebSocketProtocol.logRxOctetsc             C   s   | j jd| j|t|d dS )zq
        Hook fired right after raw octets have been sent, but only when
        self.logOctets == True.
        z6TX Octets to {peer} : sync = {sync}, octets = {octets})r   syncr"  N)r   r   r   r   )rA   rh   r$  r1   r1   r2   logTxOctetsv  s
    zWebSocketProtocol.logTxOctetsc          
   C   s\   dj |}| jjd| j|j|j|j|jr4tj	|jnd|j
|jdkrLt|nt|d dS )z
        Hook fired right after WebSocket frame has been received and decoded,
        but only when self.logFrames == True.
        r   zyRX Frame from {peer} : fin = {fin}, rsv = {rsv}, opcode = {opcode}, mask = {mask}, length = {length}, payload = {payload}-rb   )r   r]   r^   r\   r`   r_   r   N)r   r   r   r   r]   r^   r\   r`   binasciib2a_hexr_   reprr   )rA   frameHeaderr   rh   r1   r1   r2   
logRxFrame  s    
zWebSocketProtocol.logRxFramec             C   sX   | j jd| j|j|j|j|jr*tj|jnd|j	||||jdkrHt
|nt|d dS )z
        Hook fired right after WebSocket frame has been encoded and sent, but
        only when self.logFrames == True.
        zTX Frame to {peer} : fin = {fin}, rsv = {rsv}, opcode = {opcode}, mask = {mask}, length = {length}, repeat_length = {repeat_length}, chopsize = {chopsize}, sync = {sync}, payload = {payload}r&  rb   )
r   r]   r^   r\   r`   r_   Zrepeat_lengthchopsizer$  r   N)r   r   r   r]   r^   r\   r`   r'  r(  r_   r)  r   )rA   r*  r   ZrepeatLengthr,  r$  r1   r1   r2   
logTxFrame  s    zWebSocketProtocol.logTxFramec             C   sx   | j tjkr"| j jt|7  _n,| j tjks:| j tjkrN| j jt|7  _| j	r^| j
| |  j|7  _| j  dS )zj
        This is called by network framework upon receiving data on transport
        connection.
        N)r   r   r   r  rH   r7   r   r   rN   r   r#  rh   consumeData)rA   rh   r1   r1   r2   _dataReceived  s    
zWebSocketProtocol._dataReceivedc             C   s   | j tjks| j tjkr4xh| j r0| j tjkr0qW nN| j tjkrJ| j  n8| j tjkr`| j	  n"| j tjkrz| j
jd ntddS )z3
        Consume buffered (incoming) data.
        zreceived data in STATE_CLOSEDzinvalid stateN)r   r   r   r   processDatar   r   processProxyConnectr   processHandshaker   r   r   )rA   r1   r1   r2   r.    s    

zWebSocketProtocol.consumeDatac             C   s   t ddS )z(
        Process proxy connect.
        z@must implement proxy connect (client or server) in derived classN)r   )rA   r1   r1   r2   r1    s    z%WebSocketProtocol.processProxyConnectc             C   s   t ddS )z.
        Process WebSocket handshake.
        z<must implement handshake (client or server) in derived classN)r   )rA   r1   r1   r2   r2    s    z"WebSocketProtocol.processHandshakec             C   s   | j sd| _ | j  dS )zp
        Trigger sending stuff from send queue (which is only used for
        chopped/synched writes).
        TN)r  _send)rA   r1   r1   r2   _trigger  s    zWebSocketProtocol._triggerc             C   s   t | jdkr| jj }| jtjkr| jj|d  | jtjkrZ| j	 j
t |d 7  _
n0| jtjksr| jtjkr| j	 jt |d 7  _| jr| j|d |d  n| jjd tjtj| j nd| _dS )zu
        Send out stuff from send queue. For details how this works, see
        test/trickling in the repo.
        r   rb   z1skipped delayed write, since connection is closedFN)r7   r  popleftr   r   r   	transportwriter   r  rC   r   r   rM   r   r%  r   r   r   r   _QUEUED_WRITE_DELAYr3  r  )rA   er1   r1   r2   r3    s    
zWebSocketProtocol._sendNc             C   s  |rh|dkrhd}t |}d}x@|s\|| }||kr:d}|}| jj||| df ||7 }qW | j  n|szt | jdkr| jj||f | j  nn| jj| | jtjkr| j	 j
t |7  _
n,| jtjks| jtjkr| j	 jt |7  _| jr| j|d dS )a  
        Wrapper for self.transport.write which allows to give a chopsize.
        When asked to chop up writing to TCP stream, we write only chopsize
        octets and then give up control to select() in underlying reactor so
        that bytes get onto wire immediately. Note that this is different from
        and unrelated to WebSocket data message fragmentation. Note that this
        is also different from the TcpNoDelay option which can be set on the
        socket.
        r   FTN)r7   r  r   r4  r6  r7  r   r   r   r  rC   r   r   rM   r   r%  )rA   rh   r$  r,  rn   ndonejr1   r1   r2   sendData  s,    


zWebSocketProtocol.sendDatac             C   s2   | j dks|jr| j|j n| j|j|j dS )zh
        Implements :func:`autobahn.websocket.interfaces.IWebSocketChannel.sendPreparedMessage`
        N)r  doNotCompressr=  payloadHybisendMessager   binary)rA   ZpreparedMsgr1   r1   r2   sendPreparedMessage;  s    z%WebSocketProtocol.sendPreparedMessagec             C   s  t | j}| jdkr|dkr| jd }|d@ dk}|d@ d? }|d@ }| jd }|d@ dk}|d	@ }|dkr| jdk	r|dkrn| jd
j|rdS | jjr| jr| r| jdrdS | jj r| j	 r|r| jdrdS |dkr|s| jdrdS |dkr| jdrdS |d%kr4| jdj|r4dS |dkrX|dkrX| jdrXdS | jdk	r(|dkr(| jdj| jj
r(dS n|d&kr| jdj|rdS | j r|dkr| jdrdS | jr|dkr| jdrdS | jdk	r(|dkr(| jr(| jdj| jj
r(dS |r4d}nd}|dk rLd| }	n0|dkr`d'| }	n|d	krtd(| }	ntd||	krd}
|dkrtjd| j|
|
d  d }|dk r| jdrdS |
d7 }
nj|d	kr<tjd | j|
|
d  d }|d!kr| jd"rdS |d#k r2| jdr2dS |
d7 }
n|}d}|rd| j|
|
d  }|
d7 }
|r|dkr| jrt||| _nt | _| j|
d | _t|||||| _| j  |dkpt | jdkS dS ndS n| jj| jj  }||kr | jd| }|}| j|d | _n| j}|}d$| _|dkrH| jj|}nd$}| j|}|dkrddS | jj | jjkr| j }|dkrdS t | jdkS dS ))z
        After WebSocket handshake has been completed, this procedure will do
        all subsequent processing of incoming bytes.
        Nr   r      p   r   r   rb      z$RSV = {} and no extension negotiatedFzunmasked client-to-server framezmasked server-to-client frame   zfragmented control frame}   z.control frame with payload length > 125 octetsrx   	   rw   z&control frame using reserved opcode {}z/received close control frame with payload len 1z&received compressed control frame [{}]z#data frame using reserved opcode {}z;received continuation data frame outside fragmented messagezDreceived non-continuation data frame while inside fragmented messagez;received continuation data frame with compress bit set [{}]~   zlogic errorz!Hz=invalid data frame length (not using minimal length encoding)z!Ql    z!invalid data frame length (>2^63)i   r   )rx   rH  rw   )r   rb   r   r   rw   )r7   rh   current_framer  r   r-   r   r   r   r   EXTENSION_NAMEinside_messager   structunpackr   r   Zcurrent_frame_maskerr   r[   onFrameBeginr_   pointerprocessonFrameData
onFrameEnd)rA   Zbuffered_lenbZ	frame_finZ	frame_rsvZframe_opcodeZframe_maskedZframe_payload_len1Zmask_lenZframe_header_lenrn   Zframe_payload_lenZ
frame_maskrestrh   r_   r   frr1   r1   r2   r0  D  s    





























zWebSocketProtocol.processDatac             C   s   | j jdkrg | _n| jsd| _| jdk	rH| j jdkrHd| _| jj  nd| _| j jtj	krz| j
rz| jj  d| _d| _nd| _| jr| jjd | j| j jtjk | j| j j dS )	z-
        Begin of receive new frame.
        rF  TNr   Fr   r   )TTr   r   )rJ  r\   control_frame_datarL  r  r^   _isMessageCompressedZstart_decompress_messager   MESSAGE_TYPE_TEXTr   r  r@   "utf8validateIncomingCurrentMessageutf8validateLastr   rv   Z_onMessageBeginMESSAGE_TYPE_BINARYZ_onMessageFrameBeginr_   )rA   r1   r1   r2   rO  3  s"    
zWebSocketProtocol.onFrameBeginc             C   s   | j jdkr| jj| n| jrTt|}| jjd|t|d | j	j
|}t|}nt|}|}|}| jtjkr| j j|7  _| j j|7  _| jr| jj|| _| jd s| jdj| jd rdS | j| dS )	z1
        New data received within frame.
        rF  zRX compressed [length]: octets)Zlegnthr"  r   zQencountered invalid UTF-8 while processing text message at payload octet index {}r4   FN)rJ  r\   rW  r   rX  r7   r   r   r   r  Zdecompress_message_datar   r   r   r  rI   rJ   rZ  r  r   r[  r   r-   Z_onMessageFrameData)rA   r   ZcompressedLenZuncompressedLenlr1   r1   r2   rR  \  s,    

zWebSocketProtocol.onFrameDatac             C   s   | j jdkr,| jr"| j| j | j | j  n| jtjkrH| j	 j
d7  _
| jr^| j| j | j | j  | jrt| j  | j jr| jr| jj  | jr| jd s| jdj| jd rdS | jtjkr| j	 jd7  _| j  d| _d| _ dS )z(
        End of frame received.
        rF  rb   zTUTF-8 text message payload ended within Unicode code point at payload octet index {}r4   FN)rJ  r\   r   r+  rW  processControlFramer   r   r   r  rK   r   Z_onMessageFrameEndr   _cancelAutoPingTimeoutCallr]   rX  r  Zend_decompress_messagerZ  r[  r   r-   rL   Z_onMessageEndrL  )rA   r1   r1   r2   rS    s.    


zWebSocketProtocol.onFrameEndc          	   C   s,  dj | j}d| _| jjdkrtd}d}t|}|dkrbtjd|dd d }|dkrb|dd }| j||rrdS n| jjd	kr| j| n| jjd
kr(| j	ry`|| j	kr| j
jd | jr| jj  d| _	d| _| jr| jjj| j| j| _n| j
jd W n   | j
jd Y nX | j| n dS )z>
        Process a completely received control frame.
        r   Nrx   rb   z!Hr   r   FrH  rw   z8Auto ping/pong: received pending pong for auto-ping/pongz)Auto ping/pong: received non-pending pongT)r   rW  rJ  r\   r7   rM  rN  r   Z_onPingr  r   r   r   r   r   r   r  r   _sendAutoPingr  Z_onPong)rA   r   r   r   Zllr1   r1   r2   r^    s@    

z%WebSocketProtocol.processControlFramer   Tc	                s  |dk	rft  dk r(td|t  f |}	dj fddt|t   D  d|t     }
nt  }	 }
d}|r|dO }||d	 d
> O }||d O }d}|s| jj r| js| jjo| jr|dO }|stj	dt
jd}|}nd}|	dkr| jrt||	}|j|
}n|
}nd}|
}d}|	dkr<||	O }nH|	dkr\|dO }tj	d|	}n(|	dkr||dO }tj	d|	}ntddj|jdd|jdd|||g}|dkr| j jd7  _| jrt||||	|}| j| ||| | j||| dS )aO  
        Send out frame. Normally only used internally via sendMessage(),
        sendPing(), sendPong() and sendClose().

        This method deliberately allows to send invalid frames (that is frames
        invalid per-se, or frames invalid because of protocol state). Other
        than in fuzzing servers, calling methods will ensure that no invalid
        frames are sent.

        In addition, this method supports explicit specification of payload
        length. When payload_len is given, it will always write that many
        octets to the stream. It'll wrap within payload, resending parts of
        that when more octets were requested The use case is again for fuzzing
        server which want to sent increasing amounts of payload data to peers
        without having to construct potentially large messages themselves.
        Nrb   zJcannot construct repeated payload with length %d from payload of length %dr   c                s   g | ]} qS r1   r1   ).0_)r   r1   r2   
<listcomp>
  s    z/WebSocketProtocol.sendFrame.<locals>.<listcomp>r   rF  rx   r   rC  z!I    rG  i  rI  z!Hl    rE  z!Qzinvalid payload lengthbigr   rC  rC  )r   rb   r   )r7   r   r   ranger   r   r   r   rM  packrandomgetrandbitsr   r   rQ  to_bytesr  rF   r   r[   r-  r=  )rA   r\   r   r]   r^   r`   r   r,  r$  r]  plb0b1mvZmaskerplmelri   r*  r1   )r   r2   	sendFrame  sT    :$




$
zWebSocketProtocol.sendFramec             C   sP   | j tjkrdS |r@t|}|dkr0td| | jd|d n| jdd dS )z]
        Implements :func:`autobahn.websocket.interfaces.IWebSocketChannel.sendPing`
        NrG  z@invalid payload for PING (payload length must be <= 125, was %d)rH  )r\   r   )r\   )r   r   r   r7   r   rq  )rA   r   r]  r1   r1   r2   sendPingL  s    zWebSocketProtocol.sendPingc             C   sb   | j jd d | _t| jjd| _| j| j | jr^| j jd| jd | j	j
j| j| j| _d S )Nz+Auto ping/pong: sending ping auto-ping/pongr   z6Expecting ping in {seconds} seconds for auto-ping/pong)seconds)r   r   r  r   r   encoder  rr  r   r   r  r   r   r   )rA   r1   r1   r2   r`  Z  s    
zWebSocketProtocol._sendAutoPingc             C   sd   | j jd | jj  d| _d| _| jr8| jj  d| _| jr`| j jd | jjj	| j| j
| _dS )z
        When data is received from client, use it in leu of timely PONG response - cancel pending timeout call
        that will drop connection
        z3Cancelling autoPingTimeoutCall due to incoming dataNzScheduling auto-ping/pong)r   r   r   r   r  r  r   r   r  r   r`  )rA   r1   r1   r2   r_  n  s    

z,WebSocketProtocol._cancelAutoPingTimeoutCallc             C   sP   | j tjkrdS |r@t|}|dkr0td| | jd|d n| jdd dS )z]
        Implements :func:`autobahn.websocket.interfaces.IWebSocketChannel.sendPong`
        NrG  z@invalid payload for PONG (payload length must be <= 125, was %d)rw   )r\   r   )r\   )r   r   r   r7   r   rq  )rA   r   r]  r1   r1   r2   r     s    zWebSocketProtocol.sendPongc             C   s   | j tjkr| jjd n| j tjkr4| jjd n| j tjtjgkrPtdn| j tj	krd}|dk	rx|t
jd|7 }|dk	r||7 }| jd|d tj| _ | | _|| _|| _| jr| jd	kr| jjj| j| j| _ntd
dS )z
        Send a close frame and update protocol state. Note, that this is
        an internal method which deliberately allows not send close
        frame with invalid payload.
        z3ignoring sendCloseFrame since connection is closingz7ignoring sendCloseFrame since connection already closedz+cannot close a connection not yet connectedr   Nz!Hrx   )r\   r   r   zlogic error)r   r   r   r   r   r   r   r   r   r   rM  rg  rq  r  r  r  r   r   r  r   r   r   )rA   r   r   r   r   r1   r1   r2   r     s,    
z WebSocketProtocol.sendCloseFramec             C   s   |dk	rVt |tkr&tdjt ||dkrVd|  ko@dkn   rVtdj||dk	r|dkrntdt |tkrtdjt |t|d	}nd}| j||d
d dS )z^
        Implements :func:`autobahn.websocket.interfaces.IWebSocketChannel.sendClose`
        Nz5invalid type '{}' for close code (must be an integer)i  i  i  z9invalid close code {} (must be 1000 or from [3000, 4999])zclose reason without close codez)reason must be of type unicode (was '{}')r   F)r   r   r   )typeintr   r-   strr   r   )rA   r   r   r   r1   r1   r2   	sendClose  s    "zWebSocketProtocol.sendClosec             C   sz   | j tjkrdS | jtjkr$td|r.tjntj| _tj	| _| j
dk	r`| r`d| _| j
j  nd| _| j jd7  _dS )za
        Implements :func:`autobahn.websocket.interfaces.IWebSocketChannel.beginMessage`
        Nz?WebSocketProtocol.beginMessage invalid in current sending stateTFrb   )r   r   r   r  r  r   r\  rY  send_message_opcodeSEND_STATE_MESSAGE_BEGINr  send_compressedstart_compress_messager  rG   )rA   r   r>  r1   r1   r2   beginMessage  s    zWebSocketProtocol.beginMessagec             C   s  | j tjkrdS | jtjtjgkr0td| j t|tksL|dk sL|dkrTtd|| _	| j
 jd7  _| jj rz| js| jjr| jrtjdtjd| _nd| _| jr|dkr| jrt| j|| _nt | _d}| jtjkr
|| jd	 O }| jr |dO }tj| _n d}| jr&|dO }| j}nd}d}|dkrB||O }nH|dkrb|dO }tjd|}n(|dkr|dO }tjd|}ntddj|jdd|jdd||g}| j| tj| _dS )zf
        Implements :func:`autobahn.websocket.interfaces.IWebSocketChannel.beginMessageFrame`
        NzIWebSocketProtocol.beginMessageFrame invalid in current sending state [%d]r   l    z&invalid value for message frame lengthrb   z!Ird  rC  r   rx   rF  r   rG  i  rI  z!HrE  z!Qzinvalid payload lengthre  r   @   rC  )r   r   r   r  rz  SEND_STATE_INSIDE_MESSAGEr   ru  rv  send_message_frame_lengthr  rF   r   r   r   r   rM  rg  rh  ri  Zsend_message_frame_maskr   r   send_message_frame_maskerr   ry  r{  r   rj  r=  SEND_STATE_INSIDE_MESSAGE_FRAME)rA   r_   rl  rm  rn  rp  headerr1   r1   r2   beginMessageFrame  sL    




"
z#WebSocketProtocol.beginMessageFramec             C   s   | j tjkrdS | js*| j jt|7  _| j jt|7  _| jtj	krRt
dt|}| jj | | jkr| j| jj  }||  }|d| }n|}| j| jj  | }|}| jj|}| j||d | jj | jkrtj| _|S )zi
        Implements :func:`autobahn.websocket.interfaces.IWebSocketChannel.sendMessageFrameData`
        NzGWebSocketProtocol.sendMessageFrameData invalid in current sending state)r$  )r   r   r   r{  r  rE   r7   rD   r  r  r   r  rP  r  rQ  r=  r  )rA   r   r$  rlr]  rU  rk  ro  r1   r1   r2   sendMessageFrameDataI  s(    
z&WebSocketProtocol.sendMessageFrameDatac             C   sV   | j tjkrdS | jr6| jj }| j jt|7  _nd}| j	d|dd tj
| _dS )z_
        Implements :func:`autobahn.websocket.interfaces.IWebSocketChannel.endMessage`
        Nr   r   T)r\   r   r]   )r   r   r   r{  r  end_compress_messager  rD   r7   rq  r  r  )rA   r   r1   r1   r2   
endMessaget  s    
zWebSocketProtocol.endMessagec             C   sT   | j tjkrdS | jr6| j jt|7  _| jj|}| j	t| | j
|| dS )ze
        Implements :func:`autobahn.websocket.interfaces.IWebSocketChannel.sendMessageFrame`
        N)r   r   r   r{  r  rE   r7   r  compress_message_datar  r  )rA   r   r$  r1   r1   r2   sendMessageFrame  s    z"WebSocketProtocol.sendMessageFramec             C   s  t |tkstdjt |t |tks<tdjt ||dksbt |tksbtdjt |t |tkstdjt |t |tkstdjt || jtjkrt	d| j
r| j
jd |rd	}nd
}| j jd
7  _| jdk	o| rTd}| jj  | j jt|7  _| jj|}| jj }	dj||	g}t|}
| j j|
7  _n,d}t|}
| j j|
7  _| j j|
7  _d| j  k o|
k n  rd| _dj|
| j}| jj| t||dk	r|}n| jdkr| j}nd}|dkst||kr$| j||||rdndd n|d
k r:td| t|}d}d}d}xz|s|| }||krpd}|}|r| j|||| |||rdndd d}n| jd||| ||d ||7 }qPW dS )z`
        Implements :func:`autobahn.websocket.interfaces.IWebSocketChannel.sendMessage`
        z,"payload" must have type bytes, but was "{}"z,"isBinary" must have type bool, but was "{}"Nz/"fragmentSize" must have type int, but was "{}"z("sync" must have type bool, but was "{}"z1"doNotCompress" must have type bool, but was "{}"z$Attempt to send on a closed protocolr@  r   rb   Tr   Fr   zQtried to send WebSocket message with size {} exceeding payload limit of {} octetsr   )r\   r   r$  r^   z1payload fragment size must be at least 1 (was %d))r\   r   r]   r$  r^   )r\   r   r]   r$  )ru  bytesAssertionErrorr-   boolrv  r   r   r   r   r   rv   r  rG   r  r|  rE   r7   r  r  r   rD   r   r   r   r  r   r   rq  r   )rA   r   r   ZfragmentSizer$  r>  r\   ZsendCompressedZpayload1Zpayload2r   emsgZpfsr:  rn   r;  firstr<  r1   r1   r2   r@    sl    	&




&zWebSocketProtocol.sendMessagec             C   sB  g }dd |j dD }x"|D ]}|dkr dd |j dD }t|dkr |d j }i }x|dd	 D ]}	d
d |	j dD }	|	d j }
t|	dkrdj|	dd	 }|rt|dkr|d dkr|dd	 }t|dko|d dkr|d	d }nd}|
|krg ||
< ||
 j| qlW |j||f q q W |S )z<
        Parse the Sec-WebSocket-Extensions header.
        c             S   s   g | ]}t |j qS r1   )rw  rf   )ra  xr1   r1   r2   rc    s    z<WebSocketProtocol._parseExtensionsHeader.<locals>.<listcomp>, c             S   s   g | ]}|j  qS r1   )rf   )ra  r  r1   r1   r2   rc    s    ;r   rb   Nc             S   s   g | ]}|j  qS r1   )rf   )ra  r  r1   r1   r2   rc  	  s    ="Tr  )splitr7   r&   r   r   )rA   r  removeQuotes
extensionsextsr9  ext	extensionparamspro   rp   r1   r1   r2   _parseExtensionsHeader  s2    
z(WebSocketProtocol._parseExtensionsHeader)F)FN)r   Tr   NNNF)N)N)NNF)NN)FF)F)F)FNFF)T)crX   rY   rZ   ra   r   SUPPORTED_SPEC_VERSIONSSUPPORTED_PROTOCOL_VERSIONSSPEC_TO_PROTOCOL_VERSIONZPROTOCOL_TO_SPEC_VERSIONDEFAULT_SPEC_VERSION	_WS_MAGICr8  rY  r\  r   r   r   r   r   r  rz  r  r  r   ZCLOSE_STATUS_CODE_GOING_AWAYr  Z"CLOSE_STATUS_CODE_UNSUPPORTED_DATAZCLOSE_STATUS_CODE_RESERVED1ZCLOSE_STATUS_CODE_NULLr   r  Z"CLOSE_STATUS_CODE_POLICY_VIOLATIONr  Z%CLOSE_STATUS_CODE_MANDATORY_EXTENSIONZ CLOSE_STATUS_CODE_INTERNAL_ERRORZ!CLOSE_STATUS_CODE_SERVICE_RESTARTZ!CLOSE_STATUS_CODE_TRY_AGAIN_LATERZCLOSE_STATUS_CODE_UNASSIGNED1Z&CLOSE_STATUS_CODE_TLS_HANDSHAKE_FAILEDr   CONFIG_ATTRS_COMMONCONFIG_ATTRS_SERVERCONFIG_ATTRS_CLIENTrB   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r   r   r
  r  r!  r#  r%  r+  r-  r/  r.  r1  r2  r4  r3  r=  rB  r0  rO  rR  rS  r^  rq  rr  r`  r_  r   r   rx  r}  r  r  r  r  r@  r  r1   r1   r1   r2   r   d  s&  	

	
	c

t5*	
%	 p)')C      
W


+

U
+
   
Zc               @   s   e Zd ZdZdd ZdS )PreparedMessagez
    Encapsulates a prepared message to be sent later once or multiple
    times on one or more WebSocket connections.
    This can be used for optimizing Broadcast/PubSub.
    c             C   s   |s|| _ || _|| _t|}|r&dnd}|rdd}tjdtjd}|dkrR|}	qpt||j	|}	nd}d}|}	d}
|dkr||O }nD|d	kr|d
O }tjd|}
n&|dkr|dO }tjd|}
nt
ddj|jdd|jdd|
||	g| _dS )a  
        Ctor for a prepared message.

        :param payload: The message payload.
        :type payload: str
        :param isBinary: Provide `True` for binary payload.
        :type isBinary: bool
        :param applyMask: Provide `True` if WebSocket message is to be masked (required for client to server WebSocket messages).
        :type applyMask: bool
        :param doNotCompress: Iff `True`, never compress this message. This
            only applies when WebSocket compression has been negotiated on the
            WebSocket connection. Use when you know the payload incompressible
            (e.g. encrypted or already compressed).
        :type doNotCompress: bool
        rb   rF  r   z!Ird  r   r   rG  i  rI  z!Hl    rE  z!Qzinvalid payload lengthre  NrC     rC     rC  )r   rA  r>  r7   rM  rg  rh  ri  r   rQ  r   r   rj  r?  )rA   r   r   r   r>  r]  rl  rm  r`   ro  rp  r1   r1   r2   rB   $	  s4    
zPreparedMessage.__init__N)rX   rY   rZ   ra   rB   r1   r1   r1   r2   r  	  s   r  c               @   s   e Zd ZdZdddZdS )r   z
    Mixin for
    :class:`autobahn.websocket.protocol.WebSocketClientFactory` and
    :class:`autobahn.websocket.protocol.WebSocketServerFactory`.
    Fc             C   s   | j  }t||||S )a+  
        Prepare a WebSocket message. This can be later sent on multiple
        instances of :class:`autobahn.websocket.WebSocketProtocol` using
        :meth:`autobahn.websocket.WebSocketProtocol.sendPreparedMessage`.

        By doing so, you can avoid the (small) overhead of framing the
        *same* payload into WebSocket messages multiple times when that
        same payload is to be sent out on multiple connections.

        :param payload: The message payload.
        :type payload: bytes
        :param isBinary: `True` iff payload is binary, else the payload must be
            UTF-8 encoded text.
        :type isBinary: bool
        :param doNotCompress: Iff `True`, never compress this message. This
            only applies when WebSocket compression has been negotiated on the
            WebSocket connection. Use when you know the payload incompressible
            (e.g. encrypted or already compressed).
        :type doNotCompress: bool

        :returns: obj -- An instance of :class:`autobahn.websocket.protocol.PreparedMessage`.
        )r   r  )rA   r   r   r>  r   r1   r1   r2   prepareMessagek	  s    zWebSocketFactory.prepareMessageN)FF)rX   rY   rZ   ra   r  r1   r1   r1   r2   r   d	  s   a-  <!DOCTYPE html>
<html>
   <head>
      %s
      <style>
         body {
            color: #fff;
            background-color: #027eae;
            font-family: "Segoe UI", "Lucida Grande", "Helvetica Neue", Helvetica, Arial, sans-serif;
            font-size: 16px;
         }

         a, a:visited, a:hover {
            color: #fff;
         }
      </style>
   </head>
   <body>
      <h1>AutobahnPython %s</h1>
      <p>
         I am not Web server, but a <b>WebSocket Endpoint</b>.
      </p>
      <p>
         You can talk to me using the <a href="http://tools.ietf.org/html/rfc6455">WebSocket</a> protocol.
      </p>
      <p>
         For more information, please see:
         <ul>
            <li><a href="http://crossbar.io/autobahn">Autobahn</a></li>
         </ul>
      </p>
   </body>
</html>
c               @   s   e Zd ZdZej Zejej	 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dZdd Zdd ZdddZdS )r   z4
    Protocol base class for WebSocket servers.
    c             C   s   dS )a.  
        Callback fired during WebSocket opening handshake when new WebSocket client
        connection is about to be established.

        When you want to accept the connection, return the accepted protocol
        from list of WebSocket (sub)protocols provided by client or `None` to
        speak no specific one or when the client protocol list was empty.

        You may also return a pair of `(protocol, headers)` to send additional
        HTTP headers, with `headers` being a dictionary of key-values.

        Throw :class:`autobahn.websocket.types.ConnectionDeny` when you don't want
        to accept the WebSocket connection request.

        :param request: WebSocket connection request information.
        :type request: instance of :class:`autobahn.websocket.protocol.ConnectionRequest`
        Nr1   )rA   requestr1   r1   r2   	onConnect	  s    z!WebSocketServerProtocol.onConnectc             C   s0   t j|  | j jd7  _| jjd| jd dS )a1  
        Called by network framework when new transport connection from client was
        accepted. Default implementation will prepare for initial WebSocket opening
        handshake. When overriding in derived class, make sure to call this base class
        implementation *before* your code.
        rb   z$connection accepted from peer {peer})r   N)r   r  r   countConnectionsr   r   r   )rA   r1   r1   r2   r  	  s    
z'WebSocketServerProtocol._connectionMadec             C   s    t j| | | j jd8  _dS )a!  
        Called by network framework when established transport connection from client
        was lost. Default implementation will tear down all state properly.
        When overriding in derived class, make sure to call this base class
        implementation *after* your code.
        rb   N)r   r!  r   r  )rA   r   r1   r1   r2   r!  	  s    z'WebSocketServerProtocol._connectionLostc             C   s   t dd S )NzAutobahn isn't a proxy server)r   )rA   r1   r1   r2   r1  	  s    z+WebSocketServerProtocol.processProxyConnectc       %   <      sL	   j jd}|dkrֈ j d|d   _ jjd jd yt j\ _ _}W n, tk
r } z j	dj
|S d}~X nX d jkrƈ jrd	d
  jd jdD }| j d }|d  _ jjd jd  jjd jd  jj }t|dkr j	d j S |d j dkr8 j	d|d  dS |d j jd}t|dkst|d dkst|d dhkr j	d|d  dS |d j  _yZtj j\}}	}
}}}|dks|	dkr|dkr܈ j	d| S |
 _tj| _W n    j	d|d j  S d jkr$ j	d S |d dkr< j	d!S  jd j  _ jjd"dkr jjd# r jjd"d\}}ytt|j }W n2 tk
r    j	d$t|j t jf S X  jjr | jjkr j	d%|t j jjf S n jjd& | _nl jjrt jjr6 jjd'kpL jj oL jjd(ks j	d)t j jj jjf S n jjd& d* jkr` jrTd+ jkr0t jd+ dkr0 jd+ d }d, jkrt jd, dkrt jd, d } jjd-||d.  j || n jjd/|d0  j!| n jjd1  j    j"d2d3 dS  j	d4d5S d2}x2 jd* jdD ]}|j j# d6krvd7}P qvW |s j	d8 jd*  S d9 jkrȈ j	d:S d2}x2 jd9 jdD ]}|j j# d*krd7}P qW |s j	d; jd9  S d< jkr< jjd=  j	d>S  jjd? |d< dkr` j	d@S yt jd< }W n& tk
r    j	dA jd<  S X | j$krt% j$}|j&  dj'dBd
 |D } j	dC||f dDdE|fgS | _(dF jkrPdGd
  jdF jdD }i }x.|D ]&}||kr: j	dH| S d||< qW | _)ng  _) j(dIk rhdJ}ndK}d _*| jkr|| dkr j	dLS  j| j  _*yt+ j*}W n. tk
r } z j	dMj
|S d}~X nX d7}nd2}|rR|dNkr jj,rd7}n,t-| jjr dOndP jjp2 jj. j/}|sR j	dQj
 j*S dR jkrh j	dSS |dR dkr j	dTS  jdR j } t| dUkr j	dV|  S | did dWkrʈ j	dX|  S x2| ddj D ]"}|dYkr؈ j	dZ|| f S qW g  _0d[ jkr:|d[ dkr( j	d\S  j1 jd[  _0 j |d d  _ |  _2 j3dkr jj4 j3kr j	d]d^d_ nTt5 j j j j j j( j* j) j0	}!t6j7 j8|!}" fd`da}#t6j9|" j:|# nr j;	rH j jdb}$|$dk	rH jjdc  j;	r< jjdd j<de  j= j<j>df d7 _? j"  n jjdg dS )kzJ
        Process WebSocket opening handshake request from client.
        s   

r   Nr   z received HTTP request:

{data}

)rh   z@Error during parsing of HTTP status line / request headers : {0}zx-forwarded-forc             S   s   g | ]}|j  qS r1   )rf   )ra  r  r1   r1   r2   rc  	  s    z<WebSocketServerProtocol.processHandshake.<locals>.<listcomp>r  z9received HTTP status line in opening handshake : {status})statusz6received HTTP headers in opening handshake : {headers})headersr4   z!Bad HTTP request status line '%s'GETzHTTP method '%s' not allowedi  r   /HTTPrb   1.1zUnsupported HTTP version '%s'i  r  z;HTTP requested resource contains a fragment identifier '%s'z0Bad HTTP request resource - could not parse '%s'r0   z5HTTP Host header missing in opening handshake requestzDHTTP Host header appears more than once in opening handshake requestrc   ]z*invalid port '%s' in HTTP Host header '%s'zHport %d in HTTP Host header '%s' does not match server listening port %szOskipping opening handshake port checking - neither WS URL nor external port seti  r#   zXmissing port in HTTP Host header '%s' and server runs on non-standard port %d (wss = %s)upgraderedirectafterzvHTTP Upgrade header missing : render server status page and meta-refresh-redirecting to {url} after {duration} seconds)r.   durationz6HTTP Upgrade header missing : 303-redirecting to {url})r.   z7HTTP Upgrade header missing : render server status pageF)r   zHTTP Upgrade header missingi  	websocketTzMHTTP Upgrade headers do not include 'websocket' value (case-insensitive) : %s
connectionzHTTP Connection header missingzNHTTP Connection headers do not include 'upgrade' value (case-insensitive) : %szsec-websocket-versionzHixie76 protocol detectedz=WebSocket connection denied - Hixie76 protocol not supported.zHybi protocol detectedzUHTTP Sec-WebSocket-Version header appears more than once in opening handshake requestzScould not parse HTTP Sec-WebSocket-Version header '%s' in opening handshake requestc             S   s   g | ]}t |qS r1   )rw  )ra  r  r1   r1   r2   rc  
  s    z;WebSocket version %d not supported (supported versions: %s)i  zSec-WebSocket-Versionzsec-websocket-protocolc             S   s   g | ]}t |j qS r1   )rw  rf   )ra  r  r1   r1   r2   rc  
  s    zGduplicate protocol '%s' specified in HTTP Sec-WebSocket-Protocol headerr   zsec-websocket-originoriginzFHTTP Origin header appears more than once in opening handshake requestzHTTP Origin header invalid: {}r!   r$   r%   z5WebSocket connection denied: origin '{0}' not allowedzsec-websocket-keyz%HTTP Sec-WebSocket-Key header missingzQHTTP Sec-WebSocket-Key header appears more than once in opening handshake request   z:bad Sec-WebSocket-Key (length must be 24 ASCII chars) '%s'z==z4bad Sec-WebSocket-Key (invalid base64 encoding) '%s'z@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/zFbad character '%s' in Sec-WebSocket-Key (invalid base64 encoding) '%s'zsec-websocket-extensionszXHTTP Sec-WebSocket-Extensions header appears more than once in opening handshake requestz%maximum number of connections reachedi  )r   c                sb   t | jtr" j| jj| jj n< jjd| d  jjdtj	| d  jdj
| jtjS d S )Nz1Unexpected exception in onConnect ['{err.value}'])errz{tb})tbzInternal server error: {})r5   rp   r   failHandshaker   r   r   r  r   Zfailure_format_tracebackr-   INTERNAL_SERVER_ERROR)r  )rA   r1   r2   forward_error!  s
    z?WebSocketServerProtocol.processHandshake.<locals>.forward_errors   <policy-file-request/> z)received Flash Socket Policy File requestz+sending Flash Socket Policy File :
{policy})policyr   zNo Flash Policy File served. You might want to serve a Flask Socket Policy file on the destination port since you received a request for it. See WebSocketServerFactory.serveFlashSocketPolicy and WebSocketServerFactory.flashSocketPolicy)r  r  )@rh   rg   http_request_datar   r   rq   rj   rk   r   r  r-   r   r  r   r7   rf   Zhttp_request_urir   urlparseZhttp_request_pathparse_qsZhttp_request_paramsZhttp_request_hostendswithrsplitrv  rw  r,   r   externalPortisSecurer   sendServerStatussendRedirectr   r&   r   sortedreverser   r   websocket_protocolsr9   r3   r   r>   r*   r   websocket_extensionsr  _wskeyr   r  r	   r   	as_futurer  r   succeedHandshaker   r   r=  rt  r  )%rA   end_of_headerrl   r9  	addressesZtrusted_addressesr  vsr(   netlocpathr  queryfragmentrm   r  r*   r.   r  ZupgradeWebSocketr   connectionUpgradecr   svZsvs	protocolsppZwebsocket_origin_header_keyZorigin_tupleZhave_originZorigin_is_allowedro   r  r   r  Zflash_policy_file_requestr1   )rA   r2   r2  	  s   





*


""
 
2$  















z(WebSocketServerProtocol.processHandshakec             C   s  d}i }t |tkr>t|dkr(|d }t|dkrB|d }n|}|dk	r\|| jkr\td|| _| j}g | _g }g }x| jD ]\}}| j	j
d||d |tkrt| }	y|	d j|}
|j|
 W n* tk
r } z| jt|S d}~X nX q~| j	j
d|d	 q~W t|dkrv| j|}|dk	rft|j }	|	d
 j| jj|| _| jj| j |j|j  n| j	j
d|d d}| jjr|d| jj 7 }|d7 }|d7 }x| jjj |j fD ]}x|D ]z}t|d tfr|d g}n2yt|d }W n  tk
r   |d g}Y nX x"|D ]}|d|d |f 7 }qW qW qW | jdk	rf|dt| j 7 }tj }|j|j dt!j"  t#j$|j% }|d|j&  7 }t|dkr|ddj'| 7 }|d7 }d}| j	j
d|d | j(|j d |r| j	j
dt)|d | j(| || _*t!j+| _,| j-dk	rH| j	j
d | j-j.  d| _-d| _/d| _0| j1rr| jj2j3| j1| j4| _5| j6r| j6j7d | j8  t9j:| j;d t| j<dkr| j=  dS )zl
        Callback after onConnect() returns successfully. Generates the response for the handshake.
        Nr   rb   z;protocol accepted must be from the list client sent or Nonez?parsed WebSocket extension '{extension}' with params '{params}')r  r  ZOfferzSclient requested '{extension}' extension we don't support or which is not activated)r  PMCEzXclient request permessage-compress extension, but we did not accept any offer [{offers}])Zoffersz"HTTP/1.1 101 Switching Protocols
zServer: %s
zUpgrade: WebSocket
zConnection: Upgrade
z%s: %s
zSec-WebSocket-Protocol: %s
r   zSec-WebSocket-Accept: %s
zSec-WebSocket-Extensions: %s
z, z
z"sending HTTP response:

{response})responsez%sending HTTP response body:

{octets})r"  zopenHandshakeTimeoutCall.cancelFr   )>ru  r6   r7   r  r   websocket_protocol_in_user  websocket_extensions_in_user  r   r   r   r   r   r  rw  r   rK  Zcreate_from_offer_acceptr   r   r  get_extension_stringserverr  itemsr5   iter	TypeErrorhashlibsha1updatert  r   r  base64	b64encodedigestrd   r   r=  r   http_response_datar   r   r   r   rL  rJ  r   r  r   r`  r  r   rv   _onOpenr   r  r   rh   r.  )rA   r/   protocolr  ro   ZextensionResponseZ
pmceOffersr  r  r  offerr9  acceptr  Zheaders_sourceuhheader_valuesheader_valuer  sec_websocket_acceptZresponse_bodyr1   r1   r2   r  F  s    






&


z(WebSocketServerProtocol.succeedHandshake  Nc             C   s4   || _ | jjd|d | j||| | jdd dS )z
        During opening handshake the client request was invalid, we send a HTTP
        error response and then drop the connection.
        z0failing WebSocket opening handshake ('{reason}'))r   F)r   N)r   r   infosendHttpErrorResponser   )rA   r   r   responseHeadersr1   r1   r2   r    s    z%WebSocketServerProtocol.failHandshakec             C   sR   dj ||}|r6x$|D ]}|dj |d |d 7 }qW |d7 }| j|jd dS )z/
        Send out HTTP error response.
        zHTTP/1.1 {0} {1}
z
{0}: {1}
r   rb   z
r   N)r-   r=  rt  )rA   r   r   r  r  rm   r1   r1   r2   r    s    
z-WebSocketServerProtocol.sendHttpErrorResponsec             C   st   |j d}d}| jjdk	r6| jjdkr6|d| jj 7 }|d7 }|dt| 7 }|d7 }| j|j d | j| dS )	z/
        Send HTML page HTTP response.
        r   zHTTP/1.1 200 OK
Nr  zServer: %s
z(Content-Type: text/html; charset=UTF-8
zContent-Length: %d
z
)rt  r   r  r7   r=  )rA   htmlZresponseBodyr  r1   r1   r2   sendHtml
  s    
z WebSocketServerProtocol.sendHtmlc             C   sT   d}| j jdk	r,| j jdkr,|d| j j 7 }|d| 7 }|d7 }| j|jd dS )z4
        Send HTTP Redirect (303) response.
        zHTTP/1.1 303
Nr  zServer: %s
zLocation: %s
z
r   )r   r  r=  rt  )rA   r.   r  r1   r1   r2   r    s    z$WebSocketServerProtocol.sendRedirectr   c             C   s,   |rd||f }nd}| j t|tf  dS )z
        Used to send out server status/version upon receiving a HTTP/GET without
        upgrade to WebSocket header (and option serverStatus is True).
        z1<meta http-equiv="refresh" content="%d;URL='%s'">r  N)r  _SERVER_STATUS_TEMPLATEr   )rA   ZredirectUrlZredirectAfterr  r1   r1   r2   r  #  s    z(WebSocketServerProtocol.sendServerStatus)r  N)N)Nr   )rX   rY   rZ   ra   r   make_loggerr   r   r  r  r  r  r  r!  r1  r2  r  r  r  r  r  r  r1   r1   r1   r2   r   	  s"   
  i 0


c               @   s\   e Zd ZdZej ZeZdZ	ddde
 ddfddZdddZd	d
 ZdddZdd ZdS )r   z
    A protocol factory for WebSocket servers.

    Implements :func:`autobahn.websocket.interfaces.IWebSocketServerChannelFactory`
    TNzAutobahnPython/%sc             C   sN   d| _ d| _d| _tjddd| _tj  | j||||| | j	  d| _
dS )zj
        Implements :func:`autobahn.websocket.interfaces.IWebSocketServerChannelFactory.__init__`
        Fg?i  )bucket_seconds
chunk_sizer   N)r   r   r   r   make_batched_timerr  rh  seedsetSessionParametersresetProtocolOptionsr  )rA   r.   r  r  r  r  r1   r1   r2   rB   B  s    	
zWebSocketServerFactory.__init__c             C   s   t |pd\}}}}	}
}t|dkr,td|| _|| _|| _|| _|	| _|
| _|| _	|p\g | _
|| _|pli | _|r||| _n|r| j| _nd| _dS )zv
        Implements :func:`autobahn.websocket.interfaces.IWebSocketServerChannelFactory.setSessionParameters`
        zws://localhostr   z3query parameters specified for server WebSocket URLN)r   r7   r   r.   r  r0   r*   resourcer  r  r  r  r  r  )rA   r.   r  r  r  r  r  r0   r*   r  r  r  r1   r1   r2   r  d  s$    


z+WebSocketServerFactory.setSessionParametersc             C   s   t j| _d| _d| _d| _d| _d| _d| _d| _	d| _
d| _d| _d| _d| _d| _d| _d| _dd | _d| _d| _d	| _d
g| _t| j| _d| _d| _d| _dS )zv
        Implements :func:`autobahn.websocket.interfaces.IWebSocketServerChannelFactory.resetProtocolOptions`
        TFr      rb   z`<cross-domain-policy>
     <allow-access-from domain="*" to-ports="*" />
</cross-domain-policy> c             S   s   d S )Nr1   )rb  r1   r1   r2   <lambda>  s    z=WebSocketServerFactory.resetProtocolOptions.<locals>.<lambda>r   *N)r   r  r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )rA   r1   r1   r2   r    s2    
z+WebSocketServerFactory.resetProtocolOptionsFc             C   sB  |dk	rNx,|D ]$}|t jkrtd|tt jf qW t|t| jkrN|| _|dk	rf|| jkrf|| _|dk	r~|| jkr~|| _|dk	r|| jkr|| _|dk	r|| j	kr|| _	|dk	r|| j
kr|| _
|dk	r|| jkr|| _|dk	r|| jkr|| _|	dk	r|	| jkr|	| _|
dk	r.|
| jkr.|
| _|dk	rJ|| jkrJ|| _|dk	rf|| jkrf|| _|dk	r|| jkr|| _|dk	r|| jkr|| _|dk	r|| jkr|| _|dk	r|| jkr|| _|dk	r|| jkr|| _|dk	rN|| jkrNt|tks(t|tks(td|  ko<dkn  sHt|| _|dk	rj|| jkrj|| _|dk	r|| jkr|| _|dk	r|| jkr|| _t| j| _|d	krt d|| _!|dk	r|| j"krt|tkst|dkst|| _"|dk	r>|| j#kr>t|tks*t|dks8t|| _#dS )
zt
        Implements :func:`autobahn.websocket.interfaces.IWebSocketServerChannelFactory.setProtocolOptions`
        Nz:invalid WebSocket protocol version %s (allowed values: %s)r   rG  TFzallowNullOrigin must be a boolr   )TF)$r   r  r   rw  setr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   ru  rS   rv  r  r   r   r   r   r   r,   r   r   r   )rA   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   vr1   r1   r2   setProtocolOptions  sx    

  
z)WebSocketServerFactory.setProtocolOptionsc             C   s   | j S )z}
        Get number of currently connected clients.

        :returns: int -- Number of currently connected clients.
        )r  )rA   r1   r1   r2   getConnectionCount!  s    z)WebSocketServerFactory.getConnectionCount)NNNNN)NNNNNNNNNNNNNNNNNNNNNFNN)rX   rY   rZ   ra   r   r   r   r   r  r   r   rB   r  r  r  r  r1   r1   r1   r2   r   /  sP       
-                       
Xc               @   s|   e Zd ZdZej Zejej	 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 Zdd Zdd ZdS )r   z4
    Protocol base class for WebSocket clients.
    c             C   s   dS )a  
        :param transport_details: a :class:`autobahn.websocket.types.TransportDetails`

        Callback fired after the connection is established, but before the
        handshake has started. This may return a
        :class:`autobahn.websocket.types.ConnectingRequest` instance
        (or a future which resolves to one) to control aspects of the
        handshake (or None for defaults)
        Nr1   )rA   transport_detailsr1   r1   r2   onConnecting3  s    
z$WebSocketClientProtocol.onConnectingc             C   s   dS )a*  
        Callback fired directly after WebSocket opening handshake when new WebSocket server
        connection was established.

        :param response: WebSocket connection response information.
        :type response: instance of :class:`autobahn.websocket.protocol.ConnectionResponse`
        Nr1   )rA   r  r1   r1   r2   r  ?  s    z!WebSocketClientProtocol.onConnectc             C   sH   t j|  | jjd| jd | jj r<| jjdk	r<| j  n| j	  dS )aC  
        Called by network framework when new transport connection to server was established. Default
        implementation will start the initial WebSocket opening handshake (or proxy connect).
        When overriding in derived class, make sure to call this base class
        implementation _before_ your code.
        z connection to {peer} established)r   N)
r   r  r   r   r   r   r   r  startProxyConnectstartHandshake)rA   r1   r1   r2   r  I  s
    

z'WebSocketClientProtocol._connectionMadec             C   s   t j| | dS )a  
        Called by network framework when established transport connection to server was lost. Default
        implementation will tear down all state properly.
        When overriding in derived class, make sure to call this base class
        implementation _after_ your code.
        N)r   r!  )rA   r   r1   r1   r2   r!  Z  s    z'WebSocketClientProtocol._connectionLostc             C   sX   d| j j| j jf }|d| j j| j jf 7 }|d7 }| jjd|d | j|jd dS )z,
        Connect to explicit proxy.
        zCONNECT %s:%d HTTP/1.1
zHost: %s:%d
z
z	{request})r  r   N)r   r0   r*   r   r   r=  rt  )rA   r  r1   r1   r2   r  c  s
    z)WebSocketClientProtocol.startProxyConnectc       
      C   s  | j jd}|dkr| j d|d  }| jjd|d t|\}}}| jjd|d | jjd	|d
 |j }t|dk r| jd| S |d j }|dkr| jd| S yt	|d j }W n& t
k
r   | jd|d j  S X d|  k odk n  s>t|dkr(ddj|dd  }	nd}	| jd||	f S | j |d d | _ tj| _t| j dkrr| j  | jjr| j  | j  dS )z<
        Process HTTP/CONNECT response from server.
        s   

r   Nr   z%received HTTP response:

{response}

)r  z>received HTTP status line for proxy connect request : {status})r  z;received HTTP headers for proxy connect request : {headers})r  r   z"Bad HTTP response status line '%s'HTTP/1.1HTTP/1.0zUnsupported HTTP version ('%s')rb   zBad HTTP status code ('%s')   i,  z - %sr  z HTTP proxy connect failed (%d%s))r  r  )rh   rg   r   r   rq   r  r7   failProxyConnectrf   rv  r,   r   r   r   r   r.  r   r  ZstartTLSr  )
rA   r  r  rj   rk   rl   slhttp_versionstatus_coder   r1   r1   r2   r1  q  sF    

z+WebSocketClientProtocol.processProxyConnectc             C   s    | j jd|d | jdd dS )z
        During initial explicit proxy connect, the server response indicates some failure and we drop the
        connection.
        z"failing proxy connect ('{reason}'))r   T)r   N)r   r   r   )rA   r   r1   r1   r2   r    s    z(WebSocketClientProtocol.failProxyConnectc                s@    j  }tj j|} fdd} fdd}tj||| |S )z4
        Start WebSocket opening handshake.
        c          	      sH   | dkr:t  jj jj jj jj jj jj jjd}  j	|  | S )zE
            onConnecting succeeded and returned options
            N)r0   r*   r  r  	useragentr  r  )
r   r   r0   r*   r  r  r  r  r  _actuallyStartHandshake)request_options)rA   r1   r2   got_options  s    
z;WebSocketClientProtocol.startHandshake.<locals>.got_optionsc                s     j jd| d  jdd d S )NzonConnecting failed: {fail})r   F)r   )r   r   r   )r   )rA   r1   r2   options_failed  s
    z>WebSocketClientProtocol.startHandshake.<locals>.options_failed)Z_create_transport_detailsr   r  r  r   )rA   r  Z	options_dr  r  r1   )rA   r2   r    s    z&WebSocketClientProtocol.startHandshakec             C   s  d|j  }|jdk	r,|jdkr,|d|j 7 }|d|j|jf 7 }|d7 }|d7 }|d7 }|d	7 }x*|jj D ]}|d
|d |d f 7 }qlW tjtj	d| _
|d| j
j  7 }|jr| jdkr|d|j 7 }n|d|j 7 }t|jdkr|ddj|j 7 }g }x| jD ]}|j|j  qW t|dkrF|ddj| 7 }|dtj| j  7 }|d7 }|jd| _| j| j | jjd|d dS )z
        Internal helper.

        Actually send the WebSocket opening handshake after receiving
        valid request options.
        zGET %s HTTP/1.1
Nr  zUser-Agent: %s
zHost: %s:%d
zUpgrade: WebSocket
zConnection: Upgrade
zPragma: no-cache
zCache-Control: no-cache
z%s: %s
r   rb   r   zSec-WebSocket-Key: %s
rw   zOrigin: %s
zSec-WebSocket-Origin: %s
zSec-WebSocket-Protocol: %s
r  zSec-WebSocket-Extensions: %s
z, zSec-WebSocket-Version: %d
z
r   z	{request})r  )r  r  r0   r*   r  r  r  r  osurandomwebsocket_keyrd   r  r   r7   r  r   r   r   r  r   r  rt  r  r=  r   r   )rA   r  r  r  r  r  r1   r1   r2   r    s8    	

z/WebSocketClientProtocol._actuallyStartHandshakec             C   s  | j jd}|dkr| j d|d  | _| jjd| jd t| j\| _| _}| jjd| jd | jjd	| jd
 | jj }t	|dk r| j
d| j S |d j }|dkr| j
d| S yt|d j }W n& tk
r   | j
d|d j  S X |dkr>t	|dkr(ddj|dd  }nd}| j
d||f S d| jkrT| j
dS | jd j j dkr| j
d| jd  S d| jkr| j
dS d}x2| jd jdD ]}|j j dkrd}P qW |s| j
d| jd  S d| jkr| j
d S |d dkr| j
d!S | jd j }	tj }
|
j| jtj  tj|
j j }|	|krl| j
d"||	f S g | _d#| jkr|d# dkr| j
d$S | j| jd# }x|D ]\}}| jjd%||d& |tkrr| jdk	r| j
d'S t| }y|d( j|}W n, tk
r, } z| j
t |S d}~X nX | j!|}|dkrL| j
d)S |d* j"| j#j$|| _| jj%| j n| j
d+| S qW d| _&d,| jkr|d, dkr| j
d-S t | jd, j }|dkr|| j#j'kr| j
d.|t | j#j'f S || _&| j |d d | _ tj(| _)| j*dk	r>| jjd/ | j*j+  d| _*d| _,d| _-| j.| _/| j0rp| j#j1j2| j0| j3| _4y(t5| j6| j| j/| j&| j}| j7| W n6 tk
r } z| j8d0d1j9| W Y dd}~X nX | j:r| j:j;d2 | j<  t=j>| j?d t	| j dkr| j@  dS )3zK
        Process WebSocket opening handshake response from server.
        s   

r   Nr   z%received HTTP response:

{response}

)r  z9received HTTP status line in opening handshake : {status})r  z6received HTTP headers in opening handshake : {headers})r  r   z"Bad HTTP response status line '%s'zHTTP/1.1zUnsupported HTTP version ('%s')rb   zBad HTTP status code ('%s')e   z - %sr  z*WebSocket connection upgrade failed (%d%s)r  zHTTP Upgrade header missingr  zFHTTP Upgrade header different from 'websocket' (case-insensitive) : %sr  zHTTP Connection header missingFr  TzOHTTP Connection header does not include 'upgrade' value (case-insensitive) : %szsec-websocket-acceptzCHTTP Sec-WebSocket-Accept header missing in opening handshake replyzRHTTP Sec-WebSocket-Accept header appears more than once in opening handshake replyz<HTTP Sec-WebSocket-Accept bogus value : expected %s / got %szsec-websocket-extensionszVHTTP Sec-WebSocket-Extensions header appears more than once in opening handshake replyz?parsed WebSocket extension '{extension}' with params '{params}')r  r  z6multiple occurrence of a permessage-compress extensionResponsezMWebSocket permessage-compress extension response from server denied by clientr  z\server wants to use extension '%s' we did not request, haven't implemented or did not enablezsec-websocket-protocolzTHTTP Sec-WebSocket-Protocol header appears more than once in opening handshake replyzTsubprotocol selected by server (%s) not in subprotocol list requested by client (%s)zopenHandshakeTimeoutCall.canceli  z{}r   )Arh   rg   r  r   r   rq   rj   rk   r  r7   r  rf   rv  r,   r   r&   r  r  r  r!  r   r  r  r  r  rd   r  r  r   r  r   r   rw  r   Zcreate_from_response_acceptr   r   r   r  r  r   r   r   r   rL  rJ  r   r   r   r  r   r`  r  r
   r   Z
_onConnectr  r-   r   rv   r  r   r  r   r.  )rA   r  rl   r  r  r  r   r  r  Zsec_websocket_accept_gotr  r  r  r  r  r  ZpmceResponser9  r  spr  r1   r1   r2   r2  =  s    




















$z(WebSocketClientProtocol.processHandshakec             C   s&   || _ | jjd|d | jdd dS )zm
        During opening handshake the server response is invalid and we drop the
        connection.
        z0failing WebSocket opening handshake ('{reason}'))r   T)r   N)r   r   r  r   )rA   r   r1   r1   r2   r    s
    z%WebSocketClientProtocol.failHandshakeN)rX   rY   rZ   ra   r   r   r   r   r  r  r  r  r  r  r!  r  r1  r  r  r  r2  r  r1   r1   r1   r2   r   *  s   
	O,I _c               @   sV   e Zd ZdZej ZeZdZ	dddde
 ddfddZdddZd	d
 ZdddZdS )r    z
    A protocol factory for WebSocket clients.

    Implements :func:`autobahn.websocket.interfaces.IWebSocketClientChannelFactory`
    FNzAutobahnPython/%sc             C   sJ   d| _ d| _d| _tjddd| _tj  | j|||||| | j	  dS )zj
        Implements :func:`autobahn.websocket.interfaces.IWebSocketClientChannelFactory.__init__`
        Fg?i  )r  r  N)
r   r   r   r   r  r  rh  r  r  r  )rA   r.   r  r  r  r  r  r1   r1   r2   rB   ;  s    

zWebSocketClientFactory.__init__c             C   sl   t |pd\}}}	}
}}|| _|| _|| _|	| _|
| _|| _|| _|| _|pNg | _	|| _
|p^i | _|| _dS )zv
        Implements :func:`autobahn.websocket.interfaces.IWebSocketClientChannelFactory.setSessionParameters`
        zws://localhostN)r   r.   r  r0   r*   r  r  r  r  r  r  r  r  )rA   r.   r  r  r  r  r  r  r0   r*   r  r  r  r1   r1   r2   r  Z  s    

z+WebSocketClientFactory.setSessionParametersc             C   s|   t j| _d| _d| _d| _d| _d| _d| _d| _	d| _
d| _d| _d| _d| _d| _g | _dd | _d| _d| _d| _d	S )
zv
        Implements :func:`autobahn.websocket.interfaces.IWebSocketClientChannelFactory.resetProtocolOptions`
        TFr   rb   r  c             S   s   d S )Nr1   )rb  r1   r1   r2   r	    s    z=WebSocketClientFactory.resetProtocolOptions.<locals>.<lambda>r   N)r   r  r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )rA   r1   r1   r2   r  u  s&    
z+WebSocketClientFactory.resetProtocolOptionsc             C   s  |dk	r8|t jkr(td|tt jf || jkr8|| _|dk	rP|| jkrP|| _|dk	rh|| jkrh|| _|dk	r|| jkr|| _|dk	r|| jkr|| _|dk	r|| j	kr|| _	|dk	r|| j
kr|| _
|dk	r|| jkr|| _|	dk	r|	| jkr|	| _|
dk	r|
| jkr|
| _|dk	r0|| jkr0|| _|dk	rL|| jkrL|| _|dk	rh|| jkrh|| _|dk	r|| jkr|| _|dk	rtj|tj| jkrt|tkrtj|| _ntdt| |dk	r|| jkr|| _|dk	r
|| jkr
|| _|dk	r&|| jkr&|| _|dk	r|| jkrt|tks\t|tks\td|  kopdkn  s|t|| _dS )zt
        Implements :func:`autobahn.websocket.interfaces.IWebSocketClientChannelFactory.setProtocolOptions`
        Nz7invalid WebSocket draft version %s (allowed values: %s)z?invalid type %s for perMessageCompressionOffers - expected listr   rG  ) r   r  r   rw  r   r   r   r   r   r   r   r   r   r   r   r   r   r   picklerV   r   ru  listcopydeepcopyr   r   r   r   rS   rv  r  )rA   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r1   r1   r2   r    sZ    

"  z)WebSocketClientFactory.setProtocolOptions)NNNNNN)NNNNNNNNNNNNNNNNNNN)rX   rY   rZ   ra   r   r   r   r   r  r   r   rB   r  r  r  r1   r1   r1   r2   r    (  sH        
                  )r   r   r   r   r   r    )@r'  r  r  rM  rh  r  r%  r'  rU   pprintr   collectionsr   urllibr   Zautobahnr   Zautobahn.websocket.interfacesr   r   r   Zautobahn.websocket.typesr	   r
   r   r   Zautobahn.utilr   r   r   r   r   r   Z autobahn.websocket.utf8validatorr   Zautobahn.websocket.xormaskerr   r   Zautobahn.websocket.compressr   Zautobahn.websocket.utilr   Zautobahn.exceptionr   r   r   r   __all__r3   r>   objectr?   r[   rq   rr   r   registerr  r   r  r   r   r   r    r1   r1   r1   r2   <module>   s        0H->               C


GC     
 |    