U
    luf                  	   @   sB  d Z ddlZddlZddlZddlZddlZddlm	Z	 ddl
mZ ddlZddlZddlmZ ddlZddlZddlmZmZmZmZ ddlmZmZmZ ddlmZ dd	lmZm Z  e ddl!Z!dd
l!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z, e!j-r ddl!m.Z. ddl/m0Z0 ddl1Z1e	de2e2dddZ3G dd dej4j5Z6G dd de7Z8G dd de9Z:G dd de9Z;G dd de7Z<G dd de7Z=G dd de7Z>e2e(de'e2e2f e$e"e2e2f  e"e"e2e2f df f e2d d!d"Z?G d#d$ d$eZ@e2e)e"e)eA e)eA f  d%d&d'ZBe)eA e)eA eAe2d(d)d*ZCe2e)eA d+d,d-ZDdae2eEe'e2e$eE f e'e2e$e@ f e)e6 dd.d/d0ZFeEeEe'e2e$eE f e'e2e$e@ f dd1d2d3ZGe(eAeHeIejJejf e2d4d5d6ZKeLd7d8d9d:gZMeNd;ZOe2eMd<d=d>ZPeLd?d:d@dAgZQeNdBZRe2eQd<dCdDZSe2e+e2ddf dEdFdGZTe2e"e2e'e2e2f f d<dHdIZUe2e'e2e2f e2dJdKdLZVe(e2eEf e(e2eEf eEdMdNdOZWdPdQ ZXeNdRZYe2e"e2e)eA f dSdTdUZZe'e2e$e, f e#e"e2e,f  dVdWdXZ[eNdYZ\eNdZZ]d[j^Z_e2e2dEd\d]Z`e2e'e2e2f d^d_d`ZadS )bzHTTP 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    4/tmp/pip-unpacked-wheel-bmg6zs32/tornado/httputil.py
<listcomp>I   s     z%_normalize_header.<locals>.<listcomp>)joinsplit)r   r    r    r$   _normalize_headerB   s    r(   c                   @   st  e Zd ZdZejeeee f ddddZ	ejeeef ddddZ	eje
eef ddddZ	ejedd	d
dZ	ejeddddZ	eeddddZeee dddZee
eef  dddZeddddZeed dddZeeddddZeedddZeddd d!Zedd"d#Zeej dd$d%Zd dd&d'ZeZedd(d)ZeZdS )*HTTPHeadersa  A dictionary that maintains ``Http-Header-Case`` for all keys.

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

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

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

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

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

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

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

        .. versionchanged:: 5.1

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

        
NrJ   )r'   endswithrQ   )clsrR   hrH   r    r    r$   parse   s    
zHTTPHeaders.parsec                 C   s"   t |}|| j|< |g| j|< d S r+   r(   r2   r3   r?   r    r    r$   __setitem__   s    
zHTTPHeaders.__setitem__c                 C   s   | j t| S r+   )r2   r(   )r-   r   r    r    r$   __getitem__   s    zHTTPHeaders.__getitem__c                 C   s   t |}| j|= | j|= d S r+   rY   rB   r    r    r$   __delitem__   s    zHTTPHeaders.__delitem__c                 C   s
   t | jS r+   )r5   r2   r-   r    r    r$   __len__   s    zHTTPHeaders.__len__c                 C   s
   t | jS r+   )iterr2   r]   r    r    r$   __iter__   s    zHTTPHeaders.__iter__c                 C   s   t | S r+   )r)   r]   r    r    r$   copy   s    zHTTPHeaders.copyc                 C   s2   g }|   D ]\}}|d||f  qd|S )Nz%s: %s
 )r7   r>   r&   )r-   linesr   r<   r    r    r$   __str__   s    zHTTPHeaders.__str__)__name__
__module____qualname____doc__typingoverloadr   strr   r.   r   Anyr8   rC   r   r7   rQ   classmethodrX   rZ   r[   r\   intr^   r   r`   ra   __copy__rd   __unicode__r    r    r    r$   r)   L   s2   
r)   c                   @   s   e Zd ZdZdZdZdZdee ee eee	 ee
 ee eeeed f  ed ed ee dddd	Zeeeejjf d
ddZed
ddZed
ddZdeedee
f dddZdd
ddZed
ddZdS )HTTPServerRequesta7
  A single HTTP request.

    All attributes are type `str` unless otherwise noted.

    .. attribute:: method

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

    .. attribute:: uri

       The requested uri.

    .. attribute:: path

       The path portion of `uri`

    .. attribute:: query

       The query portion of `uri`

    .. attribute:: version

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

    .. attribute:: headers

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

    .. attribute:: body

       Request body, if present, as a byte string.

    .. attribute:: remote_ip

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

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

    .. attribute:: protocol

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

    .. attribute:: host

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

    .. attribute:: arguments

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

    .. attribute:: query_arguments

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

       .. versionadded:: 3.2

    .. attribute:: body_arguments

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

       .. versionadded:: 3.2

    .. attribute:: files

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

    .. attribute:: connection

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

    .. versionchanged:: 4.0
       Moved from ``tornado.httpserver.HTTPRequest``.
    NHTTP/1.0HTTPFileHTTPConnectionRequestStartLine)methoduriversionrR   bodyhostfiles
connection
start_lineserver_connectionr   c                 C   s   |	d k	r|	\}}}|| _ || _|| _|p,t | _|p6d| _t|dd }t|dd | _t|dd| _|pt| j	dptd| _
t| j
 d | _|pi | _|| _|
| _t | _d | _|d k	r|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)rv   rw   rx   r)   rR   ry   getattrr   r   rA   rz   split_host_and_portlowerZ	host_namer{   r|   r~   time_start_time_finish_time	partitionpathqueryr
   	argumentsra   deepcopyZquery_argumentsbody_arguments)r-   rv   rw   rx   rR   ry   rz   r{   r|   r}   r~   r   sepr    r    r$   r.   Z  s,    



zHTTPServerRequest.__init__rD   c              	   C   s   t | ds~tj | _d| jkr~zt| jd }W n tk
rF   Y n8X | D ],\}}z|| j|< W qP tk
rz   Y qPX qP| 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   rz   rw   r]   r    r    r$   full_url  s    zHTTPServerRequest.full_urlc                 C   s(   | j dkrt | j S | j | j S dS )z?Returns the amount of time it took for this request to execute.N)r   r   r   r]   r    r    r$   request_time  s    
zHTTPServerRequest.request_timeF)binary_formr   c                 C   s@   z$| j dkrW dS | j jjj|dW S  tk
r:   Y dS X dS )a>  Returns the client's SSL certificate, if any.

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

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

        By default, the return value is a dictionary (or None, if no
        client certificate is present).  If ``binary_form`` is true, a
        DER-encoded form of the certificate is returned instead.  See
        SSLSocket.getpeercert() in the standard library for more
        details.
        http://docs.python.org/library/ssl.html#sslsocket-objects
        N)r   )r|   streamsocketgetpeercertr   )r-   r   r    r    r$   get_ssl_certificate  s    

z%HTTPServerRequest.get_ssl_certificatec                 C   sN   t | jdd| j| j| j| j | j D ]\}}| j|g 	| q,d S )NContent-Typerb   )
parse_body_argumentsrR   rA   ry   r   r{   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   rz   rv   rw   rx   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__re   )r-   attrsr/   r    r]   r$   __repr__  s    zHTTPServerRequest.__repr__)
NNrr   NNNNNNN)F)re   rf   rg   rh   r   r   Z_body_futurer   rk   r)   bytesr   r   objectr.   propertyr   r   Morselr   floatr   boolr   r   r   r   r    r    r    r$   rq      sL   \          ( rq   c                   @   s   e Zd ZdZdS )rM   zqException class for malformed HTTP requests or responses
    from remote sources.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        Returns a future for flow control.

        .. versionchanged:: 6.0

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

        Returns a future for flow control.

        .. versionchanged:: 6.0

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

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

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

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

    * ``filename``
    * ``body``
    * ``content_type``
    filenamery   content_typeN)re   rf   rg   rh   rk   __annotations__r   r    r    r    r$   rs     s   

rs   )range_headerr   c                 C   s   |  d\}}}| |  }}|dkr.dS | d\}}}zt|}t|}W n tk
rh   Y dS X |dk	r|dkr|dkr| }d}n|d7 }||fS )ag  Parses a Range header.

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

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

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

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

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

    >>> print(_get_content_range(None, 1, 4))
    bytes 0-0/4
    >>> print(_get_content_range(1, 3, 4))
    bytes 1-2/4
    >>> print(_get_content_range(None, None, 4))
    bytes 0-3/4
    r   r1   zbytes %s-%s/%sr    )r   r   r   r    r    r$   _get_content_range  s    
r   )valr   c                 C   s   |   } | dkrd S t| S )Nrb   )rP   rn   )r   r    r    r$   r     s    r   )r   ry   r   r{   rR   r   c              
   C   sR  |  dr|r*d|kr*td|d  dS zt|dd}W n2 tk
rl } ztd| i }W 5 d}~X Y nX | D ]\}}|rv||g | qvn|  drN|rd|krtd|d  dS zX| d	}	|	D ]<}
|
	 
d
\}}}|dkr|rtt||||  qqtdW n0 tk
rL } ztd| W 5 d}~X Y nX dS )aF  Parses a form request body.

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

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

    .. versionchanged:: 5.1

       Now recognizes non-ASCII filenames in RFC 2231/5987
       (``filename*=``) format.
       "r1   rJ   s   --z.Invalid multipart/form-data: no final boundaryNs   
s   

z#multipart/form-data missing headerszutf-8zContent-Dispositionrb   z	form-datazInvalid multipart/form-data   r   z&multipart/form-data value missing namer   r   zapplication/unknown)r   ry   r   )r   rU   rfindr   r   r'   findr)   rX   decoderA   _parse_headerr   r>   rs   )r   r   r   r{   Zfinal_boundary_indexpartspartZeohrR   Zdisp_headerdispositionZdisp_paramsr<   r   ctyper    r    r$   r     sF    




  r   )tsr   c                 C   sh   t | ttfr| }nDt | ttjfr0t| }n(t | tjrLt| 	 }nt
d|  tjj|ddS )a  Formats a timestamp in the format used by HTTP.

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

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

    The response is a `collections.namedtuple`.

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

    The response is a `collections.namedtuple`.

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

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

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

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

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

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

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

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

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

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

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

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

    .. versionadded:: 4.4.2
    r   r   r1   rb   )r'   rk   rP   r4  )r5  Z
cookiedictr   r  r   r    r    r$   r   X  s    r   )N)brh   r   collections.abccollectionsra   r   email.utilsr   	functoolsr   http.clientr   http.cookiesr   resslr   r   r  urllib.parser   r   r   r   Ztornado.escaper	   r
   r   Ztornado.logr   Ztornado.utilr   r   ri   r   r   r   r   r   r   r   r   r   r   r   TYPE_CHECKINGr   Zasyncior   Zunittestrk   r(   abcMutableMappingr)   r   rq   r   rM   r   r   r   rt   r   rs   rn   r   r   r   r   r   r   r   r   r   r  
namedtupleru   compiler  r  r   r  r	  r  r   r  r!  r#  r%  r   r)  r+  r-  r&   r/  r4  r   r    r    r    r$   <module>   s   4	 , _
	././3 2; 
 
 #
 

(


2