diff --git a/core/modules/views/src/Plugin/views/row/RssFields.php b/core/modules/views/src/Plugin/views/row/RssFields.php index 9a31a028f0..2960647b03 100644 --- a/core/modules/views/src/Plugin/views/row/RssFields.php +++ b/core/modules/views/src/Plugin/views/row/RssFields.php @@ -139,9 +139,7 @@ public function render($row) { // Create the RSS item object. $item = new \stdClass(); $item->title = $this->getField($row_index, $this->options['title_field']); - // @todo Views should expect and store a leading /. See: - // https://www.drupal.org/node/2423913 - $item->link = Url::fromUserInput('/' . $this->getField($row_index, $this->options['link_field']))->setAbsolute()->toString(); + $item->link = $this->getFieldUrl($this->getField($row_index, $this->options['link_field']))->setAbsolute()->toString(); $field = $this->getField($row_index, $this->options['description_field']); $item->description = is_array($field) ? $field : ['#markup' => $field]; @@ -158,9 +156,7 @@ public function render($row) { $item_guid = $this->getField($row_index, $this->options['guid_field_options']['guid_field']); if ($this->options['guid_field_options']['guid_field_is_permalink']) { $guid_is_permalink_string = 'true'; - // @todo Enforce GUIDs as system-generated rather than user input? See - // https://www.drupal.org/node/2430589. - $item_guid = Url::fromUserInput('/' . $item_guid)->setAbsolute()->toString(); + $item_guid = $this->getFieldUrl($item_guid)->setAbsolute()->toString(); } $item->elements[] = [ 'key' => 'guid', @@ -207,4 +203,42 @@ public function getField($index, $field_id) { return $this->view->style_plugin->getField($index, $field_id); } + /** + * Retrieves a URL from a field value. + * + * @param string $field_value + * The field value retrieved with RssFields::getField(). + * + * @return \Drupal\Core\Url + * The URL object built from the field value. + */ + protected function getFieldUrl($field_value) { + // @todo Views should expect and store a leading /. See: + // https://www.drupal.org/node/2423913 + return Url::fromUserInput($this->sanitizeUrlField($field_value)); + } + + /** + * Retrieves a URL from a field value. + * + * @param string $field_value + * The field value retrieved with RssFields::getField(). + * + * @return string + * Sanitized user input for URL field. + */ + protected function sanitizeUrlField($field_value) { + global $base_path; + + $value = rawurldecode($field_value); + + // Url::fromUserInput expects the argument to be an internal path, so the + // base path should be stripped if it's there. + if (substr($value, 0, strlen($base_path)) === $base_path) { + $value = substr($value, strlen($base_path)); + } + + return '/' . $value; + } + } diff --git a/core/modules/views/tests/modules/views_test_formatter/src/Plugin/RssFieldsWrapper.php b/core/modules/views/tests/modules/views_test_formatter/src/Plugin/RssFieldsWrapper.php new file mode 100644 index 0000000000..ab615072aa --- /dev/null +++ b/core/modules/views/tests/modules/views_test_formatter/src/Plugin/RssFieldsWrapper.php @@ -0,0 +1,16 @@ +sanitizeUrlField($link); + } + +} diff --git a/core/modules/views/tests/src/Kernel/SanitizeUrlFieldTest.php b/core/modules/views/tests/src/Kernel/SanitizeUrlFieldTest.php new file mode 100644 index 0000000000..542e118034 --- /dev/null +++ b/core/modules/views/tests/src/Kernel/SanitizeUrlFieldTest.php @@ -0,0 +1,28 @@ +testRssLink('/'); + $this->assertTrue(substr($result, 0, 1) === '/', 'Link starts with slash'); + $this->assertTrue(substr($result, 0, 2) !== '//', 'Link starts with only one slash'); + } + +}