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_contextenabled (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-plandirectly. - 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 thekeep_contextredirect 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
NodeGroupViewControllerchange above (patch/MR to follow) - Add a functional test asserting
/business/development-planreturns200with 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
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
Comment #3
freelockTest 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.