Home | History | Annotate | Download | only in webob
      1 from collections import MutableMapping
      2 from webob.compat import (
      3     iteritems_,
      4     string_types,
      5     )
      6 from webob.multidict import MultiDict
      7 
      8 __all__ = ['ResponseHeaders', 'EnvironHeaders']
      9 
     10 class ResponseHeaders(MultiDict):
     11     """
     12         Dictionary view on the response headerlist.
     13         Keys are normalized for case and whitespace.
     14     """
     15     def __getitem__(self, key):
     16         key = key.lower()
     17         for k, v in reversed(self._items):
     18             if k.lower() == key:
     19                 return v
     20         raise KeyError(key)
     21 
     22     def getall(self, key):
     23         key = key.lower()
     24         result = []
     25         for k, v in self._items:
     26             if k.lower() == key:
     27                 result.append(v)
     28         return result
     29 
     30     def mixed(self):
     31         r = self.dict_of_lists()
     32         for key, val in iteritems_(r):
     33             if len(val) == 1:
     34                 r[key] = val[0]
     35         return r
     36 
     37     def dict_of_lists(self):
     38         r = {}
     39         for key, val in iteritems_(self):
     40             r.setdefault(key.lower(), []).append(val)
     41         return r
     42 
     43     def __setitem__(self, key, value):
     44         norm_key = key.lower()
     45         items = self._items
     46         for i in range(len(items)-1, -1, -1):
     47             if items[i][0].lower() == norm_key:
     48                 del items[i]
     49         self._items.append((key, value))
     50 
     51     def __delitem__(self, key):
     52         key = key.lower()
     53         items = self._items
     54         found = False
     55         for i in range(len(items)-1, -1, -1):
     56             if items[i][0].lower() == key:
     57                 del items[i]
     58                 found = True
     59         if not found:
     60             raise KeyError(key)
     61 
     62     def __contains__(self, key):
     63         key = key.lower()
     64         for k, v in self._items:
     65             if k.lower() == key:
     66                 return True
     67         return False
     68 
     69     has_key = __contains__
     70 
     71     def setdefault(self, key, default=None):
     72         c_key = key.lower()
     73         for k, v in self._items:
     74             if k.lower() == c_key:
     75                 return v
     76         self._items.append((key, default))
     77         return default
     78 
     79     def pop(self, key, *args):
     80         if len(args) > 1:
     81             raise TypeError("pop expected at most 2 arguments, got %s"
     82                               % repr(1 + len(args)))
     83         key = key.lower()
     84         for i in range(len(self._items)):
     85             if self._items[i][0].lower() == key:
     86                 v = self._items[i][1]
     87                 del self._items[i]
     88                 return v
     89         if args:
     90             return args[0]
     91         else:
     92             raise KeyError(key)
     93 
     94 
     95 
     96 
     97 
     98 
     99 key2header = {
    100     'CONTENT_TYPE': 'Content-Type',
    101     'CONTENT_LENGTH': 'Content-Length',
    102     'HTTP_CONTENT_TYPE': 'Content_Type',
    103     'HTTP_CONTENT_LENGTH': 'Content_Length',
    104 }
    105 
    106 header2key = dict([(v.upper(),k) for (k,v) in key2header.items()])
    107 
    108 def _trans_key(key):
    109     if not isinstance(key, string_types):
    110         return None
    111     elif key in key2header:
    112         return key2header[key]
    113     elif key.startswith('HTTP_'):
    114         return key[5:].replace('_', '-').title()
    115     else:
    116         return None
    117 
    118 def _trans_name(name):
    119     name = name.upper()
    120     if name in header2key:
    121         return header2key[name]
    122     return 'HTTP_'+name.replace('-', '_')
    123 
    124 class EnvironHeaders(MutableMapping):
    125     """An object that represents the headers as present in a
    126     WSGI environment.
    127 
    128     This object is a wrapper (with no internal state) for a WSGI
    129     request object, representing the CGI-style HTTP_* keys as a
    130     dictionary.  Because a CGI environment can only hold one value for
    131     each key, this dictionary is single-valued (unlike outgoing
    132     headers).
    133     """
    134 
    135     def __init__(self, environ):
    136         self.environ = environ
    137 
    138     def __getitem__(self, hname):
    139         return self.environ[_trans_name(hname)]
    140 
    141     def __setitem__(self, hname, value):
    142         self.environ[_trans_name(hname)] = value
    143 
    144     def __delitem__(self, hname):
    145         del self.environ[_trans_name(hname)]
    146 
    147     def keys(self):
    148         return filter(None, map(_trans_key, self.environ))
    149 
    150     def __contains__(self, hname):
    151         return _trans_name(hname) in self.environ
    152 
    153     def __len__(self):
    154         return len(list(self.keys()))
    155 
    156     def __iter__(self):
    157         for k in self.keys():
    158             yield k
    159