ERB::Util.html_escape_once always returns an html_safe string

This method previously maintained the `html_safe?` property of a string on the return
value. Because this string has been escaped, however, not marking it as `html_safe` causes
entities to be double-escaped.

As an example, take this view snippet:

  ```html
  <p><%= html_escape_once("this & that &amp; the other") %></p>
  ```

Before this change, that would be double-escaped and render as:

  ```html
  <p>this &amp;amp; that &amp;amp; the other</p>
  ```

After this change, it renders correctly as:

  ```html
  <p>this &amp; that &amp; the other</p>
  ```

[Fix #48256]
This commit is contained in:
Mike Dalessio 2023-05-20 13:30:01 -04:00 committed by Jean Boussier
parent a3587cd6f9
commit aea8849821
3 changed files with 31 additions and 4 deletions

@ -103,9 +103,9 @@ def test_html_escape_once
assert_equal " &#X27; &#x27; &#x03BB; &#X03bb; &quot; &#39; &lt; &gt; ", html_escape_once(" &#X27; &#x27; &#x03BB; &#X03bb; \" ' < > ")
end
def test_html_escape_once_returns_unsafe_strings_when_passed_unsafe_strings
def test_html_escape_once_returns_safe_strings_when_passed_unsafe_strings
value = html_escape_once("1 < 2 &amp; 3")
assert_not_predicate value, :html_safe?
assert_predicate value, :html_safe?
end
def test_html_escape_once_returns_safe_strings_when_passed_safe_strings

@ -1,3 +1,31 @@
* `ERB::Util.html_escape_once` always returns an `html_safe` string.
This method previously maintained the `html_safe?` property of a string on the return
value. Because this string has been escaped, however, not marking it as `html_safe` causes
entities to be double-escaped.
As an example, take this view snippet:
```html
<p><%= html_escape_once("this & that &amp; the other") %></p>
```
Before this change, that would be double-escaped and render as:
```html
<p>this &amp;amp; that &amp;amp; the other</p>
```
After this change, it renders correctly as:
```html
<p>this &amp; that &amp; the other</p>
```
Fixes #48256
*Mike Dalessio*
* Deprecate `SafeBuffer#clone_empty`.
This method has not been used internally since Rails 4.2.0.

@ -63,8 +63,7 @@ module Util
# html_escape_once('&lt;&lt; Accept & Checkout')
# # => "&lt;&lt; Accept &amp; Checkout"
def html_escape_once(s)
result = ActiveSupport::Multibyte::Unicode.tidy_bytes(s.to_s).gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE)
s.html_safe? ? result.html_safe : result
ActiveSupport::Multibyte::Unicode.tidy_bytes(s.to_s).gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE).html_safe
end
module_function :html_escape_once