Skip to content

Commit f704011

Browse files
makenowjustkou
andauthored
Reject unclosed DOCTYPE on parsing (#153)
Fix #152 --------- Co-authored-by: Sutou Kouhei <[email protected]>
1 parent d906ae2 commit f704011

File tree

3 files changed

+63
-15
lines changed

3 files changed

+63
-15
lines changed

lib/rexml/parsers/baseparser.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,12 @@ def pull_event
216216
x, @closed = @closed, nil
217217
return [ :end_element, x ]
218218
end
219-
return [ :end_document ] if empty?
219+
if empty?
220+
if @document_status == :in_doctype
221+
raise ParseException.new("Malformed DOCTYPE: unclosed", @source)
222+
end
223+
return [ :end_document ]
224+
end
220225
return @stack.shift if @stack.size > 0
221226
#STDERR.puts @source.encoding
222227
#STDERR.puts "BUFFER = #{@source.buffer.inspect}"
@@ -373,6 +378,9 @@ def pull_event
373378
@document_status = :after_doctype
374379
return [ :end_doctype ]
375380
end
381+
if @document_status == :in_doctype
382+
raise ParseException.new("Malformed DOCTYPE: invalid declaration", @source)
383+
end
376384
end
377385
if @document_status == :after_doctype
378386
@source.match(/\s*/um, true)

lib/rexml/parsers/treeparser.rb

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ def add_listener( listener )
1616

1717
def parse
1818
tag_stack = []
19-
in_doctype = false
2019
entities = nil
2120
begin
2221
while true
@@ -39,17 +38,15 @@ def parse
3938
tag_stack.pop
4039
@build_context = @build_context.parent
4140
when :text
42-
if not in_doctype
43-
if @build_context[-1].instance_of? Text
44-
@build_context[-1] << event[1]
45-
else
46-
@build_context.add(
47-
Text.new(event[1], @build_context.whitespace, nil, true)
48-
) unless (
49-
@build_context.ignore_whitespace_nodes and
50-
event[1].strip.size==0
51-
)
52-
end
41+
if @build_context[-1].instance_of? Text
42+
@build_context[-1] << event[1]
43+
else
44+
@build_context.add(
45+
Text.new(event[1], @build_context.whitespace, nil, true)
46+
) unless (
47+
@build_context.ignore_whitespace_nodes and
48+
event[1].strip.size==0
49+
)
5350
end
5451
when :comment
5552
c = Comment.new( event[1] )
@@ -60,14 +57,12 @@ def parse
6057
when :processing_instruction
6158
@build_context.add( Instruction.new( event[1], event[2] ) )
6259
when :end_doctype
63-
in_doctype = false
6460
entities.each { |k,v| entities[k] = @build_context.entities[k].value }
6561
@build_context = @build_context.parent
6662
when :start_doctype
6763
doctype = DocType.new( event[1..-1], @build_context )
6864
@build_context = doctype
6965
entities = {}
70-
in_doctype = true
7166
when :attlistdecl
7267
n = AttlistDecl.new( event[1..-1] )
7368
@build_context.add( n )

test/parse/test_document_type_declaration.rb

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,51 @@ def test_no_name
5353
end
5454
end
5555

56+
class TestUnclosed < self
57+
def test_no_extra_node
58+
exception = assert_raise(REXML::ParseException) do
59+
REXML::Document.new("<!DOCTYPE foo [")
60+
end
61+
assert_equal(<<~DETAIL.chomp, exception.to_s)
62+
Malformed DOCTYPE: unclosed
63+
Line: 1
64+
Position: 15
65+
Last 80 unconsumed characters:
66+
67+
DETAIL
68+
end
69+
70+
def test_start_element
71+
exception = assert_raise(REXML::ParseException) do
72+
REXML::Document.new(<<~DOCTYPE)
73+
<!DOCTYPE foo [ <r>
74+
DOCTYPE
75+
end
76+
assert_equal(<<~DETAIL.chomp, exception.to_s)
77+
Malformed DOCTYPE: invalid declaration
78+
Line: 1
79+
Position: 20
80+
Last 80 unconsumed characters:
81+
<r>#{' '}
82+
DETAIL
83+
end
84+
85+
def test_text
86+
exception = assert_raise(REXML::ParseException) do
87+
REXML::Document.new(<<~DOCTYPE)
88+
<!DOCTYPE foo [ text
89+
DOCTYPE
90+
end
91+
assert_equal(<<~DETAIL.chomp, exception.to_s)
92+
Malformed DOCTYPE: invalid declaration
93+
Line: 1
94+
Position: 21
95+
Last 80 unconsumed characters:
96+
text#{' '}
97+
DETAIL
98+
end
99+
end
100+
56101
class TestExternalID < self
57102
class TestSystem < self
58103
def test_left_bracket_in_system_literal

0 commit comments

Comments
 (0)