1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
require 'erb'
require 'active_support/core_ext/kernel/singleton_class'
class ERB
module Util
HTML_ESCAPE = { '&' => '&', '>' => '>', '<' => '<', '"' => '"' }
JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003E', '<' => '\u003C' }
HTML_ESCAPE_ONCE_REGEXP = /[\"><]|&(?!([a-zA-Z]+|(#\d+));)/
JSON_ESCAPE_REGEXP = /[&"><]/
# A utility method for escaping HTML tag characters.
# This method is also aliased as <tt>h</tt>.
#
# In your ERB templates, use this method to escape any unsafe content. For example:
# <%=h @person.name %>
#
# puts html_escape('is a > 0 & a < 10?')
# # => is a > 0 & a < 10?
def html_escape(s)
s = s.to_s
if s.html_safe?
s
else
s.encode(s.encoding, :xml => :attr)[1...-1].html_safe
end
end
# Aliasing twice issues a warning "discarding old...". Remove first to avoid it.
remove_method(:h)
alias h html_escape
module_function :h
singleton_class.send(:remove_method, :html_escape)
module_function :html_escape
# A utility method for escaping HTML without affecting existing escaped entities.
#
# html_escape_once('1 < 2 & 3')
# # => "1 < 2 & 3"
#
# html_escape_once('<< Accept & Checkout')
# # => "<< Accept & Checkout"
def html_escape_once(s)
result = s.to_s.gsub(HTML_ESCAPE_ONCE_REGEXP) { |special| HTML_ESCAPE[special] }
s.html_safe? ? result.html_safe : result
end
module_function :html_escape_once
# A utility method for escaping HTML entities in JSON strings
# using \uXXXX JavaScript escape sequences for string literals:
#
# json_escape('is a > 0 & a < 10?')
# # => is a \u003E 0 \u0026 a \u003C 10?
#
# Note that after this operation is performed the output is not
# valid JSON. In particular double quotes are removed:
#
# json_escape('{"name":"john","created_at":"2010-04-28T01:39:31Z","id":1}')
# # => {name:john,created_at:2010-04-28T01:39:31Z,id:1}
#
# This method is also aliased as +j+, and available as a helper
# in Rails templates:
#
# <%=j @person.to_json %>
#
def json_escape(s)
result = s.to_s.gsub(JSON_ESCAPE_REGEXP) { |special| JSON_ESCAPE[special] }
s.html_safe? ? result.html_safe : result
end
alias j json_escape
module_function :j
module_function :json_escape
end
end
class Object
def html_safe?
false
end
end
class Numeric
def html_safe?
true
end
end
module ActiveSupport #:nodoc:
class SafeBuffer < String
UNSAFE_STRING_METHODS = %w(
capitalize chomp chop delete downcase gsub lstrip next reverse rstrip
slice squeeze strip sub succ swapcase tr tr_s upcase prepend
)
alias_method :original_concat, :concat
private :original_concat
class SafeConcatError < StandardError
def initialize
super 'Could not concatenate to the buffer because it is not html safe.'
end
end
def [](*args)
if args.size < 2
super
else
if html_safe?
new_safe_buffer = super
new_safe_buffer.instance_eval { @html_safe = true }
new_safe_buffer
else
to_str[*args]
end
end
end
def safe_concat(value)
raise SafeConcatError unless html_safe?
original_concat(value)
end
def initialize(*)
@html_safe = true
super
end
def initialize_copy(other)
super
@html_safe = other.html_safe?
end
def clone_empty
self[0, 0]
end
def concat(value)
if !html_safe? || value.html_safe?
super(value)
else
super(ERB::Util.h(value))
end
end
alias << concat
def +(other)
dup.concat(other)
end
def %(args)
args = Array(args)
args.map! do |arg|
if !html_safe? || arg.html_safe?
arg
else
ERB::Util.h(arg)
end
end
self.class.new(super(args))
end
def html_safe?
defined?(@html_safe) && @html_safe
end
def to_s
self
end
def to_param
to_str
end
def encode_with(coder)
coder.represent_scalar nil, to_str
end
UNSAFE_STRING_METHODS.each do |unsafe_method|
if 'String'.respond_to?(unsafe_method)
class_eval <<-EOT, __FILE__, __LINE__ + 1
def #{unsafe_method}(*args, &block) # def capitalize(*args, &block)
to_str.#{unsafe_method}(*args, &block) # to_str.capitalize(*args, &block)
end # end
def #{unsafe_method}!(*args) # def capitalize!(*args)
@html_safe = false # @html_safe = false
super # super
end # end
EOT
end
end
end
end
class String
def html_safe
ActiveSupport::SafeBuffer.new(self)
end
end
|