Commit 87e675f0 authored by alexpott's avatar alexpott

Issue #1825952 by Fabianx, joelpittet, bdragon, heddn, chx, xjm, pwolanin,...

Issue #1825952 by Fabianx, joelpittet, bdragon, heddn, chx, xjm, pwolanin, mikey_p, ti2m, bfr, dags, cilefen, scor, mgifford: Turn on twig autoescape by default
parent 256b1971
......@@ -14,6 +14,7 @@
* @see batch_get()
*/
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Timer;
use Drupal\Core\Batch\Percentage;
use Drupal\Core\Page\DefaultHtmlPageRenderer;
......@@ -44,7 +45,12 @@ function _batch_page(Request $request) {
return new RedirectResponse(url('<front>', array('absolute' => TRUE)));
}
}
// Restore safe strings from previous batches.
// @todo Ensure we are not storing an excessively large string list in:
// https://www.drupal.org/node/2295823
if (!empty($batch['safe_strings'])) {
SafeMarkup::setMultiple($batch['safe_strings']);
}
// Register database update for the end of processing.
drupal_register_shutdown_function('_batch_shutdown');
......@@ -481,6 +487,10 @@ function _batch_finished() {
*/
function _batch_shutdown() {
if ($batch = batch_get()) {
// Update safe strings.
// @todo Ensure we are not storing an excessively large string list in:
// https://www.drupal.org/node/2295823
$batch['safe_strings'] = SafeMarkup::getAll();
\Drupal::service('batch.storage')->update($batch);
}
}
......@@ -7,6 +7,7 @@
use Drupal\Component\Datetime\DateTimePlus;
use Drupal\Component\Utility\Crypt;
use Drupal\Component\Utility\Environment;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\String;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\DrupalKernel;
......@@ -888,8 +889,27 @@ function watchdog($type, $message, array $variables = array(), $severity = WATCH
*
* @return array|null
* A multidimensional array with keys corresponding to the set message types.
* The indexed array values of each contain the set messages for that type.
* Or, if there are no messages set, the function returns NULL.
* The indexed array values of each contain the set messages for that type,
* and each message is an associative array with the following format:
* - safe: Boolean indicating whether the message string has been marked as
* safe. Non-safe strings will be escaped automatically.
* - message: The message string.
* So, the following is an example of the full return array structure:
* @code
* array(
* 'status' => array(
* array(
* 'safe' => TRUE,
* 'message' => 'A <em>safe</em> markup string.',
* ),
* array(
* 'safe' => FALSE,
* 'message' => "$arbitrary_user_input to escape.",
* ),
* ),
* );
* @endcode
* If there are no messages set, the function returns NULL.
*
* @see drupal_get_messages()
* @see theme_status_messages()
......@@ -901,7 +921,10 @@ function drupal_set_message($message = NULL, $type = 'status', $repeat = FALSE)
}
if ($repeat || !in_array($message, $_SESSION['messages'][$type])) {
$_SESSION['messages'][$type][] = $message;
$_SESSION['messages'][$type][] = array(
'safe' => SafeMarkup::isSafe($message),
'message' => $message,
);
}
// Mark this page as being uncacheable.
......@@ -928,17 +951,25 @@ function drupal_set_message($message = NULL, $type = 'status', $repeat = FALSE)
* intact. Defaults to TRUE.
*
* @return array
* A multidimensional array with keys corresponding to the set message types.
* The indexed array values of each contain the set messages for that type.
* The messages returned are limited to the type specified in the $type
* parameter. If there are no messages of the specified type, an empty array
* is returned.
* An associative, nested array of messages grouped by message type, with
* the top-level keys as the message type. The messages returned are
* limited to the type specified in the $type parameter, if any. If there
* are no messages of the specified type, an empty array is returned. See
* drupal_set_message() for the array structure of indivdual messages.
*
* @see drupal_set_message()
* @see theme_status_messages()
*/
function drupal_get_messages($type = NULL, $clear_queue = TRUE) {
if ($messages = drupal_set_message()) {
foreach ($messages as $message_type => $message_typed_messages) {
foreach ($message_typed_messages as $key => $message) {
if ($message['safe']) {
$message['message'] = SafeMarkup::set($message['message']);
}
$messages[$message_type][$key] = $message['message'];
}
}
if ($type) {
if ($clear_queue) {
unset($_SESSION['messages'][$type]);
......
......@@ -14,6 +14,7 @@
use Drupal\Component\Utility\Bytes;
use Drupal\Component\Utility\Crypt;
use Drupal\Component\Utility\Number;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\SortArray;
use Drupal\Component\Utility\String;
use Drupal\Component\Utility\Tags;
......@@ -442,11 +443,15 @@ function format_rss_item($title, $link, $description, $args = array()) {
/**
* Formats XML elements.
*
* Note: It is the caller's responsibility to sanitize any input parameters.
* This function does not perform sanitization.
*
* @param $array
* An array where each item represents an element and is either a:
* - (key => value) pair (<key>value</key>)
* - Associative array with fields:
* - 'key': element name
* - 'key': The element name. Element names are not sanitized, so do not
* pass user input.
* - 'value': element contents
* - 'attributes': associative array of element attributes
*
......@@ -475,7 +480,11 @@ function format_xml_elements($array) {
$output .= ' <' . $key . '>' . (is_array($value) ? format_xml_elements($value) : String::checkPlain($value)) . "</$key>\n";
}
}
return $output;
// @todo This is marking the output string as safe HTML, but we have only
// sanitized the attributes and tag values, not the tag names, and we
// cannot guarantee the assembled markup is safe. Consider a fix in:
// https://www.drupal.org/node/2296885
return SafeMarkup::set($output);
}
/**
......@@ -859,8 +868,7 @@ function l($text, $path, array $options = array()) {
// Sanitize the link text if necessary.
$text = $variables['options']['html'] ? $variables['text'] : String::checkPlain($variables['text']);
return '<a href="' . $url . '"' . $attributes . '>' . $text . '</a>';
return SafeMarkup::set('<a href="' . $url . '"' . $attributes . '>' . $text . '</a>');
}
/**
......@@ -2640,12 +2648,17 @@ function drupal_pre_render_conditional_comments($elements) {
/**
* Pre-render callback: Renders a generic HTML tag with attributes into #markup.
*
* Note: It is the caller's responsibility to sanitize any input parameters.
* This callback does not perform sanitization.
*
* @param array $element
* An associative array containing:
* - #tag: The tag name to output. Typical tags added to the HTML HEAD:
* - meta: To provide meta information, such as a page refresh.
* - link: To refer to stylesheets and other contextual information.
* - script: To load JavaScript.
* The value of #tag is not escaped or sanitized, so do not pass in user
* input.
* - #attributes: (optional) An array of HTML attributes to apply to the
* tag.
* - #value: (optional) A string containing tag content, such as inline
......@@ -2658,7 +2671,11 @@ function drupal_pre_render_conditional_comments($elements) {
function drupal_pre_render_html_tag($element) {
$attributes = isset($element['#attributes']) ? new Attribute($element['#attributes']) : '';
if (!isset($element['#value'])) {
$markup = '<' . $element['#tag'] . $attributes . " />\n";
// This function is intended for internal use, so we assume that no unsafe
// values are passed in #tag. The attributes are already safe because
// Attribute output is already automatically sanitized.
// @todo Escape this properly instead? https://www.drupal.org/node/2296101
$markup = SafeMarkup::set('<' . $element['#tag'] . $attributes . " />\n");
}
else {
$markup = '<' . $element['#tag'] . $attributes . '>';
......@@ -2670,6 +2687,9 @@ function drupal_pre_render_html_tag($element) {
$markup .= $element['#value_suffix'];
}
$markup .= '</' . $element['#tag'] . ">\n";
// @todo We cannot actually guarantee this markup is safe. Consider a fix
// in: https://www.drupal.org/node/2296101
$markup = SafeMarkup::set($markup);
}
if (!empty($element['#noscript'])) {
$element['#markup'] = '<noscript>' . $markup . '</noscript>';
......@@ -3109,6 +3129,7 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
if (!$is_recursive_call) {
_drupal_render_process_post_render_cache($elements);
}
$elements['#markup'] = SafeMarkup::set($elements['#markup']);
return $elements['#markup'];
}
}
......@@ -3161,6 +3182,11 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
$elements['#children'] = '';
}
// @todo Simplify after https://drupal.org/node/2273925
if (isset($elements['#markup'])) {
$elements['#markup'] = SafeMarkup::set($elements['#markup']);
}
// Assume that if #theme is set it represents an implemented hook.
$theme_is_implemented = isset($elements['#theme']);
......@@ -3184,6 +3210,7 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
foreach ($children as $key) {
$elements['#children'] .= drupal_render($elements[$key], TRUE);
}
$elements['#children'] = SafeMarkup::set($elements['#children']);
}
// If #theme is not implemented and the element has raw #markup as a
......@@ -3194,7 +3221,7 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
// required. Eventually #theme_wrappers will expect both #markup and
// #children to be a single string as #children.
if (!$theme_is_implemented && isset($elements['#markup'])) {
$elements['#children'] = $elements['#markup'] . $elements['#children'];
$elements['#children'] = SafeMarkup::set($elements['#markup'] . $elements['#children']);
}
// Let the theme functions in #theme_wrappers add markup around the rendered
......@@ -3284,6 +3311,7 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
}
$elements['#printed'] = TRUE;
$elements['#markup'] = SafeMarkup::set($elements['#markup']);
return $elements['#markup'];
}
......@@ -3311,7 +3339,7 @@ function drupal_render_children(&$element, $children_keys = NULL) {
$output .= drupal_render($element[$key]);
}
}
return $output;
return SafeMarkup::set($output);
}
/**
......
......@@ -5,10 +5,10 @@
* Functions for error handling.
*/
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Page\DefaultHtmlPageRenderer;
use Drupal\Core\Utility\Error;
use Drupal\Component\Utility\String;
use Symfony\Component\HttpFoundation\Response;
/**
......@@ -212,7 +212,7 @@ function _drupal_log_error($error, $fatal = FALSE) {
// Generate a backtrace containing only scalar argument values.
$message .= '<pre class="backtrace">' . Error::formatBacktrace($backtrace) . '</pre>';
}
drupal_set_message($message, $class, TRUE);
drupal_set_message(SafeMarkup::set($message), $class, TRUE);
}
if ($fatal) {
......
......@@ -7,6 +7,7 @@
use Drupal\Component\Utility\NestedArray;
use Drupal\Component\Utility\Number;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\String;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Component\Utility\Xss;
......@@ -907,7 +908,7 @@ function form_select_options($element, $choices = NULL) {
$options .= '<option value="' . String::checkPlain($key) . '"' . $selected . '>' . String::checkPlain($choice) . '</option>';
}
}
return $options;
return SafeMarkup::set($options);
}
/**
......@@ -1575,7 +1576,7 @@ function theme_tableselect($variables) {
// A header can span over multiple cells and in this case the cells
// are passed in an array. The order of this array determines the
// order in which they are added.
if (!isset($element['#options'][$key][$fieldname]['data']) && is_array($element['#options'][$key][$fieldname])) {
if (is_array($element['#options'][$key][$fieldname]) && !isset($element['#options'][$key][$fieldname]['data'])) {
foreach ($element['#options'][$key][$fieldname] as $cell) {
$row['data'][] = $cell;
}
......@@ -1921,13 +1922,13 @@ function form_process_machine_name($element, &$form_state) {
$element['#machine_name']['suffix'] = '#' . $suffix_id;
if ($element['#machine_name']['standalone']) {
$element['#suffix'] .= ' <small id="' . $suffix_id . '">&nbsp;</small>';
$element['#suffix'] = SafeMarkup::set($element['#suffix'] . ' <small id="' . $suffix_id . '">&nbsp;</small>');
}
else {
// Append a field suffix to the source form element, which will contain
// the live preview of the machine name.
$source += array('#field_suffix' => '');
$source['#field_suffix'] .= ' <small id="' . $suffix_id . '">&nbsp;</small>';
$source['#field_suffix'] = SafeMarkup::set($source['#field_suffix'] . ' <small id="' . $suffix_id . '">&nbsp;</small>');
$parents = array_merge($element['#machine_name']['source'], array('#field_suffix'));
NestedArray::setValue($form_state['complete_form'], $parents, $source['#field_suffix']);
......@@ -3104,6 +3105,8 @@ function _form_set_attributes(&$element, $class = array()) {
* - css: Array of paths to CSS files to be used on the progress page.
* - url_options: options passed to url() when constructing redirect URLs for
* the batch.
* - safe_strings: Internal use only. Used to store and retrieve strings
* marked as safe between requests.
*/
function batch_set($batch_definition) {
if ($batch_definition) {
......@@ -3227,6 +3230,11 @@ function batch_process($redirect = NULL, $url = 'batch', $redirect_callback = NU
$request->query->remove('destination');
}
// Store safe strings.
// @todo Ensure we are not storing an excessively large string list in:
// https://www.drupal.org/node/2295823
$batch['safe_strings'] = SafeMarkup::getAll();
// Store the batch.
\Drupal::service('batch.storage')->create($batch);
......
<?php
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\DrupalKernel;
use Drupal\Core\Config\BootstrapConfigStorageFactory;
......@@ -1707,10 +1708,10 @@ function install_finished(&$install_state) {
// @todo Temporary hack to satisfy PIFR.
// @see https://drupal.org/node/1317548
$pifr_assertion = '<span style="display: none;">Drupal installation complete</span>';
drupal_set_message(t('Congratulations, you installed @drupal!', array(
$success_message = t('Congratulations, you installed @drupal!', array(
'@drupal' => drupal_install_profile_distribution_name(),
)) . $pifr_assertion);
));
drupal_set_message(SafeMarkup::set($success_message . $pifr_assertion));
}
/**
......
......@@ -8,6 +8,7 @@
* customized by user themes.
*/
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\String;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Component\Utility\Xss;
......@@ -584,7 +585,7 @@ function _theme($hook, $variables = array()) {
$output = '';
if (isset($info['function'])) {
if (function_exists($info['function'])) {
$output = $info['function']($variables);
$output = SafeMarkup::set($info['function']($variables));
}
}
else {
......@@ -2003,7 +2004,7 @@ function template_preprocess_html(&$variables) {
// Construct page title.
if ($page->hasTitle()) {
$head_title = array(
'title' => trim(strip_tags($page->getTitle())),
'title' => SafeMarkup::set(trim(strip_tags($page->getTitle()))),
'name' => String::checkPlain($site_config->get('name')),
);
}
......@@ -2023,7 +2024,13 @@ function template_preprocess_html(&$variables) {
}
$variables['head_title_array'] = $head_title;
$variables['head_title'] = implode(' | ', $head_title);
$output = '';
$separator = '';
foreach ($head_title as $item) {
$output .= $separator . SafeMarkup::escape($item);
$separator = ' | ';
}
$variables['head_title'] = SafeMarkup::set($output);
// @todo Remove drupal_*_html_head() and refactor accordingly.
$html_heads = drupal_get_html_head(FALSE);
......
......@@ -110,6 +110,8 @@ function _drupal_maintenance_theme() {
* @param $variables
* An associative array containing:
* - items: An associative array of maintenance tasks.
* It's the caller's responsibility to ensure this array's items contain no
* dangerous HTML such as SCRIPT tags.
* - active: The key for the currently active maintenance task.
*
* @ingroup themeable
......@@ -187,6 +189,8 @@ function theme_authorize_report($variables) {
* @param $variables
* An associative array containing:
* - message: The log message.
* It's the caller's responsibility to ensure this string contains no
* dangerous HTML such as SCRIPT tags.
* - success: A boolean indicating failure or success.
*
* @ingroup themeable
......
......@@ -4,6 +4,7 @@
use Drupal\Component\Utility\String;
use Drupal\Component\Utility\Unicode;
use Drupal\Component\Utility\SafeMarkup;
/**
* Additions by Axel Boldt follow, partly taken from diff.php, phpwiki-1.3.3
......@@ -46,7 +47,9 @@ protected function _flushGroup($new_tag) {
protected function _flushLine($new_tag) {
$this->_flushGroup($new_tag);
if ($this->line != '') {
array_push($this->lines, $this->line);
// @todo This is probably not the right place to do this. To be
// addressed in https://drupal.org/node/2280963
array_push($this->lines, SafeMarkup::set($this->line));
}
else {
// make empty lines visible by inserting an NBSP
......
<?php
/**
* @file
* Contains \Drupal\Component\Utility\SafeMarkup.
*/
namespace Drupal\Component\Utility;
/**
* Manages known safe strings for rendering at the theme layer.
*
* The Twig theme engine autoescapes string variables in the template, so it
* is possible for a string of markup to become double-escaped. SafeMarkup
* provides a store for known safe strings and methods to manage them
* throughout the page request.
*
* Strings sanitized by String::checkPlain() or Xss::filter() are automatically
* marked safe, as are markup strings created from render arrays via
* drupal_render().
*
* This class should be limited to internal use only. Module developers should
* instead use the appropriate
* @link sanitization sanitization functions @endlink or the
* @link theme_render theme and render systems @endlink so that the output can
* can be themed, escaped, and altered properly.
*
* @see twig_drupal_escape_filter()
* @see twig_render_template()
* @see sanitization
* @see theme_render
*/
class SafeMarkup {
/**
* The list of safe strings.
*
* @var array
*/
protected static $safeStrings = array();
/**
* Adds a string to a list of strings marked as secure.
*
* This method is for internal use. Do not use it to prevent escaping of
* markup; instead, use the appropriate
* @link sanitization sanitization functions @endlink or the
* @link theme_render theme and render systems @endlink so that the output
* can be themed, escaped, and altered properly.
*
* This marks strings as secure for the entire page render, not just the code
* or element that set it. Therefore, only valid HTML should be
* marked as safe (never partial markup). For example, you should never do:
* @code
* SafeMarkup::set("<");
* @endcode
* or:
* @code
* SafeMarkup::set('<script>');
* @endcode
*
* @param string $string
* The content to be marked as secure.
* @param string $strategy
* The escaping strategy used for this string. Two values are supported
* by default:
* - 'html': (default) The string is safe for use in HTML code.
* - 'all': The string is safe for all use cases.
* See the
* @link http://twig.sensiolabs.org/doc/filters/escape.html Twig escape documentation @endlink
* for more information on escaping strategies in Twig.
*
* @return string
* The input string that was marked as safe.
*/
public static function set($string, $strategy = 'html') {
$string = (string) $string;
static::$safeStrings[$string][$strategy] = TRUE;
return $string;
}
/**
* Checks if a string is safe to output.
*
* @param string $string
* The content to be checked.
* @param string $strategy
* The escaping strategy. See SafeMarkup::set(). Defaults to 'html'.
*
* @return bool
* TRUE if the string has been marked secure, FALSE otherwise.
*/
public static function isSafe($string, $strategy = 'html') {
return isset(static::$safeStrings[(string) $string][$strategy]) ||
isset(static::$safeStrings[(string) $string]['all']);
}
/**
* Adds previously retrieved known safe strings to the safe string list.
*
* This is useful for the batch and form APIs, where it is important to
* preserve the safe markup state across page requests. The strings will be
* added to any safe strings already marked for the current request.
*
* @param array $safe_strings
* A list of safe strings as previously retrieved by SafeMarkup::getAll().
*
* @throws \UnexpectedValueException
*/
public static function setMultiple(array $safe_strings) {
foreach ($safe_strings as $string => $strategies) {
foreach ($strategies as $strategy => $value) {
$string = (string) $string;
if ($value === TRUE) {
static::$safeStrings[$string][$strategy] = TRUE;
}
else {
// Danger - something is very wrong.
throw new \UnexpectedValueException('Only the value TRUE is accepted for safe strings');
}
}
}
}
/**
* Encodes special characters in a plain-text string for display as HTML.
*
* @param $string
* A string.
*
* @return string
* The escaped string. If $string was already set as safe with
* SafeString::set, it won't be escaped again.
*/
public static function escape($string) {
return static::isSafe($string) ? $string : String::checkPlain($string);
}
/**
* Retrieves all strings currently marked as safe.
*
* This is useful for the batch and form APIs, where it is important to
* preserve the safe markup state across page requests.
*
* @return array
* Returns all strings currently marked safe.
*/
public static function getAll() {
return static::$safeStrings;
}
}
......@@ -17,7 +17,8 @@ class String {
/**
* Encodes special characters in a plain-text string for display as HTML.
*
* Also validates strings as UTF-8.
* Also validates strings as UTF-8. All processed strings are also
* automatically flagged as safe markup strings for rendering.
*
* @param string $text
* The text to be checked or processed.
......@@ -29,9 +30,10 @@ class String {
* @ingroup sanitization
*
* @see drupal_validate_utf8()
* @see \Drupal\Component\Utility\SafeMarkup
*/
public static function checkPlain($text) {
return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
return SafeMarkup::set(htmlspecialchars($text, ENT_QUOTES, 'UTF-8'));
}
/**
......@@ -65,7 +67,8 @@ public static function decodeEntities($text) {
* addition to formatting it.
*
* @param $string
* A string containing placeholders.
* A string containing placeholders. The string itself is not escaped, any
* unsafe content must be in $args and inserted via placeholders.
* @param $args
* An associative array of replacements to make. Occurrences in $string of
* any key in $args are replaced with the corresponding value, after
......@@ -111,7 +114,7 @@ public static function format($string, array $args = array()) {
// Pass-through.
}
}
return strtr($string, $args);
return SafeMarkup::set(strtr($string, $args));
}
/**
......@@ -126,7 +129,8 @@ public static function format($string, array $args = array()) {
* The formatted text (html).
*/
public static function placeholder($text) {
return '<em class="placeholder">' . static::checkPlain($text) . '</em>';
return SafeMarkup::set('<em class="placeholder">' . static::checkPlain($text) . '</em>');
}
}
......@@ -41,12 +41,14 @@ class Xss {
* Based on kses by Ulf Harnhammar, see http://sourceforge.net/projects/kses.
* For examples of various XSS attacks, see: http://ha.ckers.org/xss.html.
*
* This code does four things:
* This code does five things:
* - Removes characters and constructs that can trick browsers.
* - Makes sure all HTML entities are well-formed.
* - Makes sure all HTML tags and attributes are well-formed.
* - Makes sure no HTML tags contain URLs with a disallowed protocol (e.g.
* javascript:).
* - Marks the sanitized, XSS-safe version of $string as safe markup for
* rendering.
*
* @param $string
* The string with raw HTML in it. It will be stripped of everything that
......@@ -63,6 +65,7 @@ class Xss {
* valid UTF-8.
*
* @see \Drupal\Component\Utility\Unicode::validateUtf8()
* @see \Drupal\Component\Utility\SafeMarkup
*
* @ingroup sanitization
*/
......@@ -90,7 +93,7 @@ public static function filter($string, $html_tags = array('a', 'em', 'strong', '
$splitter = function ($matches) use ($html_tags, $mode) {
return static::split($matches[1], $html_tags, $mode);
};
return preg_replace_callback('%
return SafeMarkup::set(preg_replace_callback('%
(
<(?=[^a-zA-Z!/]) # a lone <
| # or
......@@ -99,7 +102,7 @@ public static function filter($string, $html_tags = array('a', 'em', 'strong', '
<[^>]*(>|$) # a string that starts with a <, up until the > or the end of the string
| # or
> # just a >
)%x', $splitter, $string);
)%x', $splitter, $string));
}
/**
......
......@@ -17,6 +17,7 @@
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\String;
use Symfony\Component\Debug\Exception\FlattenException;
use Drupal\Core\ContentNegotiation;
......@@ -316,7 +317,7 @@ public function on500Html(FlattenException $exception, Request $request) {
// Generate a backtrace containing only scalar argument values.
$message .= '<pre class="backtrace">' . Error::formatFlattenedBacktrace($backtrace) . '</pre>';
}
drupal_set_message($message, $class, TRUE);
drupal_set_message(SafeMarkup::set($message), $class, TRUE);
}
$content = $this->t('The website has encountered an error. Please try again later.');
......
......@@ -90,9 +90,7 @@ public static function registerTwig(ContainerBuilder $container) {
// When in the installer, twig_cache must be FALSE until we know the