summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Pott2018-05-18 10:13:12 (GMT)
committerAlex Pott2018-05-18 10:13:12 (GMT)
commita7fdfb64693d00bd7e094ccda45c3e58581b8bbe (patch)
tree5d9ee0617ec9adaabd05bc4b012d86c63633ec89
parentd9a566139a7a4161bf4e20ddc92a8fb767399d93 (diff)
Issue #2955685 by Wim Leers, dawehner, mpdonadio, alexpott, borisson_: Unrouted URLs cannot have have overridden query or fragments
-rw-r--r--core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php22
-rw-r--r--core/modules/rdf/tests/src/Kernel/Field/LinkFieldRdfaTest.php2
-rw-r--r--core/modules/system/tests/src/Functional/Common/UrlTest.php8
-rw-r--r--core/tests/Drupal/Tests/Core/Utility/UnroutedUrlAssemblerTest.php4
4 files changed, 23 insertions, 13 deletions
diff --git a/core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php b/core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php
index 6d68c1e..2569ee4 100644
--- a/core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php
+++ b/core/lib/Drupal/Core/Utility/UnroutedUrlAssembler.php
@@ -2,6 +2,7 @@
namespace Drupal\Core\Utility;
+use Drupal\Component\Utility\NestedArray;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\GeneratedUrl;
use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
@@ -69,13 +70,18 @@ class UnroutedUrlAssembler implements UnroutedUrlAssemblerInterface {
*/
protected function buildExternalUrl($uri, array $options = [], $collect_bubbleable_metadata = FALSE) {
$this->addOptionDefaults($options);
- // Split off the fragment.
- if (strpos($uri, '#') !== FALSE) {
- list($uri, $old_fragment) = explode('#', $uri, 2);
- // If $options contains no fragment, take it over from the path.
- if (isset($old_fragment) && !$options['fragment']) {
- $options['fragment'] = '#' . $old_fragment;
- }
+ // Split off the query & fragment.
+ $parsed = UrlHelper::parse($uri);
+ $uri = $parsed['path'];
+
+ $parsed += ['query' => []];
+ $options += ['query' => []];
+
+ $options['query'] = NestedArray::mergeDeep($parsed['query'], $options['query']);
+ ksort($options['query']);
+
+ if ($parsed['fragment'] && !$options['fragment']) {
+ $options['fragment'] = '#' . $parsed['fragment'];
}
if (isset($options['https'])) {
@@ -88,7 +94,7 @@ class UnroutedUrlAssembler implements UnroutedUrlAssemblerInterface {
}
// Append the query.
if ($options['query']) {
- $uri .= (strpos($uri, '?') !== FALSE ? '&' : '?') . UrlHelper::buildQuery($options['query']);
+ $uri .= '?' . UrlHelper::buildQuery($options['query']);
}
// Reassemble.
$url = $uri . $options['fragment'];
diff --git a/core/modules/rdf/tests/src/Kernel/Field/LinkFieldRdfaTest.php b/core/modules/rdf/tests/src/Kernel/Field/LinkFieldRdfaTest.php
index 30735e3..aac9b75 100644
--- a/core/modules/rdf/tests/src/Kernel/Field/LinkFieldRdfaTest.php
+++ b/core/modules/rdf/tests/src/Kernel/Field/LinkFieldRdfaTest.php
@@ -42,7 +42,7 @@ class LinkFieldRdfaTest extends FieldRdfaTestBase {
*/
public function testAllFormattersExternal() {
// Set up test values.
- $this->testValue = 'http://test.me/foo/bar/neque/porro/quisquam/est/qui-dolorem?foo/bar/neque/porro/quisquam/est/qui-dolorem';
+ $this->testValue = 'http://test.me/foo/bar/neque/porro/quisquam/est/qui-dolorem?path=foo/bar/neque/porro/quisquam/est/qui-dolorem';
$this->entity = EntityTest::create([]);
$this->entity->{$this->fieldName}->uri = $this->testValue;
diff --git a/core/modules/system/tests/src/Functional/Common/UrlTest.php b/core/modules/system/tests/src/Functional/Common/UrlTest.php
index cd27ca7..8e4d7b1 100644
--- a/core/modules/system/tests/src/Functional/Common/UrlTest.php
+++ b/core/modules/system/tests/src/Functional/Common/UrlTest.php
@@ -306,15 +306,15 @@ class UrlTest extends BrowserTestBase {
// Verify external URL can be extended with a query string.
$url = $test_url;
- $query = [$this->randomMachineName(5) => $this->randomMachineName(5)];
+ $query = ['awesome' => 'drupal'];
$result = Url::fromUri($url, ['query' => $query])->toString();
- $this->assertEqual($url . '?' . http_build_query($query, '', '&'), $result, 'External URL can be extended with a query string in $options.');
+ $this->assertSame('https://www.drupal.org/?awesome=drupal', $result);
// Verify query string can be extended in an external URL.
$url = $test_url . '?drupal=awesome';
- $query = [$this->randomMachineName(5) => $this->randomMachineName(5)];
+ $query = ['awesome' => 'drupal'];
$result = Url::fromUri($url, ['query' => $query])->toString();
- $this->assertEqual($url . '&' . http_build_query($query, '', '&'), $result);
+ $this->assertEqual('https://www.drupal.org/?awesome=drupal&drupal=awesome', $result);
}
}
diff --git a/core/tests/Drupal/Tests/Core/Utility/UnroutedUrlAssemblerTest.php b/core/tests/Drupal/Tests/Core/Utility/UnroutedUrlAssemblerTest.php
index a47d206..70b3880 100644
--- a/core/tests/Drupal/Tests/Core/Utility/UnroutedUrlAssemblerTest.php
+++ b/core/tests/Drupal/Tests/Core/Utility/UnroutedUrlAssemblerTest.php
@@ -96,6 +96,10 @@ class UnroutedUrlAssemblerTest extends UnitTestCase {
['http://example.com/test', ['https' => TRUE], 'https://example.com/test'],
['https://example.com/test', ['https' => FALSE], 'http://example.com/test'],
['https://example.com/test?foo=1#bar', [], 'https://example.com/test?foo=1#bar'],
+ 'override-query' => ['https://example.com/test?foo=1#bar', ['query' => ['foo' => 2]], 'https://example.com/test?foo=2#bar'],
+ 'override-query-merge' => ['https://example.com/test?foo=1#bar', ['query' => ['bar' => 2]], 'https://example.com/test?bar=2&foo=1#bar'],
+ 'override-deep-query-merge' => ['https://example.com/test?foo=1#bar', ['query' => ['bar' => ['baz' => 'foo']]], 'https://example.com/test?bar%5Bbaz%5D=foo&foo=1#bar'],
+ 'override-fragment' => ['https://example.com/test?foo=1#bar', ['fragment' => 'baz'], 'https://example.com/test?foo=1#baz'],
['//www.drupal.org', [], '//www.drupal.org'],
];
}