From af18c59623ca949792c79e5b22a151bae5eb947f Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Mon, 24 Feb 2025 10:40:11 -0500 Subject: [PATCH 1/3] work around parse_qs behavior in python < 3.11 --- www/lib/kojiweb/util.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/www/lib/kojiweb/util.py b/www/lib/kojiweb/util.py index 7aa03665..bf099f5f 100644 --- a/www/lib/kojiweb/util.py +++ b/www/lib/kojiweb/util.py @@ -211,6 +211,12 @@ class FieldStorageCompat(Mapping): """Emulate the parts of cgi.FieldStorage that we need""" def __init__(self, environ): + qs = environ.get('QUERY_STRING', '') + if not qs: + # for python < 3.11, parse_qs will error on a blank string + self.data = {} + return + data = parse_qs(environ.get('QUERY_STRING', ''), strict_parsing=True, keep_blank_values=True) # replace singleton lists with single values From abf33cea63b489b9ad6341c96ba55253428a4b8b Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Mon, 24 Feb 2025 12:16:29 -0500 Subject: [PATCH 2/3] unit test --- tests/test_www/loadwebindex.py | 2 +- tests/test_www/test_search.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/test_www/loadwebindex.py b/tests/test_www/loadwebindex.py index 7cf4d397..aad27210 100644 --- a/tests/test_www/loadwebindex.py +++ b/tests/test_www/loadwebindex.py @@ -17,4 +17,4 @@ if importlib: sys.modules[INDEX_MOD] = webidx spec.loader.exec_module(webidx) else: - cli = imp.load_source(INDEX_MOD, INDEX_FILENAME) + webidx = imp.load_source(INDEX_MOD, INDEX_FILENAME) diff --git a/tests/test_www/test_search.py b/tests/test_www/test_search.py index 3effb550..7a2d3008 100644 --- a/tests/test_www/test_search.py +++ b/tests/test_www/test_search.py @@ -19,6 +19,7 @@ class TestSearch(unittest.TestCase): } urlencode_data = "terms=test&type=package&match=testmatch" self.fs = FieldStorageCompat({'QUERY_STRING': urlencode_data}) + self.gen_html = mock.patch.object(webidx, '_genHTML').start() def __get_server(env): env['koji.form'] = self.fs @@ -29,6 +30,18 @@ class TestSearch(unittest.TestCase): def tearDown(self): mock.patch.stopall() + def test_no_args(self): + self.fs = FieldStorageCompat({'QUERY_STRING': ''}) + + webidx.search(self.environ) + + self.gen_html.assert_called_once() + # extract values + # called as _genHTML(environ, 'search.chtml') + args = self.gen_html.call_args_list[0][0] # no kwargs passed here + environ = args[0] + self.assertEqual(environ['koji.values']['terms'], '') + def test_search_exception_match(self): """Test taskinfo function raises exception""" self.server.getBuildTarget.return_info = None @@ -37,3 +50,7 @@ class TestSearch(unittest.TestCase): with self.assertRaises(koji.GenericError) as cm: webidx.search(self.environ) self.assertEqual(str(cm.exception), "No such match type: 'testmatch'") + self.gen_html.assert_not_called() + + +# the end From 28b9ef7c64cdc91989a962a06836601a08c4a302 Mon Sep 17 00:00:00 2001 From: Mike McLean Date: Tue, 25 Feb 2025 11:10:45 -0500 Subject: [PATCH 3/3] avoid duplicate environ.get call --- www/lib/kojiweb/util.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/www/lib/kojiweb/util.py b/www/lib/kojiweb/util.py index bf099f5f..fe68e503 100644 --- a/www/lib/kojiweb/util.py +++ b/www/lib/kojiweb/util.py @@ -217,8 +217,7 @@ class FieldStorageCompat(Mapping): self.data = {} return - data = parse_qs(environ.get('QUERY_STRING', ''), strict_parsing=True, - keep_blank_values=True) + data = parse_qs(qs, strict_parsing=True, keep_blank_values=True) # replace singleton lists with single values for arg in data: val = data[arg]