Overview

The Drupal stream wrapper URIs (e.g. public://path_to_file/file.txt) are validated using JSON Schema UriValidator class. Because they include <schema>://<path> but no host, the regex interprets the first path segment (e.g. path_to_file) as the authority (host), producing false invalid URI violations.

Root Cause Analysis

  • JSON Schema UriValidator assumes RFC 3986 structure: scheme://authority/path.
  • Drupal stream wrappers intentionally omit hostname in stream wrapper Uri; Syntax is scheme://path.
  • Regex shifts the first path segment as the authority (host) slot, yielding an invalid host condition.
  • This causes false negatives during validation for stored file references managed by Drupal.

Proposed resolution

Skip validating Stream Wrapper URIs.

Issue fork canvas-3560455

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

mayur-sose created an issue. See original summary.

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

vishalkhode’s picture

Title: Site Settings : Unable to upload site logo and favicon » Stream wrapper URIs are incorrectly flagged as invalid (hostname misinterpreted)
Issue summary: View changes

vishalkhode’s picture

An alternative approach could be:

  • Detect whether the value is a Drupal stream wrapper URI.
  • If it is, resolve it to its external URL using getExternalUrl().
  • Run the resolved URL through UriValidator, falling back to the original value if no stream wrapper applies.
public function validate(mixed $value, Constraint $constraint): void {
  $value = $this->getStreamWrapperForUri($value)?->getExternalUrl() ?? $value;

  $is_valid = match ($constraint->allowReferences) {
    TRUE => UriValidator::isValid($value) || RelativeReferenceValidator::isValid($value),
    FALSE => UriValidator::isValid($value),
  };

}
private function getStreamWrapperForUri(string $uri): ?StreamWrapperInterface {
  $stream_wrapper = $this->streamWrapperManager->getViaUri($uri);
  return $stream_wrapper instanceof StreamWrapperInterface ? $stream_wrapper : NULL;
}

However, this also less likely would catch invalid URIs. As getExternalUrl() normalizes and encodes the path component, turning the invalid stream wrapper URIs into valid HTTP URLs. For example, the invalid URI public://test/file name with spaces.txt becomes https://my-drupal-site.com/sites/default/files/file%20name%20with%20spaces.txt, which passes validation. We can use rawurldecode($value) and then validate, but it might decode the input uri as well.

wim leers’s picture

Title: Stream wrapper URIs are incorrectly flagged as invalid (hostname misinterpreted) » [upstream] Stream wrapper URIs are incorrectly flagged as invalid (hostname misinterpreted)
Issue tags: +Needs upstream bugfix
Related issues: +#3352063: Allow schema references in Single Directory Component prop schemas, +#3515074: Shape matching MUST work with the resolved equivalents of $refs AND must be compatible with core's upcoming $ref resolving in SDCs

I independently discovered this bug yesterday:

  1. That led me to a whole saga of discoveries. I presumed justinrainbow/json-schema to correctly validate URIs. So I concluded that we'd need to change how json-schema-definitions:// worked. So I implemented that … and then discovered that actually, their URI validation is wrong:

#3515074-32: Shape matching MUST work with the resolved equivalents of $refs AND must be compatible with core's upcoming $ref resolving in SDCs

wim leers’s picture

wim leers’s picture

Title: [upstream] Stream wrapper URIs are incorrectly flagged as invalid (hostname misinterpreted) » [upstream] Stream wrapper URIs are incorrectly flagged as invalid (hostname misinterpreted) due to bug in `justinrainbow/json-schema` — bump minimum version to 6.6.2
Component: … to be triaged » Code
Issue tags: -Needs upstream bugfix +stable blocker

I think this ought to be a stable blocker. Because it'll require bumping our versions.

vishalkhode’s picture

Status: Needs work » Needs review
deepakkm’s picture

Status: Needs review » Reviewed & tested by the community

Reviewed and validated and looks good

wim leers’s picture

Status: Reviewed & tested by the community » Fixed

Thanks!

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

wim leers’s picture

Status: Fixed » Needs work

Oops, one tiny oversight: we should now be able to remove

    // @todo Remove this line once https://www.drupal.org/project/drupal/issues/3352063#comment-16363119 is fixed, or justinrainbow/json-schema's UriValidator has been fixed upstream.
    unset($refSchema['id']);

… to avoid continuing to carry this technical debt.

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

phenaproxima’s picture

Status: Needs work » Needs review

Removed that bit of code.

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

penyaskito’s picture

Assigned: Unassigned » penyaskito
Status: Needs review » Reviewed & tested by the community

👌🏽

penyaskito’s picture

Assigned: penyaskito » Unassigned
Status: Reviewed & tested by the community » Fixed

Thanks!

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

wim leers’s picture

Nice, thanks!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.