Allow query strings in URL aliases

Created on 11 February 2007, over 17 years ago
Updated 22 January 2024, 5 months ago

Problem/Motivation

Handling of query strings in URL aliases is broken - for example, it is possible to create an alias /?p=123 pointing to /node/123, but although the alias exists and can be listed/edited/deleted, it will not have an effect. Conversely, it is possible to create an alias /withquery pointing to /my/custom/module?needs=query, but the expected path will not be invoked.

Eight years of comment history on this issue indicate that the former case is attempted often, typically to avoid breakage of existing URLs when migrating from a non-Drupal platform. The latter case seems less requested, which stands to reason given the rare use of query strings in Drupal.

Proposed resolution

For the former case (/?p=123 -> /node/123), questions arise because unlike paths, which always are matched by string comparison, query string parameters are unordered. If /path?product=123&sort=asc should alias /node/4, shouldn't /path?sort=asc&product=123? What about /path?product=123?

The answers to such questions will be site-dependent and could require rules of arbitrary complexity. But, simple support that addresses most users' needs out of the box, as well as a service custom/contrib could implement more advanced rulesets on seems reasonable in core.

In Drupal 8, this alias processing is the purview of the installed InboundPathProcessorInterface implementations, especially Drupal\Core\PathProcessor\PathProcessorAlias. Some attempts at quick fixes in PathProcessorAlias show that simple / seemingly obvious logic like concatenating the query string to the path before sending it to the alias manager do not work reliably, because the path received by PathProcessorAlias has been subjected to arbitrary futzing-with by the other InboundPathProcessorInterface implementations. For example, PathProcessorFront rewrites the path of any URI whose path component is '/' to the site's configured frontpage, which can be anything. PathProcessorAlias receives this rewritten value that bears no relation to the path '/', so your alias /?p=123 will not work. Contrib is able to add additional unknown futzing before PathProcessorAlias as well. Unfortunately, the task of reconstructing a path suitable for alias lookups based solely on the Symfony Request is nontrivial, and involves selectively applying only certain InboundPathProcessors to the Request path. See the discussion in #99 β†’ for details.

The patch of #99 hardcodes the set of path processors on a site with no contrib modules that yield reliable alias-style matching into PathProcessorAlias, which works, but has some disadvantages:

  • Modules seeking to implement their own InboundPathProcessorInterface implementations that support alias-style matching, such as to support more complex query parameter matching rulesets, and likely also modules that want to redirect rather than rewrite the path, should be able to use the same logic to build the match string.
  • The set of PathProcessors that need to be applied for aliases to match may depend on the modules in use, for example it already depends on whether or not Language is. If PathProcessors used are hardcoded in PathProcessorAlias, contrib modules can't contribute to the process.

Therefore, the proposed solution is to create a list of InboundPathProcessors that are appropriate for building a path suitable for alias-style matching, a means for non-core to supplement this list, a manager class that applies this list in a stacked fashion, and a means for users besides PathProcessorAlias to call on that manager's services. This is implemented in very little code by extending PathProcessorManager and creating a new service_collector tag which only those path processors providing useful futzing for reliable alias-style matching can be registered with.

"Resolving" the latter case (/withquery -> /my/custom/module?needs=query) might be best done by just disallowing the creation of such things for now -- even if you arrange for the expected route/controller to run, it would be necessary to provide the custom code expecting the query string with the query parameters in all places it might look for them.

Remaining tasks

New tests

User interface changes

May want to add validation to the alias creation form to prevent the latter case, TBD.

API changes

Provides a new service, alias_processor_manager. Some modules (redirect?) may benefit from using it.

Original report by geilhufe

I am trying to create a path alias for "civicrm/contribute/transact?reset=1&id=4"

I have tried escaping the characters without result. It seems like the alias works all the way up the the "?" then basically doesn't pass any of the arguments past the "?".

✨ Feature request
Status

Needs work

Version

11.0 πŸ”₯

Component
PathΒ  β†’

Last updated 6 days ago

  • Maintained by
  • πŸ‡¬πŸ‡§United Kingdom @catch
Created by

πŸ‡ΊπŸ‡ΈUnited States dgeilhufe@yahoo.com

Live updates comments and jobs are added and updated live.
  • Needs tests

    The change is currently missing an automated test that fails when run with the original code, and succeeds when the bug has been fixed.

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.

  • πŸ‡©πŸ‡°Denmark ressa Copenhagen

    I agree @ankithashetty, this would still be a great feature to add to the Path module.

  • πŸ‡«πŸ‡·France prudloff Lille

    I tried to reroll the patch for Drupal 10.1.

    It applies correctly and does not crash but I think it does not do what we need so I have not tested it fully.
    We need to create an alias from /foo to /node/42?foo and if I understand the patch correctly, it only handles the reverse scenario /?foo to /node/42?

Production build 0.69.0 2024