
    =*h\                        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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jV                  rdd
lm,Z, ddl-m.Z. ddl/Z/ e	d      de0de0fd       Z1 G d dejd                  jf                        Z4 G d de5      Z6 G d de7      Z8 G d de7      Z9 G d de5      Z: G d de5      Z; G d de5      Z<de0de&de%e0e0f   e"e e0e0f      e e e0e0f   d f   f   de0fd!Z= G d" d#e      Z>d$e0de'e e'e?   e'e?   f      fd%Z@d&e'e?   d'e'e?   d(e?de0fd)ZAd*e0de'e?   fd+ZB	 dUd,e0d-eCd.e%e0e"eC   f   d/e%e0e"e>   f   d0e'e4   ddfd1ZDd2eCd3eCd.e%e0e"eC   f   d/e%e0e"e>   f   ddf
d4ZEd5e&e?eFeGej                  ej
                  f   de0fd6ZI ej                  d7g d8      ZK ej                  d9      ZMd:e0deKfd;ZN ej                  d<g d=      ZO ej                  d>      ZPd:e0deOfd?ZQd@e0de)e0ddf   fdAZRd:e0de e0e%e0e0f   f   fdBZSdCe0dDe%e0e0f   de0fdEZTdFe&e0eCf   dGe&e0eCf   deCfdHZUdI ZV ej                  dJ      ZWdKe0de e0e'e?   f   fdLZXdMe%e0e"e*   f   de!e e0e*f      fdNZY ej                  dO      j                  Z[dPej                  de0fdQZ]d@e0de0fdRZ^dSe0de%e0e0f   fdTZ_y)VzHTTP 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)
ObjectDictunicode_type)TupleIterableListMappingIteratorDictUnionOptional	Awaitable	GeneratorAnyStr)Deque)Futurei  namereturnc                     dj                  | j                  d      D cg c]  }|j                          c}      S c c}w )ziMap a header name to Http-Header-Case.

    >>> _normalize_header("coNtent-TYPE")
    'Content-Type'
    -)joinsplit
capitalize)r   ws     2/usr/lib/python3/dist-packages/tornado/httputil.py_normalize_headerr%   A   s/     88TZZ_=Q\\^=>>=s   =c                      e Zd ZdZej
                  deeee   f   ddfd       Z	ej
                  deeef   ddfd       Z	ej
                  de
eef   ddfd       Z	ej
                  d	eddfd
       Z	dej                  d	eddfdZ	dededdfdZdedee   fdZdee
eef      fdZdeddfdZededd fd       ZdededdfdZdedefdZdeddfdZdefdZdeej                     fdZddZeZdefdZeZy)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                      y N selfr(   s     r$   __init__zHTTPHeaders.__init__h           c                      y r*   r+   r,   s     r$   r.   zHTTPHeaders.__init__l   r/   r0   argsc                      y r*   r+   )r-   r2   s     r$   r.   zHTTPHeaders.__init__p   r/   r0   kwargsc                      y r*   r+   )r-   r4   s     r$   r.   zHTTPHeaders.__init__t   r/   r0   c                    i | _         i | _        d | _        t        |      dk(  rOt        |      dk(  rAt	        |d   t
              r.|d   j                         D ]  \  }}| j                  ||        y  | j                  |i | y )N   r   )	_dict_as_list	_last_keylen
isinstancer'   get_alladdupdate)r-   r2   r4   kvs        r$   r.   zHTTPHeaders.__init__x   sz    
t9>c&kQ.:d1g{3SQ) 1A DKK((r0   r   valuec                     t        |      }|| _        || v rIt        | |         dz   t        |      z   | j                  |<   | j                  |   j                  |       y|| |<   y)z#Adds a new value for the given key.,N)r%   r:   r
   r8   r9   appendr-   r   rB   	norm_names       r$   r>   zHTTPHeaders.add   sf    %d+	"4	?+c1Ju4EE JJy! MM)$++E2#DOr0   c                 P    t        |      }| j                  j                  |g       S )z2Returns all values for the given header as a list.)r%   r9   getr-   r   rG   s      r$   get_listzHTTPHeaders.get_list   s#    %d+	}}  B//r0   c              #   j   K   | j                   j                         D ]  \  }}|D ]  }||f 
  yw)zReturns an iterable of all (name, value) pairs.

        If a header has multiple values, multiple pairs will be
        returned with the same name.
        N)r9   items)r-   r   valuesrB   s       r$   r=   zHTTPHeaders.get_all   sA      !MM//1 	$LD& $Um#$	$s   13linec                    |d   j                         rp| j                  t        d      d|j                         z   }| j                  | j                     dxx   |z  cc<   | j
                  | j                  xx   |z  cc<   y	 |j                  dd      \  }}| j                  ||j                                y# t        $ r t        d      w xY w)	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 :r7   zno colon in header line)
isspacer:   HTTPInputErrorlstripr9   r8   r!   
ValueErrorr>   strip)r-   rO   new_partr   rB   s        r$   
parse_linezHTTPHeaders.parse_line   s     7??~~%$%UVVT[[]*HMM$..)"-9-JJt~~&(2&@"jja0e HHT5;;=)  @$%>??@s   B; ;Cheadersc                      |        }|j                  d      D ],  }|j                  d      r|dd }|s|j                  |       . |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`.

        
NrR   )r!   endswithrZ   )clsr[   hrO   s       r$   parsezHTTPHeaders.parse   sR     E MM$' 	#D}}T"CRyT"		#
 r0   c                 X    t        |      }|| j                  |<   |g| j                  |<   y r*   r%   r8   r9   rF   s       r$   __setitem__zHTTPHeaders.__setitem__   s*    %d+	 %

9$)7i r0   c                 2    | j                   t        |         S r*   )r8   r%   )r-   r   s     r$   __getitem__zHTTPHeaders.__getitem__   s    zz+D122r0   c                 N    t        |      }| j                  |= | j                  |= y r*   rd   rJ   s      r$   __delitem__zHTTPHeaders.__delitem__   s$    %d+	JJy!MM)$r0   c                 ,    t        | j                        S r*   )r;   r8   r-   s    r$   __len__zHTTPHeaders.__len__   s    4::r0   c                 ,    t        | j                        S r*   )iterr8   rk   s    r$   __iter__zHTTPHeaders.__iter__   s    DJJr0   c                     t        |       S r*   )r'   rk   s    r$   copyzHTTPHeaders.copy   s    4  r0   c                     g }| j                         D ]  \  }}|j                  |d|d        dj                  |      S )Nz: r]    )r=   rE   r    )r-   linesr   rB   s       r$   __str__zHTTPHeaders.__str__   s?    <<> 	5KD%LLtU34	5wwu~r0   )r   r'   )__name__
__module____qualname____doc__typingoverloadr   strr   r.   r   Anyr>   rK   r   r=   rZ   classmethodrb   re   rg   ri   intrl   r   ro   rq   __copy__ru   __unicode__r+   r0   r$   r'   r'   K   s   8 __gc49n5 $   __gc3h/ D   __eCHo $   __   
)fjj 
)C 
)D 
)
$ 
$C 
$D 
$0S 0T#Y 0
$%S/2 $*s *t *, C M  2+ +C +D +
3 3 3% % %
  (6::.  ! H  Kr0   r'   c                   @   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Zedeeej"                  j$                  f   fd       ZdefdZdefdZ	 ddededee
f   fdZddZdefdZy)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methoduriversionr[   bodyhostfilesHTTPFile
connectionHTTPConnection
start_lineRequestStartLineserver_connectionr   c                    |	|	\  }}}|| _         || _        || _        |xs
 t               | _        |xs d| _        t        |dd       }t        |dd       | _        t        |dd      | _        |xs | j                  j                  d      xs d| _
        t        | j                  j                               d   | _        |xs i | _        || _        |
| _        t#        j"                         | _        d | _        ||j)                  d	      \  | _        }| _        t/        | j,                  d
      | _        t3        j4                  | j0                        | _        i | _        y )Nr0   context	remote_ipprotocolhttpHostz	127.0.0.1r   ?Tkeep_blank_values)r   r   r   r'   r[   r   getattrr   r   rI   r   split_host_and_portlower	host_namer   r   r   time_start_time_finish_time	partitionpathqueryr   	argumentsrq   deepcopyquery_argumentsbody_arguments)r-   r   r   r   r[   r   r   r   r   r   r   r   seps                r$   r.   zHTTPServerRequest.__init__Y  s-    !#- FC/+-KC	 *i6 +t<V<CDLL,,V4C	,TYY__->?B[b
$!299; ?),s);&DIsDJ'

dK#}}T^^< r0   c                    t        | d      s~t        j                  j                         | _        d| j
                  v rM	 t        | j
                  d         }|j                         D ]  \  }}	 || j                  |<    | j                  S | j                  S # t        $ r Y ;w xY w# t        $ r Y | j                  S w xY w)z0A dictionary of ``http.cookies.Morsel`` objects._cookiesCookie)	hasattrr   cookiesSimpleCookier   r[   parse_cookierM   	Exception)r-   parsedr@   rA   s       r$   r   zHTTPServerRequest.cookies  s     tZ())+ M 4<<'!)$,,x*@AF !' !1!/0DMM!,! }}t}}  ) ! !	! !  }}s#   B& .B	B#"B#&	B=<B=c                 T    | j                   dz   | j                  z   | j                  z   S )z+Reconstructs the full URL for this request.z://)r   r   r   rk   s    r$   full_urlzHTTPServerRequest.full_url  s#    }}u$tyy0488;;r0   c                     | j                   !t        j                         | j                  z
  S | j                   | j                  z
  S )z?Returns the amount of time it took for this request to execute.)r   r   r   rk   s    r$   request_timezHTTPServerRequest.request_time  s<    $99;!1!111$$t'7'777r0   binary_formc                     	 | j                   y| j                   j                  j                  j                  |      S # t        $ r Y yw xY 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   s     r$   get_ssl_certificatez%HTTPServerRequest.get_ssl_certificate  sS    *	&??))00<<' =    		s   ? /? 	A
Ac                 @   t        | j                  j                  dd      | j                  | j                  | j
                  | j                         | j                  j                         D ]0  \  }}| j                  j                  |g       j                  |       2 y )NContent-Typers   )
parse_body_argumentsr[   rI   r   r   r   rM   r   
setdefaultextend)r-   r@   rA   s      r$   _parse_bodyzHTTPServerRequest._parse_body  s    LL^R0IIJJLL	
 ''--/ 	7DAqNN%%a,33A6	7r0   c                     d}dj                  |D cg c]  }|dt        | |       c}      }| j                  j                  d|dS c c}w )N)r   r   r   r   r   r   z, =())r    r   	__class__rv   )r-   attrsnr2   s       r$   __repr__zHTTPServerRequest.__repr__  sG    Myy5IaQa(89IJ>>22D99 Js   A)
NNzHTTP/1.0NNNNNNN)Fr   N)rv   rw   rx   ry   r   r   _body_futurer   r|   r'   bytesr   r   objectr.   propertyr   r   Morselr   floatr   boolr   r   r   r   r+   r0   r$   r   r      sf   Zx DE L !%!!)- $"7;1537.2&!&! c]&! 	&!
 +&&! uo&! sm&! S$z"2234&! -.&! /0&! $F+&! 
&!P c4<<#6#667  ,<# <8e 8 #(	tT5 	!>
7:# :r0   r   c                       e Zd ZdZy)rU   zqException class for malformed HTTP requests or responses
    from remote sources.

    .. versionadded:: 4.0
    Nrv   rw   rx   ry   r+   r0   r$   rU   rU     s     	r0   rU   c                       e Zd ZdZy)HTTPOutputErrorzJException class for errors in HTTP output.

    .. versionadded:: 4.0
    Nr   r+   r0   r$   r   r     s    
 	r0   r   c                   4    e Zd ZdZdeddddfdZdeddfd	Zy)
HTTPServerConnectionDelegatez_Implement this interface to handle requests from `.HTTPServer`.

    .. versionadded:: 4.0
    server_connrequest_connr   r   HTTPMessageDelegatec                     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   s      r$   start_requestz*HTTPServerConnectionDelegate.start_request  s     "##r0   Nc                      y)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   s     r$   on_closez%HTTPServerConnectionDelegate.on_close       	r0   )rv   rw   rx   ry   r   r   r   r+   r0   r$   r   r     s7    
$!$1A$	$F t r0   r   c                   b    e Zd ZdZded   dedeed      fdZde	deed      fd	Z
dd
ZddZy)r   z_Implement this interface to handle an HTTP request or response.

    .. versionadded:: 4.0
    r   r   ResponseStartLiner[   r   Nc                      y)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   r[   s      r$   headers_receivedz$HTTPMessageDelegate.headers_received  s    " 	r0   chunkc                      y)ziCalled when a chunk of data has been received.

        May return a `.Future` for flow control.
        Nr+   r-   r   s     r$   data_receivedz!HTTPMessageDelegate.data_received  s    
 	r0   c                      y)z6Called after the last chunk of data has been received.Nr+   rk   s    r$   finishzHTTPMessageDelegate.finish%  r/   r0   c                      y)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+   rk   s    r$   on_connection_closez'HTTPMessageDelegate.on_connection_close)  r   r0   r   )rv   rw   rx   ry   r   r'   r   r   r   r   r   r   r   r+   r0   r$   r   r     s]    AB  
)D/	"	&5 Xio-F r0   r   c            	       P    e Zd ZdZ	 dded   dedee   ddfd	Zdeddfd
Z	ddZ
y)r   zYApplications use this interface to write their responses.

    .. versionadded:: 4.0
    Nr   r   r[   r   r   zFuture[None]c                     t               )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   r[   r   s       r$   write_headerszHTTPConnection.write_headers8  s    , "##r0   c                     t               )zWrites a chunk of body data.

        Returns a future for flow control.

        .. versionchanged:: 6.0

           The ``callback`` argument was removed.
        r   r   s     r$   writezHTTPConnection.writeP  s     "##r0   c                     t               )z3Indicates that the last body data has been written.r   rk   s    r$   r   zHTTPConnection.finish[  s    !##r0   r*   r   )rv   rw   rx   ry   r   r'   r   r   r   r   r   r+   r0   r$   r   r   2  sY     "&	$AB$ $ 	$
 
$0	$5 	$^ 	$$r0   r   urlr2   .c           	         || S t        |       }t        |t              r7t        |j                  d      }|j                  |j                                nnt        |t              st        |t              r)t        |j                  d      }|j                  |       n%dj                  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'
    Tr   z7'args' parameter should be dict, list or tuple. Not {0}r   r7            )r   r<   dictr	   r   r   rM   listtupleformattype	TypeErrorr   r   )r   r2   
parsed_urlparsed_queryerrfinal_querys         r$   
url_concatr  `  s    & |
#J$ !1!1TJDJJL)	D$	:dE#: !1!1TJD!GNNJ
 nL)K
qMqMqMqMqM	
	C Jr0   c                   0    e Zd ZU dZeed<   eed<   eed<   y)r   zRepresents a file uploaded via a form.

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

    * ``filename``
    * ``body``
    * ``content_type``
    filenamer   content_typeN)rv   rw   rx   ry   r|   __annotations__r   r+   r0   r$   r   r     s     M
Kr0   r   range_headerc                 $   | j                  d      \  }}}|j                         |j                         }}|dk7  ry|j                  d      \  }}}	 t        |      }t        |      }|||dk7  r| }d}||fS |dz  }||fS # t        $ r Y yw xY w)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   r   Nr   r   r7   )r   rX   _int_or_nonerW   )r  unit_rB   start_bend_bstartends           r$   _parse_request_ranger    s    > "++C0ND!U**,%Dw,GQW%5! =ax 3< 1HC3<  s   B 	BBr  r  totalc                 6    | xs d} |xs |dz
  }d| d|d|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   r7   zbytes r   /r+   )r  r  r  s      r$   _get_content_ranger    s(     JQE<%1
C$c511r0   valc                 D    | j                         } | dk(  ry t        |       S )Nrs   )rX   r   )r  s    r$   r
  r
    s     
))+C
bys8Or0   r  r   r   r   r[   c                    | j                  d      rb|rd|v rt        d|d   z        	 t        |d      }|j	                         D ])  \  }}|s	|j                  |g       j                  |       + y| j                  d      r|rd|v rt        d|d   z        	 | j                  d	      }	|	D ]F  }
|
j                         j                  d
      \  }}}|dk(  s,|s/t        t        |      |||        y t        d      y# t        $ r}t        d|z        |d}~ww xY w# t        $ r}t        d|z        |d}~ww xY w)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: %sTr   z&Invalid x-www-form-urlencoded body: %sNzmultipart/form-data;r   boundaryzmultipart boundary not foundzInvalid multipart/form-data: %s)
startswithrU   r   r   rM   r   r   r!   rX   r   parse_multipart_form_datar   )r  r   r   r   r[   uri_argumentser   rN   fieldsfieldr@   r   rA   s                 r$   r   r     s    BC)W4 2W=O5PP 	V*44HM *//1 	>LD&$$T2.55f=	> 
	 	 !6	7)W4 2W=O5PP 
	O!'',F E!KKM33C8	3
?q-d1gtYN	E %%CDD 
8  	V !IA!MNTUU	V&  	O !BQ!FGQN	OsA   D >D% D% D% 8D% 	D"DD"%	E.D==Er  datac                 <   | j                  d      r| j                  d      r| dd } |j                  d| z   dz         }|dk(  rt        d      |d| j	                  d| z   dz         }|D ].  }|s|j                  d      }|dk(  rt        d	      t        j                  |d| j                  d
            }|j                  dd      }	t        |	      \  }
}|
dk7  s|j                  d      st        d      ||dz   d }|j                  d      st        d      |d   }|j                  d      rD|j                  dd      }|j                  |g       j                  t        |d   ||             |j                  |g       j                  |       1 y)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.
       "r7   rR   s   --z4Invalid multipart/form-data: no final boundary foundNs   
s   

z#multipart/form-data missing headerszutf-8zContent-Dispositionrs   z	form-datazInvalid multipart/form-data   r   z multipart/form-data missing namer  r   zapplication/unknown)r  r   r  )r  r_   rfindrU   r!   findr'   rb   decoderI   _parse_headerr   rE   r   )r  r!  r   r   final_boundary_indexpartsparteohr[   disp_headerdispositiondisp_paramsrB   r   ctypes                  r$   r  r    s   , 4 X%6%6t%<Ab>::eh&6&>?r!STT&&'--eh.>.HIE 9ii$"9 !FGG##D#J$5$5g$>?kk"7<#0#= [+%T]]7-C !>??S1Wr"v& !CDD6"??:&KK0EFET2&--(45u   r*11%8/9r0   tsc                 z   t        | t        t        f      r| }nt        | t        t        j
                  f      rt        j                  |       }nLt        | t        j                        r$t        j                  | j                               }nt        d| z        t        j                  j                  |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)r<   r   r   r   r   struct_timecalendartimegmdatetimeutctimetupler   emailutils
formatdate)r2  time_nums     r$   format_timestampr>  L  s     "sEl#	B 0 01	2??2&	B))	*??2??#454r9::;;!!(4!88r0   r   )r   r   r   z^HTTP/1\.[0-9]$rO   c                     	 | j                  d      \  }}}t        j	                  |      st        d|z        t        |||      S # t        $ r t        d      w xY w)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')
    rQ   zMalformed HTTP request linez/Malformed HTTP version in HTTP Request-Line: %r)r!   rW   rU   _http_version_rematchr   )rO   r   r   r   s       r$   parse_request_start_linerB  l  sp    < $

3g
 !!'*=G
 	
 FD'22  < :;;<s   A Ar   )r   codereasonz (HTTP/1.[0-9]) ([0-9]+) ([^\r]*)c                     t        |       } t        j                  |       }|st        d      t	        |j                  d      t        |j                  d            |j                  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 liner7   r   r   )r
   _http_response_line_rerA  rU   r   groupr   )rO   rA  s     r$   parse_response_start_linerH    sY     dD"((.E@AAU[[^SQ-@%++a.QQr0   sc              #     K   | d d dk(  r| dd  } | j                  d      }|dkD  ro| j                  dd|      | j                  dd|      z
  dz  rE| j                  d|dz         }|dkD  r+| j                  dd|      | j                  dd|      z
  dz  rE|dk  rt        |       }| d | }|j                          | |d  } | d d dk(  ry y w)Nr7   r  r   "z\"r   )r'  countr;   rX   )rI  r  fs      r$   _parseparamrN    s     
BQ%3,abEffSkAg17733/!''%C2HHAM&&cAg&C Ag17733/!''%C2HHAM7a&CdsGggicdG BQ%3,s   BC4C
Cc                 *   t        d| z         }t        |      }dg}|D ]l  }|j                  d      }|dk\  s|d| j                         j	                         }||dz   d j                         }|j                  |t        |      f       n t        j                  j                  |      }|j                  d       i }	|D ]L  \  }}
t        j                  j                  |
      }t        |      dk\  r|d   dk(  r|d	   dk(  r|dd	 }||	|<   N ||	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  )DummyrB   r   r   Nr7   r   rK  rR   )rN  nextr'  rX   r   rE   r
   r:  r;  decode_paramspopcollapse_rfc2231_valuer;   )rO   r+  keyparamspir   rB   decoded_paramspdictdecoded_values              r$   r)  r)    s    d
#E
u+C !F 5FF3K6Ra5;;=&&(Da!egJ$$&EMM4E!2345 [[..v6NqE- m22=Au:?uQx3593C!BKEd	
 :r0   rU  rZ  c                     |s| S | g}t        |j                               D ]/  \  }}||j                  |       |j                  |d|       1 dj                  |      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'
    r   z; )sortedrM   rE   r    )rU  rZ  outr@   rA   s        r$   _encode_headerr_    sd     
%Cu{{}% )19JJqM JJ!Q'() 99S>r0   usernamepasswordc                     t        | t              rt        j                  d|       } t        |t              rt        j                  d|      }t	        |       dz   t	        |      z   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   :)r<   r   unicodedata	normalizer   )r`  ra  s     r$   encode_username_passwordrg    sT     (L)((9(L)((9>D 4>11r0   c                  *    dd l } | j                         S )Nr   )doctestDocTestSuite)ri  s    r$   doctestsrk    s    !!r0   z^(.+):(\d+)$netlocc                     t         j                  |       }|r/|j                  d      }t        |j                  d            }||fS | }d}||fS )zReturns ``(host, port)`` tuple from ``netloc``.

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

    .. versionadded:: 4.1
    r7   r   N)
_netloc_rerA  rG  r   )rl  rA  r   ports       r$   r   r     sX     V$E{{1~5;;q>" $< $<r0   qsc              #   V   K   | j                         D ]  \  }}|D ]  }||f 
  yw)zgGenerator converting a result of ``parse_qs`` back to name-value pairs.

    .. versionadded:: 5.0
    N)rM   )rp  r@   vsrA   s       r$   	qs_to_qslrs    s9     
  2 	Aa&L	s   ')z\\(?:([0-3][0-7][0-7])|(.))mc                 F    | d   rt        t        | d   d            S | d   S )Nr7      r   )chrr   )rt  s    r$   _unquote_replacerx    s'    t3qtQ<  tr0   c                 t    | t        |       dk  r| S | d   dk7  s| d   dk7  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.
    r   r   rK  rR   r7   )r;   _unquote_subrx  )rI  s    r$   _unquote_cookier{  #  sO     	yCFQJts{aesl 	
!BA (!,,r0   cookiec                     i }| j                  t        d            D ]n  }t        d      |v r|j                  t        d      d      \  }}nt        d      |}}|j                         |j                         }}|s|sat        |      ||<   p |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   r7   rs   )r!   r|   rX   r{  )r|  
cookiedictr   rU  r  s        r$   r   r   >  s     Jc#h' 
3s8u{{3s8Q/HC 2wC99;		S#-c2JsO
3 r0   r*   )`ry   r6  collections.abccollectionsrq   r8  email.utilsr:  	functoolsr   http.clientr   http.cookiesr   resslr   r   re  urllib.parser   r   r   r	   tornado.escaper
   r   r   tornado.utilr   r   rz   r   r   r   r   r   r   r   r   r   r   r   TYPE_CHECKINGr   asyncior   unittestr|   r%   abcMutableMappingr'   r   r   r   rU   r   r   r   r   r  r   r   r  r  r
  r   r   r  r   r   r5  r>  
namedtupler   compiler@  rB  r   rF  rH  rN  r)  r_  rg  rk  rn  r   rs  subrz  Matchrx  r{  r   r+   r0   r$   <module>r     s          !  	    C C ; ; 1
 
     
 4?C ?C ? ?h+//00 hV[: [:|	Y 		i 	6 :+& +\+$V +$\,	,
d38nd5c?3U5c?C;O5PP,
 	,^z  00eHSM8C=0120f2hsm 2(3- 2 2PS 2c hsm  &*+O+O
+O Ce$%+O T(^#$	+O
 k"+O 
+O\3939
39 Ce$%39 T(^#$	39
 
39l9c5%!1!183D3DDE990 *;))5 
 2::01 33 3+; 3* +K**6 
 $$GH RC R,= R.
3 
9S$_5 
   c4S>&9 :  F DcN s (2CJ2+0e+<2
2 " RZZ(
 c8C=.@(A "$sDL() huS&[7I.J  rzz89== S -s -s -6 c3h r0   