Fold TokenList 'part' into the 'lines' list as mime parameters. Using the decoded list of parameters and values, format them according to the RFC rules, including using RFC2231 encoding if the value cannot be expressed in 'encoding' and/or the parameter+value is too long to fit with
(part, lines, maxlen, encoding)
| 3075 | return new_last_ew if ew_combine_allowed else None |
| 3076 | |
| 3077 | def _fold_mime_parameters(part, lines, maxlen, encoding): |
| 3078 | """Fold TokenList 'part' into the 'lines' list as mime parameters. |
| 3079 | |
| 3080 | Using the decoded list of parameters and values, format them according to |
| 3081 | the RFC rules, including using RFC2231 encoding if the value cannot be |
| 3082 | expressed in 'encoding' and/or the parameter+value is too long to fit |
| 3083 | within 'maxlen'. |
| 3084 | |
| 3085 | """ |
| 3086 | # Special case for RFC2231 encoding: start from decoded values and use |
| 3087 | # RFC2231 encoding iff needed. |
| 3088 | # |
| 3089 | # Note that the 1 and 2s being added to the length calculations are |
| 3090 | # accounting for the possibly-needed spaces and semicolons we'll be adding. |
| 3091 | # |
| 3092 | for name, value in part.params: |
| 3093 | # XXX What if this ';' puts us over maxlen the first time through the |
| 3094 | # loop? We should split the header value onto a newline in that case, |
| 3095 | # but to do that we need to recognize the need earlier or reparse the |
| 3096 | # header, so I'm going to ignore that bug for now. It'll only put us |
| 3097 | # one character over. |
| 3098 | if not lines[-1].rstrip().endswith(';'): |
| 3099 | lines[-1] += ';' |
| 3100 | charset = encoding |
| 3101 | error_handler = 'strict' |
| 3102 | try: |
| 3103 | value.encode(encoding) |
| 3104 | encoding_required = False |
| 3105 | except UnicodeEncodeError: |
| 3106 | encoding_required = True |
| 3107 | if utils._has_surrogates(value): |
| 3108 | charset = 'unknown-8bit' |
| 3109 | error_handler = 'surrogateescape' |
| 3110 | else: |
| 3111 | charset = 'utf-8' |
| 3112 | if encoding_required: |
| 3113 | encoded_value = urllib.parse.quote( |
| 3114 | value, safe='', errors=error_handler) |
| 3115 | tstr = "{}*={}''{}".format(name, charset, encoded_value) |
| 3116 | else: |
| 3117 | tstr = '{}={}'.format(name, quote_string(value)) |
| 3118 | if len(lines[-1]) + len(tstr) + 1 < maxlen: |
| 3119 | lines[-1] = lines[-1] + ' ' + tstr |
| 3120 | continue |
| 3121 | elif len(tstr) + 2 <= maxlen: |
| 3122 | lines.append(' ' + tstr) |
| 3123 | continue |
| 3124 | # We need multiple sections. We are allowed to mix encoded and |
| 3125 | # non-encoded sections, but we aren't going to. We'll encode them all. |
| 3126 | section = 0 |
| 3127 | extra_chrome = charset + "''" |
| 3128 | while value: |
| 3129 | chrome_len = len(name) + len(str(section)) + 3 + len(extra_chrome) |
| 3130 | if maxlen <= chrome_len + 3: |
| 3131 | # We need room for the leading blank, the trailing semicolon, |
| 3132 | # and at least one character of the value. If we don't |
| 3133 | # have that, we'd be stuck, so in that case fall back to |
| 3134 | # the RFC standard width. |
no test coverage detected
searching dependent graphs…