rexml 3.3.5 → 3.3.7
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rexml might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/NEWS.md +61 -0
- data/lib/rexml/attribute.rb +3 -2
- data/lib/rexml/document.rb +5 -1
- data/lib/rexml/element.rb +14 -16
- data/lib/rexml/entity.rb +9 -48
- data/lib/rexml/parsers/baseparser.rb +108 -34
- data/lib/rexml/parsers/pullparser.rb +8 -0
- data/lib/rexml/parsers/sax2parser.rb +8 -0
- data/lib/rexml/parsers/streamparser.rb +15 -9
- data/lib/rexml/parsers/treeparser.rb +0 -7
- data/lib/rexml/rexml.rb +1 -1
- data/lib/rexml/text.rb +5 -3
- metadata +4 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1a402bb00d8bf352521fb6ca5354ba92a22d110feedcba40a50e2de5abad277a
|
4
|
+
data.tar.gz: 51f7b5893eef8d8183eb14c719064368029b18c9909b3454047e308c7425ce5b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ff091fe421748562931d65301e66dc1d4d313e1c28cce753bc9f31a1f9bac65c0b4939db70117e47f2c3158daa24b708e2519a98a9638114f4e5a1c0d1265e7c
|
7
|
+
data.tar.gz: 720bc72a86eacebbe9a990152d4d0dfcde2e50c71b3fbabaaba44dec91b2f6ff7ca6180b86622cf0ffb36355ab5e5d43f8948e67c70ab4fca1f8bf0882a3585d
|
data/NEWS.md
CHANGED
@@ -1,5 +1,66 @@
|
|
1
1
|
# News
|
2
2
|
|
3
|
+
## 3.3.7 - 2024-09-04 {#version-3-3-7}
|
4
|
+
|
5
|
+
### Improvements
|
6
|
+
|
7
|
+
* Added local entity expansion limit methods
|
8
|
+
* GH-192
|
9
|
+
* GH-202
|
10
|
+
* Reported by takuya kodama.
|
11
|
+
* Patch by NAITOH Jun.
|
12
|
+
|
13
|
+
* Removed explicit strscan dependency
|
14
|
+
* GH-204
|
15
|
+
* Patch by Bo Anderson.
|
16
|
+
|
17
|
+
### Thanks
|
18
|
+
|
19
|
+
* takuya kodama
|
20
|
+
|
21
|
+
* NAITOH Jun
|
22
|
+
|
23
|
+
* Bo Anderson
|
24
|
+
|
25
|
+
## 3.3.6 - 2024-08-22 {#version-3-3-6}
|
26
|
+
|
27
|
+
### Improvements
|
28
|
+
|
29
|
+
* Removed duplicated entity expansions for performance.
|
30
|
+
* GH-194
|
31
|
+
* Patch by Viktor Ivarsson.
|
32
|
+
|
33
|
+
* Improved namespace conflicted attribute check performance. It was
|
34
|
+
too slow for deep elements.
|
35
|
+
* Reported by l33thaxor.
|
36
|
+
|
37
|
+
### Fixes
|
38
|
+
|
39
|
+
* Fixed a bug that default entity expansions are counted for
|
40
|
+
security check. Default entity expansions should not be counted
|
41
|
+
because they don't have a security risk.
|
42
|
+
* GH-198
|
43
|
+
* GH-199
|
44
|
+
* Patch Viktor Ivarsson
|
45
|
+
|
46
|
+
* Fixed a parser bug that parameter entity references in internal
|
47
|
+
subsets are expanded. It's not allowed in the XML specification.
|
48
|
+
* GH-191
|
49
|
+
* Patch by NAITOH Jun.
|
50
|
+
|
51
|
+
* Fixed a stream parser bug that user-defined entity references in
|
52
|
+
text aren't expanded.
|
53
|
+
* GH-200
|
54
|
+
* Patch by NAITOH Jun.
|
55
|
+
|
56
|
+
### Thanks
|
57
|
+
|
58
|
+
* Viktor Ivarsson
|
59
|
+
|
60
|
+
* NAITOH Jun
|
61
|
+
|
62
|
+
* l33thaxor
|
63
|
+
|
3
64
|
## 3.3.5 - 2024-08-12 {#version-3-3-5}
|
4
65
|
|
5
66
|
### Fixes
|
data/lib/rexml/attribute.rb
CHANGED
@@ -148,8 +148,9 @@ module REXML
|
|
148
148
|
# have been expanded to their values
|
149
149
|
def value
|
150
150
|
return @unnormalized if @unnormalized
|
151
|
-
|
152
|
-
@unnormalized
|
151
|
+
|
152
|
+
@unnormalized = Text::unnormalize(@normalized, doctype,
|
153
|
+
entity_expansion_text_limit: @element&.document&.entity_expansion_text_limit)
|
153
154
|
end
|
154
155
|
|
155
156
|
# The normalized value of this attribute. That is, the attribute with
|
data/lib/rexml/document.rb
CHANGED
@@ -91,6 +91,8 @@ module REXML
|
|
91
91
|
#
|
92
92
|
def initialize( source = nil, context = {} )
|
93
93
|
@entity_expansion_count = 0
|
94
|
+
@entity_expansion_limit = Security.entity_expansion_limit
|
95
|
+
@entity_expansion_text_limit = Security.entity_expansion_text_limit
|
94
96
|
super()
|
95
97
|
@context = context
|
96
98
|
return if source.nil?
|
@@ -431,10 +433,12 @@ module REXML
|
|
431
433
|
end
|
432
434
|
|
433
435
|
attr_reader :entity_expansion_count
|
436
|
+
attr_writer :entity_expansion_limit
|
437
|
+
attr_accessor :entity_expansion_text_limit
|
434
438
|
|
435
439
|
def record_entity_expansion
|
436
440
|
@entity_expansion_count += 1
|
437
|
-
if @entity_expansion_count >
|
441
|
+
if @entity_expansion_count > @entity_expansion_limit
|
438
442
|
raise "number of entity expansions exceeded, processing aborted."
|
439
443
|
end
|
440
444
|
end
|
data/lib/rexml/element.rb
CHANGED
@@ -441,9 +441,14 @@ module REXML
|
|
441
441
|
# Related: #root_node, #document.
|
442
442
|
#
|
443
443
|
def root
|
444
|
-
|
445
|
-
|
446
|
-
|
444
|
+
target = self
|
445
|
+
while target
|
446
|
+
return target.elements[1] if target.kind_of? Document
|
447
|
+
parent = target.parent
|
448
|
+
return target if parent.kind_of? Document or parent.nil?
|
449
|
+
target = parent
|
450
|
+
end
|
451
|
+
nil
|
447
452
|
end
|
448
453
|
|
449
454
|
# :call-seq:
|
@@ -619,8 +624,12 @@ module REXML
|
|
619
624
|
else
|
620
625
|
prefix = "xmlns:#{prefix}" unless prefix[0,5] == 'xmlns'
|
621
626
|
end
|
622
|
-
ns =
|
623
|
-
|
627
|
+
ns = nil
|
628
|
+
target = self
|
629
|
+
while ns.nil? and target
|
630
|
+
ns = target.attributes[prefix]
|
631
|
+
target = target.parent
|
632
|
+
end
|
624
633
|
ns = '' if ns.nil? and prefix == 'xmlns'
|
625
634
|
return ns
|
626
635
|
end
|
@@ -2375,17 +2384,6 @@ module REXML
|
|
2375
2384
|
elsif old_attr.kind_of? Hash
|
2376
2385
|
old_attr[value.prefix] = value
|
2377
2386
|
elsif old_attr.prefix != value.prefix
|
2378
|
-
# Check for conflicting namespaces
|
2379
|
-
if value.prefix != "xmlns" and old_attr.prefix != "xmlns"
|
2380
|
-
old_namespace = old_attr.namespace
|
2381
|
-
new_namespace = value.namespace
|
2382
|
-
if old_namespace == new_namespace
|
2383
|
-
raise ParseException.new(
|
2384
|
-
"Namespace conflict in adding attribute \"#{value.name}\": "+
|
2385
|
-
"Prefix \"#{old_attr.prefix}\" = \"#{old_namespace}\" and "+
|
2386
|
-
"prefix \"#{value.prefix}\" = \"#{new_namespace}\"")
|
2387
|
-
end
|
2388
|
-
end
|
2389
2387
|
store value.name, {old_attr.prefix => old_attr,
|
2390
2388
|
value.prefix => value}
|
2391
2389
|
else
|
data/lib/rexml/entity.rb
CHANGED
@@ -12,6 +12,7 @@ module REXML
|
|
12
12
|
EXTERNALID = "(?:(?:(SYSTEM)\\s+#{SYSTEMLITERAL})|(?:(PUBLIC)\\s+#{PUBIDLITERAL}\\s+#{SYSTEMLITERAL}))"
|
13
13
|
NDATADECL = "\\s+NDATA\\s+#{NAME}"
|
14
14
|
PEREFERENCE = "%#{NAME};"
|
15
|
+
PEREFERENCE_RE = /#{PEREFERENCE}/um
|
15
16
|
ENTITYVALUE = %Q{((?:"(?:[^%&"]|#{PEREFERENCE}|#{REFERENCE})*")|(?:'([^%&']|#{PEREFERENCE}|#{REFERENCE})*'))}
|
16
17
|
PEDEF = "(?:#{ENTITYVALUE}|#{EXTERNALID})"
|
17
18
|
ENTITYDEF = "(?:#{ENTITYVALUE}|(?:#{EXTERNALID}(#{NDATADECL})?))"
|
@@ -19,7 +20,7 @@ module REXML
|
|
19
20
|
GEDECL = "<!ENTITY\\s+#{NAME}\\s+#{ENTITYDEF}\\s*>"
|
20
21
|
ENTITYDECL = /\s*(?:#{GEDECL})|(?:#{PEDECL})/um
|
21
22
|
|
22
|
-
attr_reader :name, :external, :ref, :ndata, :pubid
|
23
|
+
attr_reader :name, :external, :ref, :ndata, :pubid, :value
|
23
24
|
|
24
25
|
# Create a new entity. Simple entities can be constructed by passing a
|
25
26
|
# name, value to the constructor; this creates a generic, plain entity
|
@@ -68,14 +69,14 @@ module REXML
|
|
68
69
|
end
|
69
70
|
|
70
71
|
# Evaluates to the unnormalized value of this entity; that is, replacing
|
71
|
-
#
|
72
|
-
# +value()+ in that +value+ only replaces %ent; entities.
|
72
|
+
# &ent; entities.
|
73
73
|
def unnormalized
|
74
|
-
document
|
75
|
-
|
76
|
-
return nil if
|
77
|
-
|
78
|
-
@unnormalized
|
74
|
+
document&.record_entity_expansion
|
75
|
+
|
76
|
+
return nil if @value.nil?
|
77
|
+
|
78
|
+
@unnormalized = Text::unnormalize(@value, parent,
|
79
|
+
entity_expansion_text_limit: document&.entity_expansion_text_limit)
|
79
80
|
end
|
80
81
|
|
81
82
|
#once :unnormalized
|
@@ -121,46 +122,6 @@ module REXML
|
|
121
122
|
write rv
|
122
123
|
rv
|
123
124
|
end
|
124
|
-
|
125
|
-
PEREFERENCE_RE = /#{PEREFERENCE}/um
|
126
|
-
# Returns the value of this entity. At the moment, only internal entities
|
127
|
-
# are processed. If the value contains internal references (IE,
|
128
|
-
# %blah;), those are replaced with their values. IE, if the doctype
|
129
|
-
# contains:
|
130
|
-
# <!ENTITY % foo "bar">
|
131
|
-
# <!ENTITY yada "nanoo %foo; nanoo>
|
132
|
-
# then:
|
133
|
-
# doctype.entity('yada').value #-> "nanoo bar nanoo"
|
134
|
-
def value
|
135
|
-
@resolved_value ||= resolve_value
|
136
|
-
end
|
137
|
-
|
138
|
-
def parent=(other)
|
139
|
-
@resolved_value = nil
|
140
|
-
super
|
141
|
-
end
|
142
|
-
|
143
|
-
private
|
144
|
-
def resolve_value
|
145
|
-
return nil if @value.nil?
|
146
|
-
return @value unless @value.match?(PEREFERENCE_RE)
|
147
|
-
|
148
|
-
matches = @value.scan(PEREFERENCE_RE)
|
149
|
-
rv = @value.clone
|
150
|
-
if @parent
|
151
|
-
sum = 0
|
152
|
-
matches.each do |entity_reference|
|
153
|
-
entity_value = @parent.entity( entity_reference[0] )
|
154
|
-
if sum + entity_value.bytesize > Security.entity_expansion_text_limit
|
155
|
-
raise "entity expansion has grown too large"
|
156
|
-
else
|
157
|
-
sum += entity_value.bytesize
|
158
|
-
end
|
159
|
-
rv.gsub!( /%#{entity_reference.join};/um, entity_value )
|
160
|
-
end
|
161
|
-
end
|
162
|
-
rv
|
163
|
-
end
|
164
125
|
end
|
165
126
|
|
166
127
|
# This is a set of entity constants -- the ones defined in the XML
|
@@ -8,6 +8,22 @@ require "strscan"
|
|
8
8
|
|
9
9
|
module REXML
|
10
10
|
module Parsers
|
11
|
+
unless [].respond_to?(:tally)
|
12
|
+
module EnumerableTally
|
13
|
+
refine Enumerable do
|
14
|
+
def tally
|
15
|
+
counts = {}
|
16
|
+
each do |item|
|
17
|
+
counts[item] ||= 0
|
18
|
+
counts[item] += 1
|
19
|
+
end
|
20
|
+
counts
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
using EnumerableTally
|
25
|
+
end
|
26
|
+
|
11
27
|
if StringScanner::Version < "3.0.8"
|
12
28
|
module StringScannerCaptures
|
13
29
|
refine StringScanner do
|
@@ -125,6 +141,7 @@ module REXML
|
|
125
141
|
}
|
126
142
|
|
127
143
|
module Private
|
144
|
+
PEREFERENCE_PATTERN = /#{PEREFERENCE}/um
|
128
145
|
TAG_PATTERN = /((?>#{QNAME_STR}))\s*/um
|
129
146
|
CLOSE_PATTERN = /(#{QNAME_STR})\s*>/um
|
130
147
|
ATTLISTDECL_END = /\s+#{NAME}(?:#{ATTDEF})*\s*>/um
|
@@ -147,6 +164,8 @@ module REXML
|
|
147
164
|
@listeners = []
|
148
165
|
@prefixes = Set.new
|
149
166
|
@entity_expansion_count = 0
|
167
|
+
@entity_expansion_limit = Security.entity_expansion_limit
|
168
|
+
@entity_expansion_text_limit = Security.entity_expansion_text_limit
|
150
169
|
end
|
151
170
|
|
152
171
|
def add_listener( listener )
|
@@ -155,6 +174,8 @@ module REXML
|
|
155
174
|
|
156
175
|
attr_reader :source
|
157
176
|
attr_reader :entity_expansion_count
|
177
|
+
attr_writer :entity_expansion_limit
|
178
|
+
attr_writer :entity_expansion_text_limit
|
158
179
|
|
159
180
|
def stream=( source )
|
160
181
|
@source = SourceFactory.create_from( source )
|
@@ -164,7 +185,8 @@ module REXML
|
|
164
185
|
@tags = []
|
165
186
|
@stack = []
|
166
187
|
@entities = []
|
167
|
-
@
|
188
|
+
@namespaces = {}
|
189
|
+
@namespaces_restore_stack = []
|
168
190
|
end
|
169
191
|
|
170
192
|
def position
|
@@ -232,6 +254,10 @@ module REXML
|
|
232
254
|
if @document_status == :in_doctype
|
233
255
|
raise ParseException.new("Malformed DOCTYPE: unclosed", @source)
|
234
256
|
end
|
257
|
+
unless @tags.empty?
|
258
|
+
path = "/" + @tags.join("/")
|
259
|
+
raise ParseException.new("Missing end tag for '#{path}'", @source)
|
260
|
+
end
|
235
261
|
return [ :end_document ]
|
236
262
|
end
|
237
263
|
return @stack.shift if @stack.size > 0
|
@@ -264,7 +290,6 @@ module REXML
|
|
264
290
|
@source.position = start_position
|
265
291
|
raise REXML::ParseException.new(message, @source)
|
266
292
|
end
|
267
|
-
@nsstack.unshift(Set.new)
|
268
293
|
name = parse_name(base_error_message)
|
269
294
|
if @source.match(/\s*\[/um, true)
|
270
295
|
id = [nil, nil, nil]
|
@@ -334,6 +359,8 @@ module REXML
|
|
334
359
|
match[4] = match[4][1..-2] # HREF
|
335
360
|
match.delete_at(5) if match.size > 5 # Chop out NDATA decl
|
336
361
|
# match is [ :entity, name, PUBLIC, pubid, href(, ndata)? ]
|
362
|
+
elsif Private::PEREFERENCE_PATTERN.match?(match[2])
|
363
|
+
raise REXML::ParseException.new("Parameter entity references forbidden in internal subset: #{match[2]}", @source)
|
337
364
|
else
|
338
365
|
match[2] = match[2][1..-2]
|
339
366
|
match.pop if match.size == 4
|
@@ -356,7 +383,7 @@ module REXML
|
|
356
383
|
val = attdef[4] if val == "#FIXED "
|
357
384
|
pairs[attdef[0]] = val
|
358
385
|
if attdef[0] =~ /^xmlns:(.*)/
|
359
|
-
@
|
386
|
+
@namespaces[$1] = val
|
360
387
|
end
|
361
388
|
end
|
362
389
|
end
|
@@ -409,7 +436,7 @@ module REXML
|
|
409
436
|
# here explicitly.
|
410
437
|
@source.ensure_buffer
|
411
438
|
if @source.match("/", true)
|
412
|
-
@
|
439
|
+
@namespaces_restore_stack.pop
|
413
440
|
last_tag = @tags.pop
|
414
441
|
md = @source.match(Private::CLOSE_PATTERN, true)
|
415
442
|
if md and !last_tag
|
@@ -454,18 +481,18 @@ module REXML
|
|
454
481
|
@document_status = :in_element
|
455
482
|
@prefixes.clear
|
456
483
|
@prefixes << md[2] if md[2]
|
457
|
-
|
458
|
-
attributes, closed = parse_attributes(@prefixes
|
484
|
+
push_namespaces_restore
|
485
|
+
attributes, closed = parse_attributes(@prefixes)
|
459
486
|
# Verify that all of the prefixes have been defined
|
460
487
|
for prefix in @prefixes
|
461
|
-
unless @
|
488
|
+
unless @namespaces.key?(prefix)
|
462
489
|
raise UndefinedNamespaceException.new(prefix,@source,self)
|
463
490
|
end
|
464
491
|
end
|
465
492
|
|
466
493
|
if closed
|
467
494
|
@closed = tag
|
468
|
-
|
495
|
+
pop_namespaces_restore
|
469
496
|
else
|
470
497
|
if @tags.empty? and @have_root
|
471
498
|
raise ParseException.new("Malformed XML: Extra tag at the end of the document (got '<#{tag}')", @source)
|
@@ -505,15 +532,13 @@ module REXML
|
|
505
532
|
private :pull_event
|
506
533
|
|
507
534
|
def entity( reference, entities )
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
end
|
516
|
-
unnormalize( value, entities ) if value
|
535
|
+
return unless entities
|
536
|
+
|
537
|
+
value = entities[ reference ]
|
538
|
+
return if value.nil?
|
539
|
+
|
540
|
+
record_entity_expansion
|
541
|
+
unnormalize( value, entities )
|
517
542
|
end
|
518
543
|
|
519
544
|
# Escapes all possible entities
|
@@ -547,20 +572,29 @@ module REXML
|
|
547
572
|
[Integer(m)].pack('U*')
|
548
573
|
}
|
549
574
|
matches.collect!{|x|x[0]}.compact!
|
575
|
+
if filter
|
576
|
+
matches.reject! do |entity_reference|
|
577
|
+
filter.include?(entity_reference)
|
578
|
+
end
|
579
|
+
end
|
550
580
|
if matches.size > 0
|
551
|
-
matches.each do |entity_reference|
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
end
|
560
|
-
else
|
561
|
-
er = DEFAULT_ENTITIES[entity_reference]
|
562
|
-
rv.gsub!( er[0], er[2] ) if er
|
581
|
+
matches.tally.each do |entity_reference, n|
|
582
|
+
entity_expansion_count_before = @entity_expansion_count
|
583
|
+
entity_value = entity( entity_reference, entities )
|
584
|
+
if entity_value
|
585
|
+
if n > 1
|
586
|
+
entity_expansion_count_delta =
|
587
|
+
@entity_expansion_count - entity_expansion_count_before
|
588
|
+
record_entity_expansion(entity_expansion_count_delta * (n - 1))
|
563
589
|
end
|
590
|
+
re = Private::DEFAULT_ENTITIES_PATTERNS[entity_reference] || /&#{entity_reference};/
|
591
|
+
rv.gsub!( re, entity_value )
|
592
|
+
if rv.bytesize > @entity_expansion_text_limit
|
593
|
+
raise "entity expansion has grown too large"
|
594
|
+
end
|
595
|
+
else
|
596
|
+
er = DEFAULT_ENTITIES[entity_reference]
|
597
|
+
rv.gsub!( er[0], er[2] ) if er
|
564
598
|
end
|
565
599
|
end
|
566
600
|
rv.gsub!( Private::DEFAULT_ENTITIES_PATTERNS['amp'], '&' )
|
@@ -569,10 +603,35 @@ module REXML
|
|
569
603
|
end
|
570
604
|
|
571
605
|
private
|
606
|
+
def add_namespace(prefix, uri)
|
607
|
+
@namespaces_restore_stack.last[prefix] = @namespaces[prefix]
|
608
|
+
if uri.nil?
|
609
|
+
@namespaces.delete(prefix)
|
610
|
+
else
|
611
|
+
@namespaces[prefix] = uri
|
612
|
+
end
|
613
|
+
end
|
614
|
+
|
615
|
+
def push_namespaces_restore
|
616
|
+
namespaces_restore = {}
|
617
|
+
@namespaces_restore_stack.push(namespaces_restore)
|
618
|
+
namespaces_restore
|
619
|
+
end
|
572
620
|
|
573
|
-
def
|
574
|
-
|
575
|
-
|
621
|
+
def pop_namespaces_restore
|
622
|
+
namespaces_restore = @namespaces_restore_stack.pop
|
623
|
+
namespaces_restore.each do |prefix, uri|
|
624
|
+
if uri.nil?
|
625
|
+
@namespaces.delete(prefix)
|
626
|
+
else
|
627
|
+
@namespaces[prefix] = uri
|
628
|
+
end
|
629
|
+
end
|
630
|
+
end
|
631
|
+
|
632
|
+
def record_entity_expansion(delta=1)
|
633
|
+
@entity_expansion_count += delta
|
634
|
+
if @entity_expansion_count > @entity_expansion_limit
|
576
635
|
raise "number of entity expansions exceeded, processing aborted."
|
577
636
|
end
|
578
637
|
end
|
@@ -697,8 +756,9 @@ module REXML
|
|
697
756
|
[:processing_instruction, name, content]
|
698
757
|
end
|
699
758
|
|
700
|
-
def parse_attributes(prefixes
|
759
|
+
def parse_attributes(prefixes)
|
701
760
|
attributes = {}
|
761
|
+
expanded_names = {}
|
702
762
|
closed = false
|
703
763
|
while true
|
704
764
|
if @source.match(">", true)
|
@@ -740,7 +800,7 @@ module REXML
|
|
740
800
|
"(http://www.w3.org/TR/REC-xml-names/#ns-decl)"
|
741
801
|
raise REXML::ParseException.new( msg, @source, self)
|
742
802
|
end
|
743
|
-
|
803
|
+
add_namespace(local_part, value)
|
744
804
|
elsif prefix
|
745
805
|
prefixes << prefix unless prefix == "xml"
|
746
806
|
end
|
@@ -750,6 +810,20 @@ module REXML
|
|
750
810
|
raise REXML::ParseException.new(msg, @source, self)
|
751
811
|
end
|
752
812
|
|
813
|
+
unless prefix == "xmlns"
|
814
|
+
uri = @namespaces[prefix]
|
815
|
+
expanded_name = [uri, local_part]
|
816
|
+
existing_prefix = expanded_names[expanded_name]
|
817
|
+
if existing_prefix
|
818
|
+
message = "Namespace conflict in adding attribute " +
|
819
|
+
"\"#{local_part}\": " +
|
820
|
+
"Prefix \"#{existing_prefix}\" = \"#{uri}\" and " +
|
821
|
+
"prefix \"#{prefix}\" = \"#{uri}\""
|
822
|
+
raise REXML::ParseException.new(message, @source, self)
|
823
|
+
end
|
824
|
+
expanded_names[expanded_name] = prefix
|
825
|
+
end
|
826
|
+
|
753
827
|
attributes[name] = value
|
754
828
|
else
|
755
829
|
message = "Invalid attribute name: <#{@source.buffer.split(%r{[/>\s]}).first}>"
|
@@ -51,6 +51,14 @@ module REXML
|
|
51
51
|
@parser.entity_expansion_count
|
52
52
|
end
|
53
53
|
|
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
|
+
|
54
62
|
def each
|
55
63
|
while has_next?
|
56
64
|
yield self.pull
|
@@ -26,6 +26,14 @@ module REXML
|
|
26
26
|
@parser.entity_expansion_count
|
27
27
|
end
|
28
28
|
|
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
|
+
|
29
37
|
def add_listener( listener )
|
30
38
|
@parser.add_listener( listener )
|
31
39
|
end
|
@@ -7,36 +7,41 @@ module REXML
|
|
7
7
|
def initialize source, listener
|
8
8
|
@listener = listener
|
9
9
|
@parser = BaseParser.new( source )
|
10
|
-
@
|
10
|
+
@entities = {}
|
11
11
|
end
|
12
12
|
|
13
13
|
def add_listener( listener )
|
14
14
|
@parser.add_listener( listener )
|
15
15
|
end
|
16
16
|
|
17
|
+
def entity_expansion_count
|
18
|
+
@parser.entity_expansion_count
|
19
|
+
end
|
20
|
+
|
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
|
+
|
17
29
|
def parse
|
18
30
|
# entity string
|
19
31
|
while true
|
20
32
|
event = @parser.pull
|
21
33
|
case event[0]
|
22
34
|
when :end_document
|
23
|
-
unless @tag_stack.empty?
|
24
|
-
tag_path = "/" + @tag_stack.join("/")
|
25
|
-
raise ParseException.new("Missing end tag for '#{tag_path}'",
|
26
|
-
@parser.source)
|
27
|
-
end
|
28
35
|
return
|
29
36
|
when :start_element
|
30
|
-
@tag_stack << event[1]
|
31
37
|
attrs = event[2].each do |n, v|
|
32
38
|
event[2][n] = @parser.unnormalize( v )
|
33
39
|
end
|
34
40
|
@listener.tag_start( event[1], attrs )
|
35
41
|
when :end_element
|
36
42
|
@listener.tag_end( event[1] )
|
37
|
-
@tag_stack.pop
|
38
43
|
when :text
|
39
|
-
unnormalized = @parser.unnormalize( event[1] )
|
44
|
+
unnormalized = @parser.unnormalize( event[1], @entities )
|
40
45
|
@listener.text( unnormalized )
|
41
46
|
when :processing_instruction
|
42
47
|
@listener.instruction( *event[1,2] )
|
@@ -48,6 +53,7 @@ module REXML
|
|
48
53
|
when :comment, :attlistdecl, :cdata, :xmldecl, :elementdecl
|
49
54
|
@listener.send( event[0].to_s, *event[1..-1] )
|
50
55
|
when :entitydecl, :notationdecl
|
56
|
+
@entities[ event[1] ] = event[2] if event.size == 3
|
51
57
|
@listener.send( event[0].to_s, event[1..-1] )
|
52
58
|
when :externalentity
|
53
59
|
entity_reference = event[1]
|
@@ -15,7 +15,6 @@ module REXML
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def parse
|
18
|
-
tag_stack = []
|
19
18
|
entities = nil
|
20
19
|
begin
|
21
20
|
while true
|
@@ -23,19 +22,13 @@ module REXML
|
|
23
22
|
#STDERR.puts "TREEPARSER GOT #{event.inspect}"
|
24
23
|
case event[0]
|
25
24
|
when :end_document
|
26
|
-
unless tag_stack.empty?
|
27
|
-
raise ParseException.new("No close tag for #{@build_context.xpath}",
|
28
|
-
@parser.source, @parser)
|
29
|
-
end
|
30
25
|
return
|
31
26
|
when :start_element
|
32
|
-
tag_stack.push(event[1])
|
33
27
|
el = @build_context = @build_context.add_element( event[1] )
|
34
28
|
event[2].each do |key, value|
|
35
29
|
el.attributes[key]=Attribute.new(key,value,self)
|
36
30
|
end
|
37
31
|
when :end_element
|
38
|
-
tag_stack.pop
|
39
32
|
@build_context = @build_context.parent
|
40
33
|
when :text
|
41
34
|
if @build_context[-1].instance_of? Text
|
data/lib/rexml/rexml.rb
CHANGED
data/lib/rexml/text.rb
CHANGED
@@ -268,7 +268,8 @@ module REXML
|
|
268
268
|
# u = Text.new( "sean russell", false, nil, true )
|
269
269
|
# u.value #-> "sean russell"
|
270
270
|
def value
|
271
|
-
@unnormalized ||= Text::unnormalize(
|
271
|
+
@unnormalized ||= Text::unnormalize(@string, doctype,
|
272
|
+
entity_expansion_text_limit: document&.entity_expansion_text_limit)
|
272
273
|
end
|
273
274
|
|
274
275
|
# Sets the contents of this text node. This expects the text to be
|
@@ -411,11 +412,12 @@ module REXML
|
|
411
412
|
end
|
412
413
|
|
413
414
|
# 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
|
415
417
|
sum = 0
|
416
418
|
string.gsub( /\r\n?/, "\n" ).gsub( REFERENCE ) {
|
417
419
|
s = Text.expand($&, doctype, filter)
|
418
|
-
if sum + s.bytesize >
|
420
|
+
if sum + s.bytesize > entity_expansion_text_limit
|
419
421
|
raise "entity expansion has grown too large"
|
420
422
|
else
|
421
423
|
sum += s.bytesize
|
metadata
CHANGED
@@ -1,28 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rexml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.3.
|
4
|
+
version: 3.3.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kouhei Sutou
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2024-
|
11
|
-
dependencies:
|
12
|
-
- !ruby/object:Gem::Dependency
|
13
|
-
name: strscan
|
14
|
-
requirement: !ruby/object:Gem::Requirement
|
15
|
-
requirements:
|
16
|
-
- - ">="
|
17
|
-
- !ruby/object:Gem::Version
|
18
|
-
version: '0'
|
19
|
-
type: :runtime
|
20
|
-
prerelease: false
|
21
|
-
version_requirements: !ruby/object:Gem::Requirement
|
22
|
-
requirements:
|
23
|
-
- - ">="
|
24
|
-
- !ruby/object:Gem::Version
|
25
|
-
version: '0'
|
10
|
+
date: 2024-09-04 00:00:00.000000000 Z
|
11
|
+
dependencies: []
|
26
12
|
description: An XML toolkit for Ruby
|
27
13
|
email:
|
28
14
|
- kou@cozmixng.org
|
@@ -116,7 +102,7 @@ homepage: https://github.com/ruby/rexml
|
|
116
102
|
licenses:
|
117
103
|
- BSD-2-Clause
|
118
104
|
metadata:
|
119
|
-
changelog_uri: https://github.com/ruby/rexml/releases/tag/v3.3.
|
105
|
+
changelog_uri: https://github.com/ruby/rexml/releases/tag/v3.3.7
|
120
106
|
rdoc_options:
|
121
107
|
- "--main"
|
122
108
|
- README.md
|