| 748 | |
| 749 | @property |
| 750 | def params(self): |
| 751 | # The RFC specifically states that the ordering of parameters is not |
| 752 | # guaranteed and may be reordered by the transport layer. So we have |
| 753 | # to assume the RFC 2231 pieces can come in any order. However, we |
| 754 | # output them in the order that we first see a given name, which gives |
| 755 | # us a stable __str__. |
| 756 | params = {} # Using order preserving dict from Python 3.7+ |
| 757 | for token in self: |
| 758 | if not token.token_type.endswith('parameter'): |
| 759 | continue |
| 760 | if token[0].token_type != 'attribute': |
| 761 | continue |
| 762 | name = token[0].value.strip() |
| 763 | if name not in params: |
| 764 | params[name] = [] |
| 765 | params[name].append((token.section_number, token)) |
| 766 | for name, parts in params.items(): |
| 767 | parts = sorted(parts, key=itemgetter(0)) |
| 768 | first_param = parts[0][1] |
| 769 | charset = first_param.charset |
| 770 | # Our arbitrary error recovery is to ignore duplicate parameters, |
| 771 | # to use appearance order if there are duplicate rfc 2231 parts, |
| 772 | # and to ignore gaps. This mimics the error recovery of get_param. |
| 773 | if not first_param.extended and len(parts) > 1: |
| 774 | if parts[1][0] == 0: |
| 775 | parts[1][1].defects.append(errors.InvalidHeaderDefect( |
| 776 | 'duplicate parameter name; duplicate(s) ignored')) |
| 777 | parts = parts[:1] |
| 778 | # Else assume the *0* was missing...note that this is different |
| 779 | # from get_param, but we registered a defect for this earlier. |
| 780 | value_parts = [] |
| 781 | i = 0 |
| 782 | for section_number, param in parts: |
| 783 | if section_number != i: |
| 784 | # We could get fancier here and look for a complete |
| 785 | # duplicate extended parameter and ignore the second one |
| 786 | # seen. But we're not doing that. The old code didn't. |
| 787 | if not param.extended: |
| 788 | param.defects.append(errors.InvalidHeaderDefect( |
| 789 | 'duplicate parameter name; duplicate ignored')) |
| 790 | continue |
| 791 | else: |
| 792 | param.defects.append(errors.InvalidHeaderDefect( |
| 793 | "inconsistent RFC2231 parameter numbering")) |
| 794 | i += 1 |
| 795 | value = param.param_value |
| 796 | if param.extended: |
| 797 | try: |
| 798 | value = urllib.parse.unquote_to_bytes(value) |
| 799 | except UnicodeEncodeError: |
| 800 | # source had surrogate escaped bytes. What we do now |
| 801 | # is a bit of an open question. I'm not sure this is |
| 802 | # the best choice, but it is what the old algorithm did |
| 803 | value = urllib.parse.unquote(value, encoding='latin-1') |
| 804 | else: |
| 805 | try: |
| 806 | # Explicitly look up the codec for warning generation, see gh-140030 |
| 807 | # Can be removed in 3.17 |