1 |
From 1ad9075734a7fd9d58920c714953ec851efcae6b Mon Sep 17 00:00:00 2001 |
2 |
From: usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> |
3 |
Date: Fri, 22 Feb 2013 09:35:46 +0000 |
4 |
Subject: [PATCH] * lib/rexml/document.rb |
5 |
(REXML::Document.entity_expansion_text_limit): new |
6 |
attribute to read/write entity expansion text limit. the |
7 |
default limit is 10Kb. |
8 |
|
9 |
* lib/rexml/text.rb (REXML::Text.unnormalize): check above attribute. |
10 |
|
11 |
|
12 |
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@39384 b2dd03c8-39d4-4d8f-98ff-823fe69b080e |
13 |
--- |
14 |
lib/rexml/document.rb | 12 ++++++++++++ |
15 |
lib/rexml/text.rb | 40 +++++++++++++++++++++++++--------------- |
16 |
test/rexml/test_entity.rb | 18 ++++++++++++++++++ |
17 |
3 files changed, 55 insertions(+), 15 deletions(-) |
18 |
|
19 |
diff --git a/lib/rexml/document.rb b/lib/rexml/document.rb |
20 |
index f9fdbda..c528037 100644 |
21 |
--- a/lib/rexml/document.rb |
22 |
+++ b/lib/rexml/document.rb |
23 |
@@ -213,6 +213,17 @@ def Document::entity_expansion_limit |
24 |
return @@entity_expansion_limit |
25 |
end |
26 |
|
27 |
+ @@entity_expansion_text_limit = 10_240 |
28 |
+ |
29 |
+ # Set the entity expansion limit. By default the limit is set to 10240. |
30 |
+ def Document::entity_expansion_text_limit=( val ) |
31 |
+ @@entity_expansion_text_limit = val |
32 |
+ end |
33 |
+ |
34 |
+ # Get the entity expansion limit. By default the limit is set to 10240 |
35 |
+ def Document::entity_expansion_text_limit |
36 |
+ return @@entity_expansion_text_limit |
37 |
+ end |
38 |
attr_reader :entity_expansion_count |
39 |
|
40 |
def record_entity_expansion |
41 |
diff --git a/lib/rexml/text.rb b/lib/rexml/text.rb |
42 |
index 6623c0c..878d13b 100644 |
43 |
--- a/lib/rexml/text.rb |
44 |
+++ b/lib/rexml/text.rb |
45 |
@@ -308,37 +308,35 @@ def Text::normalize( input, doctype=nil, entity_filter=nil ) |
46 |
|
47 |
# Unescapes all possible entities |
48 |
def Text::unnormalize( string, doctype=nil, filter=nil, illegal=nil ) |
49 |
- rv = string.clone |
50 |
- rv.gsub!( /\r\n?/, "\n" ) |
51 |
- matches = rv.scan( REFERENCE ) |
52 |
- return rv if matches.size == 0 |
53 |
- rv.gsub!( NUMERICENTITY ) {|m| |
54 |
- m=$1 |
55 |
- m = "0#{m}" if m[0] == ?x |
56 |
- [Integer(m)].pack('U*') |
57 |
+ sum = 0 |
58 |
+ string.gsub( /\r\n?/, "\n" ).gsub( REFERENCE ) { |
59 |
+ s = Text.expand($&, doctype, filter) |
60 |
+ if sum + s.bytesize > Document.entity_expansion_text_limit |
61 |
+ raise "entity expansion has grown too large" |
62 |
+ else |
63 |
+ sum += s.bytesize |
64 |
+ end |
65 |
+ s |
66 |
} |
67 |
- matches.collect!{|x|x[0]}.compact! |
68 |
- if matches.size > 0 |
69 |
- if doctype |
70 |
- matches.each do |entity_reference| |
71 |
- unless filter and filter.include?(entity_reference) |
72 |
- entity_value = doctype.entity( entity_reference ) |
73 |
- re = /&#{entity_reference};/ |
74 |
- rv.gsub!( re, entity_value ) if entity_value |
75 |
- end |
76 |
- end |
77 |
+ end |
78 |
+ |
79 |
+ def Text.expand(ref, doctype, filter) |
80 |
+ if ref[1] == ?# |
81 |
+ if ref[2] == ?x |
82 |
+ [ref[3...-1].to_i(16)].pack('U*') |
83 |
else |
84 |
- matches.each do |entity_reference| |
85 |
- unless filter and filter.include?(entity_reference) |
86 |
- entity_value = DocType::DEFAULT_ENTITIES[ entity_reference ] |
87 |
- re = /&#{entity_reference};/ |
88 |
- rv.gsub!( re, entity_value.value ) if entity_value |
89 |
- end |
90 |
- end |
91 |
- end |
92 |
- rv.gsub!( /&/, '&' ) |
93 |
- end |
94 |
- rv |
95 |
+ [ref[2...-1].to_i].pack('U*') |
96 |
+ end |
97 |
+ elsif ref == '&' |
98 |
+ '&' |
99 |
+ elsif filter and filter.include?( ref[1...-1] ) |
100 |
+ ref |
101 |
+ elsif doctype |
102 |
+ doctype.entity( ref[1...-1] ) or ref |
103 |
+ else |
104 |
+ entity_value = DocType::DEFAULT_ENTITIES[ ref[1...-1] ] |
105 |
+ entity_value ? entity_value.value : ref |
106 |
+ end |
107 |
end |
108 |
end |
109 |
end |
110 |
diff --git a/test/rexml/test_entity.rb b/test/rexml/test_entity.rb |
111 |
index e6d6f29..5900fac 100644 |
112 |
--- /dev/null |
113 |
+++ b/test/rexml/test_entity.rb |
114 |
@@ -0,0 +1,23 @@ def test_replace_entities |
115 |
+require "test/unit/testcase" |
116 |
+ |
117 |
+require 'rexml/document' |
118 |
+ |
119 |
+class EntityTester < Test::Unit::TestCase |
120 |
+ def test_entity_string_limit |
121 |
+ template = '<!DOCTYPE bomb [ <!ENTITY a "^" > ]> <bomb>$</bomb>' |
122 |
+ len = 5120 # 5k per entity |
123 |
+ template.sub!(/\^/, "B" * len) |
124 |
+ |
125 |
+ # 10k is OK |
126 |
+ entities = '&a;' * 2 # 5k entity * 2 = 10k |
127 |
+ xmldoc = REXML::Document.new(template.sub(/\$/, entities)) |
128 |
+ assert_equal(len * 2, xmldoc.root.text.bytesize) |
129 |
+ |
130 |
+ # above 10k explodes |
131 |
+ entities = '&a;' * 3 # 5k entity * 2 = 15k |
132 |
+ xmldoc = REXML::Document.new(template.sub(/\$/, entities)) |
133 |
+ assert_raises(RuntimeError) do |
134 |
+ xmldoc.root.text |
135 |
+ end |
136 |
+ end |
137 |
+end |
138 |
-- |
139 |
1.7.10 |
140 |
|