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