Update tornado
This commit is contained in:
Regular → Executable
+45
-13
@@ -16,12 +16,16 @@
|
||||
|
||||
"""HTTP utility code shared by clients and servers."""
|
||||
|
||||
from __future__ import absolute_import, division, with_statement
|
||||
|
||||
import logging
|
||||
import urllib
|
||||
import re
|
||||
|
||||
from tornado.escape import native_str, parse_qs_bytes, utf8
|
||||
from tornado.util import b, ObjectDict
|
||||
|
||||
|
||||
class HTTPHeaders(dict):
|
||||
"""A dictionary that maintains Http-Header-Case for all keys.
|
||||
|
||||
@@ -55,7 +59,14 @@ class HTTPHeaders(dict):
|
||||
dict.__init__(self)
|
||||
self._as_list = {}
|
||||
self._last_key = None
|
||||
self.update(*args, **kwargs)
|
||||
if (len(args) == 1 and len(kwargs) == 0 and
|
||||
isinstance(args[0], HTTPHeaders)):
|
||||
# Copy constructor
|
||||
for k, v in args[0].get_all():
|
||||
self.add(k, v)
|
||||
else:
|
||||
# Dict-style initialization
|
||||
self.update(*args, **kwargs)
|
||||
|
||||
# new public methods
|
||||
|
||||
@@ -144,6 +155,10 @@ class HTTPHeaders(dict):
|
||||
for k, v in dict(*args, **kwargs).iteritems():
|
||||
self[k] = v
|
||||
|
||||
def copy(self):
|
||||
# default implementation returns dict(self), not the subclass
|
||||
return HTTPHeaders(self)
|
||||
|
||||
_NORMALIZED_HEADER_RE = re.compile(r'^[A-Z0-9][a-z0-9]*(-[A-Z0-9][a-z0-9]*)*$')
|
||||
_normalized_headers = {}
|
||||
|
||||
@@ -172,7 +187,8 @@ def url_concat(url, args):
|
||||
>>> url_concat("http://example.com/foo?a=b", dict(c="d"))
|
||||
'http://example.com/foo?a=b&c=d'
|
||||
"""
|
||||
if not args: return url
|
||||
if not args:
|
||||
return url
|
||||
if url[-1] not in ('?', '&'):
|
||||
url += '&' if ('?' in url) else '?'
|
||||
return url + urllib.urlencode(args)
|
||||
@@ -190,6 +206,24 @@ class HTTPFile(ObjectDict):
|
||||
pass
|
||||
|
||||
|
||||
def parse_body_arguments(content_type, body, arguments, files):
|
||||
if content_type.startswith("application/x-www-form-urlencoded"):
|
||||
uri_arguments = parse_qs_bytes(native_str(body))
|
||||
for name, values in uri_arguments.iteritems():
|
||||
values = [v for v in values if v]
|
||||
if values:
|
||||
arguments.setdefault(name, []).extend(values)
|
||||
elif content_type.startswith("multipart/form-data"):
|
||||
fields = content_type.split(";")
|
||||
for field in fields:
|
||||
k, sep, v = field.strip().partition("=")
|
||||
if k == "boundary" and v:
|
||||
parse_multipart_form_data(utf8(v), body, arguments, files)
|
||||
break
|
||||
else:
|
||||
logging.warning("Invalid multipart/form-data")
|
||||
|
||||
|
||||
def parse_multipart_form_data(boundary, data, arguments, files):
|
||||
"""Parses a multipart/form-data body.
|
||||
|
||||
@@ -204,13 +238,14 @@ def parse_multipart_form_data(boundary, data, arguments, files):
|
||||
# in the wild.
|
||||
if boundary.startswith(b('"')) and boundary.endswith(b('"')):
|
||||
boundary = boundary[1:-1]
|
||||
if data.endswith(b("\r\n")):
|
||||
footer_length = len(boundary) + 6
|
||||
else:
|
||||
footer_length = len(boundary) + 4
|
||||
parts = data[:-footer_length].split(b("--") + boundary + b("\r\n"))
|
||||
final_boundary_index = data.rfind(b("--") + boundary + b("--"))
|
||||
if final_boundary_index == -1:
|
||||
logging.warning("Invalid multipart/form-data: no final boundary")
|
||||
return
|
||||
parts = data[:final_boundary_index].split(b("--") + boundary + b("\r\n"))
|
||||
for part in parts:
|
||||
if not part: continue
|
||||
if not part:
|
||||
continue
|
||||
eoh = part.find(b("\r\n\r\n"))
|
||||
if eoh == -1:
|
||||
logging.warning("multipart/form-data missing headers")
|
||||
@@ -250,6 +285,7 @@ def _parseparam(s):
|
||||
yield f.strip()
|
||||
s = s[end:]
|
||||
|
||||
|
||||
def _parse_header(line):
|
||||
"""Parse a Content-type like header.
|
||||
|
||||
@@ -263,7 +299,7 @@ def _parse_header(line):
|
||||
i = p.find('=')
|
||||
if i >= 0:
|
||||
name = p[:i].strip().lower()
|
||||
value = p[i+1:].strip()
|
||||
value = p[i + 1:].strip()
|
||||
if len(value) >= 2 and value[0] == value[-1] == '"':
|
||||
value = value[1:-1]
|
||||
value = value.replace('\\\\', '\\').replace('\\"', '"')
|
||||
@@ -274,7 +310,3 @@ def _parse_header(line):
|
||||
def doctests():
|
||||
import doctest
|
||||
return doctest.DocTestSuite()
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
||||
Reference in New Issue
Block a user