diff --git a/datasette/app.py b/datasette/app.py index 2907d90eaa..7abccc058a 100644 --- a/datasette/app.py +++ b/datasette/app.py @@ -1216,6 +1216,8 @@ async def handle_404(self, request, send, exception=None): # Try the same path but with "%" replaced by "-" # and "-" replaced with "-2D" new_path = request.path.replace("-", "-2D").replace("%", "-") + if request.query_string: + new_path += "?{}".format(request.query_string) await asgi_send_redirect(send, new_path) return # If URL has a trailing slash, redirect to URL without it diff --git a/tests/test_html.py b/tests/test_html.py index 3e24009eae..de70328469 100644 --- a/tests/test_html.py +++ b/tests/test_html.py @@ -954,7 +954,18 @@ def test_no_alternate_url_json(app_client, path): ) -def test_redirect_percent_encoding_to_dash_encoding(app_client): - response = app_client.get("/fivethirtyeight/twitter-ratio%2Fsenators") +@pytest.mark.parametrize( + "path,expected", + ( + ( + "/fivethirtyeight/twitter-ratio%2Fsenators", + "/fivethirtyeight/twitter-2Dratio-2Fsenators", + ), + # query string should be preserved + ("/foo/bar%2Fbaz?id=5", "/foo/bar-2Fbaz?id=5"), + ), +) +def test_redirect_percent_encoding_to_dash_encoding(app_client, path, expected): + response = app_client.get(path) assert response.status == 302 - assert response.headers["location"] == "/fivethirtyeight/twitter-2Dratio-2Fsenators" + assert response.headers["location"] == expected