Skip to content

Commit 9621e59

Browse files
authored
Merge pull request rails#54484 from etiennebarrie/optimize-json-escape
Optimize JSON escaping
2 parents 8d4cbef + 75b4380 commit 9621e59

File tree

1 file changed

+24
-12
lines changed

1 file changed

+24
-12
lines changed

activesupport/lib/active_support/json/encoding.rb

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,20 @@ def encode(value, options = nil)
3030
end
3131

3232
module Encoding # :nodoc:
33+
U2028 = -"\u2028".b
34+
U2029 = -"\u2029".b
35+
36+
ESCAPED_CHARS = {
37+
U2028 => '\u2028'.b,
38+
U2029 => '\u2029'.b,
39+
">".b => '\u003e'.b,
40+
"<".b => '\u003c'.b,
41+
"&".b => '\u0026'.b,
42+
}
43+
44+
ESCAPE_REGEX_WITH_HTML_ENTITIES = Regexp.union(*ESCAPED_CHARS.keys)
45+
ESCAPE_REGEX_WITHOUT_HTML_ENTITIES = Regexp.union(U2028, U2029)
46+
3347
class JSONGemEncoder # :nodoc:
3448
attr_reader :options
3549

@@ -47,14 +61,13 @@ def encode(value)
4761
# Rails does more escaping than the JSON gem natively does (we
4862
# escape \u2028 and \u2029 and optionally >, <, & to work around
4963
# certain browser problems).
64+
json.force_encoding(::Encoding::BINARY)
5065
if @options.fetch(:escape_html_entities, Encoding.escape_html_entities_in_json)
51-
json.gsub!(">", '\u003e')
52-
json.gsub!("<", '\u003c')
53-
json.gsub!("&", '\u0026')
66+
json.gsub!(ESCAPE_REGEX_WITH_HTML_ENTITIES, ESCAPED_CHARS)
67+
else
68+
json.gsub!(ESCAPE_REGEX_WITHOUT_HTML_ENTITIES, ESCAPED_CHARS)
5469
end
55-
json.gsub!("\u2028", '\u2028')
56-
json.gsub!("\u2029", '\u2029')
57-
json
70+
json.force_encoding(::Encoding::UTF_8)
5871
end
5972

6073
private
@@ -130,14 +143,13 @@ def encode(value)
130143
# Rails does more escaping than the JSON gem natively does (we
131144
# escape \u2028 and \u2029 and optionally >, <, & to work around
132145
# certain browser problems).
146+
json.force_encoding(::Encoding::BINARY)
133147
if @options.fetch(:escape_html_entities, Encoding.escape_html_entities_in_json)
134-
json.gsub!(">", '\u003e')
135-
json.gsub!("<", '\u003c')
136-
json.gsub!("&", '\u0026')
148+
json.gsub!(ESCAPE_REGEX_WITH_HTML_ENTITIES, ESCAPED_CHARS)
149+
else
150+
json.gsub!(ESCAPE_REGEX_WITHOUT_HTML_ENTITIES, ESCAPED_CHARS)
137151
end
138-
json.gsub!("\u2028", '\u2028')
139-
json.gsub!("\u2029", '\u2029')
140-
json
152+
json.force_encoding(::Encoding::UTF_8)
141153
end
142154
end
143155
end

0 commit comments

Comments
 (0)