Problem/Motivation
RouteHelper::getRouteNameFromRequest() blindly passes $request->getPathInfo() to Url::fromUserInput(), which prepends internal: and dispatches to Url::fromInternalUri(). Core's Url::fromInternalUri() throws an InvalidArgumentException when the resulting path component looks like an external URI. For example, a path of /tel:1234567890 strips to tel:1234567890, which UrlHelper::isExternal() reports as TRUE.
Because ResponseSubscriber::onResponseEvent() is subscribed to KernelEvents::RESPONSE at priority -1000 and calls getRouteNameFromRequest() unconditionally on every response, every request to a path of this shape, even when no routes are configured to be protected, produces an uncaught exception, turning what would have been a clean 404 from Drupal core into a 500 plus a logged PHP error.
This class of bad request seems to be bot- and crawler-generated. Naive HTML link extractors that don't honor the tel: / mailto: URI schemes treat the href value as a relative path and resolve it against the page's host, producing requests like https://example.com/tel:8006564673. Drupal core handles these fine on its own (404, no exception). It is only the presence of this module's response subscriber that escalates them to 500s.
Steps to reproduce
- Install Route Basic Authentication on any Drupal 10 or 11 site.
- Do not configure any
protected_routes(the bug reproduces regardless, but the empty-config case proves the module needn't be doing any actual work to fail). curl -i https://example.com/tel:8006564673
Expected: HTTP 404 (Drupal core's normal not-found behavior for unrouted paths).
Actual: HTTP 500, with the following entry in watchdog:
InvalidArgumentException: The internal path component 'tel:8006564673' is external.
You are not allowed to specify an external URL together with internal:/.
in Drupal\Core\Url::fromInternalUri() (line 422 of core/lib/Drupal/Core/Url.php).
Backtrace (top frames):
#0 core/lib/Drupal/Core/Url.php(319): Drupal\Core\Url::fromInternalUri()
#1 core/lib/Drupal/Core/Url.php(221): Drupal\Core\Url::fromUri()
#2 modules/contrib/route_basic_auth/src/Routing/RouteHelper.php(27): Drupal\Core\Url::fromUserInput()
#3 modules/contrib/route_basic_auth/src/EventSubscriber/ResponseSubscriber.php(104): Drupal\route_basic_auth\Routing\RouteHelper->getRouteNameFromRequest()
The same fault reproduces for any request path whose first segment parses as an external URI, e.g.:
/mailto:foo@example.com/https://example.com/http://example.com
Proposed resolution
Guard RouteHelper::getRouteNameFromRequest() against paths that UrlHelper::isExternal() would classify as external before calling Url::fromUserInput(), and wrap the call in a defensive try/catch for \InvalidArgumentException to cover anything that slips past the scheme check. Return NULL in either case. If the requests cannot match a Drupal route by definition, the module does nothing.
Remaining tasks
- Review patch.
- Add test coverage for the external-path case in
getRouteNameFromRequest().
User interface changes
None
API changes
None
Data model changes
None
Issue fork route_basic_auth-3603890
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 #2
fmitchell commentedComment #4
fmitchell commentedComment #5
fmitchell commentedAdded merge request
Comment #6
darvanenLooks great, let's kick off our test suite with a kernel test to lock this in. The CI is in place to support it.
Comment #7
fmitchell commentedI added a few kernel tests and they pass. Confirm that removing the fix makes the tests fail: https://git.drupalcode.org/issue/route_basic_auth-3603890/-/jobs/10499047
Comment #8
darvanenThanks for that, added a line without which Drupal 12 will trip us up. It's merging now.
Comment #10
darvanen