o
    )Zh;                     @   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-rddl!m.Z. ddl/m0Z0 ddl1Z1dZ2e	dde3de3fddZ4G dd dej5j6Z7G dd de8Z9G dd de:Z;G dd de:Z<G dd de8Z=G dd de8Z>G dd  d e8Z?d!e3d"e(de'e3e3f e$e"e3e3f  e"e"e3e3f d#f f de3fd$d%Z@G d&d' d'eZAd(e3de)e"e)eB e)eB f  fd)d*ZCd+e)eB d,e)eB d-eBde3fd.d/ZDd0e3de)eB fd1d2ZE	dkd3e3d4eFd5e'e3e$eF f d6e'e3e$eA f d7e)e7 ddfd8d9ZGd:eFd;eFd5e'e3e$eF f d6e'e3e$eA f ddf
d<d=ZHd>e(eBeIeJejKejf de3fd?d@ZLeMdAg dBZNeOdCZPdDe3deNfdEdFZQeMdGg dHZReOdIZSdDe3deRfdJdKZTdLe3de+e3ddf fdMdNZUdDe3de"e3e'e3e3f f fdOdPZVdQe3dRe'e3e3f de3fdSdTZWdUe(e3eFf dVe(e3eFf deFfdWdXZXdYdZ ZYeOd[ZZd\e3de"e3e)eB f fd]d^Z[d_e'e3e$e, f de#e"e3e,f  fd`daZ\eOdbj]Z^dcej_de3fdddeZ`dLe3de3fdfdgZadhe3de'e3e3f fdidjZbdS )lzHTTP 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)Futurez 	i  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   G/var/www/html/lang_env/lib/python3.10/site-packages/tornado/httputil.py
<listcomp>L   s    z%_normalize_header.<locals>.<listcomp>)joinsplit)r   r   r   r#   _normalize_headerE   s   r'   c                   @   s  e Zd ZdZejdeeee f ddfddZ	ejdeeef ddfddZ	ejde
eef ddfd	dZ	ejd
eddfddZ	dejd
eddfddZ	dededdfddZdedee fddZdee
eef  fddZdeddfddZededd fddZdededdfddZdedefddZdeddfdd Zdefd!d"Zdeej fd#d$Zd)d%d&ZeZdef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
    _HTTPHeaders__argr   Nc                 C      d S Nr   selfr)   r   r   r#   __init__l      zHTTPHeaders.__init__c                 C   r*   r+   r   r,   r   r   r#   r.   p   r/   argsc                 G   r*   r+   r   )r-   r0   r   r   r#   r.   t   r/   kwargsc                 K   r*   r+   r   )r-   r1   r   r   r#   r.   x   r/   c                 O   sr   i | _ i | _d | _t|dkr/t|dkr/t|d tr/|d  D ]
\}}| || q"d S | 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.   |   s   &r   valuec                 C   sT   t |}|| _|| v r$t| | d t| | j|< | j| | dS || |< 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.addc                 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_listc                 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linec                 C   s   |d   r.| jdu rtdd|t }| j| j d  |7  < | j| j  |7  < dS z
|dd\}}W n tyC   tdw | 	||
t 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lstripHTTP_WHITESPACEr4   r3   r&   
ValueErrorr9   strip)r-   rG   Znew_partr   r=   r   r   r#   
parse_line   s   
zHTTPHeaders.parse_lineheadersc                 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`.

        
NrI   )r&   endswithrQ   )clsrR   hrG   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+   rY   rC   r   r   r#   __delitem__   s   zHTTPHeaders.__delitem__c                 C   
   t | jS r+   )r6   r3   r-   r   r   r#   __len__      
zHTTPHeaders.__len__c                 C   r]   r+   )iterr3   r^   r   r   r#   __iter__   r`   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__)r   r(   )__name__
__module____qualname____doc__typingoverloadr   strr   r.   r   Anyr9   rD   r   r8   rQ   classmethodrX   rZ   r[   r\   intr_   r   rb   rc   __copy__rf   __unicode__r   r   r   r#   r(   O   s4     

r(   c                   @   s
  e Zd ZdZdZdZdZ										d"dee dee dedee	 dee
 d	ee d
eeeed f  ded ded dee ddfddZedeeejjf fddZdefddZdefddZ	d#dededee
f fddZd$ddZdef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methoduriversionrR   bodyhostfilesHTTPFile
connectionHTTPConnection
start_lineRequestStartLineserver_connectionr   c                 C   s   |	d ur	|	\}}}|| _ || _|| _|pt | _|pd| _t|dd }t|dd | _t|dd| _|p:| j	dp:d| _
t| j
 d | _|pIi | _|| _|
| _t | _d | _|d urg|d	\| _}| _t| jd
d| _t| j| _i | _d S )N    context	remote_ipprotocolhttpHostz	127.0.0.1r   ?Tkeep_blank_values)ru   rv   rw   r(   rR   rx   getattrr   r   rB   ry   split_host_and_portlowerZ	host_namerz   r|   r   time_start_time_finish_time	partitionpathqueryr
   	argumentsrc   deepcopyZquery_argumentsbody_arguments)r-   ru   rv   rw   rR   rx   ry   rz   r|   r~   r   r   sepr   r   r#   r.   ]  s,   




zHTTPServerRequest.__init__c              	   C   s   t | ds>tj | _d| jv r>z	t| jd }W n ty$   Y | jS w | D ]\}}z|| j|< W q) ty=   Y q)w | jS )z0A dictionary of ``http.cookies.Morsel`` objects._cookiesCookie)	hasattrr   cookiesSimpleCookier   rR   parse_cookie	ExceptionrE   )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   ry   rv   r^   r   r   r#   full_url  s   zHTTPServerRequest.full_urlc                 C   s$   | j du rt | j S | j | j 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_formc                 C   s:   z| j du r	W dS | j jjj|dW S  ty   Y dS w )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-Typerd   )
parse_body_argumentsrR   rB   rx   r   rz   rE   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   ry   ru   rv   rw   r   z, c                    s   g | ]}d |t  |f qS )z%s=%r)r   )r!   nr^   r   r#   r$     s    z.HTTPServerRequest.__repr__.<locals>.<listcomp>z%s(%s))r%   	__class__rg   )r-   attrsr0   r   r^   r#   __repr__  s   zHTTPServerRequest.__repr__)
NNrt   NNNNNNN)Fr   N)rg   rh   ri   rj   r   r   Z_body_futurer   rm   r(   bytesr   r   objectr.   propertyr   r   Morselr   floatr   boolr   r   r   r   r   r   r   r#   rs      sd    \	

(

rs   c                   @      e Zd ZdZdS )rL   zqException class for malformed HTTP requests or responses
    from remote sources.

    .. versionadded:: 4.0
    Nrg   rh   ri   rj   r   r   r   r#   rL     s    rL   c                   @   r   )HTTPOutputErrorzJException class for errors in HTTP output.

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

    .. versionadded:: 4.0
    server_connrequest_connr}   r   HTTPMessageDelegatec                 C      t  )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`.
        NotImplementedError)r-   r   r   r   r   r#   start_request  s   z*HTTPServerConnectionDelegate.start_requestNc                 C      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     z%HTTPServerConnectionDelegate.on_close)rg   rh   ri   rj   r   r   r   r   r   r   r#   r     s    
r   c                   @   s`   e Zd ZdZded dedeed  fddZd	e	deed  fd
dZ
dddZdddZdS )r   z_Implement this interface to handle an HTTP request or response.

    .. versionadded:: 4.0
    r~   r   ResponseStartLinerR   r   Nc                 C   r   )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~   rR   r   r   r#   headers_received  s   z$HTTPMessageDelegate.headers_receivedchunkc                 C   r   )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_receivedc                 C   r   )z6Called after the last chunk of data has been received.Nr   r^   r   r   r#   finish)  r/   zHTTPMessageDelegate.finishc                 C   r   )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-  r   z'HTTPMessageDelegate.on_connection_closer   )rg   rh   ri   rj   r   r(   r   r   r   r   r   r   r   r   r   r   r#   r     s    


r   c                	   @   sR   e Zd ZdZ	dded dedee ddfd	d
ZdeddfddZ	dddZ
dS )r}   zYApplications use this interface to write their responses.

    .. versionadded:: 4.0
    Nr~   r   rR   r   r   zFuture[None]c                 C   r   )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.
        r   )r-   r~   rR   r   r   r   r#   write_headers<  s   zHTTPConnection.write_headersc                 C   r   )zWrites a chunk of body data.

        Returns a future for flow control.

        .. versionchanged:: 6.0

           The ``callback`` argument was removed.
        r   r   r   r   r#   writeT  s   	zHTTPConnection.writec                 C   r   )z3Indicates that the last body data has been written.r   r^   r   r   r#   r   _  s   zHTTPConnection.finishr+   r   )rg   rh   ri   rj   r   r(   r   r   r   r   r   r   r   r   r#   r}   6  s    	
r}   urlr0   .c                 C   s   |du r| S t | }t|trt|jdd}||  n"t|ts(t|tr5t|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   rE   listtupleformattype	TypeErrorr   r   )r   r0   
parsed_urlZparsed_queryerrZfinal_queryr   r   r#   
url_concatd  s0   

r   c                   @   s*   e Zd ZU dZeed< eed< eed< dS )r{   zRepresents a file uploaded via a form.

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

    * ``filename``
    * ``body``
    * ``content_type``
    filenamerx   content_typeN)rg   rh   ri   rj   rm   __annotations__r   r   r   r   r#   r{     s
   
 
r{   range_headerc                 C   s   |  d\}}}| | }}|dkrdS | d\}}}z
t|}t|}W n
 ty3   Y dS w |durM|du rI|dkrE| }d}||fS |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   rP   _int_or_nonerO   )r   unit_r=   Zstart_bZend_bstartendr   r   r#   _parse_request_range  s&   r   r   r   totalc                 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   valc                 C   s   |   } | dkr
d S t| S )Nrd   )rP   rp   )r   r   r   r#   r     s   r   r   rx   r   rz   rR   c              
   C   sT  |  drN|rd|v rtd|d  dS zt|dd}W n ty7 } ztd| i }W Y d}~nd}~ww | D ]\}}|rK||g | q<dS |  dr|rcd|v rctd|d  dS z+| d	}	|	D ]}
|
	 
d
\}}}|dkr|rtt||||  W dS qktd ty } ztd| W Y d}~dS d}~ww 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   rE   r   r   r&   rP   r   parse_multipart_form_datar   rO   )r   rx   r   rz   rR   Zuri_argumentser   rF   fieldsfieldr;   r   r<   r   r   r#   r     sL   


r   r   datac                 C   sZ  |  dr| dr| dd } |d|  d }|dkr$td dS |d| d|  d }|D ]w}|s8q3|d}|dkrGtd	 q3t|d| 	d
}|
dd}	t|	\}
}|
dksh|dsntd q3||d d }|
dstd q3|d }|
dr|
dd}||g t|d ||d q3||g | q3d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   rI   s   --z.Invalid multipart/form-data: no final boundaryNs   
s   

z#multipart/form-data missing headerszutf-8zContent-Dispositionrd   z	form-datazInvalid multipart/form-data   r   z&multipart/form-data value missing namer   r   zapplication/unknown)r   rx   r   )r   rU   rfindr   r   r&   findr(   rX   decoderB   _parse_headerr   r?   r{   )r   r   r   rz   Zfinal_boundary_indexpartspartZeohrR   Zdisp_headerZdispositionZdisp_paramsr=   r   ctyper   r   r#   r     sD   







r   tsc                 C   sh   t | ttfr
| }n"t | ttjfrt| }nt | tjr&t| 	 }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   rp   r   r   r   struct_timecalendartimegmdatetimeutctimetupler   emailutils
formatdate)r   Ztime_numr   r   r#   format_timestampW  s   r  r   )ru   r   rw   z^HTTP/1\.[0-9]$rG   c                 C   sN   z
|  d\}}}W n ty   tdw t|s!t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')
    rH   zMalformed HTTP request linez/Malformed HTTP version in HTTP Request-Line: %r)r&   rO   rL   _http_version_rematchr   )rG   ru   r   rw   r   r   r#   parse_request_start_linew  s   
r	  r   )rw   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  rL   r   grouprp   )rG   r  r   r   r#   parse_response_start_line  s
   
"r  sc                 c   s    | d d dkrg| dd  } |  d}|dkrD| dd|| dd| d rD|  d|d }|dkrD| dd|| dd| d s(|dk rLt| }| d | }| V  | |d  } | d d dks	d S d S )Nr2   r   r   "z\"r   )r   countr6   rP   )r  r   fr   r   r#   _parseparam  s   
((
r  c                 C   s   t d|  }t|}dg}|D ](}|d}|dkr7|d|   }||d d  }||t|f qtj	|}|
d i }	|D ]&\}}
tj|
}t|dkri|d dkri|d	 dkri|dd	 }||	|< qG||	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   )Dummyr=   r   r   Nr2   r   r  rI   )r  nextr   rP   r   r?   r	   r  r  decode_paramspopcollapse_rfc2231_valuer6   )rG   r   keyparamspir   r=   Zdecoded_paramspdictZdecoded_valuer   r   r#   r     s&   

$
r   r  r  c                 C   sT   |s| S | g}t | D ]\}}|du r|| 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; )sortedrE   r?   r%   )r  r  outr;   r<   r   r   r#   _encode_header  s   
r   usernamepasswordc                 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+)$netlocc                 C   s>   t | }|r|d}t|d}||fS | }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  rp   )r*  r  ry   portr   r   r#   r   	  s   

r   qsc                 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)rE   )r-  r;   vsr<   r   r   r#   	qs_to_qsl  s   r/  z\\(?:([0-3][0-7][0-7])|(.))mc                 C   s"   | d rt t| d dS | d S )Nr2      r   )chrrp   )r0  r   r   r#   _unquote_replace'  s   r3  c                 C   sJ   | du s
t | dk r| S | d dks| d dkr| S | dd } tt| S )zHandle double quotes and escaping in cookie values.

    This method is copied verbatim from the Python 3.13 standard
    library (http.cookies._unquote) so we don't have to depend on
    non-public interfaces.
    Nr   r   r  rI   r2   )r6   _unquote_subr3  )r  r   r   r#   _unquote_cookie.  s   	
r5  cookiec                 C   sr   i }|  tdD ]-}td|v r| tdd\}}ntd|}}| | }}|s0|r6t|||< 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   rd   )r&   rm   rP   r5  )r6  Z
cookiedictr   r  r   r   r   r#   r   I  s   r   r+   )crj   r   collections.abccollectionsrc   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   rk   r   r   r   r   r   r   r   r   r   r   r   TYPE_CHECKINGr   Zasyncior   ZunittestrN   rm   r'   abcMutableMappingr(   r   rs   r   rL   r   r   r   r}   r   r{   rp   r   r   r   r   r   r   r   r   r   r  
namedtupler   compiler  r	  r   r  r  r  r   r   r'  r)  r+  r   r/  subr4  Matchr3  r5  r   r   r   r   r#   <module>   s   4	 , _
	...
/
"3
1
:


"#



*
