B
    h	              	   @   s  d Z ddlZddlZddlZddlZddlZddlmZ ddl	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l.Z.e/dZ0G dd de1Z2e2d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>e?e%de$e?e?f e!ee?e?f  eee?e?f df f e?dd d!Z@G d"d# d#eZAe?e&ee&eB e&eB f  d$d%d&ZCe&eB e&eB eBe?d'd(d)ZDe?e&eB d*d+d,ZEd]e?eFe$e?e!eF f e$e?e!eA f e6dd-d.d/ZGeFeFe$e?e!eF f e$e?e!eA f dd0d1d2ZHe%eBeIeJejKejf e?d3d4d5ZLeMd6d7d8d9gZNe?eNd:d;d<ZOeMd=d9d>d?gZPe?ePd:d@dAZQe?e(e?ddf dBdCdDZRe?ee?e$e?e?f f d:dEdFZSe?e$e?e?f e?dGdHdIZTe%e?eFf e%e?eFf eFdJdKdLZUdMdN ZVe?ee?e&eB f dOdPdQZWe$e?e!e) f e ee?e)f  dRdSdTZXe/dUZYe/dVZZdWj[Z\e?e?dBdXdYZ]e?e$e?e?f dZd[d\Z^dS )^zHTTP utility code shared by clients and servers.

This module also defines the `HTTPServerRequest` class which is exposed
via `tornado.web.RequestHandler.request`.
    N)	responses)SSLError)	urlencodeurlparse
urlunparse	parse_qsl)
native_strparse_qs_bytesutf8)gen_log)
ObjectDictunicode_type)TupleIterableListMappingIteratorDictUnionOptional	Awaitable	GeneratorAnyStr)Deque)Futurez\r?\nc                   s8   e Zd ZdZedd fddZeedddZ  ZS )	_NormalizedHeaderCacheaK  Dynamic cached mapping of header names to Http-Header-Case.

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

    >>> normalized_headers = _NormalizedHeaderCache(10)
    >>> normalized_headers["coNtent-TYPE"]
    'Content-Type'
    N)sizereturnc                s"   t t|   || _t | _d S )N)superr   __init__r   collectionsdequequeue)selfr   )	__class__ MC:\Users\sanjo\AppData\Local\Qlobot\Launcher\ext_packages\tornado\httputil.pyr   R   s    z_NormalizedHeaderCache.__init__)keyr   c             C   sR   d dd |dD }|| |< | j| t| j| jkrN| j }| |= |S )N-c             S   s   g | ]}|  qS r%   )
capitalize).0wr%   r%   r&   
<listcomp>X   s    z6_NormalizedHeaderCache.__missing__.<locals>.<listcomp>)joinsplitr"   appendlenr   popleft)r#   r'   Z
normalizedZold_keyr%   r%   r&   __missing__W   s    
z"_NormalizedHeaderCache.__missing__)	__name__
__module____qualname____doc__intr   strr2   __classcell__r%   r%   )r$   r&   r   F   s   
r   i  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%   )r#   r;   r%   r%   r&   r      s    zHTTPHeaders.__init__c             C   s   d S )Nr%   )r#   r;   r%   r%   r&   r      s    )argsr   c             G   s   d S )Nr%   )r#   r<   r%   r%   r&   r      s    )kwargsr   c             K   s   d S )Nr%   )r#   r=   r%   r%   r&   r      s    )r<   r=   r   c             O   sp   i | _ i | _d | _t|dkr`t|dkr`t|d tr`x2|d  D ]\}}| || qFW n| j|| d S )N   r   )	_dict_as_list	_last_keyr0   
isinstancer:   get_alladdupdate)r#   r<   r=   kvr%   r%   r&   r      s    &)namevaluer   c             C   sR   t | }|| _|| krFt| | d t| | j|< | j| | n|| |< dS )z#Adds a new value for the given key.,N)_normalized_headersrA   r   r?   r@   r/   )r#   rH   rI   	norm_namer%   r%   r&   rD      s    zHTTPHeaders.add)rH   r   c             C   s   t | }| j|g S )z2Returns all values for the given header as a list.)rK   r@   get)r#   rH   rL   r%   r%   r&   get_list   s    zHTTPHeaders.get_list)r   c             c   s4   x.| j  D ] \}}x|D ]}||fV  qW qW 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)r@   items)r#   rH   valuesrI   r%   r%   r&   rC      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  < nBy|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 :r>   zno colon in header line)
isspacerA   HTTPInputErrorlstripr@   r?   r.   
ValueErrorrD   strip)r#   rQ   Znew_partrH   rI   r%   r%   r&   
parse_line   s    
zHTTPHeaders.parse_line)headersr   c             C   s,   |  }x t |D ]}|r|| qW |S )a  Returns a dictionary from HTTP header text.

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

        .. versionchanged:: 5.1

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

        )_CRLF_REr.   rZ   )clsr[   hrQ   r%   r%   r&   parse   s
    zHTTPHeaders.parsec             C   s"   t | }|| j|< |g| j|< d S )N)rK   r?   r@   )r#   rH   rI   rL   r%   r%   r&   __setitem__   s    
zHTTPHeaders.__setitem__c             C   s   | j t|  S )N)r?   rK   )r#   rH   r%   r%   r&   __getitem__   s    zHTTPHeaders.__getitem__c             C   s   t | }| j|= | j|= d S )N)rK   r?   r@   )r#   rH   rL   r%   r%   r&   __delitem__   s    zHTTPHeaders.__delitem__c             C   s
   t | jS )N)r0   r?   )r#   r%   r%   r&   __len__   s    zHTTPHeaders.__len__c             C   s
   t | jS )N)iterr?   )r#   r%   r%   r&   __iter__   s    zHTTPHeaders.__iter__c             C   s   t | S )N)r:   )r#   r%   r%   r&   copy   s    zHTTPHeaders.copyc             C   s6   g }x&|   D ]\}}|d||f  qW d|S )Nz%s: %s
 )rC   r/   r-   )r#   linesrH   rI   r%   r%   r&   __str__  s    zHTTPHeaders.__str__)r3   r4   r5   r6   typingoverloadr   r8   r   r   r   AnyrD   rN   r   rC   rZ   classmethodr_   r`   ra   rb   r7   rc   r   re   rf   __copy__ri   __unicode__r%   r%   r%   r&   r:   g   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d f dd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versionr[   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)ru   rv   rw   r:   r[   rx   getattrr   r   rM   ry   split_host_and_portlowerZ	host_namerz   r{   r}   time_start_time_finish_time	partitionpathqueryr	   	argumentsrf   deepcopyZquery_argumentsbody_arguments)r#   ru   rv   rw   r[   rx   ry   rz   r{   r|   r}   r   sepr%   r%   r&   r   q  s,    



zHTTPServerRequest.__init__)r   c          	   C   s   t | dstj | _d| jkryt| jd }W n tk
rF   Y n<X x8| D ],\}}y|| j|< W qR tk
r|   Y qRX qRW | jS )z0A dictionary of ``http.cookies.Morsel`` objects._cookiesCookie)	hasattrr   cookiesSimpleCookier   r[   parse_cookie	ExceptionrO   )r#   parsedrF   rG   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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:   y | j dkrdS | j jjj|dS  tk
r4   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   sR   t | jdd| j| j| j| j x*| j D ]\}}| j|g 	| q.W d S )NzContent-Typerg   )
parse_body_argumentsr[   rM   rx   r   rz   rO   r   
setdefaultextend)r#   rF   rG   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*   n)r#   r%   r&   r,     s    z.HTTPServerRequest.__repr__.<locals>.<listcomp>z%s(%s))r-   r$   r3   )r#   attrsr<   r%   )r#   r&   __repr__  s    zHTTPServerRequest.__repr__)
NNrq   NNNNNNN)F)r3   r4   r5   r6   r   r   Z_body_futurer8   r:   bytesr   r   objectr   propertyr   r   Morselr   floatr   boolr   r   r   r   r%   r%   r%   r&   rp     s.   [         "rp   c               @   s   e Zd ZdZdS )rV   zqException class for malformed HTTP requests or responses
    from remote sources.

    .. versionadded:: 4.0
    N)r3   r4   r5   r6   r%   r%   r%   r&   rV     s   rV   c               @   s   e Zd ZdZdS )HTTPOutputErrorzJException class for errors in HTTP output.

    .. versionadded:: 4.0
    N)r3   r4   r5   r6   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
    rs   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)r3   r4   r5   r6   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
    )rt   ResponseStartLineN)r|   r[   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|   r[   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_received4  s    z!HTTPMessageDelegate.data_received)r   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)r3   r4   r5   r6   r   r:   r   r   r   r   r   r   r   r%   r%   r%   r&   r     s   r   c               @   sH   e Zd ZdZded eeddddZeddd	d
ZddddZ	dS )rs   zYApplications use this interface to write their responses.

    .. versionadded:: 4.0
    N)rt   r   zFuture[None])r|   r[   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.
        N)r   )r#   r|   r[   r   r%   r%   r&   write_headersN  s    zHTTPConnection.write_headers)r   r   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.
        N)r   )r#   r   r%   r%   r&   writef  s    	zHTTPConnection.write)r   c             C   s
   t  dS )z<Indicates that the last body data has been written.
        N)r   )r#   r%   r%   r&   r   q  s    zHTTPConnection.finish)N)
r3   r4   r5   r6   r   r:   r   r   r   r   r%   r%   r%   r&   rs   H  s
   rs   .)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'
    NT)r   z7'args' parameter should be dict, list or tuple. Not {0}r   r>            )r   rB   dictr   r   r   rO   listtupleformattype	TypeErrorr   r   )r   r<   
parsed_urlZparsed_queryerrZfinal_queryr%   r%   r&   
url_concatw  s*    

r   c               @   s   e Zd ZdZdS )rr   zRepresents a file uploaded via a form.

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

    * ``filename``
    * ``body``
    * ``content_type``
    N)r3   r4   r5   r6   r%   r%   r%   r&   rr     s   	rr   )range_headerr   c             C   s   |  d\}}}| |  }}|dkr.dS | d\}}}yt|}t|}W n tk
rf   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   r>   )r   rY   _int_or_nonerX   )r   Zunit_rI   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   r>   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 )Nrg   )rY   r7   )r   r%   r%   r&   r     s    r   )content_typerx   r   rz   r[   r   c          
   C   sZ  |  dr|r*d|kr*td|d  dS ytt|dd}W n2 tk
rp } ztd| i }W dd}~X Y nX x| D ]\}}|r|||g | q|W n|  drV|rd|krtd|d  dS yX| 	d	}	xH|	D ]8}
|

 d
\}}}|dkr|rtt|||| P qW tdW n0 tk
rT } ztd| W d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: %sNT)r   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   r   rO   r   r   r.   rY   r   parse_multipart_form_datar
   rX   )r   rx   r   rz   r[   Zuri_argumentserH   rP   fieldsfieldrF   r   rG   r%   r%   r&   r     s8    


r   )r   datar   rz   r   c             C   sb  |  dr | dr | dd } |d|  d }|dkrHtd dS |d| d|  d }x|D ]}|srqh|d}|dkrtd	 qht|d| 	d
}|
dd}	t|	\}
}|
dks|dstd qh||d d }|
dstd qh|d }|
drH|
dd}||g t|d ||d qh||g | qhW d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.
       "r>   rS   s   --z.Invalid multipart/form-data: no final boundaryNs   
s   

z#multipart/form-data missing headerszutf-8zContent-Dispositionrg   z	form-datazInvalid multipart/form-data   rH   z&multipart/form-data value missing namefilenamezContent-Typezapplication/unknown)r   rx   r   )r   endswithrfindr   r   r.   findr:   r_   decoderM   _parse_headerr   r/   rr   )r   r   r   rz   Zfinal_boundary_indexpartspartZeohr[   Zdisp_headerZdispositionZdisp_paramsrI   rH   ctyper%   r%   r&   r   -  s>    





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.

    >>> format_timestamp(1359312200)
    'Sun, 27 Jan 2013 18:43:20 GMT'
    zunknown timestamp type: %rT)usegmt)rB   r7   r   r   r   struct_timecalendartimegmdatetimeutctimetupler   emailutils
formatdate)r   Ztime_numr%   r%   r&   format_timestampg  s    r   rt   ru   r   rw   )rQ   r   c             C   sV   y|  d\}}}W n tk
r0   tdY nX td|sJt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')
    rR   zMalformed HTTP request linez^HTTP/1\.[0-9]$z/Malformed HTTP version in HTTP Request-Line: %r)r.   rX   rV   rematchrt   )rQ   ru   r   rw   r%   r%   r&   parse_request_start_line  s    
r   r   codereasonc             C   sB   t | } td| }|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(HTTP/1.[0-9]) ([0-9]+) ([^]*)z!Error parsing response start liner>   r   r   )r   r   r   rV   r   groupr7   )rQ   r   r%   r%   r&   parse_response_start_line  s
    r   )sr   c             c   s   x| d d dkr| dd  } |  d}x<|dkrd| dd|| dd| d rd|  d|d }q*W |dk rvt| }| d | }| V  | |d  } qW d S )Nr>   r   r   "z\"r   )r   countr0   rY   )r   r   fr%   r%   r&   _parseparam  s    
*
r  c             C   s   t d|  }t|}dg}xX|D ]P}|d}|dkr |d|   }||d d  }||t|f q W tj	|}|
d i }	xT|D ]L\}}
tj|
}t|dkr|d dkr|d	 dkr|dd	 }||	|< qW ||	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DummyrI   r   r   Nr>   r   r   rS   )r  nextr   rY   r   r/   r   r   r   decode_paramspopcollapse_rfc2231_valuer0   )rQ   r   r'   paramspirH   rI   Zdecoded_paramspdictZdecoded_valuer%   r%   r&   r     s$    


$r   )r'   r
  r   c             C   sX   |s| S | g}x>t | D ].\}}|dkr8|| q|d||f  qW 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; )sortedrO   r/   r-   )r'   r
  outrF   rG   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   :)rB   r   unicodedata	normalizer
   )r  r  r%   r%   r&   encode_username_password  s
    	

r  c              C   s   dd l } |  S )Nr   )doctestDocTestSuite)r  r%   r%   r&   doctests  s    r  )netlocr   c             C   s:   t d| }|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
    z^(.+):(\d+)$r>   r   N)r   r   r   r7   )r  r   ry   portr%   r%   r&   r     s    
r   )qsr   c             c   s2   x,|   D ] \}}x|D ]}||fV  qW q
W dS )zgGenerator converting a result of ``parse_qs`` back to name-value pairs.

    .. versionadded:: 5.0
    N)rO   )r  rF   vsrG   r%   r%   r&   	qs_to_qsl   s    
r  z\\[0-3][0-7][0-7]z[\\].rg   c             C   sP  | dkst | dk r| S | d dks0| d dkr4| S | dd } d}t | }g }xd|  krh|k rFn nt| |}t| |}|s|s|| |d  P d }}|r|d}|r|d}|r|r||k r|| ||  || |d   |d }qR|| ||  |tt| |d |d  d |d }qRW t|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   rS   r>   r      )	r0   
_OctalPattsearch
_QuotePattr/   r   chrr7   	_nulljoin)r   r	  r   reso_matchq_matchjrF   r%   r%   r&   _unquote_cookie/  s6    	


$r'  )cookier   c             C   sv   i }xl|  tdD ]Z}td|kr:| tdd\}}ntd| }}| |  }}|sb|rt|||< qW |S )a[  Parse a ``Cookie`` HTTP header into a dict of name/value pairs.

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

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

    .. versionadded:: 4.4.2
    r   r   r>   rg   )r.   r8   rY   r'  )r(  Z
cookiedictr   r'   r   r%   r%   r&   r   a  s    r   )N)_r6   r   r    rf   r   email.utilsr   http.clientr   http.cookiesr   r   sslr   r   r  urllib.parser   r   r   r   tornado.escaper   r	   r
   tornado.logr   tornado.utilr   r   rj   r   r   r   r   r   r   r   r   r   r   r   TYPE_CHECKINGr   asyncior   Zunittestcompiler\   r   r   rK   abcMutableMappingr:   r   rp   r   rV   r   r   r   rs   r8   r   rr   r7   r   r   r   r   r   r   r   r   r   r   
namedtuplert   r   r   r   r  r   r  r  r  r   r  r  r   r-   r"  r'  r   r%   r%   r%   r&   <module>   s   4
 ( ]
	.00*"1$+6 #(


2