annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/wsgiref/headers.py @ 69:33d812a61356

planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author jpayne
date Tue, 18 Mar 2025 17:55:14 -0400
parents
children
rev   line source
jpayne@69 1 """Manage HTTP Response Headers
jpayne@69 2
jpayne@69 3 Much of this module is red-handedly pilfered from email.message in the stdlib,
jpayne@69 4 so portions are Copyright (C) 2001,2002 Python Software Foundation, and were
jpayne@69 5 written by Barry Warsaw.
jpayne@69 6 """
jpayne@69 7
jpayne@69 8 # Regular expression that matches `special' characters in parameters, the
jpayne@69 9 # existence of which force quoting of the parameter value.
jpayne@69 10 import re
jpayne@69 11 tspecials = re.compile(r'[ \(\)<>@,;:\\"/\[\]\?=]')
jpayne@69 12
jpayne@69 13 def _formatparam(param, value=None, quote=1):
jpayne@69 14 """Convenience function to format and return a key=value pair.
jpayne@69 15
jpayne@69 16 This will quote the value if needed or if quote is true.
jpayne@69 17 """
jpayne@69 18 if value is not None and len(value) > 0:
jpayne@69 19 if quote or tspecials.search(value):
jpayne@69 20 value = value.replace('\\', '\\\\').replace('"', r'\"')
jpayne@69 21 return '%s="%s"' % (param, value)
jpayne@69 22 else:
jpayne@69 23 return '%s=%s' % (param, value)
jpayne@69 24 else:
jpayne@69 25 return param
jpayne@69 26
jpayne@69 27
jpayne@69 28 class Headers:
jpayne@69 29 """Manage a collection of HTTP response headers"""
jpayne@69 30
jpayne@69 31 def __init__(self, headers=None):
jpayne@69 32 headers = headers if headers is not None else []
jpayne@69 33 if type(headers) is not list:
jpayne@69 34 raise TypeError("Headers must be a list of name/value tuples")
jpayne@69 35 self._headers = headers
jpayne@69 36 if __debug__:
jpayne@69 37 for k, v in headers:
jpayne@69 38 self._convert_string_type(k)
jpayne@69 39 self._convert_string_type(v)
jpayne@69 40
jpayne@69 41 def _convert_string_type(self, value):
jpayne@69 42 """Convert/check value type."""
jpayne@69 43 if type(value) is str:
jpayne@69 44 return value
jpayne@69 45 raise AssertionError("Header names/values must be"
jpayne@69 46 " of type str (got {0})".format(repr(value)))
jpayne@69 47
jpayne@69 48 def __len__(self):
jpayne@69 49 """Return the total number of headers, including duplicates."""
jpayne@69 50 return len(self._headers)
jpayne@69 51
jpayne@69 52 def __setitem__(self, name, val):
jpayne@69 53 """Set the value of a header."""
jpayne@69 54 del self[name]
jpayne@69 55 self._headers.append(
jpayne@69 56 (self._convert_string_type(name), self._convert_string_type(val)))
jpayne@69 57
jpayne@69 58 def __delitem__(self,name):
jpayne@69 59 """Delete all occurrences of a header, if present.
jpayne@69 60
jpayne@69 61 Does *not* raise an exception if the header is missing.
jpayne@69 62 """
jpayne@69 63 name = self._convert_string_type(name.lower())
jpayne@69 64 self._headers[:] = [kv for kv in self._headers if kv[0].lower() != name]
jpayne@69 65
jpayne@69 66 def __getitem__(self,name):
jpayne@69 67 """Get the first header value for 'name'
jpayne@69 68
jpayne@69 69 Return None if the header is missing instead of raising an exception.
jpayne@69 70
jpayne@69 71 Note that if the header appeared multiple times, the first exactly which
jpayne@69 72 occurrence gets returned is undefined. Use getall() to get all
jpayne@69 73 the values matching a header field name.
jpayne@69 74 """
jpayne@69 75 return self.get(name)
jpayne@69 76
jpayne@69 77 def __contains__(self, name):
jpayne@69 78 """Return true if the message contains the header."""
jpayne@69 79 return self.get(name) is not None
jpayne@69 80
jpayne@69 81
jpayne@69 82 def get_all(self, name):
jpayne@69 83 """Return a list of all the values for the named field.
jpayne@69 84
jpayne@69 85 These will be sorted in the order they appeared in the original header
jpayne@69 86 list or were added to this instance, and may contain duplicates. Any
jpayne@69 87 fields deleted and re-inserted are always appended to the header list.
jpayne@69 88 If no fields exist with the given name, returns an empty list.
jpayne@69 89 """
jpayne@69 90 name = self._convert_string_type(name.lower())
jpayne@69 91 return [kv[1] for kv in self._headers if kv[0].lower()==name]
jpayne@69 92
jpayne@69 93
jpayne@69 94 def get(self,name,default=None):
jpayne@69 95 """Get the first header value for 'name', or return 'default'"""
jpayne@69 96 name = self._convert_string_type(name.lower())
jpayne@69 97 for k,v in self._headers:
jpayne@69 98 if k.lower()==name:
jpayne@69 99 return v
jpayne@69 100 return default
jpayne@69 101
jpayne@69 102
jpayne@69 103 def keys(self):
jpayne@69 104 """Return a list of all the header field names.
jpayne@69 105
jpayne@69 106 These will be sorted in the order they appeared in the original header
jpayne@69 107 list, or were added to this instance, and may contain duplicates.
jpayne@69 108 Any fields deleted and re-inserted are always appended to the header
jpayne@69 109 list.
jpayne@69 110 """
jpayne@69 111 return [k for k, v in self._headers]
jpayne@69 112
jpayne@69 113 def values(self):
jpayne@69 114 """Return a list of all header values.
jpayne@69 115
jpayne@69 116 These will be sorted in the order they appeared in the original header
jpayne@69 117 list, or were added to this instance, and may contain duplicates.
jpayne@69 118 Any fields deleted and re-inserted are always appended to the header
jpayne@69 119 list.
jpayne@69 120 """
jpayne@69 121 return [v for k, v in self._headers]
jpayne@69 122
jpayne@69 123 def items(self):
jpayne@69 124 """Get all the header fields and values.
jpayne@69 125
jpayne@69 126 These will be sorted in the order they were in the original header
jpayne@69 127 list, or were added to this instance, and may contain duplicates.
jpayne@69 128 Any fields deleted and re-inserted are always appended to the header
jpayne@69 129 list.
jpayne@69 130 """
jpayne@69 131 return self._headers[:]
jpayne@69 132
jpayne@69 133 def __repr__(self):
jpayne@69 134 return "%s(%r)" % (self.__class__.__name__, self._headers)
jpayne@69 135
jpayne@69 136 def __str__(self):
jpayne@69 137 """str() returns the formatted headers, complete with end line,
jpayne@69 138 suitable for direct HTTP transmission."""
jpayne@69 139 return '\r\n'.join(["%s: %s" % kv for kv in self._headers]+['',''])
jpayne@69 140
jpayne@69 141 def __bytes__(self):
jpayne@69 142 return str(self).encode('iso-8859-1')
jpayne@69 143
jpayne@69 144 def setdefault(self,name,value):
jpayne@69 145 """Return first matching header value for 'name', or 'value'
jpayne@69 146
jpayne@69 147 If there is no header named 'name', add a new header with name 'name'
jpayne@69 148 and value 'value'."""
jpayne@69 149 result = self.get(name)
jpayne@69 150 if result is None:
jpayne@69 151 self._headers.append((self._convert_string_type(name),
jpayne@69 152 self._convert_string_type(value)))
jpayne@69 153 return value
jpayne@69 154 else:
jpayne@69 155 return result
jpayne@69 156
jpayne@69 157 def add_header(self, _name, _value, **_params):
jpayne@69 158 """Extended header setting.
jpayne@69 159
jpayne@69 160 _name is the header field to add. keyword arguments can be used to set
jpayne@69 161 additional parameters for the header field, with underscores converted
jpayne@69 162 to dashes. Normally the parameter will be added as key="value" unless
jpayne@69 163 value is None, in which case only the key will be added.
jpayne@69 164
jpayne@69 165 Example:
jpayne@69 166
jpayne@69 167 h.add_header('content-disposition', 'attachment', filename='bud.gif')
jpayne@69 168
jpayne@69 169 Note that unlike the corresponding 'email.message' method, this does
jpayne@69 170 *not* handle '(charset, language, value)' tuples: all values must be
jpayne@69 171 strings or None.
jpayne@69 172 """
jpayne@69 173 parts = []
jpayne@69 174 if _value is not None:
jpayne@69 175 _value = self._convert_string_type(_value)
jpayne@69 176 parts.append(_value)
jpayne@69 177 for k, v in _params.items():
jpayne@69 178 k = self._convert_string_type(k)
jpayne@69 179 if v is None:
jpayne@69 180 parts.append(k.replace('_', '-'))
jpayne@69 181 else:
jpayne@69 182 v = self._convert_string_type(v)
jpayne@69 183 parts.append(_formatparam(k.replace('_', '-'), v))
jpayne@69 184 self._headers.append((self._convert_string_type(_name), "; ".join(parts)))