# HG changeset patch # User Goffi # Date 1550513524 -3600 # Node ID dc83b1d837cf55c78be4898b75b219f36a879a3f # Parent 728b08c0d0009e03bbb3bd92349df2fb26bacfec backend: fixed recursion error on getFullItem: getFullItem was doing a deepcopy of the item which could lead to infinite recursion if element had children. This has been fixed by doing a specialised copy function. For the same reason, an itemDataCopy function has also been implemented. diff -r 728b08c0d000 -r dc83b1d837cf src/backend.py --- a/src/backend.py Fri Feb 15 22:06:19 2019 +0100 +++ b/src/backend.py Mon Feb 18 19:12:04 2019 +0100 @@ -61,6 +61,7 @@ publish-subscribe protocol. """ +import copy import uuid from zope.interface import implements @@ -84,8 +85,6 @@ from sat_pubsub import const from sat_pubsub import container -from copy import deepcopy - def _getAffiliation(node, entity): d = node.getAffiliation(entity) @@ -93,6 +92,37 @@ return d +def elementCopy(element): + """Make a copy of a domish.Element + + The copy will have its own children list, so other elements + can be added as direct children without modifying orignal one. + Children are not deeply copied, so if an element is added to a child or grandchild, + it will also affect original element. + @param element(domish.Element): Element to clone + """ + new_elt = domish.Element( + (element.uri, element.name), + defaultUri = element.defaultUri, + attribs = element.attributes, + localPrefixes = element.localPrefixes) + new_elt.parent = element.parent + new_elt.children = element.children[:] + return new_elt + + +def itemDataCopy(item_data): + """Make a copy of an item_data + + deep copy every element of the tuple but item + do an elementCopy of item_data.item + @param item_data(ItemData): item data to copy + @return (ItemData): copied data + """ + return container.ItemData(*[elementCopy(item_data.item)] + + [copy.deepcopy(d) for d in item_data[1:]]) + + class BackendService(service.Service, utility.EventDispatcher): """ Generic publish-subscribe backend service. @@ -1301,10 +1331,12 @@ # TODO: a test should check that only the owner get the item configuration back item, item_config = item_data.item, item_data.config - new_item = deepcopy(item) if item_config: + new_item = elementCopy(item) new_item.addChild(item_config.toElement()) - return new_item + return new_item + else: + return item @defer.inlineCallbacks def _notifyPublish(self, data): @@ -1423,9 +1455,9 @@ allowed_items = [] #we keep only item which subscriber can access if schema is not None: - # we have to deepcopy items because different subscribers may receive + # we have to copy items_data because different subscribers may receive # different items (e.g. read restriction in schema) - items_data = deepcopy(items_data) + items_data = itemDataCopy(items_data) self.backend.filterItemsWithSchema(items_data, schema, False) for item_data in items_data: