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