U
    Ê¼µbßa  ã                   @   s²   d dl T d dlT d dlmZmZ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 d dlmZ dd	d
gZed	ƒZed
ƒZdZdd„ Zdd„ ZG dd„ deƒZdS )é   )Ú*)ÚLocalProtocolErrorÚRemoteProtocolErrorÚmake_sentinel)ÚConnectionStateÚ_SWITCH_UPGRADEÚ_SWITCH_CONNECT)Úget_comma_headerÚset_comma_headerÚhas_expect_100_continue)ÚReceiveBuffer)ÚREADERS)ÚWRITERSÚ
ConnectionÚ	NEED_DATAÚPAUSEDi @  c                 C   s0   t | jdƒ}d|krdS t| ddƒdk r,dS dS )Nó
   connectionó   closeFÚhttp_versionó   1.1T)r	   ÚheadersÚgetattr)ÚeventÚ
connection© r   ú3/tmp/pip-unpacked-wheel-rko__zic/h11/_connection.pyÚ_keep_alive0   s    r   c                 C   sÂ   t |ƒttfkst‚t |ƒtkrf|jdksT| dksT| dkrXd|j  krPdk rXn ndS |jdksft‚t|jdƒ}|rˆ|dgks„t‚d	S t|jd
ƒ}|rªdt|d ƒffS t |ƒtkrºdS dS d S )N)éÌ   i0  ó   HEADó   CONNECTéÈ   é,  )úcontent-length)é    ó   transfer-encodings   chunked)Úchunkedr   ó   content-lengthr"   r#   )úhttp/1.0r   )ÚtypeÚRequestÚResponseÚAssertionErrorÚstatus_coder	   r   Úint)Úrequest_methodr   Ztransfer_encodingsZcontent_lengthsr   r   r   Ú_body_framing8   s0    
ÿþ ýý
r/   c                   @   sÂ   e Zd ZdZefdd„Zedd„ ƒZedd„ ƒZedd	„ ƒZ	ed
d„ ƒZ
dd„ Zdd„ Zdd„ Zdd„ Zdd„ Zd)dd„Ze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   aB  An object encapsulating the state of an HTTP connection.

    Args:
        our_role: If you're implementing a client, pass :data:`h11.CLIENT`. If
            you're implementing a server, pass :data:`h11.SERVER`.

        max_incomplete_event_size (int):
            The maximum number of bytes we're willing to buffer of an
            incomplete event. In practice this mostly sets a limit on the
            maximum size of the request/response line + headers. If this is
            exceeded, then :meth:`next_event` will raise
            :exc:`RemoteProtocolError`.

    c                 C   sŒ   || _ |ttfkr td |¡ƒ‚|| _|tkr6t| _nt| _tƒ | _|  	| jd t
¡| _|  	| jd t¡| _tƒ | _d| _d | _d | _d| _d S )Nz#expected CLIENT or SERVER, not {!r}F)Ú_max_incomplete_event_sizeÚCLIENTÚSERVERÚ
ValueErrorÚformatÚour_roleÚ
their_roler   Ú_cstateÚ_get_io_objectr   Ú_writerr   Ú_readerr   Ú_receive_bufferÚ_receive_buffer_closedÚtheir_http_versionÚ_request_methodÚ"client_is_waiting_for_100_continue)Úselfr5   Zmax_incomplete_event_sizer   r   r   Ú__init__|   s"    ÿzConnection.__init__c                 C   s   t | jjƒS )z‰A dictionary like::

           {CLIENT: <client state>, SERVER: <server state>}

        See :ref:`state-machine` for details.

        )Údictr7   Ústates©r@   r   r   r   rC   ¡   s    	zConnection.statesc                 C   s   | j j| j S )zjThe current state of whichever role we are playing. See
        :ref:`state-machine` for details.
        )r7   rC   r5   rD   r   r   r   Ú	our_state¬   s    zConnection.our_statec                 C   s   | j j| j S )znThe current state of whichever role we are NOT playing. See
        :ref:`state-machine` for details.
        )r7   rC   r6   rD   r   r   r   Útheir_state³   s    zConnection.their_statec                 C   s   | j tko| jS ©N)r6   r1   r?   rD   r   r   r   Ú!they_are_waiting_for_100_continueº   s    
ÿz,Connection.they_are_waiting_for_100_continuec                 C   s4   t | jjƒ}| j ¡  d| _| jr&t‚|  |¡ dS )a�  Attempt to reset our connection state for a new request/response
        cycle.

        If both client and server are in :data:`DONE` state, then resets them
        both to :data:`IDLE` state in preparation for a new request/response
        cycle on this same connection. Otherwise, raises a
        :exc:`LocalProtocolError`.

        See :ref:`keepalive-and-pipelining`.

        N)rB   r7   rC   Ústart_next_cycler>   r?   r+   Ú_respond_to_state_changes)r@   Ú
old_statesr   r   r   rI   ¿   s
    

zConnection.start_next_cyclec                 C   s&   t | jjƒ}| j |¡ |  |¡ d S rG   )rB   r7   rC   Zprocess_errorrJ   )r@   ÚrolerK   r   r   r   Ú_process_errorÓ   s    zConnection._process_errorc                 C   sT   t |ƒtkr|jdkrtS t |ƒtkrPt| jjkrPd|j  krHdk rPn ntS d S )Née   r    r!   )r(   ÚInformationalResponser,   r   r*   r   r7   Zpending_switch_proposals)r@   r   r   r   r   Ú_server_switch_eventØ   s     ÿÿ
zConnection._server_switch_eventc                 C   s6  t | jjƒ}|tkrNt|ƒtkrN|jdkr6| j t¡ t	|j
dƒrN| j t¡ d }|tkrd|  |¡}| j |t|ƒ|¡ t|ƒtkrŒ|j| _|| jkr°t|ƒtttfkr°|j| _t|ƒttfkrÒt|ƒsÒ| j ¡  t|ƒtkrìt|ƒrìd| _t|ƒttfk�rd| _|tk�r&t|ƒttfk�r&d| _|  ||¡ d S )Nr   s   upgradeTF)rB   r7   rC   r1   r(   r)   ÚmethodZprocess_client_switch_proposalr   r	   r   r   r2   rP   Zprocess_eventr>   r6   r*   rO   r   r=   r   Zprocess_keep_alive_disabledr   r?   ÚDataZEndOfMessagerJ   )r@   rL   r   rK   Zserver_switch_eventr   r   r   Ú_process_eventâ   s2    


ÿ
zConnection._process_eventc                 C   sF   | j j| }|tkr4t| j|ƒ\}}|t | |Ž S | ||f¡S d S rG   )r7   rC   Z	SEND_BODYr/   r>   Úget)r@   rL   r   Zio_dictÚstateÚframing_typeÚargsr   r   r   r8     s
    zConnection._get_io_objectNc                 C   sH   | j || j kr"|  | j|t¡| _| j|| j krD|  | j|t¡| _d S rG   )	rE   r5   r8   r   r9   rF   r6   r   r:   )r@   rK   r   r   r   r   rJ     s    z$Connection._respond_to_state_changesc                 C   s   t | jƒ| jfS )ab  Data that has been received, but not yet processed, represented as
        a tuple with two elements, where the first is a byte-string containing
        the unprocessed data itself, and the second is a bool that is True if
        the receive connection was closed.

        See :ref:`switching-protocols` for discussion of why you'd want this.
        )Úbytesr;   r<   rD   r   r   r   Útrailing_data$  s    	zConnection.trailing_datac                 C   s,   |r"| j rtdƒ‚|  j|7  _nd| _ dS )aØ  Add data to our internal recieve buffer.

        This does not actually do any processing on the data, just stores
        it. To trigger processing, you have to call :meth:`next_event`.

        Args:
            data (:term:`bytes-like object`):
                The new data that was just received.

                Special case: If *data* is an empty byte-string like ``b""``,
                then this indicates that the remote side has closed the
                connection (end of file). Normally this is convenient, because
                standard Python APIs like :meth:`file.read` or
                :meth:`socket.recv` use ``b""`` to indicate end-of-file, while
                other failures to read are indicated using other mechanisms
                like raising :exc:`TimeoutError`. When using such an API you
                can just blindly pass through whatever you get from ``read``
                to :meth:`receive_data`, and everything will work.

                But, if you have an API where reading an empty string is a
                valid non-EOF condition, then you need to be aware of this and
                make sure to check for such strings and avoid passing them to
                :meth:`receive_data`.

        Returns:
            Nothing, but after calling this you should call :meth:`next_event`
            to parse the newly received data.

        Raises:
            RuntimeError:
                Raised if you pass an empty *data*, indicating EOF, and then
                pass a non-empty *data*, indicating more data that somehow
                arrived after the EOF.

                (Calling ``receive_data(b"")`` multiple times is fine,
                and equivalent to calling it once.)

        z(received close, then received more data?TN)r<   ÚRuntimeErrorr;   )r@   Údatar   r   r   Úreceive_data/  s    'ÿzConnection.receive_datac                 C   sˆ   | j }|tkr| jrtS |tks(|tkr,tS | jd k	s:t‚|  | j¡}|d krx| jsx| jrxt	| jdƒrr| j 
¡ }ntƒ }|d kr„t}|S )NÚread_eof)rF   ZDONEr;   r   ZMIGHT_SWITCH_PROTOCOLZSWITCHED_PROTOCOLr:   r+   r<   Úhasattrr]   ÚConnectionClosedr   )r@   rU   r   r   r   r   Ú_extract_next_receive_event^  s    z&Connection._extract_next_receive_eventc              
   C   sÀ   | j tkrtdƒ‚zd|  ¡ }|ttfkr@|  | j|¡ | j 	¡  |tkrrt
| jƒ| jkrdtddd�‚| jrrtdƒ‚|W S  tk
rº } z&|  | j¡ t|tƒr¨| ¡  n‚ W 5 d}~X Y nX dS )aF  Parse the next event out of our receive buffer, update our internal
        state, and return it.

        This is a mutating operation -- think of it like calling :func:`next`
        on an iterator.

        Returns:
            : One of three things:

            1) An event object -- see :ref:`events`.

            2) The special constant :data:`NEED_DATA`, which indicates that
               you need to read more data from your socket and pass it to
               :meth:`receive_data` before this method will be able to return
               any more events.

            3) The special constant :data:`PAUSED`, which indicates that we
               are not in a state where we can process incoming data (usually
               because the peer has finished their part of the current
               request/response cycle, and you have not yet called
               :meth:`start_next_cycle`). See :ref:`flow-control` for details.

        Raises:
            RemoteProtocolError:
                The peer has misbehaved. You should close the connection
                (possibly after sending some kind of 4xx response).

        Once this method returns :class:`ConnectionClosed` once, then all
        subsequent calls will also return :class:`ConnectionClosed`.

        If this method raises any exception besides :exc:`RemoteProtocolError`
        then that's a bug -- if it happens please file a bug report!

        If this method raises any exception then it also sets
        :attr:`Connection.their_state` to :data:`ERROR` -- see
        :ref:`error-handling` for discussion.

        z+Can't receive data when peer state is ERRORzReceive buffer too longi¯  )Zerror_status_hintz#peer unexpectedly closed connectionN)rF   ÚERRORr   r`   r   r   rS   r6   r;   ÚcompressÚlenr0   r<   ÚBaseExceptionrM   Ú
isinstancer   Z!_reraise_as_remote_protocol_error)r@   r   Úexcr   r   r   Ú
next_eventx  s0    (
ÿ
ÿÿ

zConnection.next_eventc                 C   s$   |   |¡}|dkrdS d |¡S dS )a³  Convert a high-level event into bytes that can be sent to the peer,
        while updating our internal state machine.

        Args:
            event: The :ref:`event <events>` to send.

        Returns:
            If ``type(event) is ConnectionClosed``, then returns
            ``None``. Otherwise, returns a :term:`bytes-like object`.

        Raises:
            LocalProtocolError:
                Sending this event at this time would violate our
                understanding of the HTTP/1.1 protocol.

        If this method raises any exception then it also sets
        :attr:`Connection.our_state` to :data:`ERROR` -- see
        :ref:`error-handling` for discussion.

        Nó    )Úsend_with_data_passthroughÚjoin)r@   r   Ú	data_listr   r   r   Úsend»  s    
zConnection.sendc                 C   s”   | j tkrtdƒ‚zbt|ƒtkr*|  |¡ | j}|  | j|¡ t|ƒt	krPW dS |dk	s\t
‚g }|||jƒ |W S W n   |  | j¡ ‚ Y nX dS )ah  Identical to :meth:`send`, except that in situations where
        :meth:`send` returns a single :term:`bytes-like object`, this instead
        returns a list of them -- and when sending a :class:`Data` event, this
        list is guaranteed to contain the exact object you passed in as
        :attr:`Data.data`. See :ref:`sendfile` for discussion.

        z'Can't send data when our state is ERRORN)rE   ra   r   r(   r*   Ú&_clean_up_response_headers_for_sendingr9   rS   r5   r_   r+   ÚappendrM   )r@   r   Úwriterrk   r   r   r   ri   Ö  s$    
ÿ

z%Connection.send_with_data_passthroughc                 C   s   |   | j¡ dS )záNotify the state machine that we failed to send the data it gave
        us.

        This causes :attr:`Connection.our_state` to immediately become
        :data:`ERROR` -- see :ref:`error-handling` for discussion.

        N)rM   r5   rD   r   r   r   Úsend_failedø  s    zConnection.send_failedc                 C   sØ   t |ƒtkst‚t|jƒ}d}| j}|dkr0d}t||ƒ\}}|dkr�t|dg ƒ | jd ksf| jdk r‚t|dg ƒ | jdkr�d}nt|dd	gƒ | j	j
rœ|rÎtt|d
ƒƒ}| d¡ | d¡ t|d
t|ƒƒ ||_d S )NFr   s   GET)r%   r'   r&   r   r$   Tr%   r   s
   keep-aliver   )r(   r*   r+   Úlistr   r>   r/   r
   r=   r7   Ú
keep_aliveÚsetr	   ÚdiscardÚaddÚsorted)r@   Úresponser   Z
need_closeZmethod_for_choosing_headersrV   Ú_r   r   r   r   rm     s,    
	
ÿ


z1Connection._clean_up_response_headers_for_sending)N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ú!DEFAULT_MAX_INCOMPLETE_EVENT_SIZErA   ÚpropertyrC   rE   rF   rH   rI   rM   rP   rS   r8   rJ   rY   r\   r`   rg   rl   ri   rp   rm   r   r   r   r   r   m   s4   þ
%





,


/C"N)Z_eventsÚ_stateZ_utilr   r   r   r   r   r   Ú_headersr	   r
   r   Z_receivebufferr   Ú_readersr   Ú_writersr   Ú__all__r   r   r}   r   r/   Úobjectr   r   r   r   r   Ú<module>   s   
5