| Index: third_party/google-endpoints/future/backports/email/policy.py
|
| diff --git a/third_party/google-endpoints/future/backports/email/policy.py b/third_party/google-endpoints/future/backports/email/policy.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..2f609a23aeb4e926a25ca7a2f3e42f7c785f7380
|
| --- /dev/null
|
| +++ b/third_party/google-endpoints/future/backports/email/policy.py
|
| @@ -0,0 +1,193 @@
|
| +"""This will be the home for the policy that hooks in the new
|
| +code that adds all the email6 features.
|
| +"""
|
| +from __future__ import unicode_literals
|
| +from __future__ import division
|
| +from __future__ import absolute_import
|
| +from future.builtins import super
|
| +
|
| +from future.standard_library.email._policybase import (Policy, Compat32,
|
| + compat32, _extend_docstrings)
|
| +from future.standard_library.email.utils import _has_surrogates
|
| +from future.standard_library.email.headerregistry import HeaderRegistry as HeaderRegistry
|
| +
|
| +__all__ = [
|
| + 'Compat32',
|
| + 'compat32',
|
| + 'Policy',
|
| + 'EmailPolicy',
|
| + 'default',
|
| + 'strict',
|
| + 'SMTP',
|
| + 'HTTP',
|
| + ]
|
| +
|
| +@_extend_docstrings
|
| +class EmailPolicy(Policy):
|
| +
|
| + """+
|
| + PROVISIONAL
|
| +
|
| + The API extensions enabled by this policy are currently provisional.
|
| + Refer to the documentation for details.
|
| +
|
| + This policy adds new header parsing and folding algorithms. Instead of
|
| + simple strings, headers are custom objects with custom attributes
|
| + depending on the type of the field. The folding algorithm fully
|
| + implements RFCs 2047 and 5322.
|
| +
|
| + In addition to the settable attributes listed above that apply to
|
| + all Policies, this policy adds the following additional attributes:
|
| +
|
| + refold_source -- if the value for a header in the Message object
|
| + came from the parsing of some source, this attribute
|
| + indicates whether or not a generator should refold
|
| + that value when transforming the message back into
|
| + stream form. The possible values are:
|
| +
|
| + none -- all source values use original folding
|
| + long -- source values that have any line that is
|
| + longer than max_line_length will be
|
| + refolded
|
| + all -- all values are refolded.
|
| +
|
| + The default is 'long'.
|
| +
|
| + header_factory -- a callable that takes two arguments, 'name' and
|
| + 'value', where 'name' is a header field name and
|
| + 'value' is an unfolded header field value, and
|
| + returns a string-like object that represents that
|
| + header. A default header_factory is provided that
|
| + understands some of the RFC5322 header field types.
|
| + (Currently address fields and date fields have
|
| + special treatment, while all other fields are
|
| + treated as unstructured. This list will be
|
| + completed before the extension is marked stable.)
|
| + """
|
| +
|
| + refold_source = 'long'
|
| + header_factory = HeaderRegistry()
|
| +
|
| + def __init__(self, **kw):
|
| + # Ensure that each new instance gets a unique header factory
|
| + # (as opposed to clones, which share the factory).
|
| + if 'header_factory' not in kw:
|
| + object.__setattr__(self, 'header_factory', HeaderRegistry())
|
| + super().__init__(**kw)
|
| +
|
| + def header_max_count(self, name):
|
| + """+
|
| + The implementation for this class returns the max_count attribute from
|
| + the specialized header class that would be used to construct a header
|
| + of type 'name'.
|
| + """
|
| + return self.header_factory[name].max_count
|
| +
|
| + # The logic of the next three methods is chosen such that it is possible to
|
| + # switch a Message object between a Compat32 policy and a policy derived
|
| + # from this class and have the results stay consistent. This allows a
|
| + # Message object constructed with this policy to be passed to a library
|
| + # that only handles Compat32 objects, or to receive such an object and
|
| + # convert it to use the newer style by just changing its policy. It is
|
| + # also chosen because it postpones the relatively expensive full rfc5322
|
| + # parse until as late as possible when parsing from source, since in many
|
| + # applications only a few headers will actually be inspected.
|
| +
|
| + def header_source_parse(self, sourcelines):
|
| + """+
|
| + The name is parsed as everything up to the ':' and returned unmodified.
|
| + The value is determined by stripping leading whitespace off the
|
| + remainder of the first line, joining all subsequent lines together, and
|
| + stripping any trailing carriage return or linefeed characters. (This
|
| + is the same as Compat32).
|
| +
|
| + """
|
| + name, value = sourcelines[0].split(':', 1)
|
| + value = value.lstrip(' \t') + ''.join(sourcelines[1:])
|
| + return (name, value.rstrip('\r\n'))
|
| +
|
| + def header_store_parse(self, name, value):
|
| + """+
|
| + The name is returned unchanged. If the input value has a 'name'
|
| + attribute and it matches the name ignoring case, the value is returned
|
| + unchanged. Otherwise the name and value are passed to header_factory
|
| + method, and the resulting custom header object is returned as the
|
| + value. In this case a ValueError is raised if the input value contains
|
| + CR or LF characters.
|
| +
|
| + """
|
| + if hasattr(value, 'name') and value.name.lower() == name.lower():
|
| + return (name, value)
|
| + if isinstance(value, str) and len(value.splitlines())>1:
|
| + raise ValueError("Header values may not contain linefeed "
|
| + "or carriage return characters")
|
| + return (name, self.header_factory(name, value))
|
| +
|
| + def header_fetch_parse(self, name, value):
|
| + """+
|
| + If the value has a 'name' attribute, it is returned to unmodified.
|
| + Otherwise the name and the value with any linesep characters removed
|
| + are passed to the header_factory method, and the resulting custom
|
| + header object is returned. Any surrogateescaped bytes get turned
|
| + into the unicode unknown-character glyph.
|
| +
|
| + """
|
| + if hasattr(value, 'name'):
|
| + return value
|
| + return self.header_factory(name, ''.join(value.splitlines()))
|
| +
|
| + def fold(self, name, value):
|
| + """+
|
| + Header folding is controlled by the refold_source policy setting. A
|
| + value is considered to be a 'source value' if and only if it does not
|
| + have a 'name' attribute (having a 'name' attribute means it is a header
|
| + object of some sort). If a source value needs to be refolded according
|
| + to the policy, it is converted into a custom header object by passing
|
| + the name and the value with any linesep characters removed to the
|
| + header_factory method. Folding of a custom header object is done by
|
| + calling its fold method with the current policy.
|
| +
|
| + Source values are split into lines using splitlines. If the value is
|
| + not to be refolded, the lines are rejoined using the linesep from the
|
| + policy and returned. The exception is lines containing non-ascii
|
| + binary data. In that case the value is refolded regardless of the
|
| + refold_source setting, which causes the binary data to be CTE encoded
|
| + using the unknown-8bit charset.
|
| +
|
| + """
|
| + return self._fold(name, value, refold_binary=True)
|
| +
|
| + def fold_binary(self, name, value):
|
| + """+
|
| + The same as fold if cte_type is 7bit, except that the returned value is
|
| + bytes.
|
| +
|
| + If cte_type is 8bit, non-ASCII binary data is converted back into
|
| + bytes. Headers with binary data are not refolded, regardless of the
|
| + refold_header setting, since there is no way to know whether the binary
|
| + data consists of single byte characters or multibyte characters.
|
| +
|
| + """
|
| + folded = self._fold(name, value, refold_binary=self.cte_type=='7bit')
|
| + return folded.encode('ascii', 'surrogateescape')
|
| +
|
| + def _fold(self, name, value, refold_binary=False):
|
| + if hasattr(value, 'name'):
|
| + return value.fold(policy=self)
|
| + maxlen = self.max_line_length if self.max_line_length else float('inf')
|
| + lines = value.splitlines()
|
| + refold = (self.refold_source == 'all' or
|
| + self.refold_source == 'long' and
|
| + (lines and len(lines[0])+len(name)+2 > maxlen or
|
| + any(len(x) > maxlen for x in lines[1:])))
|
| + if refold or refold_binary and _has_surrogates(value):
|
| + return self.header_factory(name, ''.join(lines)).fold(policy=self)
|
| + return name + ': ' + self.linesep.join(lines) + self.linesep
|
| +
|
| +
|
| +default = EmailPolicy()
|
| +# Make the default policy use the class default header_factory
|
| +del default.header_factory
|
| +strict = default.clone(raise_on_defect=True)
|
| +SMTP = default.clone(linesep='\r\n')
|
| +HTTP = default.clone(linesep='\r\n', max_line_length=None)
|
|
|