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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8e2ee370ff6c1ab70149f6743a12ddf1eeae2c2af3c20f8cb7c6e56ff9699eec
4
- data.tar.gz: 158254197a12b1038b9b5e116c9abc89a329ef97acda8031399a56d3aee45fe9
3
+ metadata.gz: 1a402bb00d8bf352521fb6ca5354ba92a22d110feedcba40a50e2de5abad277a
4
+ data.tar.gz: 51f7b5893eef8d8183eb14c719064368029b18c9909b3454047e308c7425ce5b
5
5
  SHA512:
6
- metadata.gz: 6b805e28e50ef71bbc5d0349fdd4ec57ec4811bba94fe4c3f8aa17bedb81971da48e98205c53a8eadd18f07b69a2f68c8200529d546aef4187f9f3e903670857
7
- data.tar.gz: df3e369135f9b156475772a77702a91d45b8ee64ad49f608b2b33dc63d7b07dd271d7ac458d0b5e944e613798a0940231282997a747c4838e3e5c3afaf60253b
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
@@ -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
- @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)
153
154
  end
154
155
 
155
156
  # The normalized value of this attribute. That is, the attribute with
@@ -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 > Security.entity_expansion_limit
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
- return elements[1] if self.kind_of? Document
445
- return self if parent.kind_of? Document or parent.nil?
446
- return parent.root
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 = attributes[ prefix ]
623
- ns = parent.namespace(prefix) if ns.nil? and parent
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
- # all entities -- both %ent; and &ent; entities. This differs from
72
- # +value()+ in that +value+ only replaces %ent; entities.
72
+ # &ent; entities.
73
73
  def unnormalized
74
- document.record_entity_expansion unless document.nil?
75
- v = value()
76
- return nil if v.nil?
77
- @unnormalized = Text::unnormalize(v, parent)
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
- @nsstack = []
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
- @nsstack[0] << $1
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
- @nsstack.shift
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
- @nsstack.unshift(curr_ns=Set.new)
458
- attributes, closed = parse_attributes(@prefixes, curr_ns)
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 @nsstack.find{|k| k.member?(prefix)}
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
- @nsstack.shift
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
- value = nil
509
- value = entities[ reference ] if entities
510
- if value
511
- record_entity_expansion
512
- else
513
- value = DEFAULT_ENTITIES[ reference ]
514
- value = value[2] if value
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
- 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
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 record_entity_expansion
574
- @entity_expansion_count += 1
575
- if @entity_expansion_count > Security.entity_expansion_limit
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, curr_ns)
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
- curr_ns << local_part
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
- @tag_stack = []
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
@@ -31,7 +31,7 @@
31
31
  module REXML
32
32
  COPYRIGHT = "Copyright © 2001-2008 Sean Russell <ser@germane-software.com>"
33
33
  DATE = "2008/019"
34
- VERSION = "3.3.5"
34
+ VERSION = "3.3.7"
35
35
  REVISION = ""
36
36
 
37
37
  Copyright = COPYRIGHT
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( @string, doctype )
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 > Security.entity_expansion_text_limit
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.5
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-08-12 00:00:00.000000000 Z
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.5
105
+ changelog_uri: https://github.com/ruby/rexml/releases/tag/v3.3.7
120
106
  rdoc_options:
121
107
  - "--main"
122
108
  - README.md