4xx Recursion issue on non-existent html routes

Created on 5 April 2018, over 6 years ago
Updated 9 August 2024, 3 months ago

Issue Summary

I've run into an error case related to rest, the rest_export view display, breadcrumb, and the way 4xx errors are handled in the routing system. The result is that REST resources without an html route can get stuck in an infinite recursion loop of Exceptions due to the html 4xx error page response.

Steps to Reproduce

  1. Create a rest_export view without an HTML format ex. /api/rest_export?_format=json . This resource will return a 400 error via the system.4xx route if accessed via /api/rest_export.
  2. Using the Bartik theme add the breadcrumbs block using the standard block layout.
  3. Now navigate to /api/rest_export and you'll trigger an infinite loop of NotAcceptableHttpException(s) from RequestFormatRouteFilter::filter() due to PathBasedBreadcrumbBuilder::getRequestForPath().

A stacktrace for the recursion for this request can be found at https://gist.github.com/malcolmp/d7bac0ed439c25bbf6bc9be357a7ddcb

Proposed Resolution

  1. Minimally patch system to catch ALL exceptions from $this->router->matchRequest($request) in PathBasedBreadcrumbBuilder::getRequestForPath() to prevent recursion in this specific case
  2. Ideally, the way 4xx errors are handled could be addressed to not use the sub-request in DefaultExceptionHtmlSubscriber::makeSubrequest() as that opens up to this kind of exception recursion. Otherwise, minimally catching exceptions to prevent recursion should be attempted.

A patch for #1 is attached. #2 is clearly a much bigger issue that I'm not quite clear how to resolve yet.

πŸ› Bug report
Status

Closed: outdated

Version

10.1 ✨

Component
RoutingΒ  β†’

Last updated about 10 hours ago

Created by

πŸ‡ΊπŸ‡ΈUnited States malcolm_p

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.

  • πŸ‡³πŸ‡ΏNew Zealand quietone

    @malcolm_p, Thank you for reporting this problem. We rely on issue reports like this to improve Drupal core.

    I tested this on 10.1.x, standard install, and was not able to reproduce this error. I followed the steps given in the Issue Summary.

    Therefore, closing as outdated. If you are experiencing this problem on a supported version of Drupal reopen the issue, by setting the status to 'Active', and provide complete steps to reproduce the issue β†’ (starting from "Install Drupal core").

    Thanks!

  • Was unable to replicate this in a clean core install. Core will simply return a "A client error happened" response.

    For me, it was triggered because another custom kernel.request event subscriber made a call to \Drupal\Core\Path\PathValidatorInterface::getUrlIfValid(), but didn't have any error handling in place, resulting in an infinite recursion.

    A similar

        try {
          // ...
        }
        catch (ResourceNotFoundException $e) {
          $result = FALSE;
        }
        catch (ParamNotConvertedException $e) {
          $result = FALSE;
        }
        catch (AccessDeniedHttpException $e) {
          $result = FALSE;
        }
        catch (MethodNotAllowedException $e) {
          $result = FALSE;
        }
    

    try catch used in \Drupal\system\PathBasedBreadcrumbBuilder::getRequestForPath() is also present in \Drupal\Core\Path\PathValidator::getPathAttributes(), so they're probably somewhat related.

  • πŸ‡ΊπŸ‡ΈUnited States millenniumtree Holualoa, HI

    I had this happen in Drupal 9.5.11. Sorry it's not the latest, but that's what I have currently and where it was triggered.

    I've attached a sanitized backtrace showing where it loops. The inner block looped hundreds of times before running out of memory.

    I've also attached a basic patch that uses a static integer to count how many times ParamNotConvertedException is thrown (and then just don't throw the exception if it's more than once).

    For me, this specifically triggers on an invalid /node/## path, and when NOT logged in. I used the path /node/8675309, but any number that is not a node ID should trigger it as well.

    I do hope someone can make sense of this information, and find the actual cause instead of my static int counter workaround.

    This is a pretty serious bug, because we had a rogue web scraper hit HUNDREDS of bad /node/## pages, tying up all of our PHP processes, and essentially DDOS'ing our server for a little while.

Production build 0.71.5 2024