Skip to content

Commit a659c63

Browse files
koumame
authored andcommitted
Fix a bug that invalid notation declaration may be generated
HackerOne: HO-1104077 It's caused by quote character. Reported by Juho Nurminen. Thanks!!!
1 parent 790dd11 commit a659c63

File tree

2 files changed

+118
-5
lines changed

2 files changed

+118
-5
lines changed

lib/rexml/doctype.rb

+20-4
Original file line numberDiff line numberDiff line change
@@ -255,13 +255,29 @@ def to_s
255255
c = nil
256256
c = parent.context if parent
257257
if c and c[:prologue_quote] == :apostrophe
258-
quote = "'"
258+
default_quote = "'"
259259
else
260-
quote = "\""
260+
default_quote = "\""
261261
end
262262
notation = "<!NOTATION #{@name} #{@middle}"
263-
notation << " #{quote}#{@public}#{quote}" if @public
264-
notation << " #{quote}#{@system}#{quote}" if @system
263+
if @public
264+
if @public.include?("'")
265+
quote = "\""
266+
else
267+
quote = default_quote
268+
end
269+
notation << " #{quote}#{@public}#{quote}"
270+
end
271+
if @system
272+
if @system.include?("'")
273+
quote = "\""
274+
elsif @system.include?("\"")
275+
quote = "'"
276+
else
277+
quote = default_quote
278+
end
279+
notation << " #{quote}#{@system}#{quote}"
280+
end
265281
notation << ">"
266282
notation
267283
end

test/test_doctype.rb

+98-1
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,26 @@ def test_to_s
8989
decl(@id, nil).to_s)
9090
end
9191

92+
def test_to_s_pubid_literal_include_apostrophe
93+
assert_equal("<!NOTATION #{@name} PUBLIC \"#{@id}'\">",
94+
decl("#{@id}'", nil).to_s)
95+
end
96+
9297
def test_to_s_with_uri
9398
assert_equal("<!NOTATION #{@name} PUBLIC \"#{@id}\" \"#{@uri}\">",
9499
decl(@id, @uri).to_s)
95100
end
96101

102+
def test_to_s_system_literal_include_apostrophe
103+
assert_equal("<!NOTATION #{@name} PUBLIC \"#{@id}\" \"system'literal\">",
104+
decl(@id, "system'literal").to_s)
105+
end
106+
107+
def test_to_s_system_literal_include_double_quote
108+
assert_equal("<!NOTATION #{@name} PUBLIC \"#{@id}\" 'system\"literal'>",
109+
decl(@id, "system\"literal").to_s)
110+
end
111+
97112
def test_to_s_apostrophe
98113
document = REXML::Document.new(<<-XML)
99114
<!DOCTYPE root SYSTEM "urn:x-test:sysid" [
@@ -107,6 +122,49 @@ def test_to_s_apostrophe
107122
notation.to_s)
108123
end
109124

125+
def test_to_s_apostrophe_pubid_literal_include_apostrophe
126+
document = REXML::Document.new(<<-XML)
127+
<!DOCTYPE root SYSTEM "urn:x-test:sysid" [
128+
#{decl("#{@id}'", @uri).to_s}
129+
]>
130+
<root/>
131+
XML
132+
# This isn't used for PubidLiteral because PubidChar includes '.
133+
document.context[:prologue_quote] = :apostrophe
134+
notation = document.doctype.notations[0]
135+
assert_equal("<!NOTATION #{@name} PUBLIC \"#{@id}'\" '#{@uri}'>",
136+
notation.to_s)
137+
end
138+
139+
def test_to_s_apostrophe_system_literal_include_apostrophe
140+
document = REXML::Document.new(<<-XML)
141+
<!DOCTYPE root SYSTEM "urn:x-test:sysid" [
142+
#{decl(@id, "system'literal").to_s}
143+
]>
144+
<root/>
145+
XML
146+
# This isn't used for SystemLiteral because SystemLiteral includes '.
147+
document.context[:prologue_quote] = :apostrophe
148+
notation = document.doctype.notations[0]
149+
assert_equal("<!NOTATION #{@name} PUBLIC '#{@id}' \"system'literal\">",
150+
notation.to_s)
151+
end
152+
153+
def test_to_s_apostrophe_system_literal_include_double_quote
154+
document = REXML::Document.new(<<-XML)
155+
<!DOCTYPE root SYSTEM "urn:x-test:sysid" [
156+
#{decl(@id, "system\"literal").to_s}
157+
]>
158+
<root/>
159+
XML
160+
# This isn't used for SystemLiteral because SystemLiteral includes ".
161+
# But quoted by ' because SystemLiteral includes ".
162+
document.context[:prologue_quote] = :apostrophe
163+
notation = document.doctype.notations[0]
164+
assert_equal("<!NOTATION #{@name} PUBLIC '#{@id}' 'system\"literal'>",
165+
notation.to_s)
166+
end
167+
110168
private
111169
def decl(id, uri)
112170
REXML::NotationDecl.new(@name, "PUBLIC", id, uri)
@@ -124,6 +182,16 @@ def test_to_s
124182
decl(@id).to_s)
125183
end
126184

185+
def test_to_s_include_apostrophe
186+
assert_equal("<!NOTATION #{@name} SYSTEM \"#{@id}'\">",
187+
decl("#{@id}'").to_s)
188+
end
189+
190+
def test_to_s_include_double_quote
191+
assert_equal("<!NOTATION #{@name} SYSTEM '#{@id}\"'>",
192+
decl("#{@id}\"").to_s)
193+
end
194+
127195
def test_to_s_apostrophe
128196
document = REXML::Document.new(<<-XML)
129197
<!DOCTYPE root SYSTEM "urn:x-test:sysid" [
@@ -137,9 +205,38 @@ def test_to_s_apostrophe
137205
notation.to_s)
138206
end
139207

208+
def test_to_s_apostrophe_include_apostrophe
209+
document = REXML::Document.new(<<-XML)
210+
<!DOCTYPE root SYSTEM "urn:x-test:sysid" [
211+
#{decl("#{@id}'").to_s}
212+
]>
213+
<root/>
214+
XML
215+
# This isn't used for SystemLiteral because SystemLiteral includes '.
216+
document.context[:prologue_quote] = :apostrophe
217+
notation = document.doctype.notations[0]
218+
assert_equal("<!NOTATION #{@name} SYSTEM \"#{@id}'\">",
219+
notation.to_s)
220+
end
221+
222+
def test_to_s_apostrophe_include_double_quote
223+
document = REXML::Document.new(<<-XML)
224+
<!DOCTYPE root SYSTEM "urn:x-test:sysid" [
225+
#{decl("#{@id}\"").to_s}
226+
]>
227+
<root/>
228+
XML
229+
# This isn't used for SystemLiteral because SystemLiteral includes ".
230+
# But quoted by ' because SystemLiteral includes ".
231+
document.context[:prologue_quote] = :apostrophe
232+
notation = document.doctype.notations[0]
233+
assert_equal("<!NOTATION #{@name} SYSTEM '#{@id}\"'>",
234+
notation.to_s)
235+
end
236+
140237
private
141238
def decl(id)
142-
REXML::NotationDecl.new(@name, "SYSTEM", id, nil)
239+
REXML::NotationDecl.new(@name, "SYSTEM", nil, id)
143240
end
144241
end
145242
end

0 commit comments

Comments
 (0)