xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/email/policy.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker"""This will be the home for the policy that hooks in the new
2*cda5da8dSAndroid Build Coastguard Workercode that adds all the email6 features.
3*cda5da8dSAndroid Build Coastguard Worker"""
4*cda5da8dSAndroid Build Coastguard Worker
5*cda5da8dSAndroid Build Coastguard Workerimport re
6*cda5da8dSAndroid Build Coastguard Workerimport sys
7*cda5da8dSAndroid Build Coastguard Workerfrom email._policybase import Policy, Compat32, compat32, _extend_docstrings
8*cda5da8dSAndroid Build Coastguard Workerfrom email.utils import _has_surrogates
9*cda5da8dSAndroid Build Coastguard Workerfrom email.headerregistry import HeaderRegistry as HeaderRegistry
10*cda5da8dSAndroid Build Coastguard Workerfrom email.contentmanager import raw_data_manager
11*cda5da8dSAndroid Build Coastguard Workerfrom email.message import EmailMessage
12*cda5da8dSAndroid Build Coastguard Worker
13*cda5da8dSAndroid Build Coastguard Worker__all__ = [
14*cda5da8dSAndroid Build Coastguard Worker    'Compat32',
15*cda5da8dSAndroid Build Coastguard Worker    'compat32',
16*cda5da8dSAndroid Build Coastguard Worker    'Policy',
17*cda5da8dSAndroid Build Coastguard Worker    'EmailPolicy',
18*cda5da8dSAndroid Build Coastguard Worker    'default',
19*cda5da8dSAndroid Build Coastguard Worker    'strict',
20*cda5da8dSAndroid Build Coastguard Worker    'SMTP',
21*cda5da8dSAndroid Build Coastguard Worker    'HTTP',
22*cda5da8dSAndroid Build Coastguard Worker    ]
23*cda5da8dSAndroid Build Coastguard Worker
24*cda5da8dSAndroid Build Coastguard Workerlinesep_splitter = re.compile(r'\n|\r')
25*cda5da8dSAndroid Build Coastguard Worker
26*cda5da8dSAndroid Build Coastguard Worker@_extend_docstrings
27*cda5da8dSAndroid Build Coastguard Workerclass EmailPolicy(Policy):
28*cda5da8dSAndroid Build Coastguard Worker
29*cda5da8dSAndroid Build Coastguard Worker    """+
30*cda5da8dSAndroid Build Coastguard Worker    PROVISIONAL
31*cda5da8dSAndroid Build Coastguard Worker
32*cda5da8dSAndroid Build Coastguard Worker    The API extensions enabled by this policy are currently provisional.
33*cda5da8dSAndroid Build Coastguard Worker    Refer to the documentation for details.
34*cda5da8dSAndroid Build Coastguard Worker
35*cda5da8dSAndroid Build Coastguard Worker    This policy adds new header parsing and folding algorithms.  Instead of
36*cda5da8dSAndroid Build Coastguard Worker    simple strings, headers are custom objects with custom attributes
37*cda5da8dSAndroid Build Coastguard Worker    depending on the type of the field.  The folding algorithm fully
38*cda5da8dSAndroid Build Coastguard Worker    implements RFCs 2047 and 5322.
39*cda5da8dSAndroid Build Coastguard Worker
40*cda5da8dSAndroid Build Coastguard Worker    In addition to the settable attributes listed above that apply to
41*cda5da8dSAndroid Build Coastguard Worker    all Policies, this policy adds the following additional attributes:
42*cda5da8dSAndroid Build Coastguard Worker
43*cda5da8dSAndroid Build Coastguard Worker    utf8                -- if False (the default) message headers will be
44*cda5da8dSAndroid Build Coastguard Worker                           serialized as ASCII, using encoded words to encode
45*cda5da8dSAndroid Build Coastguard Worker                           any non-ASCII characters in the source strings.  If
46*cda5da8dSAndroid Build Coastguard Worker                           True, the message headers will be serialized using
47*cda5da8dSAndroid Build Coastguard Worker                           utf8 and will not contain encoded words (see RFC
48*cda5da8dSAndroid Build Coastguard Worker                           6532 for more on this serialization format).
49*cda5da8dSAndroid Build Coastguard Worker
50*cda5da8dSAndroid Build Coastguard Worker    refold_source       -- if the value for a header in the Message object
51*cda5da8dSAndroid Build Coastguard Worker                           came from the parsing of some source, this attribute
52*cda5da8dSAndroid Build Coastguard Worker                           indicates whether or not a generator should refold
53*cda5da8dSAndroid Build Coastguard Worker                           that value when transforming the message back into
54*cda5da8dSAndroid Build Coastguard Worker                           stream form.  The possible values are:
55*cda5da8dSAndroid Build Coastguard Worker
56*cda5da8dSAndroid Build Coastguard Worker                           none  -- all source values use original folding
57*cda5da8dSAndroid Build Coastguard Worker                           long  -- source values that have any line that is
58*cda5da8dSAndroid Build Coastguard Worker                                    longer than max_line_length will be
59*cda5da8dSAndroid Build Coastguard Worker                                    refolded
60*cda5da8dSAndroid Build Coastguard Worker                           all  -- all values are refolded.
61*cda5da8dSAndroid Build Coastguard Worker
62*cda5da8dSAndroid Build Coastguard Worker                           The default is 'long'.
63*cda5da8dSAndroid Build Coastguard Worker
64*cda5da8dSAndroid Build Coastguard Worker    header_factory      -- a callable that takes two arguments, 'name' and
65*cda5da8dSAndroid Build Coastguard Worker                           'value', where 'name' is a header field name and
66*cda5da8dSAndroid Build Coastguard Worker                           'value' is an unfolded header field value, and
67*cda5da8dSAndroid Build Coastguard Worker                           returns a string-like object that represents that
68*cda5da8dSAndroid Build Coastguard Worker                           header.  A default header_factory is provided that
69*cda5da8dSAndroid Build Coastguard Worker                           understands some of the RFC5322 header field types.
70*cda5da8dSAndroid Build Coastguard Worker                           (Currently address fields and date fields have
71*cda5da8dSAndroid Build Coastguard Worker                           special treatment, while all other fields are
72*cda5da8dSAndroid Build Coastguard Worker                           treated as unstructured.  This list will be
73*cda5da8dSAndroid Build Coastguard Worker                           completed before the extension is marked stable.)
74*cda5da8dSAndroid Build Coastguard Worker
75*cda5da8dSAndroid Build Coastguard Worker    content_manager     -- an object with at least two methods: get_content
76*cda5da8dSAndroid Build Coastguard Worker                           and set_content.  When the get_content or
77*cda5da8dSAndroid Build Coastguard Worker                           set_content method of a Message object is called,
78*cda5da8dSAndroid Build Coastguard Worker                           it calls the corresponding method of this object,
79*cda5da8dSAndroid Build Coastguard Worker                           passing it the message object as its first argument,
80*cda5da8dSAndroid Build Coastguard Worker                           and any arguments or keywords that were passed to
81*cda5da8dSAndroid Build Coastguard Worker                           it as additional arguments.  The default
82*cda5da8dSAndroid Build Coastguard Worker                           content_manager is
83*cda5da8dSAndroid Build Coastguard Worker                           :data:`~email.contentmanager.raw_data_manager`.
84*cda5da8dSAndroid Build Coastguard Worker
85*cda5da8dSAndroid Build Coastguard Worker    """
86*cda5da8dSAndroid Build Coastguard Worker
87*cda5da8dSAndroid Build Coastguard Worker    message_factory = EmailMessage
88*cda5da8dSAndroid Build Coastguard Worker    utf8 = False
89*cda5da8dSAndroid Build Coastguard Worker    refold_source = 'long'
90*cda5da8dSAndroid Build Coastguard Worker    header_factory = HeaderRegistry()
91*cda5da8dSAndroid Build Coastguard Worker    content_manager = raw_data_manager
92*cda5da8dSAndroid Build Coastguard Worker
93*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, **kw):
94*cda5da8dSAndroid Build Coastguard Worker        # Ensure that each new instance gets a unique header factory
95*cda5da8dSAndroid Build Coastguard Worker        # (as opposed to clones, which share the factory).
96*cda5da8dSAndroid Build Coastguard Worker        if 'header_factory' not in kw:
97*cda5da8dSAndroid Build Coastguard Worker            object.__setattr__(self, 'header_factory', HeaderRegistry())
98*cda5da8dSAndroid Build Coastguard Worker        super().__init__(**kw)
99*cda5da8dSAndroid Build Coastguard Worker
100*cda5da8dSAndroid Build Coastguard Worker    def header_max_count(self, name):
101*cda5da8dSAndroid Build Coastguard Worker        """+
102*cda5da8dSAndroid Build Coastguard Worker        The implementation for this class returns the max_count attribute from
103*cda5da8dSAndroid Build Coastguard Worker        the specialized header class that would be used to construct a header
104*cda5da8dSAndroid Build Coastguard Worker        of type 'name'.
105*cda5da8dSAndroid Build Coastguard Worker        """
106*cda5da8dSAndroid Build Coastguard Worker        return self.header_factory[name].max_count
107*cda5da8dSAndroid Build Coastguard Worker
108*cda5da8dSAndroid Build Coastguard Worker    # The logic of the next three methods is chosen such that it is possible to
109*cda5da8dSAndroid Build Coastguard Worker    # switch a Message object between a Compat32 policy and a policy derived
110*cda5da8dSAndroid Build Coastguard Worker    # from this class and have the results stay consistent.  This allows a
111*cda5da8dSAndroid Build Coastguard Worker    # Message object constructed with this policy to be passed to a library
112*cda5da8dSAndroid Build Coastguard Worker    # that only handles Compat32 objects, or to receive such an object and
113*cda5da8dSAndroid Build Coastguard Worker    # convert it to use the newer style by just changing its policy.  It is
114*cda5da8dSAndroid Build Coastguard Worker    # also chosen because it postpones the relatively expensive full rfc5322
115*cda5da8dSAndroid Build Coastguard Worker    # parse until as late as possible when parsing from source, since in many
116*cda5da8dSAndroid Build Coastguard Worker    # applications only a few headers will actually be inspected.
117*cda5da8dSAndroid Build Coastguard Worker
118*cda5da8dSAndroid Build Coastguard Worker    def header_source_parse(self, sourcelines):
119*cda5da8dSAndroid Build Coastguard Worker        """+
120*cda5da8dSAndroid Build Coastguard Worker        The name is parsed as everything up to the ':' and returned unmodified.
121*cda5da8dSAndroid Build Coastguard Worker        The value is determined by stripping leading whitespace off the
122*cda5da8dSAndroid Build Coastguard Worker        remainder of the first line, joining all subsequent lines together, and
123*cda5da8dSAndroid Build Coastguard Worker        stripping any trailing carriage return or linefeed characters.  (This
124*cda5da8dSAndroid Build Coastguard Worker        is the same as Compat32).
125*cda5da8dSAndroid Build Coastguard Worker
126*cda5da8dSAndroid Build Coastguard Worker        """
127*cda5da8dSAndroid Build Coastguard Worker        name, value = sourcelines[0].split(':', 1)
128*cda5da8dSAndroid Build Coastguard Worker        value = value.lstrip(' \t') + ''.join(sourcelines[1:])
129*cda5da8dSAndroid Build Coastguard Worker        return (name, value.rstrip('\r\n'))
130*cda5da8dSAndroid Build Coastguard Worker
131*cda5da8dSAndroid Build Coastguard Worker    def header_store_parse(self, name, value):
132*cda5da8dSAndroid Build Coastguard Worker        """+
133*cda5da8dSAndroid Build Coastguard Worker        The name is returned unchanged.  If the input value has a 'name'
134*cda5da8dSAndroid Build Coastguard Worker        attribute and it matches the name ignoring case, the value is returned
135*cda5da8dSAndroid Build Coastguard Worker        unchanged.  Otherwise the name and value are passed to header_factory
136*cda5da8dSAndroid Build Coastguard Worker        method, and the resulting custom header object is returned as the
137*cda5da8dSAndroid Build Coastguard Worker        value.  In this case a ValueError is raised if the input value contains
138*cda5da8dSAndroid Build Coastguard Worker        CR or LF characters.
139*cda5da8dSAndroid Build Coastguard Worker
140*cda5da8dSAndroid Build Coastguard Worker        """
141*cda5da8dSAndroid Build Coastguard Worker        if hasattr(value, 'name') and value.name.lower() == name.lower():
142*cda5da8dSAndroid Build Coastguard Worker            return (name, value)
143*cda5da8dSAndroid Build Coastguard Worker        if isinstance(value, str) and len(value.splitlines())>1:
144*cda5da8dSAndroid Build Coastguard Worker            # XXX this error message isn't quite right when we use splitlines
145*cda5da8dSAndroid Build Coastguard Worker            # (see issue 22233), but I'm not sure what should happen here.
146*cda5da8dSAndroid Build Coastguard Worker            raise ValueError("Header values may not contain linefeed "
147*cda5da8dSAndroid Build Coastguard Worker                             "or carriage return characters")
148*cda5da8dSAndroid Build Coastguard Worker        return (name, self.header_factory(name, value))
149*cda5da8dSAndroid Build Coastguard Worker
150*cda5da8dSAndroid Build Coastguard Worker    def header_fetch_parse(self, name, value):
151*cda5da8dSAndroid Build Coastguard Worker        """+
152*cda5da8dSAndroid Build Coastguard Worker        If the value has a 'name' attribute, it is returned to unmodified.
153*cda5da8dSAndroid Build Coastguard Worker        Otherwise the name and the value with any linesep characters removed
154*cda5da8dSAndroid Build Coastguard Worker        are passed to the header_factory method, and the resulting custom
155*cda5da8dSAndroid Build Coastguard Worker        header object is returned.  Any surrogateescaped bytes get turned
156*cda5da8dSAndroid Build Coastguard Worker        into the unicode unknown-character glyph.
157*cda5da8dSAndroid Build Coastguard Worker
158*cda5da8dSAndroid Build Coastguard Worker        """
159*cda5da8dSAndroid Build Coastguard Worker        if hasattr(value, 'name'):
160*cda5da8dSAndroid Build Coastguard Worker            return value
161*cda5da8dSAndroid Build Coastguard Worker        # We can't use splitlines here because it splits on more than \r and \n.
162*cda5da8dSAndroid Build Coastguard Worker        value = ''.join(linesep_splitter.split(value))
163*cda5da8dSAndroid Build Coastguard Worker        return self.header_factory(name, value)
164*cda5da8dSAndroid Build Coastguard Worker
165*cda5da8dSAndroid Build Coastguard Worker    def fold(self, name, value):
166*cda5da8dSAndroid Build Coastguard Worker        """+
167*cda5da8dSAndroid Build Coastguard Worker        Header folding is controlled by the refold_source policy setting.  A
168*cda5da8dSAndroid Build Coastguard Worker        value is considered to be a 'source value' if and only if it does not
169*cda5da8dSAndroid Build Coastguard Worker        have a 'name' attribute (having a 'name' attribute means it is a header
170*cda5da8dSAndroid Build Coastguard Worker        object of some sort).  If a source value needs to be refolded according
171*cda5da8dSAndroid Build Coastguard Worker        to the policy, it is converted into a custom header object by passing
172*cda5da8dSAndroid Build Coastguard Worker        the name and the value with any linesep characters removed to the
173*cda5da8dSAndroid Build Coastguard Worker        header_factory method.  Folding of a custom header object is done by
174*cda5da8dSAndroid Build Coastguard Worker        calling its fold method with the current policy.
175*cda5da8dSAndroid Build Coastguard Worker
176*cda5da8dSAndroid Build Coastguard Worker        Source values are split into lines using splitlines.  If the value is
177*cda5da8dSAndroid Build Coastguard Worker        not to be refolded, the lines are rejoined using the linesep from the
178*cda5da8dSAndroid Build Coastguard Worker        policy and returned.  The exception is lines containing non-ascii
179*cda5da8dSAndroid Build Coastguard Worker        binary data.  In that case the value is refolded regardless of the
180*cda5da8dSAndroid Build Coastguard Worker        refold_source setting, which causes the binary data to be CTE encoded
181*cda5da8dSAndroid Build Coastguard Worker        using the unknown-8bit charset.
182*cda5da8dSAndroid Build Coastguard Worker
183*cda5da8dSAndroid Build Coastguard Worker        """
184*cda5da8dSAndroid Build Coastguard Worker        return self._fold(name, value, refold_binary=True)
185*cda5da8dSAndroid Build Coastguard Worker
186*cda5da8dSAndroid Build Coastguard Worker    def fold_binary(self, name, value):
187*cda5da8dSAndroid Build Coastguard Worker        """+
188*cda5da8dSAndroid Build Coastguard Worker        The same as fold if cte_type is 7bit, except that the returned value is
189*cda5da8dSAndroid Build Coastguard Worker        bytes.
190*cda5da8dSAndroid Build Coastguard Worker
191*cda5da8dSAndroid Build Coastguard Worker        If cte_type is 8bit, non-ASCII binary data is converted back into
192*cda5da8dSAndroid Build Coastguard Worker        bytes.  Headers with binary data are not refolded, regardless of the
193*cda5da8dSAndroid Build Coastguard Worker        refold_header setting, since there is no way to know whether the binary
194*cda5da8dSAndroid Build Coastguard Worker        data consists of single byte characters or multibyte characters.
195*cda5da8dSAndroid Build Coastguard Worker
196*cda5da8dSAndroid Build Coastguard Worker        If utf8 is true, headers are encoded to utf8, otherwise to ascii with
197*cda5da8dSAndroid Build Coastguard Worker        non-ASCII unicode rendered as encoded words.
198*cda5da8dSAndroid Build Coastguard Worker
199*cda5da8dSAndroid Build Coastguard Worker        """
200*cda5da8dSAndroid Build Coastguard Worker        folded = self._fold(name, value, refold_binary=self.cte_type=='7bit')
201*cda5da8dSAndroid Build Coastguard Worker        charset = 'utf8' if self.utf8 else 'ascii'
202*cda5da8dSAndroid Build Coastguard Worker        return folded.encode(charset, 'surrogateescape')
203*cda5da8dSAndroid Build Coastguard Worker
204*cda5da8dSAndroid Build Coastguard Worker    def _fold(self, name, value, refold_binary=False):
205*cda5da8dSAndroid Build Coastguard Worker        if hasattr(value, 'name'):
206*cda5da8dSAndroid Build Coastguard Worker            return value.fold(policy=self)
207*cda5da8dSAndroid Build Coastguard Worker        maxlen = self.max_line_length if self.max_line_length else sys.maxsize
208*cda5da8dSAndroid Build Coastguard Worker        lines = value.splitlines()
209*cda5da8dSAndroid Build Coastguard Worker        refold = (self.refold_source == 'all' or
210*cda5da8dSAndroid Build Coastguard Worker                  self.refold_source == 'long' and
211*cda5da8dSAndroid Build Coastguard Worker                    (lines and len(lines[0])+len(name)+2 > maxlen or
212*cda5da8dSAndroid Build Coastguard Worker                     any(len(x) > maxlen for x in lines[1:])))
213*cda5da8dSAndroid Build Coastguard Worker        if refold or refold_binary and _has_surrogates(value):
214*cda5da8dSAndroid Build Coastguard Worker            return self.header_factory(name, ''.join(lines)).fold(policy=self)
215*cda5da8dSAndroid Build Coastguard Worker        return name + ': ' + self.linesep.join(lines) + self.linesep
216*cda5da8dSAndroid Build Coastguard Worker
217*cda5da8dSAndroid Build Coastguard Worker
218*cda5da8dSAndroid Build Coastguard Workerdefault = EmailPolicy()
219*cda5da8dSAndroid Build Coastguard Worker# Make the default policy use the class default header_factory
220*cda5da8dSAndroid Build Coastguard Workerdel default.header_factory
221*cda5da8dSAndroid Build Coastguard Workerstrict = default.clone(raise_on_defect=True)
222*cda5da8dSAndroid Build Coastguard WorkerSMTP = default.clone(linesep='\r\n')
223*cda5da8dSAndroid Build Coastguard WorkerHTTP = default.clone(linesep='\r\n', max_line_length=None)
224*cda5da8dSAndroid Build Coastguard WorkerSMTPUTF8 = SMTP.clone(utf8=True)
225