Return 400 for unknown ?_search* parameters (#2994)

SearchFilters collected every key starting with _search but resolved the column with split("_search_", 1)[1], so ?_searchfoo= raised IndexError and the table view answered 500. Accept only _search and _search_* and raise BadRequest for any other _search key, matching the Invalid _fts_table or _fts_pk and Cannot search by that column errors already in this function.
This commit is contained in:
fei 2026-10-10 22:37:16 +08:00
commit 4e2f9b3175
No known key found for this signature in database
2 changed files with 36 additions and 5 deletions

View file

@ -66,11 +66,12 @@ def search_filters(request, database, table, datasette):
requested_fts_pk and requested_fts_pk != fts_pk
):
raise BadRequest("Invalid _fts_table or _fts_pk")
search_args = {
key: request.args[key]
for key in request.args
if key.startswith("_search") and key != "_searchmode"
}
search_args = {}
for key in request.args:
if key == "_search" or key.startswith("_search_"):
search_args[key] = request.args[key]
elif key != "_searchmode" and key.startswith("_search"):
raise BadRequest(f"Invalid _search parameter: {key}")
search = ""
search_mode_raw = table_metadata.get("searchmode") == "raw"
# Or set search mode from the querystring

View file

@ -165,3 +165,33 @@ async def test_search_filters_from_request(ds_client):
assert filter_args.params == {"search": "bobcat"}
assert filter_args.human_descriptions == ['search matches "bobcat"']
assert filter_args.extra_context == {"supports_search": True, "search": "bobcat"}
@pytest.mark.asyncio
@pytest.mark.parametrize("key", ("_searchfoo", "_search2"))
async def test_search_invalid_parameter(ds_client, key):
# ?_searchfoo= used to crash with an IndexError from
# key.split("_search_", 1)[1] - it should return a 400 like every other
# invalid search parameter
response = await ds_client.get(f"/fixtures/searchable.json?{key}=bobcat")
assert response.status_code == 400
assert response.json() == {
"ok": False,
"error": f"Invalid _search parameter: {key}",
"errors": [f"Invalid _search parameter: {key}"],
"status": 400,
}
@pytest.mark.asyncio
async def test_search_valid_parameters_still_work(ds_client):
# The three documented search parameters keep working
response = await ds_client.get(
"/fixtures/searchable.json?_shape=arrays&_search=weasel&_searchmode=raw"
)
assert response.status_code == 200
assert response.json()["rows"] == [[2, "terry dog", "sara weasel", "puma"]]
response = await ds_client.get(
"/fixtures/searchable.json?_shape=arrays&_search_text2=dog"
)
assert response.status_code == 200