From a45286cd7ce49df20964dc6672fa30966393dab1 Mon Sep 17 00:00:00 2001 From: Bo Bayles Date: Thu, 9 Apr 2026 15:19:00 -0500 Subject: [PATCH 1/4] Use ffi.buffer to better handle nulls --- ada_url/ada_adapter.py | 3 +-- tests/test_ada_url.py | 7 +++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ada_url/ada_adapter.py b/ada_url/ada_adapter.py index 0d62059..6f65815 100644 --- a/ada_url/ada_adapter.py +++ b/ada_url/ada_adapter.py @@ -116,8 +116,7 @@ def _get_obj(constructor, destructor, *args): def _get_str(x): - ret = ffi.string(x.data, x.length).decode() if x.length else '' - return ret + return bytes(ffi.buffer(x.data, x.length)).decode() if x.length else '' class URL: diff --git a/tests/test_ada_url.py b/tests/test_ada_url.py index ce82a97..081c7a9 100644 --- a/tests/test_ada_url.py +++ b/tests/test_ada_url.py @@ -531,6 +531,13 @@ def test_replace_search_params(self): expected = 'key2=value3&key1=value4&key1=value5' self.assertEqual(actual, expected) + def test_null_handling(self): + evil_input = 'admin\x00hidden=true&safe=value' + params = SearchParams(evil_input) + actual = list(params.keys()) + expected = ['admin\x00hidden', 'safe'] + self.assertEqual(actual, expected) + class ParseTests(TestCase): def test_url_suite(self): From c5cd794cc92edbf6d9101cbf164ba187d6c50457 Mon Sep 17 00:00:00 2001 From: Bo Bayles Date: Thu, 9 Apr 2026 15:19:43 -0500 Subject: [PATCH 2/4] Call destructor in __deepcopy__ --- ada_url/ada_adapter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ada_url/ada_adapter.py b/ada_url/ada_adapter.py index 6f65815..f63602c 100644 --- a/ada_url/ada_adapter.py +++ b/ada_url/ada_adapter.py @@ -216,7 +216,7 @@ def __deepcopy__(self, memo): cls = self.__class__ ret = cls.__new__(cls) super(URL, ret).__init__() - ret.urlobj = lib.ada_copy(self.urlobj) + ret.urlobj = _get_obj(lib.ada_copy, lib.ada_free, self.urlobj) return ret From c52111f32a1ca84cc3b1540d028d184a662e8bd2 Mon Sep 17 00:00:00 2001 From: Bo Bayles Date: Thu, 9 Apr 2026 15:20:47 -0500 Subject: [PATCH 3/4] Call ada_free_strings in URLSearchParams.get_all --- ada_url/ada_adapter.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ada_url/ada_adapter.py b/ada_url/ada_adapter.py index f63602c..6fd544d 100644 --- a/ada_url/ada_adapter.py +++ b/ada_url/ada_adapter.py @@ -395,14 +395,16 @@ def get(self, key: str) -> str: return _get_str(item) def get_all(self, key: str) -> List[str]: + ret = [] key_bytes = key.encode() items = lib.ada_search_params_get_all(self.paramsobj, key_bytes, len(key_bytes)) - count = lib.ada_strings_size(items) - - ret = [] - for i in range(count): - value = _get_str(lib.ada_strings_get(items, i)) - ret.append(value) + try: + count = lib.ada_strings_size(items) + for i in range(count): + value = _get_str(lib.ada_strings_get(items, i)) + ret.append(value) + finally: + lib.ada_free_strings(items) return ret From 1bac023ed6d6b224deda8170a5c49973f7fbe38a Mon Sep 17 00:00:00 2001 From: Bo Bayles Date: Thu, 9 Apr 2026 15:21:42 -0500 Subject: [PATCH 4/4] Bump version to 1.32.0 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 02d9b0f..8c55a31 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "ada-url" -version = "1.31.0" +version = "1.32.0" authors = [ {name = "Bo Bayles", email = "bo@bbayles.com"}, ]