Skip to content

Commit 83be597

Browse files
vikiv480kou
andcommitted
Improve #unnormalize
* Reject filtered matches earlier in the loop * Improve `#unnormalize` by removing redundant calls to `rv.gsub!` * Improve `entity_expansion_limit` tests Co-Authored-By: Sutou Kouhei <[email protected]>
1 parent e14847c commit 83be597

File tree

3 files changed

+38
-25
lines changed

3 files changed

+38
-25
lines changed

lib/rexml/parsers/baseparser.rb

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -547,20 +547,29 @@ def unnormalize( string, entities=nil, filter=nil )
547547
[Integer(m)].pack('U*')
548548
}
549549
matches.collect!{|x|x[0]}.compact!
550+
if filter
551+
matches.reject! do |entity_reference|
552+
filter.include?(entity_reference)
553+
end
554+
end
550555
if matches.size > 0
551-
matches.each do |entity_reference|
552-
unless filter and filter.include?(entity_reference)
553-
entity_value = entity( entity_reference, entities )
554-
if entity_value
555-
re = Private::DEFAULT_ENTITIES_PATTERNS[entity_reference] || /&#{entity_reference};/
556-
rv.gsub!( re, entity_value )
557-
if rv.bytesize > Security.entity_expansion_text_limit
558-
raise "entity expansion has grown too large"
559-
end
560-
else
561-
er = DEFAULT_ENTITIES[entity_reference]
562-
rv.gsub!( er[0], er[2] ) if er
556+
matches.tally.each do |entity_reference, n|
557+
entity_expansion_count_before = @entity_expansion_count
558+
entity_value = entity( entity_reference, entities )
559+
if entity_value
560+
if n > 1
561+
entity_expansion_count_delta =
562+
@entity_expansion_count - entity_expansion_count_before
563+
record_entity_expansion(entity_expansion_count_delta * (n - 1))
564+
end
565+
re = Private::DEFAULT_ENTITIES_PATTERNS[entity_reference] || /&#{entity_reference};/
566+
rv.gsub!( re, entity_value )
567+
if rv.bytesize > Security.entity_expansion_text_limit
568+
raise "entity expansion has grown too large"
563569
end
570+
else
571+
er = DEFAULT_ENTITIES[entity_reference]
572+
rv.gsub!( er[0], er[2] ) if er
564573
end
565574
end
566575
rv.gsub!( Private::DEFAULT_ENTITIES_PATTERNS['amp'], '&' )
@@ -570,8 +579,8 @@ def unnormalize( string, entities=nil, filter=nil )
570579

571580
private
572581

573-
def record_entity_expansion
574-
@entity_expansion_count += 1
582+
def record_entity_expansion(delta=1)
583+
@entity_expansion_count += delta
575584
if @entity_expansion_count > Security.entity_expansion_limit
576585
raise "number of entity expansions exceeded, processing aborted."
577586
end

test/test_pullparser.rb

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,21 +206,23 @@ def test_empty_value
206206
</member>
207207
XML
208208

209+
REXML::Security.entity_expansion_limit = 100000
209210
parser = REXML::Parsers::PullParser.new(source)
210-
assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do
211-
while parser.has_next?
212-
parser.pull
213-
end
211+
while parser.has_next?
212+
parser.pull
214213
end
214+
assert_equal(11111, parser.entity_expansion_count)
215215

216-
REXML::Security.entity_expansion_limit = 100
216+
REXML::Security.entity_expansion_limit = @default_entity_expansion_limit
217217
parser = REXML::Parsers::PullParser.new(source)
218218
assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do
219219
while parser.has_next?
220220
parser.pull
221221
end
222222
end
223-
assert_equal(101, parser.entity_expansion_count)
223+
assert do
224+
parser.entity_expansion_count > @default_entity_expansion_limit
225+
end
224226
end
225227

226228
def test_with_default_entity

test/test_sax.rb

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -147,17 +147,19 @@ def test_empty_value
147147
</member>
148148
XML
149149

150+
REXML::Security.entity_expansion_limit = 100000
150151
sax = REXML::Parsers::SAX2Parser.new(source)
151-
assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do
152-
sax.parse
153-
end
152+
sax.parse
153+
assert_equal(11111, sax.entity_expansion_count)
154154

155-
REXML::Security.entity_expansion_limit = 100
155+
REXML::Security.entity_expansion_limit = @default_entity_expansion_limit
156156
sax = REXML::Parsers::SAX2Parser.new(source)
157157
assert_raise(RuntimeError.new("number of entity expansions exceeded, processing aborted.")) do
158158
sax.parse
159159
end
160-
assert_equal(101, sax.entity_expansion_count)
160+
assert do
161+
sax.entity_expansion_count > @default_entity_expansion_limit
162+
end
161163
end
162164

163165
def test_with_default_entity

0 commit comments

Comments
 (0)