diff --git a/src/Protocol/ActivityPub/Processor.php b/src/Protocol/ActivityPub/Processor.php index 672589a64f..6c4071f975 100644 --- a/src/Protocol/ActivityPub/Processor.php +++ b/src/Protocol/ActivityPub/Processor.php @@ -540,7 +540,7 @@ class Processor } DBA::close($replies); - if (!empty($activity['completion-mode']) && !empty($item['replies'])) { + if (!empty($item['replies'])) { self::fetchReplies($item['replies'], $activity); } } @@ -558,6 +558,8 @@ class Processor */ private static function fetchParent(array $activity, bool $in_background = false): string { + $activity['callstack'] = self::addToCallstack($activity['callstack'] ?? []); + if (self::isFetched($activity['reply-to-id'])) { Logger::info('Id is already fetched', ['id' => $activity['reply-to-id']]); return ''; @@ -757,6 +759,8 @@ class Processor */ private static function getUriIdForFeaturedCollection(array $activity) { + $activity['callstack'] = self::addToCallstack($activity['callstack'] ?? []); + $actor = APContact::getByURL($activity['actor']); if (empty($actor)) { return null; @@ -1722,6 +1726,7 @@ class Processor Logger::debug('Fetch announced activity', ['type' => $type, 'id' => $object_id, 'actor' => $relay_actor, 'signer' => $signer]); if (!self::alreadyKnown($object_id, $child['id'] ?? '')) { + $child['callstack'] = self::addToCallstack($child['callstack'] ?? []); return self::fetchMissingActivity($object_id, $child, $relay_actor, $completion, $uid); } } @@ -1736,7 +1741,8 @@ class Processor $ldactivity['recursion-depth'] = !empty($child['recursion-depth']) ? $child['recursion-depth'] + 1 : 0; $ldactivity['children'] = $child['children'] ?? []; - // This check ist mostly superflous, since there are similar checks before. This covers the case, when the fetched id doesn't match the url + $ldactivity['callstack'] = $child['callstack'] ?? []; + // This check is mostly superfluous, since there are similar checks before. This covers the case, when the fetched id doesn't match the url if (in_array($activity['id'], $ldactivity['children'])) { Logger::notice('Fetched id is already in the list of children. It will not be processed.', ['id' => $activity['id'], 'children' => $ldactivity['children'], 'depth' => count($ldactivity['children'])]); return null; @@ -1788,6 +1794,12 @@ class Processor private static function fetchReplies(string $url, array $child) { + if (in_array(__FUNCTION__, $child['callstack'] ?? [])) { + Logger::notice('Callstack already contains "' . __FUNCTION__ . '"', ['callstack' => $child['callstack']]); + return; + } + $child['callstack'] = self::addToCallstack($child['callstack'] ?? []); + $replies = ActivityPub::fetchItems($url); if (empty($replies)) { Logger::notice('No replies', ['replies' => $url]); @@ -2572,4 +2584,25 @@ class Processor return $body; } + + /** + * Add the current function to the callstack + * + * @param array $callstack + * @return array + */ + public static function addToCallstack(array $callstack): array + { + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); + $functions = array_slice(array_column($trace, 'function'), 1); + $function = array_shift($functions); + + if (in_array($function, $callstack)) { + Logger::notice('Callstack already contains "' . $function . '"', ['callstack' => $callstack]); + } + + $callstack[] = $function; + + return $callstack; + } } diff --git a/src/Protocol/ActivityPub/Queue.php b/src/Protocol/ActivityPub/Queue.php index b2e8cb301b..a9918e5ea0 100644 --- a/src/Protocol/ActivityPub/Queue.php +++ b/src/Protocol/ActivityPub/Queue.php @@ -333,6 +333,7 @@ class Queue return false; } $activity['recursion-depth'] = 0; + $activity['callstack'] = Processor::addToCallstack($activity['callstack'] ?? []); $wid = Worker::add(Worker::PRIORITY_HIGH, 'FetchMissingActivity', $entry['in-reply-to-id'], $activity, '', Receiver::COMPLETION_ASYNC); Fetch::setWorkerId($entry['in-reply-to-id'], $wid); Logger::debug('Fetch missing activity', ['wid' => $wid, 'id' => $entry['activity-id'], 'reply-to-id' => $entry['in-reply-to-id']]); diff --git a/src/Protocol/ActivityPub/Receiver.php b/src/Protocol/ActivityPub/Receiver.php index 9660827cd3..39090df413 100644 --- a/src/Protocol/ActivityPub/Receiver.php +++ b/src/Protocol/ActivityPub/Receiver.php @@ -250,7 +250,6 @@ class Receiver } elseif (!Fetch::hasWorker($object_id)) { Logger::notice('Fetching is done by worker.', ['id' => $object_id]); Fetch::add($object_id); - $activity['recursion-depth'] = 0; $wid = Worker::add(Worker::PRIORITY_HIGH, 'FetchMissingActivity', $object_id, [], $actor, self::COMPLETION_RELAY); Fetch::setWorkerId($object_id, $wid); } else { @@ -757,7 +756,8 @@ class Receiver $object_data['recursion-depth'] = $activity['recursion-depth']; } - $object_data['children'] = $activity['children'] ?? []; + $object_data['children'] = $activity['children'] ?? []; + $object_data['callstack'] = $activity['callstack'] ?? []; if (!self::routeActivities($object_data, $type, $push, true, $uid)) { self::storeUnhandledActivity(true, $type, $object_data, $activity, $body, $uid, $trust_source, $push, $signer);