from collections import MutableMapping
from webob.compat import (
iteritems_,
string_types,
)
from webob.multidict import MultiDict
__all__ = ['ResponseHeaders', 'EnvironHeaders']
class ResponseHeaders(MultiDict):
"""
Dictionary view on the response headerlist.
Keys are normalized for case and whitespace.
"""
def __getitem__(self, key):
key = key.lower()
for k, v in reversed(self._items):
if k.lower() == key:
return v
raise KeyError(key)
def getall(self, key):
key = key.lower()
result = []
for k, v in self._items:
if k.lower() == key:
result.append(v)
return result
def mixed(self):
r = self.dict_of_lists()
for key, val in iteritems_(r):
if len(val) == 1:
r[key] = val[0]
return r
def dict_of_lists(self):
r = {}
for key, val in iteritems_(self):
r.setdefault(key.lower(), []).append(val)
return r
def __setitem__(self, key, value):
norm_key = key.lower()
items = self._items
for i in range(len(items)-1, -1, -1):
if items[i][0].lower() == norm_key:
del items[i]
self._items.append((key, value))
def __delitem__(self, key):
key = key.lower()
items = self._items
found = False
for i in range(len(items)-1, -1, -1):
if items[i][0].lower() == key:
del items[i]
found = True
if not found:
raise KeyError(key)
def __contains__(self, key):
key = key.lower()
for k, v in self._items:
if k.lower() == key:
return True
return False
has_key = __contains__
def setdefault(self, key, default=None):
c_key = key.lower()
for k, v in self._items:
if k.lower() == c_key:
return v
self._items.append((key, default))
return default
def pop(self, key, *args):
if len(args) > 1:
raise TypeError("pop expected at most 2 arguments, got %s"
% repr(1 + len(args)))
key = key.lower()
for i in range(len(self._items)):
if self._items[i][0].lower() == key:
v = self._items[i][1]
del self._items[i]
return v
if args:
return args[0]
else:
raise KeyError(key)
key2header = {
'CONTENT_TYPE': 'Content-Type',
'CONTENT_LENGTH': 'Content-Length',
'HTTP_CONTENT_TYPE': 'Content_Type',
'HTTP_CONTENT_LENGTH': 'Content_Length',
}
header2key = dict([(v.upper(),k) for (k,v) in key2header.items()])
def _trans_key(key):
if not isinstance(key, string_types):
return None
elif key in key2header:
return key2header[key]
elif key.startswith('HTTP_'):
return key[5:].replace('_', '-').title()
else:
return None
def _trans_name(name):
name = name.upper()
if name in header2key:
return header2key[name]
return 'HTTP_'+name.replace('-', '_')
class EnvironHeaders(MutableMapping):
"""An object that represents the headers as present in a
WSGI environment.
This object is a wrapper (with no internal state) for a WSGI
request object, representing the CGI-style HTTP_* keys as a
dictionary. Because a CGI environment can only hold one value for
each key, this dictionary is single-valued (unlike outgoing
headers).
"""
def __init__(self, environ):
self.environ = environ
def __getitem__(self, hname):
return self.environ[_trans_name(hname)]
def __setitem__(self, hname, value):
self.environ[_trans_name(hname)] = value
def __delitem__(self, hname):
del self.environ[_trans_name(hname)]
def keys(self):
return filter(None, map(_trans_key, self.environ))
def __contains__(self, hname):
return _trans_name(hname) in self.environ
def __len__(self):
return len(list(self.keys()))
def __iter__(self):
for k in self.keys():
yield k