Skip to content

Commit caec187

Browse files
naitohkou
andauthored
Add local entity expansion limit methods (#202)
GitHub: fix GH-192 Add local entity expansion limit methods. - `REXML::Document#entity_expansion_limit=` - `REXML::Document#entity_expansion_text_limit=` - `REXML::Parsers::SAX2Parser#entity_expansion_limit=` - `REXML::Parsers::SAX2Parser#entity_expansion_text_limit=` - `REXML::Parsers::StreamParser#entity_expansion_limit=` - `REXML::Parsers::StreamParser#entity_expansion_text_limit=` - `REXML::Parsers::PullParser#entity_expansion_limit=` - `REXML::Parsers::PullParser#entity_expansion_text_limit=` --------- Co-authored-by: Sutou Kouhei <[email protected]>
1 parent 1c694d1 commit caec187

12 files changed

+83
-88
lines changed

lib/rexml/attribute.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,9 @@ def to_s
148148
# have been expanded to their values
149149
def value
150150
return @unnormalized if @unnormalized
151-
@unnormalized = Text::unnormalize( @normalized, doctype )
152-
@unnormalized
151+
152+
@unnormalized = Text::unnormalize(@normalized, doctype,
153+
entity_expansion_text_limit: @element&.document&.entity_expansion_text_limit)
153154
end
154155

155156
# The normalized value of this attribute. That is, the attribute with

lib/rexml/document.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ class Document < Element
9191
#
9292
def initialize( source = nil, context = {} )
9393
@entity_expansion_count = 0
94+
@entity_expansion_limit = Security.entity_expansion_limit
95+
@entity_expansion_text_limit = Security.entity_expansion_text_limit
9496
super()
9597
@context = context
9698
return if source.nil?
@@ -431,10 +433,12 @@ def Document::entity_expansion_text_limit
431433
end
432434

433435
attr_reader :entity_expansion_count
436+
attr_writer :entity_expansion_limit
437+
attr_accessor :entity_expansion_text_limit
434438

435439
def record_entity_expansion
436440
@entity_expansion_count += 1
437-
if @entity_expansion_count > Security.entity_expansion_limit
441+
if @entity_expansion_count > @entity_expansion_limit
438442
raise "number of entity expansions exceeded, processing aborted."
439443
end
440444
end

lib/rexml/entity.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,12 @@ def Entity::matches? string
7171
# Evaluates to the unnormalized value of this entity; that is, replacing
7272
# &ent; entities.
7373
def unnormalized
74-
document.record_entity_expansion unless document.nil?
74+
document&.record_entity_expansion
75+
7576
return nil if @value.nil?
76-
@unnormalized = Text::unnormalize(@value, parent)
77+
78+
@unnormalized = Text::unnormalize(@value, parent,
79+
entity_expansion_text_limit: document&.entity_expansion_text_limit)
7780
end
7881

7982
#once :unnormalized

lib/rexml/parsers/baseparser.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ def initialize( source )
164164
@listeners = []
165165
@prefixes = Set.new
166166
@entity_expansion_count = 0
167+
@entity_expansion_limit = Security.entity_expansion_limit
168+
@entity_expansion_text_limit = Security.entity_expansion_text_limit
167169
end
168170

169171
def add_listener( listener )
@@ -172,6 +174,8 @@ def add_listener( listener )
172174

173175
attr_reader :source
174176
attr_reader :entity_expansion_count
177+
attr_writer :entity_expansion_limit
178+
attr_writer :entity_expansion_text_limit
175179

176180
def stream=( source )
177181
@source = SourceFactory.create_from( source )
@@ -585,7 +589,7 @@ def unnormalize( string, entities=nil, filter=nil )
585589
end
586590
re = Private::DEFAULT_ENTITIES_PATTERNS[entity_reference] || /&#{entity_reference};/
587591
rv.gsub!( re, entity_value )
588-
if rv.bytesize > Security.entity_expansion_text_limit
592+
if rv.bytesize > @entity_expansion_text_limit
589593
raise "entity expansion has grown too large"
590594
end
591595
else
@@ -627,7 +631,7 @@ def pop_namespaces_restore
627631

628632
def record_entity_expansion(delta=1)
629633
@entity_expansion_count += delta
630-
if @entity_expansion_count > Security.entity_expansion_limit
634+
if @entity_expansion_count > @entity_expansion_limit
631635
raise "number of entity expansions exceeded, processing aborted."
632636
end
633637
end

lib/rexml/parsers/pullparser.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ def entity_expansion_count
5151
@parser.entity_expansion_count
5252
end
5353

54+
def entity_expansion_limit=( limit )
55+
@parser.entity_expansion_limit = limit
56+
end
57+
58+
def entity_expansion_text_limit=( limit )
59+
@parser.entity_expansion_text_limit = limit
60+
end
61+
5462
def each
5563
while has_next?
5664
yield self.pull

lib/rexml/parsers/sax2parser.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ def entity_expansion_count
2626
@parser.entity_expansion_count
2727
end
2828

29+
def entity_expansion_limit=( limit )
30+
@parser.entity_expansion_limit = limit
31+
end
32+
33+
def entity_expansion_text_limit=( limit )
34+
@parser.entity_expansion_text_limit = limit
35+
end
36+
2937
def add_listener( listener )
3038
@parser.add_listener( listener )
3139
end

lib/rexml/parsers/streamparser.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ def entity_expansion_count
1818
@parser.entity_expansion_count
1919
end
2020

21+
def entity_expansion_limit=( limit )
22+
@parser.entity_expansion_limit = limit
23+
end
24+
25+
def entity_expansion_text_limit=( limit )
26+
@parser.entity_expansion_text_limit = limit
27+
end
28+
2129
def parse
2230
# entity string
2331
while true

lib/rexml/text.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,8 @@ def inspect
268268
# u = Text.new( "sean russell", false, nil, true )
269269
# u.value #-> "sean russell"
270270
def value
271-
@unnormalized ||= Text::unnormalize( @string, doctype )
271+
@unnormalized ||= Text::unnormalize(@string, doctype,
272+
entity_expansion_text_limit: document&.entity_expansion_text_limit)
272273
end
273274

274275
# Sets the contents of this text node. This expects the text to be
@@ -411,11 +412,12 @@ def Text::normalize( input, doctype=nil, entity_filter=nil )
411412
end
412413

413414
# Unescapes all possible entities
414-
def Text::unnormalize( string, doctype=nil, filter=nil, illegal=nil )
415+
def Text::unnormalize( string, doctype=nil, filter=nil, illegal=nil, entity_expansion_text_limit: nil )
416+
entity_expansion_text_limit ||= Security.entity_expansion_text_limit
415417
sum = 0
416418
string.gsub( /\r\n?/, "\n" ).gsub( REFERENCE ) {
417419
s = Text.expand($&, doctype, filter)
418-
if sum + s.bytesize > Security.entity_expansion_text_limit
420+
if sum + s.bytesize > entity_expansion_text_limit
419421
raise "entity expansion has grown too large"
420422
else
421423
sum += s.bytesize

test/test_document.rb

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,6 @@ def test_new
3131
end
3232

3333
class EntityExpansionLimitTest < Test::Unit::TestCase
34-
def setup
35-
@default_entity_expansion_limit = REXML::Security.entity_expansion_limit
36-
@default_entity_expansion_text_limit = REXML::Security.entity_expansion_text_limit
37-
end
38-
39-
def teardown
40-
REXML::Security.entity_expansion_limit = @default_entity_expansion_limit
41-
REXML::Security.entity_expansion_text_limit = @default_entity_expansion_text_limit
42-
end
43-
4434
class GeneralEntityTest < self
4535
def test_have_value
4636
xml = <<XML
@@ -64,9 +54,8 @@ def test_have_value
6454
doc.root.children.first.value
6555
end
6656

67-
REXML::Security.entity_expansion_limit = 100
68-
assert_equal(100, REXML::Security.entity_expansion_limit)
6957
doc = REXML::Document.new(xml)
58+
doc.entity_expansion_limit = 100
7059
assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do
7160
doc.root.children.first.value
7261
end
@@ -95,9 +84,8 @@ def test_empty_value
9584
doc.root.children.first.value
9685
end
9786

98-
REXML::Security.entity_expansion_limit = 100
99-
assert_equal(100, REXML::Security.entity_expansion_limit)
10087
doc = REXML::Document.new(xml)
88+
doc.entity_expansion_limit = 100
10189
assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do
10290
doc.root.children.first.value
10391
end
@@ -118,12 +106,12 @@ def test_with_default_entity
118106
</member>
119107
XML
120108

121-
REXML::Security.entity_expansion_limit = 4
122109
doc = REXML::Document.new(xml)
110+
doc.entity_expansion_limit = 4
123111
assert_equal("\na\na a\n<\n", doc.root.children.first.value)
124112

125-
REXML::Security.entity_expansion_limit = 3
126113
doc = REXML::Document.new(xml)
114+
doc.entity_expansion_limit = 3
127115
assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do
128116
doc.root.children.first.value
129117
end
@@ -142,8 +130,8 @@ def test_entity_expansion_text_limit
142130
<member>&a;</member>
143131
XML
144132

145-
REXML::Security.entity_expansion_text_limit = 90
146133
doc = REXML::Document.new(xml)
134+
doc.entity_expansion_text_limit = 90
147135
assert_equal(90, doc.root.children.first.value.bytesize)
148136
end
149137
end

test/test_pullparser.rb

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -157,16 +157,6 @@ def test_peek
157157
end
158158

159159
class EntityExpansionLimitTest < Test::Unit::TestCase
160-
def setup
161-
@default_entity_expansion_limit = REXML::Security.entity_expansion_limit
162-
@default_entity_expansion_text_limit = REXML::Security.entity_expansion_text_limit
163-
end
164-
165-
def teardown
166-
REXML::Security.entity_expansion_limit = @default_entity_expansion_limit
167-
REXML::Security.entity_expansion_text_limit = @default_entity_expansion_text_limit
168-
end
169-
170160
class GeneralEntityTest < self
171161
def test_have_value
172162
source = <<-XML
@@ -206,22 +196,21 @@ def test_empty_value
206196
</member>
207197
XML
208198

209-
REXML::Security.entity_expansion_limit = 100000
210199
parser = REXML::Parsers::PullParser.new(source)
200+
parser.entity_expansion_limit = 100000
211201
while parser.has_next?
212202
parser.pull
213203
end
214204
assert_equal(11111, parser.entity_expansion_count)
215205

216-
REXML::Security.entity_expansion_limit = @default_entity_expansion_limit
217206
parser = REXML::Parsers::PullParser.new(source)
218207
assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do
219208
while parser.has_next?
220209
parser.pull
221210
end
222211
end
223212
assert do
224-
parser.entity_expansion_count > @default_entity_expansion_limit
213+
parser.entity_expansion_count > REXML::Security.entity_expansion_limit
225214
end
226215
end
227216

@@ -239,14 +228,14 @@ def test_with_default_entity
239228
</member>
240229
XML
241230

242-
REXML::Security.entity_expansion_limit = 4
243231
parser = REXML::Parsers::PullParser.new(source)
232+
parser.entity_expansion_limit = 4
244233
while parser.has_next?
245234
parser.pull
246235
end
247236

248-
REXML::Security.entity_expansion_limit = 3
249237
parser = REXML::Parsers::PullParser.new(source)
238+
parser.entity_expansion_limit = 3
250239
assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do
251240
while parser.has_next?
252241
parser.pull
@@ -255,7 +244,7 @@ def test_with_default_entity
255244
end
256245

257246
def test_with_only_default_entities
258-
member_value = "&lt;p&gt;#{'A' * @default_entity_expansion_text_limit}&lt;/p&gt;"
247+
member_value = "&lt;p&gt;#{'A' * REXML::Security.entity_expansion_text_limit}&lt;/p&gt;"
259248
source = <<-XML
260249
<?xml version="1.0" encoding="UTF-8"?>
261250
<member>
@@ -276,11 +265,11 @@ def test_with_only_default_entities
276265
end
277266
end
278267

279-
expected_value = "<p>#{'A' * @default_entity_expansion_text_limit}</p>"
268+
expected_value = "<p>#{'A' * REXML::Security.entity_expansion_text_limit}</p>"
280269
assert_equal(expected_value, events['member'].strip)
281270
assert_equal(0, parser.entity_expansion_count)
282271
assert do
283-
events['member'].bytesize > @default_entity_expansion_text_limit
272+
events['member'].bytesize > REXML::Security.entity_expansion_text_limit
284273
end
285274
end
286275

@@ -296,8 +285,8 @@ def test_entity_expansion_text_limit
296285
<member>&a;</member>
297286
XML
298287

299-
REXML::Security.entity_expansion_text_limit = 90
300288
parser = REXML::Parsers::PullParser.new(source)
289+
parser.entity_expansion_text_limit = 90
301290
events = {}
302291
element_name = ''
303292
while parser.has_next?

test/test_sax.rb

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -100,16 +100,6 @@ def test_sax2
100100
end
101101

102102
class EntityExpansionLimitTest < Test::Unit::TestCase
103-
def setup
104-
@default_entity_expansion_limit = REXML::Security.entity_expansion_limit
105-
@default_entity_expansion_text_limit = REXML::Security.entity_expansion_text_limit
106-
end
107-
108-
def teardown
109-
REXML::Security.entity_expansion_limit = @default_entity_expansion_limit
110-
REXML::Security.entity_expansion_text_limit = @default_entity_expansion_text_limit
111-
end
112-
113103
class GeneralEntityTest < self
114104
def test_have_value
115105
source = <<-XML
@@ -147,18 +137,17 @@ def test_empty_value
147137
</member>
148138
XML
149139

150-
REXML::Security.entity_expansion_limit = 100000
151140
sax = REXML::Parsers::SAX2Parser.new(source)
141+
sax.entity_expansion_limit = 100000
152142
sax.parse
153143
assert_equal(11111, sax.entity_expansion_count)
154144

155-
REXML::Security.entity_expansion_limit = @default_entity_expansion_limit
156145
sax = REXML::Parsers::SAX2Parser.new(source)
157146
assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do
158147
sax.parse
159148
end
160149
assert do
161-
sax.entity_expansion_count > @default_entity_expansion_limit
150+
sax.entity_expansion_count > REXML::Security.entity_expansion_limit
162151
end
163152
end
164153

@@ -176,19 +165,19 @@ def test_with_default_entity
176165
</member>
177166
XML
178167

179-
REXML::Security.entity_expansion_limit = 4
180168
sax = REXML::Parsers::SAX2Parser.new(source)
169+
sax.entity_expansion_limit = 4
181170
sax.parse
182171

183-
REXML::Security.entity_expansion_limit = 3
184172
sax = REXML::Parsers::SAX2Parser.new(source)
173+
sax.entity_expansion_limit = 3
185174
assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do
186175
sax.parse
187176
end
188177
end
189178

190179
def test_with_only_default_entities
191-
member_value = "&lt;p&gt;#{'A' * @default_entity_expansion_text_limit}&lt;/p&gt;"
180+
member_value = "&lt;p&gt;#{'A' * REXML::Security.entity_expansion_text_limit}&lt;/p&gt;"
192181
source = <<-XML
193182
<?xml version="1.0" encoding="UTF-8"?>
194183
<member>
@@ -203,11 +192,11 @@ def test_with_only_default_entities
203192
end
204193
sax.parse
205194

206-
expected_value = "<p>#{'A' * @default_entity_expansion_text_limit}</p>"
195+
expected_value = "<p>#{'A' * REXML::Security.entity_expansion_text_limit}</p>"
207196
assert_equal(expected_value, text_value.strip)
208197
assert_equal(0, sax.entity_expansion_count)
209198
assert do
210-
text_value.bytesize > @default_entity_expansion_text_limit
199+
text_value.bytesize > REXML::Security.entity_expansion_text_limit
211200
end
212201
end
213202

@@ -223,8 +212,8 @@ def test_entity_expansion_text_limit
223212
<member>&a;</member>
224213
XML
225214

226-
REXML::Security.entity_expansion_text_limit = 90
227215
sax = REXML::Parsers::SAX2Parser.new(source)
216+
sax.entity_expansion_text_limit = 90
228217
text_size = nil
229218
sax.listen(:characters, ["member"]) do |text|
230219
text_size = text.size

0 commit comments

Comments
 (0)