Infinite Loop in link field, block field and embedded entity importer plugins

Created on 21 February 2022, about 3 years ago
Updated 24 February 2023, about 2 years ago

Problem/Motivation

I am experiencing an infinite loop when importing content that contains circular links to each other, when the embedded entity importer is enabled in my import configurations.

Steps to reproduce

On the server, in the body field of node A, use linkit to generate a link to node B. in the body field of node B, use linkit to generate a link to node A. On the client, enable import embedded entities in the import configuration and attempt to synchronize one of the nodes. Regardless of whether you have a "max recursion" set, the import will create an infinite loop and eventually crash the server.

Proposed resolution

I think this is because the embedded entity importer calls EntityReference->importUrl without checking to see if the max_recursion_depth has been reached. Am example of such a check can be seen in BlockFieldBlockContentImporter, which overrides the importUrl function as:

protected function importUrl(RuntimeImportContext $runtime_import_context, $url) {
    // In the case of block field, if the block content entity is already
    // present on the website, there is nothing to do.
    if ($this->currentRecursionDepth == $this->configuration['max_recursion_depth']) {
      return [];
    }

    return parent::importUrl($runtime_import_context, $url);
  }
πŸ› Bug report
Status

Fixed

Version

3.0

Component

Code

Created by

πŸ‡ΊπŸ‡ΈUnited States dgroene

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • πŸ‡«πŸ‡·France Grimreaper France πŸ‡«πŸ‡·
  • @grimreaper opened merge request.
  • πŸ‡«πŸ‡·France Grimreaper France πŸ‡«πŸ‡·
  • πŸ‡«πŸ‡·France Grimreaper France πŸ‡«πŸ‡·

    I pushed a new solution.

    In fact I found 2 problems.

    The max_recursion_depth setting not taken into account.

    But even with that problem fixed, having no recursion limit should not provoke infinite loop.

    This was also due to the fact that the mechanism put in place to prevent infinite loop relayed on the following lines in ImportService::importEntityListData():

    $processed_entity = $this->getProcessedEntity($entity_data);
          $imported_entity_ids[$processed_entity->uuid()] = $processed_entity->id();
    
          // Prevent infinite loop.
          // Check if we try to import an already imported entity translation.
          // We can't check this in the STAGE_IS_ENTITY_IMPORTABLE stage because we
          // need to obtain the entity ID to return it for entity reference fields.
          $processed_entity_langcode = $processed_entity->language()->getId();
          $processed_entity_uuid = $processed_entity->uuid();
          if ($this->runtimeImportContext->isEntityTranslationImported($processed_entity_langcode, $processed_entity_uuid)) {
            continue;
          }
          else {
            // Store data to prevent the entity of being re-imported.
            $this->runtimeImportContext->addImportedEntity($processed_entity_langcode, $processed_entity_uuid);
          }
    

    Which happens after the prepare_importable_entity_data stage, which is the stage where the link field, embedded entity and block field importer plugins act. While the standard entity reference importer plugin acts in the process_entity stage, which happens right after the check to prevent infinite loop.

    So I have added a new property to the RuntimeImportContext object to store the entities that are going to be imported. The existing $importedEntities could not be used otherwise this would prevent entities to be imported.

    I currently do not handle entity language because currently in the JSON data the importer plugins have access, this data is not present so it would require to add more data injected by the JSON:API Extras field enhancer.

    This would mean that if regarding the "reference" during the same import, an entity should be imported in multiple languages, this would prevent that.

    As currently channels are still for one language, I don't think this is currently problematic.

    Enhanced version may become later.

    Still needs to write tests.

  • Issue was unassigned.
  • Status changed to Fixed about 2 years ago
  • πŸ‡«πŸ‡·France Grimreaper France πŸ‡«πŸ‡·

    Tests ok.

    I have not written tests for block field, because it would have required to prepare a block content type that contains a block field.

    Not impossible to do, but I have only a short time available.

Production build 0.71.5 2024