K im dZddlZddlZddlZddlZddlZddlm Z ddl m Z ddl Z ddlZddlmZddlZddlZddlmZmZmZmZddlmZmZmZmZddlmZmZe ddl Z dd l m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+e jXr,dd l m-Z-dd l.m/Z/ddl0Z0ejbjde3e3fZ4nejbjdZ4d Z5ejld Z7GddZ8e dde3de3fdZ9Gdde4Z:GddZ;Gdde<Z=Gdde<Z>GddZ?GddZ@Gd d!ZAd"e3d#e'de&e3e3fe#e!e3e3fe!e!e3e3fd$ffde3fd%ZBGd&d'eZCd(e3de(e!e(eDe(eDffd)ZEd*e(eDd+e(eDd,eDde3fd-ZFd.e3de(eDfd/ZG dWd0e3d1eHd2e&e3e#eHfd3e&e3e#eCfd4e(e:ddf d5ZId6eHd7eHd2e&e3e#eHfd3e&e3e#eCfddf d8ZJd9e'eDeKeLejej fde3fd:ZNGd;dZQGd?d@e jZRd=e3deRfdAZSdBe3de*e3ddffdCZTd=e3de!e3e&e3e3fffdDZUdEe3dFe&e3e3fde3fdGZVdHe'e3eHfdIe'e3eHfdeHfdJZWdKZXejldLZYdMe3de!e3e(eDffdNZZdOe&e3e#e+fde"e!e3e+ffdPZ[ejldQjZ]dRejde3fdSZ_dBe3de3fdTZ`dUe3de&e3e3ffdVZay)XzHTTP 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) urlencodeurlparse urlunparse parse_qsl) native_strparse_qs_bytesutf8 to_unicode) ObjectDict unicode_type) TupleIterableListMappingIteratorDictUnionOptional Awaitable GeneratorAnyStr)Deque)Futurez z [\x00-\x08\x0B\x0C\x0E-\x1F\x7F]c eZdZdZej dZej dZej dZej dejdejdejdZ ej dZ ej d Z ej d Z ej d e jde jd Zej dejdejd ejd ejZej dZej ejdZeZeZej d e jde jdZej dZej de jde jdZej ejdZej dejdejdejd Zej dZej dejdejdejdZy)_ABNFa}Class that holds a subset of ABNF rules from RFC 9110 and friends. Class attributes are re.Pattern objects, with the same name as in the RFC (with hyphens changed to underscores). Currently contains only the subset we use (which is why this class is not public). Unfortunately the fields cannot be alphabetized as they are in the RFCs because of dependencies. z[A-Za-z0-9\-._~]z [!$&'()*+,;=]z%[0-9A-Fa-f]{2}z (?:[\[\]:]||z)*z[0-9]*z [\x21-\x7E]z [\x80-\xFF]z(?:)z| |\t)*z[!#$%&'*+\-.^_`|~0-9A-Za-z]+z)(?::z)?zHTTP/[0-9]\.[0-9]z (?:[\t ]|z)+(z) (z[0-9]{3}N)__name__ __module__ __qualname____doc__recompileuri_unreserveduri_sub_delimsuri_pct_encodedpatternuri_hosturi_portVCHARobs_text field_vchar field_valuetchartoken field_namemethodhost HTTP_version reason_phraserequest_target request_line status_code status_lineV/mnt/ssd/data/python-lab/Trading/venv/lib/python3.12/site-packages/tornado/httputil.pyrrNsu RZZ 34NRZZ 01N bjj!34Orzz ~--.a0F0F/GqI`I`HaacdHrzz)$H BJJ~ &Erzz.)H"**EMM?!H4D4D3EQGHK"**        K$7$7#8 @S@S?T VK BJJ5 6E BJJ5==/+ ,EJ F 2::X--.eH4D4D3ERH ID2::23LBJJ)EMM?!HS>S=TTVWKr?rinamereturncdj|jdDcgc]}|jc}Scc}w)ziMap a header name to Http-Header-Case. >>> _normalize_header("coNtent-TYPE") 'Content-Type' -)joinsplit capitalize)rAws r@_normalize_headerrIs/ 88TZZ_=Q\\^= >>=s=c $eZdZdZej deeeefddfdZ ej deeefddfdZ ej de eefddfdZ ej d eddfd Z dejd eddfd Z d d dedede ddfdZ dedeefdZdee eeffdZd d dede ddfdZed d dede ddfdZdededdfdZdedefdZdeddfdZdefdZdeejfdZddZeZdefdZeZy) HTTPHeadersaA 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__argrBNcyNr>selfrLs r@__init__zHTTPHeaders.__init__ r?cyrNr>rOs r@rQzHTTPHeaders.__init__rRr?argscyrNr>)rPrTs r@rQzHTTPHeaders.__init__rRr?kwargsc yrNr>)rPrVs r@rQzHTTPHeaders.__init__rRr?c i|_i|_d|_t|dk(rOt|dk(rAt |dt r.|dj D]\}}|j||y|j|i|y)Nr) _dict_as_list _last_keylen isinstancerKget_alladdupdate)rPrTrVkvs r@rQzHTTPHeaders.__init__sz   t9>c&kQ.:d1g{3SQ) 1A  DKK ( (r?T_chars_are_bytesrAvaluerectjj|std|z|r6tjjt |s1td|zt j|rtd|zt|}||_ ||vrIt||dzt|z|j|<|j|j|y|||<y)z#Adds a new value for the given key.zInvalid header name %rInvalid header value %r,N)rr5 fullmatchHTTPInputErrorr2r _FORBIDDEN_HEADER_CHARS_REsearchrIr\r rZr[append)rPrArfre norm_names r@r`zHTTPHeaders.adds))$/ !9D!@A A $$..z%/@A%%>%FGG)007$%>%FGG%d+ "  4 ?+c1Ju4EE JJy ! MM) $ + +E 2#DOr?cPt|}|jj|gS)z2Returns all values for the given header as a list.)rIr[getrPrAros r@get_listzHTTPHeaders.get_lists#%d+ }}  B//r?c#jK|jjD]\}}|D]}||f yw)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)rPrAvaluesrfs r@r_zHTTPHeaders.get_allsA !MM//1 $LD& $Um# $ $s13linectjd|x}r|d|j}|sy|dtvr|j t dd|j tz}|r0tjj|dds1t d|ztj|rt d|z|j|jd xx|z cc<|j|jxx|z cc<y |jd d\}}|j||j t| y#t$r t d wxYw) aUpdates the dictionary with a single header line. >>> h = HTTPHeaders() >>> h.parse_line("Content-Type: text/html") >>> h.get('content-type') 'text/html' >>> h.parse_line("Content-Length: 42\r\n") >>> h.get('content-type') 'text/html' .. versionchanged:: 6.5 Now supports lines with or without the trailing CRLF, making it possible to pass lines from AsyncHTTPClient's header_callback directly to this method. .. deprecated:: 6.5 In Tornado 7.0, certain deprecated features of HTTP will become errors. Specifically, line folding and the use of LF (with CR) as a line separator will be removed. z\r?\n$Nrz.first header line cannot start with whitespace rYzInvalid header continuation %rrh:zno colon in header linerd)r'rmstartHTTP_WHITESPACEr\rkstriprr2rjrlr[rZrF ValueErrorr`)rPrwremnew_partrArfs r@ parse_linezHTTPHeaders.parse_linesJ( )T* *1 * !'')$D  7o %~~%$%UVVTZZ88H((228AB<@()IH)TUU-44X>()BX)MNN MM$.. )" - 9 - JJt~~ &( 2 & @"jja0 e HHekk/2EU   @$%>?? @s EEheadersc|}d} |jd|}|dk(r|j||d| |S|||dz}|dz}|j||Q)aReturns 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`. r rzNrdrY)findr)clsrrehr|lfrws r@parsezHTTPHeaders.parse#s|8 EdE*BRx WUV_?O P526*DFE LL0@L Ar?cXt|}||j|<|g|j|<yrNrIrZr[)rPrArfros r@ __setitem__zHTTPHeaders.__setitem__Ns*%d+ % 9$)7 i r?c2|jt|SrN)rZrI)rPrAs r@ __getitem__zHTTPHeaders.__getitem__Sszz+D122r?cNt|}|j|=|j|=yrNrrrs r@ __delitem__zHTTPHeaders.__delitem__Vs$%d+ JJy ! MM) $r?c,t|jSrN)r]rZrPs r@__len__zHTTPHeaders.__len__[s4::r?c,t|jSrN)iterrZrs r@__iter__zHTTPHeaders.__iter__^sDJJr?ct|SrN)rKrs r@copyzHTTPHeaders.copyas 4  r?cg}|jD]\}}|j|d|ddj|S)Nz: r)r_rnrE)rPlinesrArfs r@__str__zHTTPHeaders.__str__jsG<<> /KD% LLD6E7"- . /wwu~r?)rBrK)r#r$r%r&typingoverloadrstrrrQrAnyboolr`rsrr_r classmethodrrrrintrrrr__copy__r __unicode__r>r?r@rKrKs8 __ gc49n5 $   __ gc3h/ D   __ eCHo $   __     )fjj )C )D )FJ$$C$d$d$,0S0T#Y0 $%S/2$AE1s111f=A&C&d&m&&T++C+D+ 333%%%  (6::. !H Kr?rKc@eZdZdZdZdZdZ ddeedeededee dee deed ee ee d fd ed d eddee ddfdZede eej"j$ffdZdefdZdefdZ ddedede e ffdZddZdefdZy)HTTPServerRequesta/ 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``. .. deprecated:: 6.5.2 The ``host`` argument to the ``HTTPServerRequest`` constructor is deprecated. Use ``headers["Host"]`` instead. This argument was mistakenly removed in Tornado 6.5.0 and temporarily restored in 6.5.2. Nr6uriversionrbodyr7filesHTTPFile connectionHTTPConnection start_lineRequestStartLineserver_connectionrBc | | \}}}||_||_||_|xs t|_|xsd|_t |dd} t | dd|_t | dd|_ |xs|jd|_ tjj|jstd |jzd |jvrtd |jzt|jjd |_|xsi|_||_| |_t)j(|_d|_||j/d\|_} |_t5|j2d|_t9j:|j6|_i|_y#t$r|dk(rd|_ n td YXwxYw)Nr?context remote_ipprotocolhttpHostHTTP/1.0z 127.0.0.1zMissing Host headerzInvalid Host header: %rriz%Multiple host headers not allowed: %rr?Tkeep_blank_values) r6rrrKrrgetattrrrr7KeyErrorrkrrjsplit_host_and_portlower host_namerrrtime _start_time _finish_time partitionpathqueryr argumentsrdeepcopyquery_argumentsbody_arguments) rPr6rrrrr7rrrrrseps r@rQzHTTPServerRequest.__init__s  !#- FC  /+- KC *i6 +t<V<  <4 V 4DIzz##DII. !:TYY!FG G $)) "!!H499!TU U,TYY__->?B[b $!299;  ?),s); &DIsDJ' dK#}}T^^< K <*$' $%:;; 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)rstreamsocket getpeercertr)rPrs r@get_ssl_certificatez%HTTPServerRequest.get_ssl_certificate@sS* &??))00<<'=   s ?/? A  A c@t|jjdd|j|j|j |j|jj D]0\}}|jj|gj|2y)N Content-Typer) parse_body_argumentsrrqrrrrur setdefaultextend)rPrbrcs r@ _parse_bodyzHTTPServerRequest._parse_body_s LL  ^R 0 II    JJ LL  ''--/ 7DAq NN % %a , 3 3A 6 7r?c d}dj|Dcgc]}|dt||c}}|jjd|dScc}w)N)rr7r6rrrz, =r"r )rEr __class__r#)rPattrsnrTs r@__repr__zHTTPServerRequest.__repr__ksWMyyuE!QCqq!1 45EF..))*!D633FsA ) NNrNNNNNNN)FrBN)r#r$r%r&rr _body_futurerrrKbytesrrobjectrQpropertyrrMorselrfloatrrrrrrr>r?r@rrssr_B D EL!%!!)- $"7;1537.2A! A!c]A! A! +& A! uo A!smA!S$z"2234A!-.A!/0A!$F+A! A!Fc4<<#6#667,<#<8e8#( tT5 !> 74#4r?rceZdZdZy)rkzqException class for malformed HTTP requests or responses from remote sources. .. versionadded:: 4.0 Nr#r$r%r&r>r?r@rkrkqs   r?rkceZdZdZy)HTTPOutputErrorzJException class for errors in HTTP output. .. versionadded:: 4.0 Nrr>r?r@rr{s   r?rc4eZdZdZdeddddfdZdeddfd Zy) HTTPServerConnectionDelegatez_Implement this interface to handle requests from `.HTTPServer`. .. versionadded:: 4.0 server_conn request_connrrBHTTPMessageDelegatect)ajThis method is called by the server when a new request has started. :arg server_conn: is an opaque object representing the long-lived (e.g. tcp-level) connection. :arg request_conn: is a `.HTTPConnection` object for a single request/response exchange. This method should return a `.HTTPMessageDelegate`. NotImplementedError)rPrrs r@ start_requestz*HTTPServerConnectionDelegate.start_requests "##r?Ncy)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>)rPrs r@on_closez%HTTPServerConnectionDelegate.on_close r?)r#r$r%r&rrrr>r?r@rrs7 $! $1A $  $ F t r?rcbeZdZdZdeddedeedfdZde deedfd Z d d Z d d Z y) rz_Implement this interface to handle an HTTP request or response. .. versionadded:: 4.0 rrResponseStartLinerrBNcy)aCalled 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>)rPrrs r@headers_receivedz$HTTPMessageDelegate.headers_receiveds" r?chunkcy)ziCalled when a chunk of data has been received. May return a `.Future` for flow control. Nr>rPrs r@ data_receivedz!HTTPMessageDelegate.data_receiveds r?cy)z6Called after the last chunk of data has been received.Nr>rs r@finishzHTTPMessageDelegate.finishrRr?cy)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>rs r@on_connection_closez'HTTPMessageDelegate.on_connection_closerr?r) r#r$r%r&rrKrrrrr r rr>r?r@rrs]  AB   )D/ "  & 5 Xio-F   r?rc PeZdZdZ d deddedeeddfd Zdeddfd Z d d Z y)rzYApplications use this interface to write their responses. .. versionadded:: 4.0 NrrrrrBz Future[None]ct)aWrite an HTTP header block. :arg start_line: a `.RequestStartLine` or `.ResponseStartLine`. :arg headers: a `.HTTPHeaders` instance. :arg chunk: the first (optional) chunk of data. This is an optimization so that small responses can be written in the same call as their headers. The ``version`` field of ``start_line`` is ignored. Returns a future for flow control. .. versionchanged:: 6.0 The ``callback`` argument was removed. r)rPrrrs r@ write_headerszHTTPConnection.write_headerss ,"##r?ct)zWrites a chunk of body data. Returns a future for flow control. .. versionchanged:: 6.0 The ``callback`` argument was removed. rr s r@writezHTTPConnection.writes "##r?ct)z3Indicates that the last body data has been written.rrs r@r zHTTPConnection.finishs !##r?rNr) r#r$r%r&rrKrrrrr r>r?r@rrsY"& $AB$$ $  $0 $5 $^ $$r?rurlrT.c ||St|}t|tr7t|jd}|j |j nnt|tst|tr)t|jd}|j |n%djt|}t|t|}t|d|d|d|d||df}|S) aConcatenate url and arguments regardless of whether url has existing query parameters. ``args`` may be either a dictionary or a list of key-value pairs (the latter allows for multiple values with the same key. >>> url_concat("http://example.com/foo", dict(c="d")) 'http://example.com/foo?c=d' >>> url_concat("http://example.com/foo?a=b", dict(c="d")) 'http://example.com/foo?a=b&c=d' >>> url_concat("http://example.com/foo?a=b", [("c", "d"), ("c", "d2")]) 'http://example.com/foo?a=b&c=d&c=d2' Trz7'args' parameter should be dict, list or tuple. Not {0}rrY)rr^dictr rrrulisttupleformattype TypeErrorrr)rrT parsed_url parsed_queryerr final_querys r@ url_concatr%s& | #J$ !1!1TJ DJJL) D$ :dE#: !1!1TJ D!GNN J nL)K  qM qM qM qM  qM   C Jr?c0eZdZUdZeed<eed<eed<y)rzRepresents a file uploaded via a form. For backwards compatibility, its instance attributes are also accessible as dictionary keys. * ``filename`` * ``body`` * ``content_type`` filenamer content_typeN)r#r$r%r&r__annotations__rr>r?r@rr,sM Kr?r range_headerc$|jd\}}}|j|j}}|dk7ry|jd\}}} t|}t|}|||dk7r| }d}||fS|dz }||fS#t$rYywxYw)agParses a Range header. Returns either ``None`` or tuple ``(start, end)``. Note that while the HTTP headers use inclusive byte positions, this method returns indexes suitable for use in slices. >>> start, end = _parse_request_range("bytes=1-2") >>> start, end (1, 3) >>> [0, 1, 2, 3, 4][start:end] [1, 2] >>> _parse_request_range("bytes=6-") (6, None) >>> _parse_request_range("bytes=-6") (-6, None) >>> _parse_request_range("bytes=-0") (None, 0) >>> _parse_request_range("bytes=") (None, None) >>> _parse_request_range("foo=42") >>> _parse_request_range("bytes=1-2,6-10") Note: only supports one range (ex, ``bytes=1-2,6-10`` is not allowed). See [0] for the details of the range header. [0]: http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p5-range-latest.html#byte.ranges rrNrDrrY)rr~ _int_or_noner)r*unit_rfstart_bend_br|ends r@_parse_request_ranger2<s>"++C0ND!U**, %D w,GQW%5!  =ax 3< 1HC 3< sB BBr|r1totalc6|xsd}|xs|dz }d|d|d|S)zReturns a suitable Content-Range header: >>> print(_get_content_range(None, 1, 4)) bytes 0-0/4 >>> print(_get_content_range(1, 3, 4)) bytes 1-2/4 >>> print(_get_content_range(None, None, 4)) bytes 0-3/4 rrYzbytes rD/r>)r|r1r3s r@_get_content_ranger6os4 JQE <%1 C E7!C5% ))r?valcD|j}|dk(ryt|S)Nr)r~r)r7s r@r,r,~s ))+C by s8Or?r(rrrrc|jdrb|rd|vrtd|dz t|d}|j D])\}}|s |j |gj |+y|jdr|rd|vrtd|dz |jd } | D]F} | jjd \} } } | d k(s,| s/tt| |||ytd y#t$r}td|z|d}~wwxYw#t$r}td |z|d}~wwxYw)aFParses a form request body. Supports ``application/x-www-form-urlencoded`` and ``multipart/form-data``. The ``content_type`` parameter should be a string and ``body`` should be a byte string. The ``arguments`` and ``files`` parameters are dictionaries that will be updated with the parsed contents. z!application/x-www-form-urlencodedzContent-Encodingz Unsupported Content-Encoding: %sTrz&Invalid x-www-form-urlencoded body: %sNzmultipart/form-data;rboundaryzmultipart boundary not foundzInvalid multipart/form-data: %s) startswithrkr rrurrrFr~rparse_multipart_form_datar )r(rrrr uri_argumentserArvfieldsfieldrbrrcs r@rrsBC )W4 2W=O5PP  V*44HM*//1 >LD&$$T2.55f= >  !6 7 )W4 2W=O5PP  O!'',F E!KKM33C8 3 ?q-d1gtYN  E %%CDD 8  V !IA!MNTU U V& O !BQ!FGQ N OsA D>D%D%D%8 D% D"DD"% E.D==Er;datac@|jdr|jdr|dd}|jd|zdz}|dk(r td|d|j d|zdz}|D]0}|s|j d}|dk(r td t j|d|jd d }|jd d} t| \} } | dk7s|jds td||dzd} | jds td| d} | jdrD|jdd}|j| gjt| d| ||j| gj| 3y)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. "rYrzs--z4Invalid multipart/form-data: no final boundary foundNs s z#multipart/form-data missing headerszutf-8FrdzContent-Dispositionrz form-datazInvalid multipart/form-datarAz multipart/form-data missing namer'rzapplication/unknown)r'rr()r<endswithrfindrkrFrrKrdecoderq _parse_headerrrnr)r;rBrrfinal_boundary_indexpartsparteohr disp_header disposition disp_paramsrfrActypes r@r=r=s,4 X%6%6t%<Ab>::eh&6&>?r!STT && ' - -eh.>.H IE9 ii $ "9 !FG G##D#J$5$5g$>QV#Wkk"7< #0#= [ + %T]]7-C !>? ?S1Wr"v& !CD D6" ??: &KK0EFE   T2 & - -(45u   r * 1 1% 8/9r?tsczt|ttfr|}nt|ttj frt j|}nLt|tjr$t j|j}ntd|ztjj|dS)aFormats a timestamp in the format used by HTTP. The argument may be a numeric timestamp as returned by `time.time`, a time tuple as returned by `time.gmtime`, or a `datetime.datetime` object. 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' zunknown timestamp type: %rT)usegmt)r^rrrr struct_timecalendartimegmdatetime utctimetupler emailutils formatdate)rStime_nums r@format_timestampr_s"sEl# B 0 01 2??2& B)) *??2??#454r9:: ;; ! !(4 ! 88r?c,eZdZUeed<eed<eed<y)rr6rrN)r#r$r%rr)r>r?r@rrs K I Lr?rrwc8tjj|}|s tdt |j d|j d|j d}|j jdstd|j z|S)zReturns a (method, path, version) tuple for an HTTP 1.x request line. The response is a `typing.NamedTuple`. >>> parse_request_start_line("GET /foo HTTP/1.1") RequestStartLine(method='GET', path='/foo', version='HTTP/1.1') zMalformed HTTP request linerYrrHTTP/1Unexpected HTTP version %r)rr;rjrkrgrouprr<rwmatchrs r@parse_request_start_linerhs    ( ( .E :;;QQQHA 99   )9AIIEFF Hr?c,eZdZUeed<eed<eed<y)rrcodereasonN)r#r$r%rr)rr>r?r@rrs L I Kr?rcJtjj|}|s tdt |j dt |j d|j d}|jjdstd|jz|S)zReturns a (version, code, reason) tuple for an HTTP 1.x response line. The response is a `typing.NamedTuple`. >>> parse_response_start_line("HTTP/1.1 200 OK") ResponseStartLine(version='HTTP/1.1', code=200, reason='OK') z!Error parsing response start linerYrrrbrc) rr=rjrkrrdrrr<res r@parse_response_start_linerm#s    ' ' -E @AA%++a.#ekk!n*=u{{1~NA 99   )9AIIEFF Hr?sc#K|dddk(r|dd}|jd}|dkDro|jdd||jdd|z dzrE|jd|dz}|dkDr+|jdd||jdd|z dzrE|dkr t|}|d|}|j||d}|dddk(ryyw)NrYr:r"z\"r)rcountr]r~)rnr1fs r@ _parseparamrs=s BQ%3, abEffSkAg17733/!''%C2HHAM&&cAg&CAg17733/!''%C2HHAM 7a&C dsGggi cdG BQ%3,sBC 4C  C c*td|z}t|}dg}|D]l}|jd}|dk\s|d|jj }||dzdj}|j |t |fntjj|}|jdi} |D]L\}} tjj| }t|dk\r|ddk(r |d dk(r|dd }|| |<N|| fS) aYParse a Content-type like header. Return the main content-type and a dictionary of options. >>> d = "form-data; foo=\"b\\\\a\\\"r\"; file*=utf-8''T%C3%A4st" >>> ct, d = _parse_header(d) >>> ct 'form-data' >>> d['file'] == r'T\u00e4st'.encode('ascii').decode('unicode_escape') True >>> d['foo'] 'b\\a"r' r:)DummyrfrrNrYrrprz) rsnextrr~rrnr r[r\ decode_paramspopcollapse_rfc2231_valuer]) rwrLkeyparamspirArfdecoded_paramspdict decoded_values r@rJrJJs d #E u+C !F 5 FF3K 6Ra5;;=&&(Da!egJ$$&E MM4E!23 4 5 [[..v6Nq E-m 22=A u:?uQx3593C!BKEd  :r?rzrc|s|S|g}t|jD]/\}}||j||j|d|1dj|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' rz; )sortedrurnrE)rzroutrbrcs r@_encode_headerrmsi  %Cu{{}%#1 9 JJqM JJ!AaSz " # 99S>r?usernamepasswordct|trtjd|}t|trtjd|}t |dzt |zS)zEncodes a username/password pair in the format used by HTTP auth. The return value is a byte string in the form ``username:password``. .. versionadded:: 5.1 NFC:)r^r unicodedata normalizer )rrs r@encode_username_passwordrsT(L)((9(L)((9 >D 4> 11r?c*ddl}|jS)Nr)doctest DocTestSuite)rs r@doctestsrs    !!r?z ^(.+):(\d+)$netlocctj|}|r/|jd}t|jd}||fS|}d}||fS)zReturns ``(host, port)`` tuple from ``netloc``. Returned ``port`` will be ``None`` if not present. .. versionadded:: 4.1 rYrN) _netloc_rerfrdr)rrfr7ports r@rrsX   V $E {{1~5;;q>" $< $<r?qsc#VK|jD]\}}|D]}||f yw)zgGenerator converting a result of ``parse_qs`` back to name-value pairs. .. versionadded:: 5.0 N)ru)rrbvsrcs r@ qs_to_qslrs9 2 Aa&L s')z\\(?:([0-3][0-7][0-7])|(.))rcF|drtt|ddS|dS)NrYr)chrr)rs r@_unquote_replacers't3qtQ<  t r?ct|t|dkr|S|ddk7s|ddk7r|S|dd}tt|S)zHandle double quotes and escaping in cookie values. This method is copied verbatim from the Python 3.13 standard library (http.cookies._unquote) so we don't have to depend on non-public interfaces. rrrprzrY)r] _unquote_subr)rns r@_unquote_cookiersO yCFQJts{aesl !BA (! ,,r?cookieci}|jdD]S}d|vr|jdd\}}nd|}}|j|j}}|s|sFt|||<U|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:rrYr)rFr~r)r cookiedictrrzr7s r@rrswJc" 3 %<{{3*HC5C99; S #-c2JsO 3 r?rN)br&rWcollections.abc collectionsrrY email.utilsr[ functoolsr http.clientr http.cookiesrr'sslrrr urllib.parserrrr tornado.escaper r r r tornado.utilrrrrrrrrrrrrrr TYPE_CHECKINGrasynciorunittestabcMutableMappingrStrMutableMappingr}r(rlrrIrKrrrkrrrrr%rrr2r6r,rrr=rrrVr_ NamedTuplerrhrrmrsrJrrrrrrsubrMatchrrrr>r?r@rs   !  CCGG1       $66sCx@#66(RZZ(KL55p 4?C?C??`#`F{4{4| Y  i   :+ + \+$+$\, ,  d38nd5c?3U5c?C;O5PP ,  ,^ z  00 eHSM8C=0120f *hsm *(3- * *PS *chsm&* +O+O +OCe$%+O T(^# $ +O k " +O  +O\3939 39Ce$%39 T(^# $ 39  39l9 c5%!1!183D3DDE990v((  3 +; ,))  C ,= 4 3 9S$_5   c4S>&9 : FDcNs( 2CJ 2+0e+< 2  2 "RZZ ( c8C=.@(A"$sDL()huS&[7I.Jrzz89== S-s-s-6c3hr?