changeset 1493:1702b8c821c4

pages (blog/view): avoid infinite recursion when comment nodes are making a loop
author Goffi <goffi@goffi.org>
date Tue, 22 Mar 2022 16:56:45 +0100
parents 3a34d78f2717
children 1671d187e71d
files libervia/pages/blog/view/page_meta.py
diffstat 1 files changed, 39 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/libervia/pages/blog/view/page_meta.py	Wed Jan 26 17:15:36 2022 +0100
+++ b/libervia/pages/blog/view/page_meta.py	Tue Mar 22 16:56:45 2022 +0100
@@ -1,17 +1,19 @@
 #!/usr/bin/env python3
 
 import html
-from typing import Dict, Any
-from libervia.server.constants import Const as C
-from twisted.words.protocols.jabber import jid
-from twisted.web import server
-from sat.core.i18n import _, D_
-from sat.tools.common.template import safe
+from typing import Any, Dict, Optional
+
+from sat.core.i18n import D_, _
+from sat.core.log import getLogger
 from sat.tools.common import uri
 from sat.tools.common import data_format
 from sat.tools.common import regex
-from sat.core.log import getLogger
+from sat.tools.common.template import safe
+from twisted.web import server
+from twisted.words.protocols.jabber import jid
+
 from libervia.server import utils
+from libervia.server.constants import Const as C
 from libervia.server.utils import SubPage
 
 log = getLogger(__name__)
@@ -116,7 +118,21 @@
         })
 
 
-async def appendComments(self, request, blog_items, profile):
+async def appendComments(
+    self,
+    request: server.Request,
+    blog_items: dict,
+    profile: str,
+    _seen: Optional[set] = None
+) -> None:
+    """Recursively download and append comments of items
+
+    @param blog_items: items data
+    @param profile: Libervia profile
+    @param _seen: used to avoid infinite recursion. For internal use only
+    """
+    if _seen is None:
+        _seen = set()
     await self.fillMissingIdentities(
         request, [i['author_jid'] for i in blog_items['items']])
     extra: Dict[str, Any] = {C.KEY_ORDER_BY: C.ORDER_BY_CREATION}
@@ -126,6 +142,16 @@
         for comment_data in blog_item['comments']:
             service = comment_data['service']
             node = comment_data['node']
+            service_node = (service, node)
+            if service_node in _seen:
+                log.warning(
+                    f"Items from {node!r} at {service} have already been retrieved, "
+                    "there is a recursion at this service"
+                )
+                comment_data["items"] = []
+                continue
+            else:
+                _seen.add(service_node)
             try:
                 comments_data = await self.host.bridgeCall('mbGet',
                                       service,
@@ -146,8 +172,12 @@
                 continue
 
             comments = data_format.deserialise(comments_data)
+            if comments is None:
+                log.error(f"Comments should not be None: {comment_data}")
+                comment_data["items"] = []
+                continue
             comment_data['items'] = comments['items']
-            await appendComments(self, request, comments, profile)
+            await appendComments(self, request, comments, profile, _seen=_seen)
 
 async def getBlogItems(
     self,