Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow non-ascii keys #240

Merged
merged 9 commits into from
Jan 16, 2022
Merged
Show file tree
Hide file tree
Changes from 8 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
13 changes: 7 additions & 6 deletions aiomcache/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,22 @@ def __init__(self, host: str, port: int = 11211, *,
self._pool = MemcachePool(
host, port, minsize=pool_minsize, maxsize=pool_size)

# key supports ascii sans space and control chars
# \x21 is !, right after space, and \x7e is -, right before DEL
# also 1 <= len <= 250 as per the spec
_valid_key_re = re.compile(b'^[\x21-\x7e]{1,250}$')
# key may be anything except whitespace and control chars, upto 250 characters.
# Must be str for unicode-aware regex.
_valid_key_re = re.compile("^[^\\s\x00-\x1F\x7F-\x9F]{1,250}$")

def _validate_key(self, key: bytes) -> bytes:
if not isinstance(key, bytes): # avoid bugs subtle and otherwise
raise ValidationException('key must be bytes', key)

m = self._valid_key_re.match(key)
# Must decode to str for unicode-aware comparison.
key_str = key.decode()
m = self._valid_key_re.match(key_str)
if m:
# in python re, $ matches either end of line or right before
# \n at end of line. We can't allow latter case, so
# making sure length matches is simplest way to detect
if len(m.group(0)) != len(key):
if len(m.group(0)) != len(key_str):
raise ValidationException('trailing newline', key)
else:
raise ValidationException('invalid key', key)
Expand Down
36 changes: 36 additions & 0 deletions tests/commands_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,42 @@
from aiomcache.exceptions import ClientException, ValidationException


@pytest.mark.parametrize("key", (
b"key",
b"123",
bytes("!@#", "utf-8"),
bytes("中文", "utf-8"),
bytes("こんにちは", "utf-8"),
bytes("안녕하세요", "utf-8"),
))
@pytest.mark.asyncio
async def test_valid_key(mcache, key):
assert mcache._validate_key(key) == key


@pytest.mark.parametrize("key", (
# Whitespace
b"foo bar",
b"foo\t",
b"\nbar",
b"foo\x20\x0Dbar",
b"\x18\x0E",
b"\x20\x60",
b"\x30\x00",
b"\x20\x01",
# Control characters
b"foo\x00bar",
b"\x1F",
b"\x7F",
"\u0080".encode(),
"\u009F".encode(),
))
@pytest.mark.asyncio
async def test_invalid_key(mcache, key):
with pytest.raises(ValidationException):
mcache._validate_key(key)


@pytest.mark.asyncio
async def test_version(mcache):
version = await mcache.version()
Expand Down