| 115 | raise UnicodeEncodeError("idna", label, 0, len(label), "label too long") |
| 116 | |
| 117 | def ToUnicode(label): |
| 118 | if len(label) > 1024: |
| 119 | # Protection from https://github.com/python/cpython/issues/98433. |
| 120 | # https://datatracker.ietf.org/doc/html/rfc5894#section-6 |
| 121 | # doesn't specify a label size limit prior to NAMEPREP. But having |
| 122 | # one makes practical sense. |
| 123 | # This leaves ample room for nameprep() to remove Nothing characters |
| 124 | # per https://www.rfc-editor.org/rfc/rfc3454#section-3.1 while still |
| 125 | # preventing us from wasting time decoding a big thing that'll just |
| 126 | # hit the actual <= 63 length limit in Step 6. |
| 127 | if isinstance(label, str): |
| 128 | label = label.encode("utf-8", errors="backslashreplace") |
| 129 | raise UnicodeDecodeError("idna", label, 0, len(label), "label way too long") |
| 130 | # Step 1: Check for ASCII |
| 131 | if isinstance(label, bytes): |
| 132 | pure_ascii = True |
| 133 | else: |
| 134 | try: |
| 135 | label = label.encode("ascii") |
| 136 | pure_ascii = True |
| 137 | except UnicodeEncodeError: |
| 138 | pure_ascii = False |
| 139 | if not pure_ascii: |
| 140 | assert isinstance(label, str) |
| 141 | # Step 2: Perform nameprep |
| 142 | label = nameprep(label) |
| 143 | # It doesn't say this, but apparently, it should be ASCII now |
| 144 | try: |
| 145 | label = label.encode("ascii") |
| 146 | except UnicodeEncodeError as exc: |
| 147 | raise UnicodeEncodeError("idna", label, exc.start, exc.end, |
| 148 | "Invalid character in IDN label") |
| 149 | # Step 3: Check for ACE prefix |
| 150 | assert isinstance(label, bytes) |
| 151 | if not label.lower().startswith(ace_prefix): |
| 152 | return str(label, "ascii") |
| 153 | |
| 154 | # Step 4: Remove ACE prefix |
| 155 | label1 = label[len(ace_prefix):] |
| 156 | |
| 157 | # Step 5: Decode using PUNYCODE |
| 158 | try: |
| 159 | result = label1.decode("punycode") |
| 160 | except UnicodeDecodeError as exc: |
| 161 | offset = len(ace_prefix) |
| 162 | raise UnicodeDecodeError("idna", label, offset+exc.start, offset+exc.end, exc.reason) |
| 163 | |
| 164 | # Step 6: Apply ToASCII |
| 165 | label2 = ToASCII(result) |
| 166 | |
| 167 | # Step 7: Compare the result of step 6 with the one of step 3 |
| 168 | # label2 will already be in lower case. |
| 169 | if str(label, "ascii").lower() != str(label2, "ascii"): |
| 170 | raise UnicodeDecodeError("idna", label, 0, len(label), |
| 171 | f"IDNA does not round-trip, '{label!r}' != '{label2!r}'") |
| 172 | |
| 173 | # Step 8: return the result of step 5 |
| 174 | return result |