Change ASGI spec regarding headers.

This commit is contained in:
Andrew Godwin 2016-03-11 10:20:17 -08:00
parent a06026c99a
commit 820e955515
3 changed files with 30 additions and 13 deletions

View File

@ -58,16 +58,26 @@ class AsgiRequest(http.HttpRequest):
if self.message.get('server', None):
self.META['SERVER_NAME'] = self.message['server'][0]
self.META['SERVER_PORT'] = self.message['server'][1]
# Handle old style-headers for a transition period
if "headers" in self.message and isinstance(self.message['headers'], dict):
self.message['headers'] = [
(x.encode("latin1"), y) for x, y in
self.message['headers'].items()
]
# Headers go into META
for name, value in self.message.get('headers', {}).items():
for name, value in self.message.get('headers', []):
name = name.decode("latin1")
if name == "content-length":
corrected_name = "CONTENT_LENGTH"
elif name == "content-type":
corrected_name = "CONTENT_TYPE"
else:
corrected_name = 'HTTP_%s' % name.upper().replace("-", "_")
# HTTPbis say only ASCII chars are allowed in headers
self.META[corrected_name] = value.decode("ascii")
# HTTPbis say only ASCII chars are allowed in headers, but we latin1 just in case
value = value.decode("latin1")
if corrected_name in self.META:
value = self.META[corrected_name] + "," + value.decode("latin1")
self.META[corrected_name] = value
# Pull out request encoding if we find it
if "CONTENT_TYPE" in self.META:
_, content_params = cgi.parse_header(self.META["CONTENT_TYPE"])
@ -212,13 +222,13 @@ class AsgiHandler(base.BaseHandler):
# compliant clients that want things like Content-Type correct. Ugh.
response_headers = []
for header, value in response.items():
if isinstance(header, six.binary_type):
header = header.decode("latin1")
if isinstance(header, six.text_type):
header = header.encode("ascii")
if isinstance(value, six.text_type):
value = value.encode("latin1")
response_headers.append(
(
six.text_type(header),
six.binary_type(header),
six.binary_type(value),
)
)

View File

@ -30,5 +30,11 @@ class Message(object):
def __getitem__(self, key):
return self.content[key]
def __setitem__(self, key, value):
self.content[key] = value
def __contains__(self, key):
return key in self.content
def get(self, key, default=None):
return self.content.get(key, default)

View File

@ -454,11 +454,11 @@ Keys:
is mounted at; same as ``SCRIPT_NAME`` in WSGI. Optional, defaults
to ``""``.
* ``headers``: Dict of ``{name: value}``, where ``name`` is the lowercased
HTTP header name as unicode string and ``value`` is the header value as a byte
string. If multiple headers with the same name are received, they should
be concatenated into a single header as per RFC 7230. Header names containing
underscores should be discarded by the server. Optional, defaults to ``{}``.
* ``headers``: A list of ``[name, value]`` pairs, where ``name`` is the
byte string header name, and ``value`` is the byte string
header value. Order should be preserved from the original HTTP request;
duplicates are possible and must be preserved in the message as received.
Header names must be lowercased.
* ``body``: Body of the request, as a byte string. Optional, defaults to ``""``.
If ``body_channel`` is set, treat as start of body and concatenate
@ -514,8 +514,9 @@ Keys:
or left as empty string if no default found.
* ``headers``: A list of ``[name, value]`` pairs, where ``name`` is the
unicode string header name, and ``value`` is the byte string
header value. Order should be preserved in the HTTP response.
byte string header name, and ``value`` is the byte string
header value. Order should be preserved in the HTTP response. Header names
must be lowercased.
* ``content``: Byte string of HTTP body content.
Optional, defaults to empty string.