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