o
    Qœ_]Œ  ã                   @   sz  d Z ddlZddlZddlZddlZddlZddlmZ ddl	m
Z
 ddlZddlZddlmZ ddlZddlZddlmZmZmZmZ ddlmZmZmZ ddlmZ dd	lmZmZ e
 ddl Z dd
l m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+ e j,r�ddl m-Z- ddl.m/Z/ ddl0Z0edƒde1de1fdd„ƒZ2G dd„ dej3j4ƒZ5G dd„ de6ƒZ7G dd„ de8ƒZ9G dd„ de8ƒZ:G dd„ de6ƒZ;G dd„ de6ƒZ<G dd„ de6ƒZ=d e1d!e'de&e1e1f e#e!e1e1f  e!e!e1e1f d"f f de1fd#d$„Z>G d%d&„ d&eƒZ?d'e1de(e!e(e@ e(e@ f  fd(d)„ZAd*e(e@ d+e(e@ d,e@de1fd-d.„ZBd/e1de(e@ fd0d1„ZC	did2e1d3eDd4e&e1e#eD f d5e&e1e#e? f d6e(e5 ddfd7d8„ZEd9eDd:eDd4e&e1e#eD f d5e&e1e#e? f ddf
d;d<„ZFd=e'e@eGeHejIejf de1fd>d?„ZJe Kd@g dA¢¡ZLe MdB¡ZNdCe1deLfdDdE„ZOe KdFg dG¢¡ZPe MdH¡ZQdCe1dePfdIdJ„ZRdKe1de*e1ddf fdLdM„ZSdCe1de!e1e&e1e1f f fdNdO„ZTdPe1dQe&e1e1f de1fdRdS„ZUdTe'e1eDf dUe'e1eDf deDfdVdW„ZVdXdY„ ZWe MdZ¡ZXd[e1de!e1e(e@ f fd\d]„ZYd^e&e1e#e+ f de"e!e1e+f  fd_d`„ZZe Mda¡Z[e Mdb¡Z\dcj]Z^dKe1de1fddde„Z_dfe1de&e1e1f fdgdh„Z`dS )jz¤HTTP utility code shared by clients and servers.

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

    >>> _normalize_header("coNtent-TYPE")
    'Content-Type'
    ú-c                 S   s   g | ]}|  ¡ ‘qS © )Ú
capitalize)Ú.0Úwr   r   ú2/usr/lib/python3/dist-packages/tornado/httputil.pyÚ
<listcomp>I   s    z%_normalize_header.<locals>.<listcomp>)ÚjoinÚsplit)r   r   r   r#   Ú_normalize_headerB   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__i   ó   zHTTPHeaders.__init__c                 C   r*   r+   r   r,   r   r   r#   r.   m   r/   Úargsc                 G   r*   r+   r   )r-   r0   r   r   r#   r.   q   r/   Úkwargsc                 K   r*   r+   r   )r-   r1   r   r   r#   r.   u   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.   y   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 )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)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| ¡  }| j| j d  |7  < | j| j  |7  < dS z
| dd¡\}}W n tyB   tdƒ‚w |  || 	¡ ¡ dS )	zÃUpdates the dictionary with a single header line.

        >>> h = HTTPHeaders()
        >>> h.parse_line("Content-Type: text/html")
        >>> h.get('content-type')
        'text/html'
        r   Nz.first header line cannot start with whitespaceú éÿÿÿÿú:r2   zno colon in header line)
Úisspacer5   ÚHTTPInputErrorÚlstripr4   r3   r&   Ú
ValueErrorr9   Ústrip)r-   rG   Ú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(   L   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ÚlowerÚ	host_namerz   r|   r€   ÚtimeÚ_start_timeÚ_finish_timeÚ	partitionÚpathÚqueryr
   Ú	argumentsrc   ÚdeepcopyÚquery_argumentsÚbody_arguments)r-   ru   rv   rw   rR   rx   ry   rz   r|   r~   r€   r‚   Úsepr   r   r#   r.   Z  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“   Ú_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 )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_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Ä   )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*  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_headers9  s   zHTTPConnection.write_headersc                 C   rÀ   )z¥Writes a chunk of body data.

        Returns a future for flow control.

        .. versionchanged:: 6.0

           The ``callback`` argument was removed.
        rÁ   rË   r   r   r#   ÚwriteQ  s   	zHTTPConnection.writec                 C   rÀ   )z<Indicates 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}   3  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_urlÚparsed_queryÚerrÚfinal_queryr   r   r#   Ú
url_concatb  s0   
ÿúÿ
rß   c                   @   r¹   )r{   zËRepresents a file uploaded via a form.

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

    * ``filename``
    * ``body``
    * ``content_type``
    Nrº   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‘   rO   Ú_int_or_nonerN   )rà   ÚunitÚ_r=   Ústart_bÚend_bÚstartÚendr   r   r#   Ú_parse_request_rangeŸ  s&   ÿÿré   rç   rè   Útotalc                 C   s"   | pd} |p|d }d| ||f S )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
    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   )rO   rp   )rì   r   r   r#   râ   á  s   râ   Úcontent_typerx   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Š|rŠt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&   rO   r‘   Úparse_multipart_form_datar   rN   )rí   rx   r”   rz   rR   Ú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¡s�t 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 nameÚfilenamer¨   zapplication/unknown)rû   rx   rí   )rð   rU   Úrfindr   rñ   r&   Úfindr(   rX   ÚdecoderB   Ú_parse_headerrª   r?   r{   )rï   r÷   r”   rz   Úfinal_boundary_indexÚpartsÚpartÚeohrR   Údisp_headerÚdispositionÚ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.

    >>> 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  Útime_numr   r   r#   Úformat_timestampS  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 )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')
    rH   zMalformed HTTP request linez/Malformed HTTP version in HTTP Request-Line: %r)r&   rN   rL   Ú_http_version_reÚmatchr   )rG   ru   r’   rw   r   r   r#   Úparse_request_start_liner  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 )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!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   rO   )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ý   rO   rŒ   r?   r	   r  r  Údecode_paramsÚpopÚcollapse_rfc2231_valuer6   )rG   r  ÚkeyÚparamsÚpÚir   r=   Údecoded_paramsÚpdictÚ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 )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; )Ú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 )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
    ÚNFCó   :)r7   r   ÚunicodedataÚ	normalizer   )r0  r1  r   r   r#   Úencode_username_passwordê  s
   
	
r6  c                  C   s   dd l } |  ¡ S )Nr   )ÚdoctestÚDocTestSuite)r7  r   r   r#   Údoctestsú  s   r9  z^(.+):(\d+)$Únetlocc                 C   s>   t  | ¡}|r| d¡}t| d¡ƒ}||fS | }d}||fS )z‡Returns ``(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]z[\\].rd   c                 C   sn  | du s
t | ƒdk r| S | d dks| d dkr| S | dd… } d}t | ƒ}g }d|  kr2|k r³n t|ƒS t | |¡}t | |¡}|sU|sU| | |d… ¡ 	 t|ƒS d }}|r`| d¡}|rg| d¡}|r†|ro||k r†| | ||… ¡ | | |d  ¡ |d }n| | ||… ¡ | tt| |d |d … dƒƒ¡ |d }d|  kr²|k s7t|ƒS  t|ƒ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Ò   r   r  rI   r2   rù   é   )	r6   Ú
_OctalPattÚsearchÚ
_QuotePattr?   rç   Úchrrp   Ú	_nulljoin)r  r)  r­   ÚresÚo_matchÚq_matchÚjr;   r   r   r#   Ú_unquote_cookie$  s@   	íó


$íìrJ  Ú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   rO   rJ  )rK  Ú
cookiedictrÊ   r&  rì   r   r   r#   rž   V  s   €rž   r+   )arj   r  Úcollectionsrc   r  Úemail.utilsr  Ú	functoolsr   Úhttp.clientr   Úhttp.cookiesr…   ÚreÚsslr   rŽ   r4  Úurllib.parser   r   r   r   Útornado.escaper	   r
   r   Útornado.logr   Útornado.utilr   r   rk   r   r   r   r   r   r   r   r   r   r   r   ÚTYPE_CHECKINGr   Úasyncior   Úunittestrm   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/  r6  r9  r;  r‹   r?  rA  rC  r%   rE  rJ  rž   r   r   r   r#   Ú<module>   sÞ   4	 , _
	./ÿ.ÿþ
û/ÿ
þ"3ûÿþýüû
ú1ÿþýü
û:ÿ
þÿ
ÿ
"#
ÿ
ÿ
þ
*


2