Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions Lib/encodings/idna.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,14 +234,16 @@ def decode(self, input, errors='strict'):
if errors != 'strict':
raise UnicodeError(f"Unsupported error handling: {errors}")

if not isinstance(input, bytes):
try:
input = bytes(memoryview(input))
except TypeError:
raise TypeError("a bytes-like object is required, not "
f"'{type(input).__name__}'") from None

if not input:
return "", 0

# IDNA allows decoding to operate on Unicode strings, too.
if not isinstance(input, bytes):
# XXX obviously wrong, see #3232
input = bytes(input)

if ace_prefix not in input.lower():
# Fast path
try:
Expand Down
20 changes: 20 additions & 0 deletions Lib/test/test_codecs.py
Original file line number Diff line number Diff line change
Expand Up @@ -1688,6 +1688,26 @@ def test_builtin_decode_invalid(self):
self.assertEqual(exc.start, expected.start, msg=f'reason: {exc.reason}')
self.assertEqual(exc.end, expected.end)

def test_decode_bytes_like(self):
# Bytes-like objects other than bytes are still accepted.
for case in (bytearray(b"xn--pythn-mua.org"),
memoryview(b"xn--pythn-mua.org")):
with self.subTest(case=case):
self.assertEqual(codecs.decode(case, "idna"), "pyth\xf6n.org")

def test_decode_invalid_type(self):
# The decoder used to call bytes(input) on any non-bytes input, which
# silently produced nonsense for objects bytes() happens to accept:
# decoding 5 returned '\x00\x00\x00\x00\x00' and [65, 66] returned 'AB'.
for case in ("python.org", "", 5, 0, [65, 66], (67,), None, 3.5, {}):
with self.subTest(case=case):
with self.assertRaises(TypeError) as cm:
codecs.decode(case, "idna")
self.assertEqual(
str(cm.exception),
"a bytes-like object is required, "
f"not '{type(case).__name__}'")

def test_builtin_encode(self):
self.assertEqual("python.org".encode("idna"), b"python.org")
self.assertEqual("python.org.".encode("idna"), b"python.org.")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
The ``idna`` codec now raises :exc:`TypeError` when asked to decode an object
that is not bytes-like, instead of silently coercing it with ``bytes()``.
Previously ``codecs.decode(5, "idna")`` returned ``'\x00\x00\x00\x00\x00'``
and ``codecs.decode([65, 66], "idna")`` returned ``'AB'``. Bytes-like objects
such as :class:`bytearray` and :class:`memoryview` are still accepted.
Loading