diff --git a/core/lib/Drupal/Component/Utility/UrlHelper.php b/core/lib/Drupal/Component/Utility/UrlHelper.php index 9619dcf0703105754d04ad8d84a829822a44e6fd..27dfc945b18f02a7fef696ce43e975011cf6975b 100644 --- a/core/lib/Drupal/Component/Utility/UrlHelper.php +++ b/core/lib/Drupal/Component/Utility/UrlHelper.php @@ -187,13 +187,18 @@ public static function parse($url) { ]; // External URLs: not using parse_url() here, so we do not have to rebuild - // the scheme, host, and path without having any use for it. - // The URL is considered external if it contains the '://' delimiter. Since - // a URL can also be passed as a query argument, we check if this delimiter - // appears in front of the '?' query argument delimiter. + // the scheme, host, and path without having any use for it. The URL is + // considered external if it contains the '://' delimiter. Since a URL can + // also be passed as a query or fragment argument, check if this delimiter + // appears in front of the '?' and '#' query/fragment argument delimiters. $scheme_delimiter_position = strpos($url, '://'); $query_delimiter_position = strpos($url, '?'); - if ($scheme_delimiter_position !== FALSE && ($query_delimiter_position === FALSE || $scheme_delimiter_position < $query_delimiter_position)) { + $fragment_delimiter_position = strpos($url, '#'); + if ( + $scheme_delimiter_position !== FALSE && + ($query_delimiter_position === FALSE || $scheme_delimiter_position < $query_delimiter_position) && + ($fragment_delimiter_position === FALSE || $scheme_delimiter_position < $fragment_delimiter_position) + ) { // Split off the fragment, if any. if (str_contains($url, '#')) { [$url, $options['fragment']] = explode('#', $url, 2); diff --git a/core/tests/Drupal/Tests/Component/Utility/UrlHelperTest.php b/core/tests/Drupal/Tests/Component/Utility/UrlHelperTest.php index 158e626c821301afe77e48226b5681bd33a93f7d..f22d6ac3118aa8473cb74270ff833b3d3fc0f994 100644 --- a/core/tests/Drupal/Tests/Component/Utility/UrlHelperTest.php +++ b/core/tests/Drupal/Tests/Component/Utility/UrlHelperTest.php @@ -386,6 +386,30 @@ public static function providerTestParse() { 'fragment' => 'footer', ], ], + 'Absolute URL with URL as fragment' => [ + 'http://example.com/my/path#http://example.com', + [ + 'fragment' => 'http://example.com', + 'path' => 'http://example.com/my/path', + 'query' => [], + ], + ], + 'Relative URL with URL as fragment' => [ + '/my/path#http://example.com', + [ + 'fragment' => 'http://example.com', + 'path' => '/my/path', + 'query' => [], + ], + ], + 'URL as fragment' => [ + '#http://example.com', + [ + 'fragment' => 'http://example.com', + 'path' => '', + 'query' => [], + ], + ], ]; }