1 # -*- test-case-name: twisted.web.test.test_http_headers
2 # Copyright (c) Twisted Matrix Laboratories.
3 # See LICENSE for details.
6 An API for storing HTTP header names and values.
10 from UserDict import DictMixin
13 def _dashCapitalize(name):
15 Return a string which is capitalized using '-' as a word separator.
17 @param name: The name of the header to capitalize.
20 @return: The given header capitalized using '-' as a word separator.
23 return '-'.join([word.capitalize() for word in name.split('-')])
27 class _DictHeaders(DictMixin):
29 A C{dict}-like wrapper around L{Headers} to provide backwards compatibility
30 for L{Request.received_headers} and L{Request.headers} which used to be
31 plain C{dict} instances.
33 @type _headers: L{Headers}
34 @ivar _headers: The real header storage object.
36 def __init__(self, headers):
37 self._headers = headers
40 def __getitem__(self, key):
42 Return the last value for header of C{key}.
44 if self._headers.hasHeader(key):
45 return self._headers.getRawHeaders(key)[-1]
49 def __setitem__(self, key, value):
53 self._headers.setRawHeaders(key, [value])
56 def __delitem__(self, key):
58 Delete the given header.
60 if self._headers.hasHeader(key):
61 self._headers.removeHeader(key)
68 Return a list of all header names.
70 return [k.lower() for k, v in self._headers.getAllRawHeaders()]
75 Return a C{dict} mapping each header name to the last corresponding
78 return dict(self.items())
81 # Python 2.3 DictMixin.setdefault is defined so as not to have a default
82 # for the value parameter. This is necessary to make this setdefault look
83 # like dict.setdefault on Python 2.3. -exarkun
84 def setdefault(self, name, value=None):
86 Retrieve the last value for the given header name. If there are no
87 values present for that header, set the value to C{value} and return
88 that instead. Note that C{None} is the default for C{value} for
89 backwards compatibility, but header values may only be of type C{str}.
91 return DictMixin.setdefault(self, name, value)
94 # The remaining methods are only for efficiency. The same behavior
95 # should remain even if they are removed. For details, see
96 # <http://docs.python.org/lib/module-UserDict.html>.
98 def __contains__(self, name):
100 Return C{True} if the named header is present, C{False} otherwise.
102 return self._headers.getRawHeaders(name) is not None
107 Return an iterator of the lowercase name of each header present.
109 for k, v in self._headers.getAllRawHeaders():
115 Return an iterable of two-tuples of each lower-case header name and the
116 last value for that header.
118 for k, v in self._headers.getAllRawHeaders():
119 yield k.lower(), v[-1]
123 class Headers(object):
125 This class stores the HTTP headers as both a parsed representation
126 and the raw string representation. It converts between the two on
129 @cvar _caseMappings: A C{dict} that maps lowercase header names
130 to their canonicalized representation.
132 @ivar _rawHeaders: A C{dict} mapping header names as C{str} to C{lists} of
133 header values as C{str}.
136 'content-md5': 'Content-MD5',
141 'www-authenticate': 'WWW-Authenticate',
142 'x-xss-protection': 'X-XSS-Protection'}
144 def __init__(self, rawHeaders=None):
145 self._rawHeaders = {}
146 if rawHeaders is not None:
147 for name, values in rawHeaders.iteritems():
148 self.setRawHeaders(name, values[:])
153 Return a string fully describing the headers set on this object.
155 return '%s(%r)' % (self.__class__.__name__, self._rawHeaders,)
158 def __cmp__(self, other):
160 Define L{Headers} instances as being equal to each other if they have
161 the same raw headers.
163 if isinstance(other, Headers):
164 return cmp(self._rawHeaders, other._rawHeaders)
165 return NotImplemented
170 Return a copy of itself with the same headers set.
172 return self.__class__(self._rawHeaders)
175 def hasHeader(self, name):
177 Check for the existence of a given header.
180 @param name: The name of the HTTP header to check for.
183 @return: C{True} if the header exists, otherwise C{False}.
185 return name.lower() in self._rawHeaders
188 def removeHeader(self, name):
190 Remove the named header from this header object.
193 @param name: The name of the HTTP header to remove.
197 self._rawHeaders.pop(name.lower(), None)
200 def setRawHeaders(self, name, values):
202 Sets the raw representation of the given header.
205 @param name: The name of the HTTP header to set the values for.
207 @type values: C{list}
208 @param values: A list of strings each one being a header value of
213 if not isinstance(values, list):
214 raise TypeError("Header entry %r should be list but found "
215 "instance of %r instead" % (name, type(values)))
216 self._rawHeaders[name.lower()] = values
219 def addRawHeader(self, name, value):
221 Add a new raw value for the given header.
224 @param name: The name of the header for which to set the value.
227 @param value: The value to set for the named header.
229 values = self.getRawHeaders(name)
231 self.setRawHeaders(name, [value])
236 def getRawHeaders(self, name, default=None):
238 Returns a list of headers matching the given name as the raw string
242 @param name: The name of the HTTP header to get the values of.
244 @param default: The value to return if no header with the given C{name}
248 @return: A C{list} of values for the given header.
250 return self._rawHeaders.get(name.lower(), default)
253 def getAllRawHeaders(self):
255 Return an iterator of key, value pairs of all headers contained in this
256 object, as strings. The keys are capitalized in canonical
259 for k, v in self._rawHeaders.iteritems():
260 yield self._canonicalNameCaps(k), v
263 def _canonicalNameCaps(self, name):
265 Return the canonical name for the given header.
268 @param name: The all-lowercase header name to capitalize in its
272 @return: The canonical name of the header.
274 return self._caseMappings.get(name, _dashCapitalize(name))
277 __all__ = ['Headers']