summaryrefslogtreecommitdiffstats
path: root/core/lib/Drupal/Core/Routing
diff options
context:
space:
mode:
authorNathaniel Catchpole2016-10-19 09:54:55 (GMT)
committerNathaniel Catchpole2016-10-19 09:54:55 (GMT)
commit3a8b4eee946f6e8905456f03ee5dd91fc0fb4a56 (patch)
tree173985d4e16341d2b4bd70fc85f01cc4b4ed3906 /core/lib/Drupal/Core/Routing
parentbc7dcc916e564a1d8400f5878ccd0e69eba16e89 (diff)
Issue #2809789 by pwolanin, dawehner: UrlGenerator fails to urlencode aliases, incorrectly encodes "system" path
Diffstat (limited to 'core/lib/Drupal/Core/Routing')
-rw-r--r--core/lib/Drupal/Core/Routing/NullGenerator.php2
-rw-r--r--core/lib/Drupal/Core/Routing/RedirectDestination.php2
-rw-r--r--core/lib/Drupal/Core/Routing/UrlGenerator.php95
-rw-r--r--core/lib/Drupal/Core/Routing/UrlGeneratorInterface.php3
4 files changed, 45 insertions, 57 deletions
diff --git a/core/lib/Drupal/Core/Routing/NullGenerator.php b/core/lib/Drupal/Core/Routing/NullGenerator.php
index d9bc9b0..9d6db83 100644
--- a/core/lib/Drupal/Core/Routing/NullGenerator.php
+++ b/core/lib/Drupal/Core/Routing/NullGenerator.php
@@ -52,7 +52,7 @@ class NullGenerator extends UrlGenerator {
/**
* {@inheritdoc}
*/
- protected function getInternalPathFromRoute($name, Route $route, $parameters = array(), $query_params = array()) {
+ protected function getInternalPathFromRoute($name, Route $route, $parameters = array(), &$query_params = array()) {
return $route->getPath();
}
diff --git a/core/lib/Drupal/Core/Routing/RedirectDestination.php b/core/lib/Drupal/Core/Routing/RedirectDestination.php
index 873694a..1945e33 100644
--- a/core/lib/Drupal/Core/Routing/RedirectDestination.php
+++ b/core/lib/Drupal/Core/Routing/RedirectDestination.php
@@ -64,7 +64,7 @@ class RedirectDestination implements RedirectDestinationInterface {
$this->destination = $query->get('destination');
}
else {
- $this->destination = $this->urlGenerator->generateFromRoute('<current>', [], ['query' => UrlHelper::buildQuery(UrlHelper::filterQueryParameters($query->all()))]);
+ $this->destination = $this->urlGenerator->generateFromRoute('<current>', [], ['query' => UrlHelper::filterQueryParameters($query->all())]);
}
}
diff --git a/core/lib/Drupal/Core/Routing/UrlGenerator.php b/core/lib/Drupal/Core/Routing/UrlGenerator.php
index ccf2b60..b13d3db 100644
--- a/core/lib/Drupal/Core/Routing/UrlGenerator.php
+++ b/core/lib/Drupal/Core/Routing/UrlGenerator.php
@@ -149,12 +149,14 @@ class UrlGenerator implements UrlGeneratorInterface {
* The route parameters passed to the generator. Parameters that do not
* match any variables will be added to the result as query parameters.
* @param array $query_params
- * Query parameters passed to the generator as $options['query'].
+ * Query parameters passed to the generator as $options['query']. This may
+ * be modified if there are extra parameters not used as route variables.
* @param string $name
* The route name or other identifying string from ::getRouteDebugMessage().
*
* @return string
- * The url path, without any base path, including possible query string.
+ * The url path, without any base path, without the query string, not URL
+ * encoded.
*
* @throws MissingMandatoryParametersException
* When some parameters are missing that are mandatory for the route.
@@ -162,7 +164,7 @@ class UrlGenerator implements UrlGeneratorInterface {
* When a parameter value for a placeholder is not correct because it does
* not match the requirement.
*/
- protected function doGenerate(array $variables, array $defaults, array $tokens, array $parameters, array $query_params, $name) {
+ protected function doGenerate(array $variables, array $defaults, array $tokens, array $parameters, array &$query_params, $name) {
$variables = array_flip($variables);
$mergedParams = array_replace($defaults, $this->context->getParameters(), $parameters);
@@ -208,30 +210,8 @@ class UrlGenerator implements UrlGeneratorInterface {
$url = '/';
}
- // The contexts base URL is already encoded (see Symfony\Component\HttpFoundation\Request)
- $url = str_replace($this->decodedChars[0], $this->decodedChars[1], rawurlencode($url));
-
- // Drupal paths rarely include dots, so skip this processing if possible.
- if (strpos($url, '/.') !== FALSE) {
- // the path segments "." and ".." are interpreted as relative reference when
- // resolving a URI; see http://tools.ietf.org/html/rfc3986#section-3.3
- // so we need to encode them as they are not used for this purpose here
- // otherwise we would generate a URI that, when followed by a user agent
- // (e.g. browser), does not match this route
- $url = strtr($url, array('/../' => '/%2E%2E/', '/./' => '/%2E/'));
- if ('/..' === substr($url, -3)) {
- $url = substr($url, 0, -2) . '%2E%2E';
- }
- elseif ('/.' === substr($url, -2)) {
- $url = substr($url, 0, -1) . '%2E';
- }
- }
-
- // Add a query string if needed, including extra parameters.
+ // Add extra parameters to the query parameters.
$query_params += array_diff_key($parameters, $variables, $defaults);
- if ($query_params && $query = UrlHelper::buildQuery($query_params)) {
- $url .= '?' . $query;
- }
return $url;
}
@@ -251,9 +231,10 @@ class UrlGenerator implements UrlGeneratorInterface {
* $parameters merged in.
*
* @return string
- * The url path corresponding to the route, without the base path.
+ * The URL path corresponding to the route, without the base path, not URL
+ * encoded.
*/
- protected function getInternalPathFromRoute($name, SymfonyRoute $route, $parameters = array(), $query_params = array()) {
+ protected function getInternalPathFromRoute($name, SymfonyRoute $route, $parameters = array(), &$query_params = array()) {
// The Route has a cache of its own and is not recompiled as long as it does
// not get modified.
$compiledRoute = $route->compile();
@@ -274,15 +255,13 @@ class UrlGenerator implements UrlGeneratorInterface {
*/
public function generateFromRoute($name, $parameters = array(), $options = array(), $collect_bubbleable_metadata = FALSE) {
$options += array('prefix' => '');
+ if (!isset($options['query']) || !is_array($options['query'])) {
+ $options['query'] = array();
+ }
+
$route = $this->getRoute($name);
$generated_url = $collect_bubbleable_metadata ? new GeneratedUrl() : NULL;
- $query_params = [];
- // Symfony adds any parameters that are not path slugs as query strings.
- if (isset($options['query']) && is_array($options['query'])) {
- $query_params = $options['query'];
- }
-
$fragment = '';
if (isset($options['fragment'])) {
if (($fragment = trim($options['fragment'])) != '') {
@@ -292,7 +271,7 @@ class UrlGenerator implements UrlGeneratorInterface {
// Generate a relative URL having no path, just query string and fragment.
if ($route->getOption('_no_path')) {
- $query = $query_params ? '?' . http_build_query($query_params, '', '&') : '';
+ $query = $options['query'] ? '?' . UrlHelper::buildQuery($options['query']) : '';
$url = $query . $fragment;
return $collect_bubbleable_metadata ? $generated_url->setGeneratedUrl($url) : $url;
}
@@ -302,13 +281,32 @@ class UrlGenerator implements UrlGeneratorInterface {
$name = $this->getRouteDebugMessage($name);
$this->processRoute($name, $route, $parameters, $generated_url);
- $path = $this->getInternalPathFromRoute($name, $route, $parameters, $query_params);
+ $path = $this->getInternalPathFromRoute($name, $route, $parameters, $options['query']);
// Outbound path processors might need the route object for the path, e.g.
// to get the path pattern.
$options['route'] = $route;
if ($options['path_processing']) {
$path = $this->processPath($path, $options, $generated_url);
}
+ // The contexts base URL is already encoded
+ // (see Symfony\Component\HttpFoundation\Request).
+ $path = str_replace($this->decodedChars[0], $this->decodedChars[1], rawurlencode($path));
+
+ // Drupal paths rarely include dots, so skip this processing if possible.
+ if (strpos($path, '/.') !== FALSE) {
+ // the path segments "." and ".." are interpreted as relative reference when
+ // resolving a URI; see http://tools.ietf.org/html/rfc3986#section-3.3
+ // so we need to encode them as they are not used for this purpose here
+ // otherwise we would generate a URI that, when followed by a user agent
+ // (e.g. browser), does not match this route
+ $path = strtr($path, array('/../' => '/%2E%2E/', '/./' => '/%2E/'));
+ if ('/..' === substr($path, -3)) {
+ $path = substr($path, 0, -2) . '%2E%2E';
+ }
+ elseif ('/.' === substr($path, -2)) {
+ $path = substr($path, 0, -1) . '%2E';
+ }
+ }
if (!empty($options['prefix'])) {
$path = ltrim($path, '/');
@@ -316,6 +314,8 @@ class UrlGenerator implements UrlGeneratorInterface {
$path = '/' . str_replace('%2F', '/', rawurlencode($prefix)) . $path;
}
+ $query = $options['query'] ? '?' . UrlHelper::buildQuery($options['query']) : '';
+
// The base_url might be rewritten from the language rewrite in domain mode.
if (isset($options['base_url'])) {
$base_url = $options['base_url'];
@@ -329,7 +329,7 @@ class UrlGenerator implements UrlGeneratorInterface {
}
}
- $url = $base_url . $path . $fragment;
+ $url = $base_url . $path . $query . $fragment;
return $collect_bubbleable_metadata ? $generated_url->setGeneratedUrl($url) : $url;
}
@@ -337,7 +337,7 @@ class UrlGenerator implements UrlGeneratorInterface {
$absolute = !empty($options['absolute']);
if (!$absolute || !$host = $this->context->getHost()) {
- $url = $base_url . $path . $fragment;
+ $url = $base_url . $path . $query . $fragment;
return $collect_bubbleable_metadata ? $generated_url->setGeneratedUrl($url) : $url;
}
@@ -363,29 +363,16 @@ class UrlGenerator implements UrlGeneratorInterface {
if ($collect_bubbleable_metadata) {
$generated_url->addCacheContexts(['url.site']);
}
- $url = $scheme . '://' . $host . $port . $base_url . $path . $fragment;
+ $url = $scheme . '://' . $host . $port . $base_url . $path . $query . $fragment;
return $collect_bubbleable_metadata ? $generated_url->setGeneratedUrl($url) : $url;
-
}
/**
* Passes the path to a processor manager to allow alterations.
*/
protected function processPath($path, &$options = array(), BubbleableMetadata $bubbleable_metadata = NULL) {
- // Router-based paths may have a querystring on them.
- if ($query_pos = strpos($path, '?')) {
- // We don't need to do a strict check here because position 0 would mean we
- // have no actual path to work with.
- $actual_path = substr($path, 0, $query_pos);
- $query_string = substr($path, $query_pos);
- }
- else {
- $actual_path = $path;
- $query_string = '';
- }
- $path = $this->pathProcessor->processOutbound($actual_path === '/' ? $actual_path : rtrim($actual_path, '/'), $options, $this->requestStack->getCurrentRequest(), $bubbleable_metadata);
- $path .= $query_string;
- return $path;
+ $actual_path = $path === '/' ? $path : rtrim($path, '/');
+ return $this->pathProcessor->processOutbound($actual_path, $options, $this->requestStack->getCurrentRequest(), $bubbleable_metadata);
}
/**
diff --git a/core/lib/Drupal/Core/Routing/UrlGeneratorInterface.php b/core/lib/Drupal/Core/Routing/UrlGeneratorInterface.php
index 70829cd..b2b8196 100644
--- a/core/lib/Drupal/Core/Routing/UrlGeneratorInterface.php
+++ b/core/lib/Drupal/Core/Routing/UrlGeneratorInterface.php
@@ -21,7 +21,8 @@ interface UrlGeneratorInterface extends VersatileGeneratorInterface {
* \Symfony\Component\Routing\Generator\UrlGeneratorInterface::generate().
*
* @return string
- * The internal Drupal path corresponding to the route.
+ * The internal Drupal path corresponding to the route. This string is
+ * not urlencoded and will be an empty string for the front page.
*/
public function getPathFromRoute($name, $parameters = array());