U
    Ê¼µbôX  ã                   @   s  d Z ddlZddlmZmZ ddl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 dd	lmZ dd
lmZmZ e e¡ZdZdZdZdd„ edƒD ƒZzeZW n ek
rÄ   e e!fZY nX dZ"dd„ Z#dd„ Z$dd„ Z%dd„ Z&dd„ Z'G dd„ de(ƒZ)G dd„ de(ƒZ*dS ) ze
hpack/hpack
~~~~~~~~~~~

Implements the HPACK header compression algorithm as detailed by the IETF.
é    Né   )ÚHeaderTableÚtable_entry_size)Úto_byteÚto_bytes)ÚHPACKDecodingErrorÚOversizedHeaderListErrorÚInvalidTableSizeError)ÚHuffmanEncoder)ÚREQUEST_CODESÚREQUEST_CODES_LENGTH)Údecode_huffman)ÚHeaderTupleÚNeverIndexedHeaderTupleó    ó   ó   @c                 C   s   g | ]}d | d ‘qS )é   r   © )Ú.0Úir   r   ú//tmp/pip-unpacked-wheel-vloce9av/hpack/hpack.pyÚ
<listcomp>   s     r   é	   i   c                 C   s<   t | d ƒ}t | d ƒ}|s0| d¡}| d¡}|  ||¡S )zj
    Provides a header as a unicode string if raw is False, otherwise returns
    it as a bytestring.
    r   r   úutf-8)r   ÚdecodeÚ	__class__)ÚheaderÚrawÚnameÚvaluer   r   r   Ú_unicode_if_needed,   s    

r!   c                 C   s    t  d| |¡ | dk r"td|  ƒ‚|dk s2|dkr>td| ƒ‚t| }| |k rXt| gƒS |g}| |8 } | dkrŠ| | d@ d ¡ | d	L } qf| | ¡ t|ƒS d
S )zn
    This encodes an integer according to the wacky integer encoding rules
    defined in the HPACK spec.
    zEncoding %d with %d bitsr   z)Can only encode positive integers, got %sr   é   ú+Prefix bits must be between 1 and 8, got %sé€   é   é   N)ÚlogÚdebugÚ
ValueErrorÚ_PREFIX_BIT_MAX_NUMBERSÚ	bytearrayÚappend)ÚintegerÚprefix_bitsÚ
max_numberÚelementsr   r   r   Úencode_integer9   s&    ÿÿ


r1   c                 C   sÒ   |dk s|dkrt d| ƒ‚t| }d}d}dd| ? }zbt| d ƒ|@ }||kr˜t| | ƒ}|d7 }|dkr€||d |> 7 }n|||> 7 }q˜|d7 }qRW n  tk
rº   td|  ƒ‚Y nX t d	||¡ ||fS )
zô
    This decodes an integer according to the wacky integer encoding rules
    defined in the HPACK spec. Returns a tuple of the decoded integer and the
    number of bytes that were consumed from ``data`` in order to get that
    integer.
    r   r"   r#   r   éÿ   r$   r&   z5Unable to decode HPACK integer representation from %rzDecoded %d, consumed %d bytes)r)   r*   r   Ú
IndexErrorr   r'   r(   )Údatar.   r/   ÚindexÚshiftÚmaskÚnumberZ	next_byter   r   r   Údecode_integer[   s0    ÿÿ
r9   c                 c   s>   t | tƒst‚t|  ¡ dd„ d�}|D ]}|| | fV  q&dS )z®
    This converts a dictionary to an iterable of two-tuples. This is a
    HPACK-specific function becuase it pulls "special-headers" out first and
    then emits them.
    c                 S   s   t | ƒ d¡ S )Nó   :)Ú	_to_bytesÚ
startswith)Úkr   r   r   Ú<lambda>�   ó    z#_dict_to_iterable.<locals>.<lambda>)ÚkeyN)Ú
isinstanceÚdictÚAssertionErrorÚsortedÚkeys)Zheader_dictrE   r@   r   r   r   Ú_dict_to_iterable„   s    þrF   c                 C   s*   t | tƒst| ƒ} t | tƒr | S |  d¡S )z"
    Convert string to bytes.
    r   )rA   Ú
basestringÚstrÚbytesÚencode)Ústringr   r   r   r;   “   s    
r;   c                   @   sj   e Zd ZdZdd„ Zedd„ ƒZejdd„ ƒZddd	„Zddd„Z	dd„ Z
ddd„Zddd„Zdd„ ZdS )ÚEncoderzm
    An HPACK encoder object. This object takes HTTP headers and emits encoded
    HTTP/2 header blocks.
    c                 C   s   t ƒ | _tttƒ| _g | _d S ©N)r   Úheader_tabler
   r   r   Úhuffman_coderÚtable_size_changes©Úselfr   r   r   Ú__init__£   s     ÿzEncoder.__init__c                 C   s   | j jS ©z>
        Controls the size of the HPACK header table.
        ©rN   ÚmaxsizerQ   r   r   r   Úheader_table_sizeª   s    zEncoder.header_table_sizec                 C   s    || j _| j jr| j |¡ d S rM   )rN   rV   ÚresizedrP   r,   ©rR   r    r   r   r   rW   ±   s    Tc                 C   s¼   t  d|¡ g }t|tƒr"t|ƒ}| jjr@| |  ¡ ¡ d| j_|D ]\}d}t|t	ƒr`|j
 }nt|ƒdkrt|d }t|d ƒt|d ƒf}| |  |||¡¡ qDd |¡}t  d|¡ |S )a•	  
        Takes a set of headers and encodes them into a HPACK-encoded header
        block.

        :param headers: The headers to encode. Must be either an iterable of
                        tuples, an iterable of :class:`HeaderTuple
                        <hpack.struct.HeaderTuple>`, or a ``dict``.

                        If an iterable of tuples, the tuples may be either
                        two-tuples or three-tuples. If they are two-tuples, the
                        tuples must be of the format ``(name, value)``. If they
                        are three-tuples, they must be of the format
                        ``(name, value, sensitive)``, where ``sensitive`` is a
                        boolean value indicating whether the header should be
                        added to header tables anywhere. If not present,
                        ``sensitive`` defaults to ``False``.

                        If an iterable of :class:`HeaderTuple
                        <hpack.struct.HeaderTuple>`, the tuples must always be
                        two-tuples. Instead of using ``sensitive`` as a third
                        tuple entry, use :class:`NeverIndexedHeaderTuple
                        <hpack.struct.NeverIndexedHeaderTuple>` to request that
                        the field never be indexed.

                        .. warning:: HTTP/2 requires that all special headers
                            (headers whose names begin with ``:`` characters)
                            appear at the *start* of the header block. While
                            this method will ensure that happens for ``dict``
                            subclasses, callers using any other iterable of
                            tuples **must** ensure they place their special
                            headers at the start of the iterable.

                            For efficiency reasons users should prefer to use
                            iterables of two-tuples: fixing the ordering of
                            dictionary headers is an expensive operation that
                            should be avoided if possible.

        :param huffman: (optional) Whether to Huffman-encode any header sent as
                        a literal value. Except for use when debugging, it is
                        recommended that this be left enabled.

        :returns: A bytestring containing the HPACK-encoded header block.
        zHPACK encoding %sFr   r   r   r?   zEncoded header block to %s)r'   r(   rA   rB   rF   rN   rX   r,   Ú_encode_table_size_changer   Z	indexableÚlenr;   ÚaddÚjoin)rR   ÚheadersÚhuffmanZheader_blockr   Ú	sensitiver   r   r   rJ   ·   s$    2



zEncoder.encodeFc                 C   sœ   t  d|¡ |\}}|stnt}| j ||¡}|dkr\|  ||||¡}|sX| j ||¡ |S |\}	}}
|
rv|  |	¡}n"|  	|	|||¡}|s˜| j ||¡ |S )zQ
        This function takes a header key-value tuple and serializes it.
        zAdding %s to the header tableN)
r'   r(   ÚINDEX_INCREMENTALÚINDEX_NEVERrN   ÚsearchÚ_encode_literalr\   Ú_encode_indexedÚ_encode_indexed_literal)rR   Zto_addr`   r_   r   r    ÚindexbitÚmatchÚencodedr5   Zperfectr   r   r   r\   	  s*    
   ÿzEncoder.addc                 C   s"   t |dƒ}|d  dO  < t|ƒS )zD
        Encodes a header using the indexed representation.
        r&   r   r$   )r1   rI   )rR   r5   Úfieldr   r   r   re   5  s    
zEncoder._encode_indexedc                 C   sx   |r| j  |¡}| j  |¡}tt|ƒdƒ}tt|ƒdƒ}|r\|d  dO  < |d  dO  < d |t|ƒ|t|ƒ|g¡S )z·
        Encodes a header with a literal name and literal value. If ``indexing``
        is True, the header will be added to the header table: otherwise it
        will not.
        r&   r   r$   r?   )rO   rJ   r1   r[   r]   rI   )rR   r   r    rg   r_   Úname_lenÚ	value_lenr   r   r   rd   =  s    ÿzEncoder._encode_literalc                 C   s|   |t krt|dƒ}n
t|dƒ}|d  t|ƒO  < |rB| j |¡}tt|ƒdƒ}|rd|d  dO  < d t|ƒt|ƒ|g¡S )zv
        Encodes a header with an indexed name and a literal value and performs
        incremental indexing.
        é   é   r   r&   r$   r?   )ra   r1   ÚordrO   rJ   r[   r]   rI   )rR   r5   r    rg   r_   Úprefixrl   r   r   r   rf   R  s    
zEncoder._encode_indexed_literalc                 C   s@   d}| j D ]*}t|dƒ}|d  dO  < |t|ƒ7 }q
g | _ |S )zd
        Produces the encoded form of all header table size change context
        updates.
        r?   é   r   é    )rP   r1   rI   )rR   ÚblockZ
size_bytesr   r   r   rZ   h  s    

z!Encoder._encode_table_size_changeN)T)F)F)F)Ú__name__Ú
__module__Ú__qualname__Ú__doc__rS   ÚpropertyrW   ÚsetterrJ   r\   re   rd   rf   rZ   r   r   r   r   rL   �   s   


R
,

rL   c                   @   sp   e Zd ZdZefdd„Zedd„ ƒZejdd„ ƒZddd	„Z	d
d„ Z
dd„ Zdd„ Zdd„ Zdd„ Zdd„ ZdS )ÚDecodera  
    An HPACK decoder object.

    .. versionchanged:: 2.3.0
       Added ``max_header_list_size`` argument.

    :param max_header_list_size: The maximum decompressed size we will allow
        for any single header block. This is a protection against DoS attacks
        that attempt to force the application to expand a relatively small
        amount of data into a really large header list, allowing enormous
        amounts of memory to be allocated.

        If this amount of data is exceeded, a `OversizedHeaderListError
        <hpack.OversizedHeaderListError>` exception will be raised. At this
        point the connection should be shut down, as the HPACK state will no
        longer be useable.

        Defaults to 64kB.
    :type max_header_list_size: ``int``
    c                 C   s   t ƒ | _|| _| jj| _d S rM   )r   rN   Úmax_header_list_sizerV   Úmax_allowed_table_size)rR   r{   r   r   r   rS   ‹  s    	zDecoder.__init__c                 C   s   | j jS rT   rU   rQ   r   r   r   rW   §  s    zDecoder.header_table_sizec                 C   s   || j _d S rM   rU   rY   r   r   r   rW   ®  s    Fc                    sd  t  d|¡ t|ƒ}g }t|ƒ}d}d}||k �r$t|| ƒ}|d@ rJdnd}	|d@ rZdnd}
|d@ rjdnd}|	rŠ|  ||d… ¡\}}nZ|
r¦|  ||d… ¡\}}n>|rÎ|r¶td	ƒ‚|  ||d… ¡}d}n|  	||d… ¡\}}|�r| 
|¡ |t|Ž 7 }|| jk�rtd
| j ƒ‚||7 }q(|  ¡  z‡ fdd„|D ƒW S  tk
�r^   tdƒ‚Y nX dS )aê  
        Takes an HPACK-encoded header block and decodes it into a header set.

        :param data: A bytestring representing a complete HPACK-encoded header
                     block.
        :param raw: (optional) Whether to return the headers as tuples of raw
                    byte strings or to decode them as UTF-8 before returning
                    them. The default value is False, which returns tuples of
                    Unicode strings
        :returns: A list of two-tuples of ``(name, value)`` representing the
                  HPACK-encoded headers, in the order they were decoded.
        :raises HPACKDecodingError: If an error is encountered while decoding
                                    the header block.
        zDecoding %sr   r$   TFé@   rr   Nz/Table size update not at the start of the blockz.A header list larger than %d has been receivedc                    s   g | ]}t |ˆ ƒ‘qS r   )r!   )r   Úh©r   r   r   r     s     z"Decoder.decode.<locals>.<listcomp>z"Unable to decode headers as UTF-8.)r'   r(   Ú
memoryviewr[   r   Ú_decode_indexedÚ_decode_literal_indexr   Ú_update_encoding_contextÚ_decode_literal_no_indexr,   r   r{   r   Ú_assert_valid_table_sizeÚUnicodeDecodeError)rR   r4   r   Zdata_memr^   Zdata_lenZinflated_sizeZcurrent_indexÚcurrentZindexedZliteral_indexZencoding_updater   Úconsumedr   r   r   r   ²  s\    

ÿ

ÿ
ÿ
ÿ
ÿ
ÿÿ
zDecoder.decodec                 C   s   | j | jkrtdƒ‚dS )zs
        Check that the table size set by the encoder is lower than the maximum
        we expect to have.
        z3Encoder did not shrink table size to within the maxN)rW   r|   r	   rQ   r   r   r   r…     s    ÿz Decoder._assert_valid_table_sizec                 C   s*   t |dƒ\}}|| jkr tdƒ‚|| _|S )zC
        Handles a byte that updates the encoding context.
        rq   z)Encoder exceeded max allowable table size)r9   r|   r	   rW   )rR   r4   Znew_sizerˆ   r   r   r   rƒ     s    
ÿz Decoder._update_encoding_contextc                 C   s4   t |dƒ\}}t| j |¡Ž }t d||¡ ||fS )zP
        Decodes a header represented using the indexed representation.
        r&   zDecoded %s, consumed %d)r9   r   rN   Úget_by_indexr'   r(   )rR   r4   r5   rˆ   r   r   r   r   r�     s    zDecoder._decode_indexedc                 C   s   |   |d¡S )NF©Ú_decode_literal©rR   r4   r   r   r   r„   '  s    z Decoder._decode_literal_no_indexc                 C   s   |   |d¡S )NTrŠ   rŒ   r   r   r   r‚   *  s    zDecoder._decode_literal_indexc                 C   s‚  d}|r"t |d ƒd@ }d}d}n t |d ƒ}|d@ }d}|d@ }|rnt||ƒ\}}	| j |¡d }
|	}d}nb|dd	… }t|d
ƒ\}}	||	|	| … }
t|
ƒ|kr¬tdƒ‚t |d ƒd@ rÄt|
ƒ}
|	| d }||	| d	… }t|d
ƒ\}}	||	|	| … }t|ƒ|k�rtdƒ‚t |d ƒd@ �r.t|ƒ}|||	 7 }|�rLt|
|ƒ}n
t|
|ƒ}|�rj| j 	|
|¡ t
 d|||¡ ||fS )z>
        Decodes a header represented with a literal.
        r   é?   rn   Fé   rm   é   r   Nr&   zTruncated header blockr$   z/Decoded %s, total consumed %d bytes, indexed %s)r   r9   rN   r‰   r[   r   r   r   r   r\   r'   r(   )rR   r4   Zshould_indexZtotal_consumedZindexed_namerk   Znot_indexableZ	high_byter5   rˆ   r   Úlengthr    r   r   r   r   r‹   -  sT    
üzDecoder._decode_literalN)F)rt   ru   rv   rw   ÚDEFAULT_MAX_HEADER_LIST_SIZErS   rx   rW   ry   r   r…   rƒ   r�   r„   r‚   r‹   r   r   r   r   rz   v  s   


U
	rz   )+rw   ÚloggingÚtabler   r   Úcompatr   r   Ú
exceptionsr   r   r	   r_   r
   Zhuffman_constantsr   r   Zhuffman_tabler   Ústructr   r   Ú	getLoggerrt   r'   Z
INDEX_NONErb   ra   Úranger*   rG   Ú	NameErrorrH   rI   r‘   r!   r1   r9   rF   r;   ÚobjectrL   rz   r   r   r   r   Ú<module>   s4   
")
 Z