Problem/Motivation

In core/modules/system/src/Controller/AssetControllerBase.php Drupal collects and delivers assets necessary to display the current page based on some parameters in the request. Parameter include contains a hash with names of all libraries that should be loaded, while parameter exclude contains names of libraries already loaded.
If for whatever reasons uncompressing the hash results in an array containing empty strings, validating the library names fails. This is because the validation function simply checks if the given library names contains slashes which is always FALSE for an empty string.

Steps to reproduce

That's somehow hard. On a clients site with heavy use of javascript we run into this error on some (not all pages). I still haven't found why the exclude parameter has the value eJwDAAAAAAE.
Running this through the code in AssetControllerBase that extracts the library names results in said array with an empty value:

<?php
$exclude_libraries = explode(',', UrlHelper::uncompressQueryParameter($request->query->get('exclude')));
?>

The easiest way to reproduce this is to take the URL of an aggregated asset (.css or .js) and set the "exclude" parameter in the URL to eJwDAAAAAAE. Trying to open this URL (uncached) in the browser results in the message The "" library name must include at least one slash..

detailled steps

* install Drupal 11
* open the home page
* inspect the source of the page and copy the link to one of the loaded css files
* clear caches
* paste the URL into your browsers address bar and append &exclude=eJwDAAAAAAE

Result: the page displays The "" library name must include at least one slash..

Proposed resolution

Make validating the library names more robust by filter empty strings.

Issue fork drupal-3541527

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

stborchert created an issue. See original summary.

stborchert’s picture

Status: Active » Needs review
catch’s picture

Even if we can never generate a URL parameter like this someone could theoretically send one so it's worth accounting for it.

Could use some test coverage - there's existing coverage of invalid asset URLs so should be straightforward to add to that.

stborchert’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests

Do you happen to know which test this is in? I just took a quick look (not on my laptop right now), but unfortunately couldn't find the right test.

stborchert’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests
akashkumar07’s picture

+1 to the overall change and test coverage. LGTM!

1. In the return statement, instead of

an arbitrary string

can we please update this to

empty
/**
 * Replaces the 'include' query parameter with an empty value.
 *
 * @param string $url
 *   The source URL.
 *
 * @return string
 *   The URL with 'include' set to an empty string.
 */

2. I was just thinking if we can refactor the code duplication in test file.
A common function something like..

/**
 * Creates a URL with an empty query parameter validation.
 *
 * @param string $url
 *   The source URL.
 * @param string $parameter
 *   The query parameter to set as empty ('include' or 'exclude').
 *
 * @return string
 *   The URL with the specified parameter set to empty.
 */
protected function createUrlWithEmptyParameter(string $url, string $parameter): string {
  $url = $this->replaceGroupHash($url);
  $parts = UrlHelper::parse($url);
  $parts['query'][$parameter] = UrlHelper::compressQueryParameter('');
  
  $query = UrlHelper::buildQuery($parts['query']);
  return $this->getAbsoluteUrl($parts['path'] . '?' . $query . $fragment);
}

In terms of readability, the current code is clear and straightforward. So we can ignore this.

Thanks!

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs steps to reproduce

Can we clean up the steps some to be more concrete? Will help with the review.

stborchert’s picture

Issue summary: View changes
stborchert’s picture

Status: Needs work » Needs review

While debugging the test to see why it fails, I noticed that it is impossible for the include parameter to ever be empty (or eJwDAAAAAAE). Even if it passes the validation changed by the MR it would fail shortly with message "Invalid filename" after because the (empty) library definition could not be grouped.
Therefore I removed the test for an empty include parameter.

akashkumar07’s picture

Status: Needs review » Reviewed & tested by the community
StatusFileSize
new51.31 KB
new138.38 KB

Thank you @stborchert for providing the steps.
I verified the changes and looks good to me.

Before changes:
https://drupal11-ddev.ddev.site/sites/default/files/css/css_kRHLMdVsfEc-...
Before change

After changes:
https://drupal11-ddev.ddev.site/sites/default/files/css/css_kRHLMdVsfEc-...
after chnage

Thanks!

catch’s picture

Status: Reviewed & tested by the community » Needs work

One comment on the MR - I would have expected the validation to mean there's no need to change any code outside AssetControllerBase.

Therefore I removed the test for an empty include parameter.

I think this coverage is probably worth having - if we change the validation logic, it would prevent a possible regression.

stborchert’s picture

One comment on the MR - I would have expected the validation to mean there's no need to change any code outside AssetControllerBase.

I thought so, too. But unfortunately I ran into an error without the changes:
Exception: Warning: Undefined array key 1 Drupal\Core\Asset\LibraryDependencyResolver->doGetDependencies()() (Line: 67)

The other changes do not alter the test results so I reverted them.

Adding the test for empty includes again leads to other errors. You'll get BadRequestHttpException('Invalid filename.') from AssetControllerBase::getGroup() because the "loaded" library groups are empty.

Trying to fix this directly in AssetControllerBase by changing <?php $include_libraries = explode(',', UrlHelper::uncompressQueryParameter($request->query->get('include')));?> to <?php $include_libraries = array_filter(explode(',', UrlHelper::uncompressQueryParameter($request->query->get('include'))));?> or by changing the code in LibraryDependencyResover does not work since later Drupal tries to load the assets for "group with delta 1" (<?php $group = $this->getGroup($groups, $request->query->get('delta')); ?> (AssetControllerBase:181) but since there are no asset groups, this fails the "Invalid filename" exception.

I'm unsure where to fix this. AssetControllerBase::getGroups() correctly does not create groups for empty libraries but if this happens we always run into the "Invalid filename" exception because a non-existing asset group is requested.

stborchert’s picture

Status: Needs work » Needs review
Issue tags: -Needs steps to reproduce
catch’s picture

I thought so, too. But unfortunately I ran into an error without the changes:
Exception: Warning: Undefined array key 1 Drupal\Core\Asset\LibraryDependencyResolver->doGetDependencies()() (Line: 67)

Right but this can only happen based on how it's called from AssetControllerBase, so this suggests the validation in AssetControllerBase still isn't enough?

grimreaper made their first commit to this issue’s fork.

grimreaper’s picture

Hi,

I rebased and tried to update the MR regarding the issue discussion to only make change in AssetControllerBase (if I understood correctly).

I kept commented changes if need to revert and still apply change in LibraryDependencyResolver.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new3.21 KB

The Needs Review Queue Bot tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.

prudloff made their first commit to this issue’s fork.

prudloff’s picture

Status: Needs work » Needs review

If I understand correctly, the changes in LibraryDependencyResolverTest and LibraryDependencyResolver only fix an error that emerged in tests but is not triggered by a real life scenarios?
So I removed the commented changes in these classes.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new98 bytes

The Needs Review Queue Bot tested this issue. The merge request has merge conflicts and cannot be merged. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

stborchert’s picture

Status: Needs work » Needs review

rebased the branch

smustgrave’s picture

Status: Needs review » Needs work

Small comment on the MR.

stborchert’s picture

Status: Needs work » Needs review