Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f9d88e4

Browse filesBrowse files
koumame
authored andcommitted
Fix a bug that invalid document declaration may be generated
HackerOne: HO-1104077 It's caused by quote character. Reported by Juho Nurminen. Thanks!!!
1 parent f7bab89 commit f9d88e4
Copy full SHA for f9d88e4

File tree

Expand file treeCollapse file tree

2 files changed

+155
-35
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+155
-35
lines changed

‎lib/rexml/doctype.rb

Copy file name to clipboardExpand all lines: lib/rexml/doctype.rb
+50-35Lines changed: 50 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,44 @@
77
require_relative 'xmltokens'
88

99
module REXML
10+
class ReferenceWriter
11+
def initialize(id_type,
12+
public_id_literal,
13+
system_literal,
14+
context=nil)
15+
@id_type = id_type
16+
@public_id_literal = public_id_literal
17+
@system_literal = system_literal
18+
if context and context[:prologue_quote] == :apostrophe
19+
@default_quote = "'"
20+
else
21+
@default_quote = "\""
22+
end
23+
end
24+
25+
def write(output)
26+
output << " #{@id_type}"
27+
if @public_id_literal
28+
if @public_id_literal.include?("'")
29+
quote = "\""
30+
else
31+
quote = @default_quote
32+
end
33+
output << " #{quote}#{@public_id_literal}#{quote}"
34+
end
35+
if @system_literal
36+
if @system_literal.include?("'")
37+
quote = "\""
38+
elsif @system_literal.include?("\"")
39+
quote = "'"
40+
else
41+
quote = @default_quote
42+
end
43+
output << " #{quote}#{@system_literal}#{quote}"
44+
end
45+
end
46+
end
47+
1048
# Represents an XML DOCTYPE declaration; that is, the contents of <!DOCTYPE
1149
# ... >. DOCTYPES can be used to declare the DTD of a document, as well as
1250
# being used to declare entities used in the document.
@@ -110,19 +148,17 @@ def clone
110148
# Ignored
111149
def write( output, indent=0, transitive=false, ie_hack=false )
112150
f = REXML::Formatters::Default.new
113-
c = context
114-
if c and c[:prologue_quote] == :apostrophe
115-
quote = "'"
116-
else
117-
quote = "\""
118-
end
119151
indent( output, indent )
120152
output << START
121153
output << ' '
122154
output << @name
123-
output << " #{@external_id}" if @external_id
124-
output << " #{quote}#{@long_name}#{quote}" if @long_name
125-
output << " #{quote}#{@uri}#{quote}" if @uri
155+
if @external_id
156+
reference_writer = ReferenceWriter.new(@external_id,
157+
@long_name,
158+
@uri,
159+
context)
160+
reference_writer.write(output)
161+
end
126162
unless @children.empty?
127163
output << ' ['
128164
@children.each { |child|
@@ -252,32 +288,11 @@ def initialize name, middle, pub, sys
252288
end
253289

254290
def to_s
255-
c = nil
256-
c = parent.context if parent
257-
if c and c[:prologue_quote] == :apostrophe
258-
default_quote = "'"
259-
else
260-
default_quote = "\""
261-
end
262-
notation = "<!NOTATION #{@name} #{@middle}"
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
291+
context = nil
292+
context = parent.context if parent
293+
notation = "<!NOTATION #{@name}"
294+
reference_writer = ReferenceWriter.new(@middle, @public, @system, context)
295+
reference_writer.write(notation)
281296
notation << ">"
282297
notation
283298
end

‎test/test_doctype.rb

Copy file name to clipboardExpand all lines: test/test_doctype.rb
+105Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,111 @@ def test_notations
7777
end
7878
end
7979

80+
class TestDocType < Test::Unit::TestCase
81+
class TestExternalID < self
82+
class TestSystem < self
83+
class TestSystemLiteral < self
84+
def test_to_s
85+
doctype = REXML::DocType.new(["root", "SYSTEM", nil, "root.dtd"])
86+
assert_equal("<!DOCTYPE root SYSTEM \"root.dtd\">",
87+
doctype.to_s)
88+
end
89+
90+
def test_to_s_apostrophe
91+
doctype = REXML::DocType.new(["root", "SYSTEM", nil, "root.dtd"])
92+
doc = REXML::Document.new
93+
doc << doctype
94+
doctype.parent.context[:prologue_quote] = :apostrophe
95+
assert_equal("<!DOCTYPE root SYSTEM 'root.dtd'>",
96+
doctype.to_s)
97+
end
98+
99+
def test_to_s_single_quote_apostrophe
100+
doctype = REXML::DocType.new(["root", "SYSTEM", nil, "root'.dtd"])
101+
doc = REXML::Document.new
102+
doc << doctype
103+
# This isn't used.
104+
doctype.parent.context[:prologue_quote] = :apostrophe
105+
assert_equal("<!DOCTYPE root SYSTEM \"root'.dtd\">",
106+
doctype.to_s)
107+
end
108+
109+
def test_to_s_double_quote
110+
doctype = REXML::DocType.new(["root", "SYSTEM", nil, "root\".dtd"])
111+
doc = REXML::Document.new
112+
doc << doctype
113+
# This isn't used.
114+
doctype.parent.context[:prologue_quote] = :apostrophe
115+
assert_equal("<!DOCTYPE root SYSTEM 'root\".dtd'>",
116+
doctype.to_s)
117+
end
118+
end
119+
end
120+
121+
class TestPublic < self
122+
class TestPublicIDLiteral < self
123+
def test_to_s
124+
doctype = REXML::DocType.new(["root", "PUBLIC", "pub", "root.dtd"])
125+
assert_equal("<!DOCTYPE root PUBLIC \"pub\" \"root.dtd\">",
126+
doctype.to_s)
127+
end
128+
129+
def test_to_s_apostrophe
130+
doctype = REXML::DocType.new(["root", "PUBLIC", "pub", "root.dtd"])
131+
doc = REXML::Document.new
132+
doc << doctype
133+
doctype.parent.context[:prologue_quote] = :apostrophe
134+
assert_equal("<!DOCTYPE root PUBLIC 'pub' 'root.dtd'>",
135+
doctype.to_s)
136+
end
137+
138+
def test_to_s_apostrophe_include_apostrophe
139+
doctype = REXML::DocType.new(["root", "PUBLIC", "pub'", "root.dtd"])
140+
doc = REXML::Document.new
141+
doc << doctype
142+
# This isn't used.
143+
doctype.parent.context[:prologue_quote] = :apostrophe
144+
assert_equal("<!DOCTYPE root PUBLIC \"pub'\" 'root.dtd'>",
145+
doctype.to_s)
146+
end
147+
end
148+
149+
class TestSystemLiteral < self
150+
def test_to_s
151+
doctype = REXML::DocType.new(["root", "PUBLIC", "pub", "root.dtd"])
152+
assert_equal("<!DOCTYPE root PUBLIC \"pub\" \"root.dtd\">",
153+
doctype.to_s)
154+
end
155+
156+
def test_to_s_apostrophe
157+
doctype = REXML::DocType.new(["root", "PUBLIC", "pub", "root.dtd"])
158+
doc = REXML::Document.new
159+
doc << doctype
160+
doctype.parent.context[:prologue_quote] = :apostrophe
161+
assert_equal("<!DOCTYPE root PUBLIC 'pub' 'root.dtd'>",
162+
doctype.to_s)
163+
end
164+
165+
def test_to_s_apostrophe_include_apostrophe
166+
doctype = REXML::DocType.new(["root", "PUBLIC", "pub", "root'.dtd"])
167+
doc = REXML::Document.new
168+
doc << doctype
169+
# This isn't used.
170+
doctype.parent.context[:prologue_quote] = :apostrophe
171+
assert_equal("<!DOCTYPE root PUBLIC 'pub' \"root'.dtd\">",
172+
doctype.to_s)
173+
end
174+
175+
def test_to_s_double_quote
176+
doctype = REXML::DocType.new(["root", "PUBLIC", "pub", "root\".dtd"])
177+
assert_equal("<!DOCTYPE root PUBLIC \"pub\" 'root\".dtd'>",
178+
doctype.to_s)
179+
end
180+
end
181+
end
182+
end
183+
end
184+
80185
class TestNotationDeclPublic < Test::Unit::TestCase
81186
def setup
82187
@name = "vrml"

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.