Browse Source

[fix] JSON & CSV format return error 500

For CSV and JSON output, the LegacyResult and the Result objects needs to be
converted to a python dictionary.

Closes: https://github.com/searxng/searxng/issues/4244
Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
Markus Heiser 3 months ago
parent
commit
df3344e5d5
2 changed files with 15 additions and 10 deletions
  1. 6 1
      searx/result_types/_base.py
  2. 9 9
      searx/webutils.py

+ 6 - 1
searx/result_types/_base.py

@@ -110,6 +110,9 @@ class Result(msgspec.Struct, kw_only=True):
 
 
         return iter(self.__struct_fields__)
         return iter(self.__struct_fields__)
 
 
+    def as_dict(self):
+        return {f: getattr(self, f) for f in self.__struct_fields__}
+
 
 
 class LegacyResult(dict):
 class LegacyResult(dict):
     """A wrapper around a legacy result item.  The SearXNG core uses this class
     """A wrapper around a legacy result item.  The SearXNG core uses this class
@@ -130,10 +133,12 @@ class LegacyResult(dict):
     UNSET = object()
     UNSET = object()
     WHITESPACE_REGEX = re.compile('( |\t|\n)+', re.M | re.U)
     WHITESPACE_REGEX = re.compile('( |\t|\n)+', re.M | re.U)
 
 
+    def as_dict(self):
+        return self
+
     def __init__(self, *args, **kwargs):
     def __init__(self, *args, **kwargs):
 
 
         super().__init__(*args, **kwargs)
         super().__init__(*args, **kwargs)
-        self.__dict__ = self
 
 
         # Init fields with defaults / compare with defaults of the fields in class Result
         # Init fields with defaults / compare with defaults of the fields in class Result
         self.engine = self.get("engine", "")
         self.engine = self.get("engine", "")

+ 9 - 9
searx/webutils.py

@@ -123,17 +123,18 @@ def write_csv_response(csv: CSVWriter, rc: ResultContainer) -> None:  # pylint:
 
 
     """
     """
 
 
-    results = rc.get_ordered_results()
     keys = ('title', 'url', 'content', 'host', 'engine', 'score', 'type')
     keys = ('title', 'url', 'content', 'host', 'engine', 'score', 'type')
     csv.writerow(keys)
     csv.writerow(keys)
 
 
-    for row in results:
+    for res in rc.get_ordered_results():
+        row = res.as_dict()
         row['host'] = row['parsed_url'].netloc
         row['host'] = row['parsed_url'].netloc
         row['type'] = 'result'
         row['type'] = 'result'
         csv.writerow([row.get(key, '') for key in keys])
         csv.writerow([row.get(key, '') for key in keys])
 
 
     for a in rc.answers:
     for a in rc.answers:
-        row = {'title': a, 'type': 'answer'}
+        row = a.as_dict()
+        row['host'] = row['parsed_url'].netloc
         csv.writerow([row.get(key, '') for key in keys])
         csv.writerow([row.get(key, '') for key in keys])
 
 
     for a in rc.suggestions:
     for a in rc.suggestions:
@@ -158,18 +159,17 @@ class JSONEncoder(json.JSONEncoder):  # pylint: disable=missing-class-docstring
 
 
 def get_json_response(sq: SearchQuery, rc: ResultContainer) -> str:
 def get_json_response(sq: SearchQuery, rc: ResultContainer) -> str:
     """Returns the JSON string of the results to a query (``application/json``)"""
     """Returns the JSON string of the results to a query (``application/json``)"""
-    results = rc.number_of_results
-    x = {
+    data = {
         'query': sq.query,
         'query': sq.query,
-        'number_of_results': results,
-        'results': rc.get_ordered_results(),
-        'answers': list(rc.answers),
+        'number_of_results': rc.number_of_results,
+        'results': [_.as_dict() for _ in rc.get_ordered_results()],
+        'answers': [_.as_dict() for _ in rc.answers],
         'corrections': list(rc.corrections),
         'corrections': list(rc.corrections),
         'infoboxes': rc.infoboxes,
         'infoboxes': rc.infoboxes,
         'suggestions': list(rc.suggestions),
         'suggestions': list(rc.suggestions),
         'unresponsive_engines': get_translated_errors(rc.unresponsive_engines),
         'unresponsive_engines': get_translated_errors(rc.unresponsive_engines),
     }
     }
-    response = json.dumps(x, cls=JSONEncoder)
+    response = json.dumps(data, cls=JSONEncoder)
     return response
     return response