a
    Df                  	   @   s>  d 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ZddlZddlmZ ddlZddlZddlmZ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  e ddl!Z!dd
l!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z, e!j-r ddl!m.Z. ddl/m0Z0 ddl1Z1e	de2e2dddZ3G dd dej4j5Z6G dd de7Z8G dd de9Z:G dd de9Z;G dd de7Z<G dd de7Z=G dd de7Z>e2e(de'e2e2f e$e"e2e2f  e"e"e2e2f df f e2d d!d"Z?G d#d$ d$eZ@e2e)e"e)eA e)eA f  d%d&d'ZBe)eA e)eA eAe2d(d)d*ZCe2e)eA d+d,d-ZDd^e2eEe'e2e$eE f e'e2e$e@ f e)e6 dd.d/d0ZFeEeEe'e2e$eE f e'e2e$e@ f dd1d2d3ZGe(eAeHeIejJejf e2d4d5d6ZKeLd7g d8ZMeNd9ZOe2eMd:d;d<ZPeLd=g d>ZQeNd?ZRe2eQd:d@dAZSe2e+e2ddf dBdCdDZTe2e"e2e'e2e2f f d:dEdFZUe2e'e2e2f e2dGdHdIZVe(e2eEf e(e2eEf eEdJdKdLZWdMdN ZXeNdOZYe2e"e2e)eA f dPdQdRZZe'e2e$e, f e#e"e2e,f  dSdTdUZ[eNdVZ\eNdWZ]dXj^Z_e2e2dBdYdZZ`e2e'e2e2f d[d\d]ZadS )_zHTTP utility code shared by clients and servers.

This module also defines the `HTTPServerRequest` class which is exposed
via `tornado.web.RequestHandler.request`.
    N)	lru_cache)	responses)SSLError)	urlencodeurlparse
urlunparse	parse_qsl)
native_strparse_qs_bytesutf8)gen_log)
ObjectDictunicode_type)TupleIterableListMappingIteratorDictUnionOptional	Awaitable	GeneratorAnyStr)Deque)Futurei  namereturnc                 C   s   d dd | dD S )ziMap a header name to Http-Header-Case.

    >>> _normalize_header("coNtent-TYPE")
    'Content-Type'
    -c                 S   s   g | ]}|  qS  )
capitalize).0wr    r    ]/nfs/NAS7/SABIOD/METHODE/ermites/ermites_venv/lib/python3.9/site-packages/tornado/httputil.py
<listcomp>I       z%_normalize_header.<locals>.<listcomp>)joinsplit)r   r    r    r$   _normalize_headerB   s    r)   c                   @   st  e Zd ZdZejeeee f ddddZ	ejeeef ddddZ	eje
eef ddddZ	ejedd	d
dZ	ejeddddZ	eeddddZeee dddZee
eef  dddZeddddZeed dddZeeddddZeedddZeddd d!Zedd"d#Zeej dd$d%Zd dd&d'ZeZedd(d)ZeZdS )*HTTPHeadersa  A dictionary that maintains ``Http-Header-Case`` for all keys.

    Supports multiple values per key via a pair of new methods,
    `add()` and `get_list()`.  The regular dictionary interface
    returns a single value per key, with multiple values joined by a
    comma.

    >>> h = HTTPHeaders({"content-type": "text/html"})
    >>> list(h.keys())
    ['Content-Type']
    >>> h["Content-Type"]
    'text/html'

    >>> h.add("Set-Cookie", "A=B")
    >>> h.add("Set-Cookie", "C=D")
    >>> h["set-cookie"]
    'A=B,C=D'
    >>> h.get_list("set-cookie")
    ['A=B', 'C=D']

    >>> for (k,v) in sorted(h.get_all()):
    ...    print('%s: %s' % (k,v))
    ...
    Content-Type: text/html
    Set-Cookie: A=B
    Set-Cookie: C=D
    N)_HTTPHeaders__argr   c                 C   s   d S Nr    selfr+   r    r    r$   __init__i   s    zHTTPHeaders.__init__c                 C   s   d S r,   r    r-   r    r    r$   r/   m   s    )argsr   c                 G   s   d S r,   r    )r.   r0   r    r    r$   r/   q   s    )kwargsr   c                 K   s   d S r,   r    )r.   r1   r    r    r$   r/   u   s    )r0   r1   r   c                 O   sp   i | _ i | _d | _t|dkr\t|dkr\t|d tr\|d  D ]\}}| || qDn| j|i | d S )N   r   )	_dict_as_list	_last_keylen
isinstancer*   get_alladdupdate)r.   r0   r1   kvr    r    r$   r/   y   s    &)r   valuer   c                 C   sR   t |}|| _|| v rFt| | d t| | j|< | j| | n|| |< dS )z#Adds a new value for the given key.,N)r)   r5   r	   r3   r4   appendr.   r   r=   	norm_namer    r    r$   r9      s    zHTTPHeaders.addr   c                 C   s   t |}| j|g S )z2Returns all values for the given header as a list.)r)   r4   getr.   r   rA   r    r    r$   get_list   s    zHTTPHeaders.get_listr   c                 c   s,   | j  D ]\}}|D ]}||fV  qq
dS )zReturns an iterable of all (name, value) pairs.

        If a header has multiple values, multiple pairs will be
        returned with the same name.
        N)r4   items)r.   r   valuesr=   r    r    r$   r8      s    zHTTPHeaders.get_allliner   c                 C   s   |d   rX| jdu rtdd|  }| j| j d  |7  < | j| j  |7  < n@z|dd\}}W n ty   tdY n0 | ||	  dS )	zUpdates the dictionary with a single header line.

        >>> h = HTTPHeaders()
        >>> h.parse_line("Content-Type: text/html")
        >>> h.get('content-type')
        'text/html'
        r   Nz.first header line cannot start with whitespace :r2   zno colon in header line)
isspacer5   HTTPInputErrorlstripr4   r3   r(   
ValueErrorr9   strip)r.   rI   Znew_partr   r=   r    r    r$   
parse_line   s    
zHTTPHeaders.parse_line)headersr   c                 C   s>   |  }| dD ](}|dr*|dd }|r|| q|S )a  Returns a dictionary from HTTP header text.

        >>> h = HTTPHeaders.parse("Content-Type: text/html\r\nContent-Length: 42\r\n")
        >>> sorted(h.items())
        [('Content-Length', '42'), ('Content-Type', 'text/html')]

        .. versionchanged:: 5.1

           Raises `HTTPInputError` on malformed headers instead of a
           mix of `KeyError`, and `ValueError`.

        
NrK   )r(   endswithrR   )clsrS   hrI   r    r    r$   parse   s    
zHTTPHeaders.parsec                 C   s"   t |}|| j|< |g| j|< d S r,   r)   r3   r4   r@   r    r    r$   __setitem__   s    
zHTTPHeaders.__setitem__c                 C   s   | j t| S r,   )r3   r)   )r.   r   r    r    r$   __getitem__   s    zHTTPHeaders.__getitem__c                 C   s   t |}| j|= | j|= d S r,   rZ   rC   r    r    r$   __delitem__   s    zHTTPHeaders.__delitem__c                 C   s
   t | jS r,   )r6   r3   r.   r    r    r$   __len__   s    zHTTPHeaders.__len__c                 C   s
   t | jS r,   )iterr3   r^   r    r    r$   __iter__   s    zHTTPHeaders.__iter__c                 C   s   t | S r,   )r*   r^   r    r    r$   copy   s    zHTTPHeaders.copyc                 C   s2   g }|   D ]\}}|d||f  qd|S )Nz%s: %s
 )r8   r?   r'   )r.   linesr   r=   r    r    r$   __str__   s    zHTTPHeaders.__str__)__name__
__module____qualname____doc__typingoverloadr   strr   r/   r   Anyr9   rD   r   r8   rR   classmethodrY   r[   r\   r]   intr_   r   ra   rb   __copy__re   __unicode__r    r    r    r$   r*   L   s2   
r*   c                   @   s   e Zd ZdZdZdZdZdee ee eee	 ee
 ee eeeed f  ed ed ee dddd	Zeeeejjf d
ddZed
ddZed
ddZdeedee
f dddZdd
ddZed
ddZdS )HTTPServerRequesta7
  A single HTTP request.

    All attributes are type `str` unless otherwise noted.

    .. attribute:: method

       HTTP request method, e.g. "GET" or "POST"

    .. attribute:: uri

       The requested uri.

    .. attribute:: path

       The path portion of `uri`

    .. attribute:: query

       The query portion of `uri`

    .. attribute:: version

       HTTP version specified in request, e.g. "HTTP/1.1"

    .. attribute:: headers

       `.HTTPHeaders` dictionary-like object for request headers.  Acts like
       a case-insensitive dictionary with additional methods for repeated
       headers.

    .. attribute:: body

       Request body, if present, as a byte string.

    .. attribute:: remote_ip

       Client's IP address as a string.  If ``HTTPServer.xheaders`` is set,
       will pass along the real IP address provided by a load balancer
       in the ``X-Real-Ip`` or ``X-Forwarded-For`` header.

    .. versionchanged:: 3.1
       The list format of ``X-Forwarded-For`` is now supported.

    .. attribute:: protocol

       The protocol used, either "http" or "https".  If ``HTTPServer.xheaders``
       is set, will pass along the protocol used by a load balancer if
       reported via an ``X-Scheme`` header.

    .. attribute:: host

       The requested hostname, usually taken from the ``Host`` header.

    .. attribute:: arguments

       GET/POST arguments are available in the arguments property, which
       maps arguments names to lists of values (to support multiple values
       for individual names). Names are of type `str`, while arguments
       are byte strings.  Note that this is different from
       `.RequestHandler.get_argument`, which returns argument values as
       unicode strings.

    .. attribute:: query_arguments

       Same format as ``arguments``, but contains only arguments extracted
       from the query string.

       .. versionadded:: 3.2

    .. attribute:: body_arguments

       Same format as ``arguments``, but contains only arguments extracted
       from the request body.

       .. versionadded:: 3.2

    .. attribute:: files

       File uploads are available in the files property, which maps file
       names to lists of `.HTTPFile`.

    .. attribute:: connection

       An HTTP request is attached to a single HTTP connection, which can
       be accessed through the "connection" attribute. Since connections
       are typically kept open in HTTP/1.1, multiple requests can be handled
       sequentially on a single connection.

    .. versionchanged:: 4.0
       Moved from ``tornado.httpserver.HTTPRequest``.
    NHTTP/1.0HTTPFileHTTPConnectionRequestStartLine)methoduriversionrS   bodyhostfiles
connection
start_lineserver_connectionr   c                 C   s   |	d ur|	\}}}|| _ || _|| _|p,t | _|p6d| _t|dd }t|dd | _t|dd| _|pt| j	dptd| _
t| j
 d | _|pi | _|| _|
| _t | _d | _|d ur|d	\| _}| _t| jd
d| _t| j| _i | _d S )Nr&   context	remote_ipprotocolhttpHostz	127.0.0.1r   ?Tkeep_blank_values)rw   rx   ry   r*   rS   rz   getattrr   r   rB   r{   split_host_and_portlowerZ	host_namer|   r}   r   time_start_time_finish_time	partitionpathqueryr
   	argumentsrb   deepcopyZquery_argumentsbody_arguments)r.   rw   rx   ry   rS   rz   r{   r|   r}   r~   r   r   sepr    r    r$   r/   Z  s,    



zHTTPServerRequest.__init__rE   c              	   C   s   t | dsztj | _d| jv rzzt| jd }W n tyD   Y n60 | D ]*\}}z|| j|< W qN tyv   Y qN0 qN| jS )z0A dictionary of ``http.cookies.Morsel`` objects._cookiesCookie)	hasattrr   cookiesSimpleCookier   rS   parse_cookie	ExceptionrF   )r.   parsedr;   r<   r    r    r$   r     s    

zHTTPServerRequest.cookiesc                 C   s   | j d | j | j S )z+Reconstructs the full URL for this request.z://)r   r{   rx   r^   r    r    r$   full_url  s    zHTTPServerRequest.full_urlc                 C   s(   | j du rt | j S | j | j S dS )z?Returns the amount of time it took for this request to execute.N)r   r   r   r^   r    r    r$   request_time  s    
zHTTPServerRequest.request_timeF)binary_formr   c                 C   s>   z$| j du rW dS | j jjj|dW S  ty8   Y dS 0 dS )a>  Returns the client's SSL certificate, if any.

        To use client certificates, the HTTPServer's
        `ssl.SSLContext.verify_mode` field must be set, e.g.::

            ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
            ssl_ctx.load_cert_chain("foo.crt", "foo.key")
            ssl_ctx.load_verify_locations("cacerts.pem")
            ssl_ctx.verify_mode = ssl.CERT_REQUIRED
            server = HTTPServer(app, ssl_options=ssl_ctx)

        By default, the return value is a dictionary (or None, if no
        client certificate is present).  If ``binary_form`` is true, a
        DER-encoded form of the certificate is returned instead.  See
        SSLSocket.getpeercert() in the standard library for more
        details.
        http://docs.python.org/library/ssl.html#sslsocket-objects
        N)r   )r}   streamsocketgetpeercertr   )r.   r   r    r    r$   get_ssl_certificate  s    

z%HTTPServerRequest.get_ssl_certificatec                 C   sN   t | jdd| j| j| j| j | j D ]\}}| j|g 	| q,d S )NContent-Typerc   )
parse_body_argumentsrS   rB   rz   r   r|   rF   r   
setdefaultextend)r.   r;   r<   r    r    r$   _parse_body  s    zHTTPServerRequest._parse_bodyc                    s,   d}d  fdd|D }d jj|f S )N)r   r{   rw   rx   ry   r   z, c                    s   g | ]}d |t  |f qS )z%s=%r)r   )r"   nr^   r    r$   r%     r&   z.HTTPServerRequest.__repr__.<locals>.<listcomp>z%s(%s))r'   	__class__rf   )r.   attrsr0   r    r^   r$   __repr__  s    zHTTPServerRequest.__repr__)
NNrs   NNNNNNN)F)rf   rg   rh   ri   r   r   Z_body_futurer   rl   r*   bytesr   r   objectr/   propertyr   r   Morselr   floatr   boolr   r   r   r   r    r    r    r$   rr      sL   \          ( rr   c                   @   s   e Zd ZdZdS )rN   zqException class for malformed HTTP requests or responses
    from remote sources.

    .. versionadded:: 4.0
    Nrf   rg   rh   ri   r    r    r    r$   rN     s   rN   c                   @   s   e Zd ZdZdS )HTTPOutputErrorzJException class for errors in HTTP output.

    .. versionadded:: 4.0
    Nr   r    r    r    r$   r     s   r   c                   @   s2   e Zd ZdZedddddZeddd	d
ZdS )HTTPServerConnectionDelegatez_Implement this interface to handle requests from `.HTTPServer`.

    .. versionadded:: 4.0
    ru   HTTPMessageDelegate)server_connrequest_connr   c                 C   s
   t  dS )aj  This method is called by the server when a new request has started.

        :arg server_conn: is an opaque object representing the long-lived
            (e.g. tcp-level) connection.
        :arg request_conn: is a `.HTTPConnection` object for a single
            request/response exchange.

        This method should return a `.HTTPMessageDelegate`.
        NNotImplementedError)r.   r   r   r    r    r$   start_request  s    z*HTTPServerConnectionDelegate.start_requestN)r   r   c                 C   s   dS )zThis method is called when a connection has been closed.

        :arg server_conn: is a server connection that has previously been
            passed to ``start_request``.
        Nr    )r.   r   r    r    r$   on_close  s    z%HTTPServerConnectionDelegate.on_close)rf   rg   rh   ri   r   r   r   r    r    r    r$   r     s
   r   c                   @   sb   e Zd ZdZed eeed  dddZe	eed  ddd	Z
dd
ddZdd
ddZdS )r   z_Implement this interface to handle an HTTP request or response.

    .. versionadded:: 4.0
    rv   ResponseStartLineN)r~   rS   r   c                 C   s   dS )a  Called when the HTTP headers have been received and parsed.

        :arg start_line: a `.RequestStartLine` or `.ResponseStartLine`
            depending on whether this is a client or server message.
        :arg headers: a `.HTTPHeaders` instance.

        Some `.HTTPConnection` methods can only be called during
        ``headers_received``.

        May return a `.Future`; if it does the body will not be read
        until it is done.
        Nr    )r.   r~   rS   r    r    r$   headers_received  s    z$HTTPMessageDelegate.headers_receivedchunkr   c                 C   s   dS )ziCalled when a chunk of data has been received.

        May return a `.Future` for flow control.
        Nr    r.   r   r    r    r$   data_received  s    z!HTTPMessageDelegate.data_receivedrE   c                 C   s   dS )z6Called after the last chunk of data has been received.Nr    r^   r    r    r$   finish&  s    zHTTPMessageDelegate.finishc                 C   s   dS )zCalled if the connection is closed without finishing the request.

        If ``headers_received`` is called, either ``finish`` or
        ``on_connection_close`` will be called, but not both.
        Nr    r^   r    r    r$   on_connection_close*  s    z'HTTPMessageDelegate.on_connection_close)rf   rg   rh   ri   r   r*   r   r   r   r   r   r   r   r    r    r    r$   r     s   
r   c                   @   sL   e Zd ZdZded eee ddddZeddd	d
Z	ddddZ
dS )ru   zYApplications use this interface to write their responses.

    .. versionadded:: 4.0
    Nr   zFuture[None])r~   rS   r   r   c                 C   s
   t  dS )a  Write an HTTP header block.

        :arg start_line: a `.RequestStartLine` or `.ResponseStartLine`.
        :arg headers: a `.HTTPHeaders` instance.
        :arg chunk: the first (optional) chunk of data.  This is an optimization
            so that small responses can be written in the same call as their
            headers.

        The ``version`` field of ``start_line`` is ignored.

        Returns a future for flow control.

        .. versionchanged:: 6.0

           The ``callback`` argument was removed.
        Nr   )r.   r~   rS   r   r    r    r$   write_headers9  s    zHTTPConnection.write_headersr   c                 C   s
   t  dS )zWrites a chunk of body data.

        Returns a future for flow control.

        .. versionchanged:: 6.0

           The ``callback`` argument was removed.
        Nr   r   r    r    r$   writeQ  s    	zHTTPConnection.writerE   c                 C   s
   t  dS )z3Indicates that the last body data has been written.Nr   r^   r    r    r$   r   \  s    zHTTPConnection.finish)N)rf   rg   rh   ri   r   r*   r   r   r   r   r   r    r    r    r$   ru   3  s   	 ru   .)urlr0   r   c                 C   s   |du r| S t | }t|tr<t|jdd}||  nDt|tsPt|trjt|jdd}|| nd	t
|}t|t|}t|d |d |d |d ||d	 f} | S )
a  Concatenate url and arguments regardless of whether
    url has existing query parameters.

    ``args`` may be either a dictionary or a list of key-value pairs
    (the latter allows for multiple values with the same key.

    >>> url_concat("http://example.com/foo", dict(c="d"))
    'http://example.com/foo?c=d'
    >>> url_concat("http://example.com/foo?a=b", dict(c="d"))
    'http://example.com/foo?a=b&c=d'
    >>> url_concat("http://example.com/foo?a=b", [("c", "d"), ("c", "d2")])
    'http://example.com/foo?a=b&c=d&c=d2'
    NTr   z7'args' parameter should be dict, list or tuple. Not {0}r   r2            )r   r7   dictr   r   r   rF   listtupleformattype	TypeErrorr   r   )r   r0   
parsed_urlZparsed_queryerrZfinal_queryr    r    r$   
url_concata  s0    

r   c                   @   s*   e Zd ZU dZeed< eed< eed< dS )rt   zRepresents a file uploaded via a form.

    For backwards compatibility, its instance attributes are also
    accessible as dictionary keys.

    * ``filename``
    * ``body``
    * ``content_type``
    filenamerz   content_typeN)rf   rg   rh   ri   rl   __annotations__r   r    r    r    r$   rt     s   

rt   )range_headerr   c                 C   s   |  d\}}}| |  }}|dkr.dS | d\}}}zt|}t|}W n tyf   Y dS 0 |dur|du r|dkr| }d}n|d7 }||fS )ag  Parses a Range header.

    Returns either ``None`` or tuple ``(start, end)``.
    Note that while the HTTP headers use inclusive byte positions,
    this method returns indexes suitable for use in slices.

    >>> start, end = _parse_request_range("bytes=1-2")
    >>> start, end
    (1, 3)
    >>> [0, 1, 2, 3, 4][start:end]
    [1, 2]
    >>> _parse_request_range("bytes=6-")
    (6, None)
    >>> _parse_request_range("bytes=-6")
    (-6, None)
    >>> _parse_request_range("bytes=-0")
    (None, 0)
    >>> _parse_request_range("bytes=")
    (None, None)
    >>> _parse_request_range("foo=42")
    >>> _parse_request_range("bytes=1-2,6-10")

    Note: only supports one range (ex, ``bytes=1-2,6-10`` is not allowed).

    See [0] for the details of the range header.

    [0]: http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p5-range-latest.html#byte.ranges
    =r   Nr   r   r2   )r   rQ   _int_or_nonerP   )r   unit_r=   Zstart_bZend_bstartendr    r    r$   _parse_request_range  s"    r   )r   r   totalr   c                 C   s"   | pd} |p|d }d| ||f S )zReturns a suitable Content-Range header:

    >>> print(_get_content_range(None, 1, 4))
    bytes 0-0/4
    >>> print(_get_content_range(1, 3, 4))
    bytes 1-2/4
    >>> print(_get_content_range(None, None, 4))
    bytes 0-3/4
    r   r2   zbytes %s-%s/%sr    )r   r   r   r    r    r$   _get_content_range  s    
r   )valr   c                 C   s   |   } | dkrd S t| S )Nrc   )rQ   ro   )r   r    r    r$   r     s    r   )r   rz   r   r|   rS   r   c              
   C   sV  |  dr|r*d|v r*td|d  dS zt|dd}W n4 tyn } ztd| i }W Y d}~n
d}~0 0 | D ]\}}|rx||g | qxn|  drR|rd|v rtd|d  dS zX| d	}	|	D ]<}
|
	 
d
\}}}|dkr|rtt||||  qqtdW n2 tyP } ztd| W Y d}~n
d}~0 0 dS )aF  Parses a form request body.

    Supports ``application/x-www-form-urlencoded`` and
    ``multipart/form-data``.  The ``content_type`` parameter should be
    a string and ``body`` should be a byte string.  The ``arguments``
    and ``files`` parameters are dictionaries that will be updated
    with the parsed contents.
    z!application/x-www-form-urlencodedzContent-Encodingz Unsupported Content-Encoding: %sNTr   z&Invalid x-www-form-urlencoded body: %szmultipart/form-data;r   boundaryzmultipart boundary not foundzInvalid multipart/form-data: %s)
startswithr   warningr
   r   rF   r   r   r(   rQ   r   parse_multipart_form_datar   rP   )r   rz   r   r|   rS   Zuri_argumentser   rG   fieldsfieldr;   r   r<   r    r    r$   r     s<    

r   )r   datar   r|   r   c                 C   s^  |  dr | dr | dd } |d|  d }|dkrHtd dS |d| d|  d }|D ]}|spqf|d}|dkrtd	 qft|d| 	d
}|
dd}	t|	\}
}|
dks|dstd qf||d d }|
dstd qf|d }|
drF|
dd}||g t|d ||d qf||g | qfdS )a]  Parses a ``multipart/form-data`` body.

    The ``boundary`` and ``data`` parameters are both byte strings.
    The dictionaries given in the arguments and files parameters
    will be updated with the contents of the body.

    .. versionchanged:: 5.1

       Now recognizes non-ASCII filenames in RFC 2231/5987
       (``filename*=``) format.
       "r2   rK   s   --z.Invalid multipart/form-data: no final boundaryNs   
s   

z#multipart/form-data missing headerszutf-8zContent-Dispositionrc   z	form-datazInvalid multipart/form-data   r   z&multipart/form-data value missing namer   r   zapplication/unknown)r   rz   r   )r   rV   rfindr   r   r(   findr*   rY   decoderB   _parse_headerr   r?   rt   )r   r   r   r|   Zfinal_boundary_indexpartspartZeohrS   Zdisp_headerdispositionZdisp_paramsr=   r   ctyper    r    r$   r     sB    





r   )tsr   c                 C   sh   t | ttfr| }nDt | ttjfr0t| }n(t | tjrLt| 	 }nt
d|  tjj|ddS )a  Formats a timestamp in the format used by HTTP.

    The argument may be a numeric timestamp as returned by `time.time`,
    a time tuple as returned by `time.gmtime`, or a `datetime.datetime`
    object. Naive `datetime.datetime` objects are assumed to represent
    UTC; aware objects are converted to UTC before formatting.

    >>> format_timestamp(1359312200)
    'Sun, 27 Jan 2013 18:43:20 GMT'
    zunknown timestamp type: %rT)usegmt)r7   ro   r   r   r   struct_timecalendartimegmdatetimeutctimetupler   emailutils
formatdate)r   Ztime_numr    r    r$   format_timestampT  s    r  rv   )rw   r   ry   z^HTTP/1\.[0-9]$rH   c                 C   sR   z|  d\}}}W n ty.   tdY n0 t|sFtd| t|||S )zReturns a (method, path, version) tuple for an HTTP 1.x request line.

    The response is a `collections.namedtuple`.

    >>> parse_request_start_line("GET /foo HTTP/1.1")
    RequestStartLine(method='GET', path='/foo', version='HTTP/1.1')
    rJ   zMalformed HTTP request linez/Malformed HTTP version in HTTP Request-Line: %r)r(   rP   rN   _http_version_rematchrv   )rI   rw   r   ry   r    r    r$   parse_request_start_linet  s    
r  r   )ry   codereasonz (HTTP/1.[0-9]) ([0-9]+) ([^\r]*)c                 C   s@   t | } t| }|stdt|dt|d|dS )zReturns a (version, code, reason) tuple for an HTTP 1.x response line.

    The response is a `collections.namedtuple`.

    >>> parse_response_start_line("HTTP/1.1 200 OK")
    ResponseStartLine(version='HTTP/1.1', code=200, reason='OK')
    z!Error parsing response start liner2   r   r   )r	   _http_response_line_rer  rN   r   groupro   )rI   r  r    r    r$   parse_response_start_line  s
    
r	  )sr   c                 c   s   | d d dkr| dd  } |  d}|dkr`| dd|| dd| d r`|  d|d }q&|dk rpt| }| d | }| V  | |d  } q d S )Nr2   r   r   "z\"r   )r   countr6   rQ   )r
  r   fr    r    r$   _parseparam  s    
(
r  c                 C   s   t d|  }t|}dg}|D ]P}|d}|dkr|d|   }||d d  }||t|f qtj	|}|
d i }	|D ]L\}}
tj|
}t|dkr|d dkr|d	 dkr|dd	 }||	|< q||	fS )
aY  Parse a Content-type like header.

    Return the main content-type and a dictionary of options.

    >>> d = "form-data; foo=\"b\\\\a\\\"r\"; file*=utf-8''T%C3%A4st"
    >>> ct, d = _parse_header(d)
    >>> ct
    'form-data'
    >>> d['file'] == r'T\u00e4st'.encode('ascii').decode('unicode_escape')
    True
    >>> d['foo']
    'b\\a"r'
    r   )ZDummyr=   r   r   Nr2   r   r  rK   )r  nextr   rQ   r   r?   r	   r   r   decode_paramspopcollapse_rfc2231_valuer6   )rI   r   keyparamspir   r=   Zdecoded_paramspdictZdecoded_valuer    r    r$   r     s$    

$
r   )r  r  r   c                 C   sT   |s| S | g}t | D ].\}}|du r6|| q|d||f  qd|S )zInverse of _parse_header.

    >>> _encode_header('permessage-deflate',
    ...     {'client_max_window_bits': 15, 'client_no_context_takeover': None})
    'permessage-deflate; client_max_window_bits=15; client_no_context_takeover'
    Nz%s=%sz; )sortedrF   r?   r'   )r  r  outr;   r<   r    r    r$   _encode_header  s    r  )usernamepasswordr   c                 C   s@   t | trtd| } t |tr,td|}t| d t| S )zEncodes a username/password pair in the format used by HTTP auth.

    The return value is a byte string in the form ``username:password``.

    .. versionadded:: 5.1
    NFC   :)r7   r   unicodedata	normalizer   )r  r  r    r    r$   encode_username_password  s
    	

r!  c                  C   s   dd l } |  S )Nr   )doctestZDocTestSuite)r"  r    r    r$   doctests  s    r#  z^(.+):(\d+)$)netlocr   c                 C   s8   t | }|r(|d}t|d}n| }d}||fS )zReturns ``(host, port)`` tuple from ``netloc``.

    Returned ``port`` will be ``None`` if not present.

    .. versionadded:: 4.1
    r2   r   N)
_netloc_rer  r  ro   )r$  r  r{   portr    r    r$   r     s    

r   )qsr   c                 c   s*   |   D ]\}}|D ]}||fV  qqdS )zgGenerator converting a result of ``parse_qs`` back to name-value pairs.

    .. versionadded:: 5.0
    N)rF   )r'  r;   vsr<   r    r    r$   	qs_to_qsl  s    r)  z\\[0-3][0-7][0-7]z[\\].rc   c                 C   sN  | du st | dk r| S | d dks0| d dkr4| S | dd } d}t | }g }d|  krf|k rFn nt| |}t| |}|s|s|| |d  qFd }}|r|d}|r|d}|r|r||k r|| ||  || |d   |d }qP|| ||  |tt| |d |d  d |d }qPt|S )	zHandle double quotes and escaping in cookie values.

    This method is copied verbatim from the Python 3.5 standard
    library (http.cookies._unquote) so we don't have to depend on
    non-public interfaces.
    Nr   r   r  rK   r2   r      )	r6   
_OctalPattsearch
_QuotePattr?   r   chrro   	_nulljoin)r
  r  r   reso_matchq_matchjr;   r    r    r$   _unquote_cookie&  s6    	


$
r4  )cookier   c                 C   sr   i }|  tdD ]Z}td|v r8| tdd\}}ntd| }}| |  }}|s`|rt|||< q|S )a[  Parse a ``Cookie`` HTTP header into a dict of name/value pairs.

    This function attempts to mimic browser cookie parsing behavior;
    it specifically does not follow any of the cookie-related RFCs
    (because browsers don't either).

    The algorithm used is identical to that used by Django version 1.9.10.

    .. versionadded:: 4.4.2
    r   r   r2   rc   )r(   rl   rQ   r4  )r5  Z
cookiedictr   r  r   r    r    r$   r   X  s    r   )N)bri   r   collections.abccollectionsrb   r   email.utilsr   	functoolsr   http.clientr   http.cookiesr   resslr   r   r  urllib.parser   r   r   r   Ztornado.escaper	   r
   r   Ztornado.logr   Ztornado.utilr   r   rj   r   r   r   r   r   r   r   r   r   r   r   TYPE_CHECKINGr   Zasyncior   Zunittestrl   r)   abcMutableMappingr*   r   rr   r   rN   r   r   r   ru   r   rt   ro   r   r   r   r   r   r   r   r   r   r  
namedtuplerv   compiler  r  r   r  r	  r  r   r  r!  r#  r%  r   r)  r+  r-  r'   r/  r4  r   r    r    r    r$   <module>   s   4	 , _
	././3 2;

 #
(


2