Skip to content

Commit

Permalink
New encode/decode_path_component functions
Browse files Browse the repository at this point in the history
ASGI cannot differentiate between / and %2F in a URL, so we need an
alternative scheme for encoding the names of tables that contain special
characters such as /

For background, see
    django/asgiref#51 (comment)

Some examples:

    "table/and/slashes" => "tableU+002FandU+002Fslashes"
    "~table" => "U+007Etable"
    "+bobcats!" => "U+002Bbobcats!"
    "U+007Etable" => "UU+002B007Etable"
  • Loading branch information
simonw committed May 9, 2019
1 parent bfa2ae0 commit 9fdb47c
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 0 deletions.
21 changes: 21 additions & 0 deletions datasette/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,27 @@ def escape_sqlite(s):
return "[{}]".format(s)


_decode_path_component_re = re.compile(r"U\+([\da-h]{4})", re.IGNORECASE)
_encode_path_component_re = re.compile(
"[{}]".format(
"".join(
re.escape(c)
for c in (";", "/", "?", ":", "@", "&", "=", "+", "$", ",", "~")
)
)
)


def decode_path_component(table_name):
return _decode_path_component_re.sub(lambda m: chr(int(m.group(1), 16)), table_name)


def encode_path_component(table_name):
return _encode_path_component_re.sub(
lambda m: "U+{0:0{1}x}".format(ord(m.group(0)), 4).upper(), table_name
)


def make_dockerfile(
files,
metadata_file,
Expand Down
16 changes: 16 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,3 +381,19 @@ def test_path_with_format(path, format, extra_qs, expected):
)
def test_format_bytes(bytes, expected):
assert expected == utils.format_bytes(bytes)


@pytest.mark.parametrize(
"name,expected",
[
("table", "table"),
("table/and/slashes", "tableU+002FandU+002Fslashes"),
("~table", "U+007Etable"),
("+bobcats!", "U+002Bbobcats!"),
("U+007Etable", "UU+002B007Etable"),
],
)
def test_encode_decode_path_component(name, expected):
encoded = utils.encode_path_component(name)
assert encoded == expected
assert name == utils.decode_path_component(encoded)

0 comments on commit 9fdb47c

Please sign in to comment.