BYPASS SHELL BY ./RAZORGANZ
Server: nginx/1.20.1
System: Linux iZdzfnv9mwfppeZ 5.10.134-19.2.al8.x86_64 #1 SMP Wed Oct 29 22:47:09 CST 2025 x86_64
User: apache (48)
PHP: 8.2.30
Disabled: NONE
Upload Files
File: //lib64/python3.6/site-packages/tornado/__pycache__/httputil.cpython-36.opt-1.pyc
3

	��f	��	@sdZddlZddlZddlZddlZddlZddlmZddl	Z
ddlZddlm
Z
ddlZddlZddlmZmZmZmZddlmZmZmZddlmZddlmZmZeddlZdd	lmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)ej*�rdd
lm+Z+ddl,m-Z-ddl.Z.ej/d�Z0Gd
d�de1�Z2e2d�Z3Gdd�dej4j5�Z6Gdd�de7�Z8Gdd�de9�Z:Gdd�de9�Z;Gdd�de7�Z<Gdd�de7�Z=Gdd�de7�Z>e?e%de$e?e?fe!ee?e?feee?e?fdffe?d�d d!�Z@Gd"d#�d#e�ZAe?e&ee&eBe&eBfd$�d%d&�ZCe&eBe&eBeBe?d'�d(d)�ZDe?e&eBd*�d+d,�ZEd]e?eFe$e?e!eFfe$e?e!eAfe6dd-�d.d/�ZGeFeFe$e?e!eFfe$e?e!eAfdd0�d1d2�ZHe%eBeIeJejKejfe?d3�d4d5�ZLejMd6d7d8d9g�ZNe?eNd:�d;d<�ZOejMd=d9d>d?g�ZPe?ePd:�d@dA�ZQe?e(e?ddfdB�dCdD�ZRe?ee?e$e?e?ffd:�dEdF�ZSe?e$e?e?fe?dG�dHdI�ZTe%e?eFfe%e?eFfeFdJ�dKdL�ZUdMdN�ZVe?ee?e&eBfdO�dPdQ�ZWe$e?e!e)fe ee?e)fdR�dSdT�ZXej/dU�ZYej/dV�ZZdWj[Z\e?e?dB�dXdY�Z]e?e$e?e?fdZ�d[d\�Z^dS)^z�HTTP utility code shared by clients and servers.

This module also defines the `HTTPServerRequest` class which is exposed
via `tornado.web.RequestHandler.request`.
�N)�	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\r?\ncs8eZdZdZedd��fdd�Zeed�dd�Z�ZS)	�_NormalizedHeaderCacheaKDynamic cached mapping of header names to Http-Header-Case.

    Implemented as a dict subclass so that cache hits are as fast as a
    normal dict lookup, without the overhead of a python function
    call.

    >>> normalized_headers = _NormalizedHeaderCache(10)
    >>> normalized_headers["coNtent-TYPE"]
    'Content-Type'
    N)�size�returncs"tt|�j�||_tj�|_dS)N)�superr�__init__r�collections�deque�queue)�selfr)�	__class__�� /usr/lib64/python3.6/httputil.pyrRsz_NormalizedHeaderCache.__init__)�keyrcCsRdjdd�|jd�D��}|||<|jj|�t|j�|jkrN|jj�}||=|S)N�-cSsg|]}|j��qSr%)�
capitalize)�.0�wr%r%r&�
<listcomp>Xsz6_NormalizedHeaderCache.__missing__.<locals>.<listcomp>)�join�splitr"�append�lenr�popleft)r#r'Z
normalizedZold_keyr%r%r&�__missing__Ws
z"_NormalizedHeaderCache.__missing__)	�__name__�
__module__�__qualname__�__doc__�intr�strr2�
__classcell__r%r%)r$r&rFs
ri�c@steZdZdZejeeeefdd�dd��Z	ejeeefdd�dd��Z	eje
eefdd�dd��Z	ejedd	�d
d��Z	ejedd�dd�Z	eedd
�dd�Zeeed�dd�Z
ee
eefd�dd�Zedd�dd�Zeedd�dd��Zeedd
�dd�Zeed�dd�Zedd�d d!�Zed�d"d#�Zeejd�d$d%�Zdd�d&d'�ZeZed�d(d)�ZeZdS)*�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__argrcCsdS)Nr%)r#r;r%r%r&r�szHTTPHeaders.__init__cCsdS)Nr%)r#r;r%r%r&r�s)�argsrcGsdS)Nr%)r#r<r%r%r&r�s)�kwargsrcKsdS)Nr%)r#r=r%r%r&r�s)r<r=rcOspi|_i|_d|_t|�dkr`t|�dkr`t|dt�r`x2|dj�D]\}}|j||�qFWn|j||�dS)N�r)	�_dict�_as_list�	_last_keyr0�
isinstancer:�get_all�add�update)r#r<r=�k�vr%r%r&r�s&)�name�valuercCsRt|}||_||krFt||�dt|�|j|<|j|j|�n|||<dS)z#Adds a new value for the given key.�,N)�_normalized_headersrArr?r@r/)r#rHrI�	norm_namer%r%r&rD�szHTTPHeaders.add)rHrcCst|}|jj|g�S)z2Returns all values for the given header as a list.)rKr@�get)r#rHrLr%r%r&�get_list�szHTTPHeaders.get_list)rccs4x.|jj�D] \}}x|D]}||fVqWqWdS)z�Returns an iterable of all (name, value) pairs.

        If a header has multiple values, multiple pairs will be
        returned with the same name.
        N)r@�items)r#rH�valuesrIr%r%r&rC�s
zHTTPHeaders.get_all)�linercCs�|dj�rX|jdkrtd��d|j�}|j|jd|7<|j|j|7<nBy|jdd�\}}Wntk
r�td��YnX|j||j	��dS)	z�Updates the dictionary with a single header line.

        >>> h = HTTPHeaders()
        >>> h.parse_line("Content-Type: text/html")
        >>> h.get('content-type')
        'text/html'
        rNz.first header line cannot start with whitespace� r>�:zno colon in header line���)
�isspacerA�HTTPInputError�lstripr@r?r.�
ValueErrorrD�strip)r#rQZnew_partrHrIr%r%r&�
parse_line�s
zHTTPHeaders.parse_line)�headersrcCs,|�}x tj|�D]}|r|j|�qW|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`.

        )�_CRLF_REr.rZ)�clsr[�hrQr%r%r&�parse�s
zHTTPHeaders.parsecCs"t|}||j|<|g|j|<dS)N)rKr?r@)r#rHrIrLr%r%r&�__setitem__�s
zHTTPHeaders.__setitem__cCs|jt|S)N)r?rK)r#rHr%r%r&�__getitem__�szHTTPHeaders.__getitem__cCst|}|j|=|j|=dS)N)rKr?r@)r#rHrLr%r%r&�__delitem__�szHTTPHeaders.__delitem__cCs
t|j�S)N)r0r?)r#r%r%r&�__len__�szHTTPHeaders.__len__cCs
t|j�S)N)�iterr?)r#r%r%r&�__iter__�szHTTPHeaders.__iter__cCst|�S)N)r:)r#r%r%r&�copy�szHTTPHeaders.copycCs6g}x&|j�D]\}}|jd||f�qWdj|�S)Nz%s: %s
�)rCr/r-)r#�linesrHrIr%r%r&�__str__szHTTPHeaders.__str__)r3r4r5r6�typingZoverloadrr8rrrZAnyrDrNrrCrZ�classmethodr_r`rarbr7rcrrerf�__copy__riZ__unicode__r%r%r%r&r:gs2
r:c
@s�eZdZdZdZdZdZdeeeee	ee
eedfddedd�dd	�Z
ee
eejjfd
�dd��Zed
�d
d�Zed
�dd�Zdeede
e	fd�dd�Zdd
�dd�Zed
�dd�ZdS)�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�versionr[�body�host�files�
connection�
start_line�server_connectionrc
Cs�|	dk	r|	\}}}||_||_||_|p,t�|_|p6d|_t|dd�}t|dd�|_t|dd�|_|pt|jj	d�ptd|_
t|j
j��d|_
|p�i|_||_|
|_tj�|_d|_|dk	r�|jd	�\|_}|_t|jd
d�|_tj|j�|_i|_dS)N��context�	remote_ip�protocol�httpZHostz	127.0.0.1r�?T)�keep_blank_values)rrrsrtr:r[ru�getattrr}r~rMrv�split_host_and_port�lowerZ	host_namerwrxrz�time�_start_time�_finish_time�	partition�path�queryr	�	argumentsrf�deepcopyZquery_arguments�body_arguments)
r#rrrsrtr[rurvrwrxryrzr|�sepr%r%r&rqs,




zHTTPServerRequest.__init__)rcCs�t|d�s�tjj�|_d|jkr�yt|jd�}Wntk
rFYn<Xx8|j�D],\}}y||j|<WqRtk
r|YqRXqRW|jS)z0A dictionary of ``http.cookies.Morsel`` objects.�_cookiesZCookie)	�hasattrr�cookiesZSimpleCookier�r[�parse_cookie�	ExceptionrO)r#ZparsedrFrGr%r%r&r��s


zHTTPServerRequest.cookiescCs|jd|j|jS)z+Reconstructs the full URL for this request.z://)r~rvrs)r#r%r%r&�full_url�szHTTPServerRequest.full_urlcCs(|jdkrtj�|jS|j|jSdS)z?Returns the amount of time it took for this request to execute.N)r�r�r�)r#r%r%r&�request_time�s
zHTTPServerRequest.request_timeF)�binary_formrcCs:y |jdkrdS|jjjj|d�Stk
r4dSXdS)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�)rx�streamZsocketZgetpeercertr)r#r�r%r%r&�get_ssl_certificate�s

z%HTTPServerRequest.get_ssl_certificatecCsRt|jjdd�|j|j|j|j�x*|jj�D]\}}|jj|g�j	|�q.WdS)NzContent-Typerg)
�parse_body_argumentsr[rMrur�rwrOr��
setdefault�extend)r#rFrGr%r%r&�_parse_body�szHTTPServerRequest._parse_bodycs,d}dj�fdd	�|D��}d
�jj|fS)Nr~rvrrrsrtr}z, csg|]}d|t�|�f�qS)z%s=%r)r�)r*�n)r#r%r&r,�sz.HTTPServerRequest.__repr__.<locals>.<listcomp>z%s(%s))r~rvrrrsrtr})r-r$r3)r#Zattrsr<r%)r#r&�__repr__�szHTTPServerRequest.__repr__)
NNrnNNNNNNN)F)r3r4r5r6r�r�Z_body_futurer8r:�bytesrr�objectr�propertyrr�ZMorselr��floatr��boolrr�r�r�r%r%r%r&rms.["rmc@seZdZdZdS)rVzqException class for malformed HTTP requests or responses
    from remote sources.

    .. versionadded:: 4.0
    N)r3r4r5r6r%r%r%r&rV�srVc@seZdZdZdS)�HTTPOutputErrorzJException class for errors in HTTP output.

    .. versionadded:: 4.0
    N)r3r4r5r6r%r%r%r&r��sr�c@s2eZdZdZeddd�dd�Zedd�d	d
�ZdS)�HTTPServerConnectionDelegatez_Implement this interface to handle requests from `.HTTPServer`.

    .. versionadded:: 4.0
    rp�HTTPMessageDelegate)�server_conn�request_connrcCs
t��dS)ajThis 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_requestsz*HTTPServerConnectionDelegate.start_requestN)r�rcCsdS)z�This 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_closesz%HTTPServerConnectionDelegate.on_close)r3r4r5r6r�r�r�r%r%r%r&r��sr�c@sbeZdZdZedeeedd�dd�Ze	eedd�d	d
�Z
dd�dd
�Zdd�dd�ZdS)r�z_Implement this interface to handle an HTTP request or response.

    .. versionadded:: 4.0
    rq�ResponseStartLineN)ryr[rcCsdS)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#ryr[r%r%r&�headers_received!sz$HTTPMessageDelegate.headers_received)�chunkrcCsdS)ziCalled when a chunk of data has been received.

        May return a `.Future` for flow control.
        Nr%)r#r�r%r%r&�
data_received4sz!HTTPMessageDelegate.data_received)rcCsdS)z6Called after the last chunk of data has been received.Nr%)r#r%r%r&�finish;szHTTPMessageDelegate.finishcCsdS)z�Called 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?sz'HTTPMessageDelegate.on_connection_close)rqr�)
r3r4r5r6rr:rrr�r�r�r�r�r%r%r%r&r�sr�c@sHeZdZdZdedeedd�dd�Zedd	�d
d�Zdd�d
d�Z	dS)rpzYApplications use this interface to write their responses.

    .. versionadded:: 4.0
    Nrqr�zFuture[None])ryr[r�rcCs
t��dS)aWrite 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.
        N)r�)r#ryr[r�r%r%r&�
write_headersNszHTTPConnection.write_headers)r�rcCs
t��dS)z�Writes a chunk of body data.

        Returns a future for flow control.

        .. versionchanged:: 6.0

           The ``callback`` argument was removed.
        N)r�)r#r�r%r%r&�writefs	zHTTPConnection.write)rcCs
t��dS)z<Indicates that the last body data has been written.
        N)r�)r#r%r%r&r�qszHTTPConnection.finish)N)rqr�)
r3r4r5r6rr:r�r�r�r�r%r%r%r&rpHs
rp.)�urlr<rcCs�|dkr|St|�}t|t�r<t|jdd�}|j|j��nDt|t�sPt|t�rjt|jdd�}|j|�ndj	t
|��}t|��t|�}t
|d|d|d|d||d	f�}|S)
aConcatenate 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'
    NT)r�z7'args' parameter should be dict, list or tuple. Not {0}rr>���)rrB�dictrr�r�rO�list�tuple�format�type�	TypeErrorrr)r�r<Z
parsed_urlZparsed_query�errZfinal_queryr%r%r&�
url_concatws*

r�c@seZdZdZdS)roz�Represents a file uploaded via a form.

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

    * ``filename``
    * ``body``
    * ``content_type``
    N)r3r4r5r6r%r%r%r&ro�s	ro)�range_headerrcCs�|jd�\}}}|j�|j�}}|dkr.dS|jd�\}}}yt|�}t|�}Wntk
rfdSX|dk	r�|dkr�|dkr�|}d}n|d7}||fS)agParses 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(rr>)r�rY�_int_or_nonerX)r�Zunit�_rIZstart_bZend_b�start�endr%r%r&�_parse_request_range�s"r�)r�r��totalrcCs"|pd}|p|d}d|||fS)z�Returns 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
    rr>zbytes %s-%s/%sr%)r�r�r�r%r%r&�_get_content_range�s
r�)�valrcCs|j�}|dkrdSt|�S)Nrg)rYr7)r�r%r%r&r��sr�)�content_typerur�rwr[rcCsZ|jd�r�|r*d|kr*tjd|d�dSytt|�dd�}Wn2tk
rp}ztjd|�i}WYdd}~XnXx�|j�D]\}}|r||j|g�j|�q|Wn�|jd��rV|r�d|kr�tjd|d�dSyX|j	d	�}	xH|	D]8}
|
j
�jd
�\}}}
|dkr�|
r�tt
|
�|||�Pq�Wtd��Wn0tk
�rT}ztjd
|�WYdd}~XnXdS)aFParses 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-urlencodedzContent-Encodingz Unsupported Content-Encoding: %sNT)r�z&Invalid x-www-form-urlencoded body: %szmultipart/form-data�;r��boundaryzmultipart boundary not foundzInvalid multipart/form-data: %s)�
startswithr�warningr	rr�rOr�r�r.rYr��parse_multipart_form_datar
rX)r�rur�rwr[Z
uri_arguments�erHrPZfieldsZfieldrFr�rGr%r%r&r��s8


r�)r��datar�rwrcCsf|jd�r |jd�r |dd�}|jd|d�}|dkrHtjd�dS|d|�jd|d�}�x�|D]�}|stqj|jd�}|dkr�tjd�qjtj|d|�j	d	��}|j
d
d�}	t|	�\}
}|
dks�|jd�r�tjd
�qj||dd�}|j
d��s
tjd�qj|d}
|j
d��rL|j
dd�}|j|
g�j
t|d||d��qj|j|
g�j
|�qjWdS)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.
    �"r>s--z.Invalid multipart/form-data: no final boundaryNs
s

z#multipart/form-data missing headerszutf-8zContent-Dispositionrgz	form-datazInvalid multipart/form-data�r�rHz&multipart/form-data value missing name�filenamezContent-Typezapplication/unknown)r�rur�rTrTrT���)r��endswith�rfindrr�r.�findr:r_�decoderM�
_parse_headerr�r/ro)r�r�r�rwZfinal_boundary_index�parts�partZeohr[Zdisp_headerZdispositionZdisp_paramsrIrHZctyper%r%r&r�-s>




r�)�tsrcCsht|ttf�r|}nDt|ttjf�r0tj|�}n(t|tj�rLtj|j	��}nt
d|��tjj
|dd�S)aFormats 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.

    >>> format_timestamp(1359312200)
    'Sun, 27 Jan 2013 18:43:20 GMT'
    zunknown timestamp type: %rT)Zusegmt)rBr7r�r�r��struct_time�calendarZtimegm�datetimeZutctimetupler��email�utilsZ
formatdate)r�Ztime_numr%r%r&�format_timestampgsr�rqrrr�rt)rQrcCsVy|jd�\}}}Wntk
r0td��YnXtjd|�sJtd|��t|||�S)z�Returns 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')
    rRzMalformed HTTP request linez^HTTP/1\.[0-9]$z/Malformed HTTP version in HTTP Request-Line: %r)r.rXrV�re�matchrq)rQrrr�rtr%r%r&�parse_request_start_line�s
r�r��code�reasoncCsBt|�}tjd|�}|s td��t|jd�t|jd��|jd��S)z�Returns 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(HTTP/1.[0-9]) ([0-9]+) ([^
]*)z!Error parsing response start liner>r�r�)rr�r�rVr��groupr7)rQr�r%r%r&�parse_response_start_line�s
r�)�srccs�x�|dd�dkr�|dd�}|jd�}x<|dkrd|jdd|�|jdd|�drd|jd|d�}q*W|dkrvt|�}|d|�}|j�V||d�}qWdS)Nr>r�r�"z\"r�)r��countr0rY)r�r��fr%r%r&�_parseparam�s
*
r�cCs�td|�}t|�}d
g}xX|D]P}|jd�}|dkr |d|�j�j�}||dd�j�}|j|t|�f�q Wtjj	|�}|j
d�i}	xT|D]L\}}
tjj|
�}t|�dkr�|dd	kr�|dd	kr�|dd�}||	|<q�W||	fS)
aYParse 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��DummyrIr�rNr>r�r�)r�rIrTrT)
r��nextr�rYr�r/rr�r�Z
decode_params�popZcollapse_rfc2231_valuer0)rQr�r'Zparams�p�irHrIZdecoded_params�pdictZ
decoded_valuer%r%r&r��s$


$r�)r'r�rcCsX|s|S|g}x>t|j��D].\}}|dkr8|j|�q|jd||f�qWdj|�S)z�Inverse 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; )�sortedrOr/r-)r'r��outrFrGr%r%r&�_encode_header�sr�)�username�passwordrcCs@t|t�rtjd|�}t|t�r,tjd|�}t|�dt|�S)z�Encodes 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
    ZNFC�:)rBr
�unicodedataZ	normalizer
)r�r�r%r%r&�encode_username_password�s
	

r�cCsddl}|j�S)Nr)�doctestZDocTestSuite)r�r%r%r&�doctestssr�)�netlocrcCs:tjd|�}|r*|jd�}t|jd��}n|}d}||fS)z�Returns ``(host, port)`` tuple from ``netloc``.

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

    .. versionadded:: 4.1
    z^(.+):(\d+)$r>r�N)r�r�r�r7)rr�rvZportr%r%r&r�s
r�)�qsrccs2x,|j�D] \}}x|D]}||fVqWq
WdS)zgGenerator converting a result of ``parse_qs`` back to name-value pairs.

    .. versionadded:: 5.0
    N)rO)rrFZvsrGr%r%r&�	qs_to_qsl s
rz\\[0-3][0-7][0-7]z[\\].rgcCsT|dkst|�dkr|S|ddks0|ddkr4|S|dd	�}d}t|�}g}x�d|kod|kn�rJtj||�}tj||�}|r�|r�|j||d��Pd
}}|r�|jd�}|r�|jd�}|o�|s�||k�r
|j|||��|j||d�|d}qR|j|||��|jtt||d|d�d���|d}qRWt|�S)z�Handle 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�rr�r>r��rTrTrT)	r0�
_OctalPatt�search�
_QuotePattr/r��chrr7�	_nulljoin)r�r�r��resZo_matchZq_match�jrFr%r%r&�_unquote_cookie/s6	


$r)�cookiercCsvi}xl|jtd��D]Z}td�|kr:|jtd�d�\}}ntd�|}}|j�|j�}}|sb|rt|�||<qW|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�r>rg)r.r8rYr)rZ
cookiedictr�r'r�r%r%r&r�asr�)N)_r6r�r rfr�Zemail.utilsr�Zhttp.clientrZhttp.cookiesrr�Zsslrr�r�Zurllib.parserrrrZtornado.escaperr	r
Ztornado.logrZtornado.utilrr
rjrrrrrrrrrrrZ
TYPE_CHECKINGrZasynciorZunittest�compiler\r�rrK�abc�MutableMappingr:r�rmr�rVr�r�r�rpr8r�ror7r�r�r�r�r�r�r�r�r�r��
namedtuplerqr�r�r�r�r�r�r�r�r�rrrr-rrr�r%r%r%r&�<module>s�4
(]
	.00*"1$+6
 #(


2