Commit f4ad770
committed
Allow GCI.escapeHTML to take a custom escape table
In some cases you may want to escape a string in a different way than
the default behavior.
For instance, if you are trying to make some JSON save to include
in a `<script>` tag, you may want to escape less, and using JavaScript
codepoints:
```ruby
>> CGI.escapeHTML('Hello </script>', ">" => '\u003e', "<" => '\u003c', "&" => '\u0026')
=> "Hello \\u003c/script\\u003e"
```
Of course you can always use `gsub` for that, but `CGI.escapeHTML` being
specialized is able to be very significantly faster:
```
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin23]
Warming up --------------------------------------
gsub 82.135k i/100ms
escapeHTML 221.405k i/100ms
Calculating -------------------------------------
gsub 821.890k (± 2.2%) i/s (1.22 μs/i) - 4.189M in 5.099152s
escapeHTML 2.330M (± 0.5%) i/s (429.22 ns/i) - 11.734M in 5.036770s
Comparison:
escapeHTML: 2329816.5 i/s
gsub: 821889.7 i/s - 2.83x slower
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +YJIT +PRISM [arm64-darwin23]
Warming up --------------------------------------
gsub 36.235k i/100ms
escapeHTML 171.347k i/100ms
Calculating -------------------------------------
gsub 359.528k (± 1.5%) i/s (2.78 μs/i) - 1.812M in 5.040422s
escapeHTML 1.812M (± 0.7%) i/s (551.84 ns/i) - 9.081M in 5.011762s
Comparison:
escapeHTML: 1812105.3 i/s
gsub: 359527.5 i/s - 5.04x slower
```
```ruby
require "benchmark/ips"
require "cgi"
ESCAPE = {
">" => '\u003e', "<" => '\u003c', "&" => '\u0026',
}
ESCAPE_B = {
">".b => '\u003e'.b,
"<".b => '\u003c'.b,
"&".b => '\u0026'.b,
}
ESCAPE_REGEX = Regexp.union(ESCAPE_B.keys)
str = ("a" * 1024).freeze
Benchmark.ips do |x|
x.report("gsub") do
b = str.b
b.gsub!(ESCAPE_REGEX, ESCAPE_B)
b.force_encoding(str.encoding)
end
x.report("escapeHTML") do
CGI.escapeHTML(str, ESCAPE)
end
x.compare!
end
str = (("a" * 1023) + "<").freeze
Benchmark.ips do |x|
x.report("gsub") do
b = str.b
b.gsub!(ESCAPE_REGEX, ESCAPE_B)
b.force_encoding(str.encoding)
end
x.report("escapeHTML") do
CGI.escapeHTML(str, ESCAPE)
end
x.compare!
end
```1 parent bbfac89 commit f4ad770
3 files changed
Lines changed: 148 additions & 13 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
36 | | - | |
| 36 | + | |
37 | 37 | | |
38 | 38 | | |
39 | | - | |
40 | | - | |
| 39 | + | |
| 40 | + | |
41 | 41 | | |
42 | | - | |
| 42 | + | |
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
50 | | - | |
| 50 | + | |
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
| |||
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
78 | 158 | | |
79 | 159 | | |
80 | 160 | | |
| |||
331 | 411 | | |
332 | 412 | | |
333 | 413 | | |
334 | | - | |
| 414 | + | |
335 | 415 | | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
336 | 419 | | |
337 | 420 | | |
338 | 421 | | |
339 | | - | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
340 | 429 | | |
341 | 430 | | |
342 | | - | |
| 431 | + | |
343 | 432 | | |
344 | 433 | | |
345 | 434 | | |
| |||
474 | 563 | | |
475 | 564 | | |
476 | 565 | | |
477 | | - | |
| 566 | + | |
478 | 567 | | |
479 | 568 | | |
480 | 569 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
80 | 80 | | |
81 | 81 | | |
82 | 82 | | |
83 | | - | |
| 83 | + | |
84 | 84 | | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
85 | 94 | | |
86 | 95 | | |
87 | 96 | | |
88 | 97 | | |
89 | 98 | | |
90 | 99 | | |
91 | | - | |
92 | | - | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
93 | 110 | | |
94 | 111 | | |
95 | 112 | | |
96 | 113 | | |
97 | | - | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
98 | 119 | | |
99 | 120 | | |
100 | 121 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
130 | 130 | | |
131 | 131 | | |
132 | 132 | | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
133 | 146 | | |
134 | 147 | | |
135 | 148 | | |
| |||
260 | 273 | | |
261 | 274 | | |
262 | 275 | | |
| 276 | + | |
263 | 277 | | |
264 | 278 | | |
265 | 279 | | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
266 | 291 | | |
267 | 292 | | |
268 | 293 | | |
| |||
0 commit comments