Problem/Motivation

When a content type has keep_context enabled and a node of that type belongs to a group, visiting the node's already-correct group-prefixed URL directly (e.g. /business/development-plan) causes NodeGroupViewController::view() to compute a redirect to that exact same URL, resulting in an infinite 302 redirect loop.

This surfaced while diagnosing a Drupal 11.4 purl subrequest bug (see purl #3608029 and the companion purl #3608542), but the loop itself is independent of that bug and reproducible without it (see verification below).

purl processes the group-prefixed request in two places:

  • purl's internal subrequest, created for the stripped path (e.g. /development-plan), to render the content.
  • The main request itself, which - via PurlRouteProvider's inbound path processing - also resolves to the same route/controller once the subrequest's response is set on the main event.

NodeGroupViewController::view() ran identical keep_context redirect logic in both places, with no check for whether the current request was already at the computed target URL. On the main request (already at the correct prefixed URL), this redirected to itself.

Steps to reproduce

  • Create a group with a path alias (e.g. /business).
  • Create a content type with keep_context enabled (Structure → Content types → [type] → PURL settings → "Keep context of the node").
  • Create a node of that type, add it to the group, and give it a path alias (e.g. /development-plan).
  • Visit /business/development-plan directly.
  • Observe an infinite redirect loop back to the same URL (browsers will eventually show "too many redirects").

Proposed resolution

In src/Controller/NodeGroupViewController.php, view():

  • Detect whether the current request is purl's internal subrequest ($requestStack->getMainRequest() !== $request) and skip the keep_context redirect entirely there - the subrequest exists specifically to render the content, not to redirect it further.
  • Independently, only issue the redirect if the computed target URL differs from the current request path ($redirect_url !== $request_path) - this is the guard that actually stops the loop, and does so correctly regardless of whether the subrequest is correctly detected.

Remaining tasks

  • Apply the NodeGroupViewController change above (patch/MR to follow)
  • Add a functional test asserting /business/development-plan returns 200 with no redirect when visited directly, and that /development-plan (missing prefix) still redirects exactly once to /business/development-plan

User interface changes

None.

API changes

None — behavioral fix only, no signature changes.

Data model changes

None.

Issue fork group_purl-3608553

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

freelock created an issue.

freelock’s picture

Test failures are known issues related to upstream Purl issues. Code works, behat tests all pass on a site in production after applying the related Purl patch for 11.4.0 - and should be safe to run on older Drupal core without the Purl patch.

  • freelock committed c5948599 on 3.0.x
    fix: #3608553 Node redirects to itself in an infinite loop when...