Skip to content

Commit d26fffa

Browse files
committed
WIP gh-71 : implemented the option for stream, and some minimal test
1 parent 9ec785a commit d26fffa

File tree

4 files changed

+48
-13
lines changed

4 files changed

+48
-13
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66

77
* Improvement on the doc
88

9+
### ADDED
10+
11+
* Added option to raise on DTD definitions
12+
913
## [0.6.6] (2019-02-24)
1014

1115
* small bugfix: Fix compilation warnings on newer versions of Elixir

lib/sweet_xml.ex

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,8 @@ defmodule SweetXml do
227227
"""
228228
def parse(doc, opts \\ []) do
229229
ets = :ets.new(nil, [])
230-
{dtd_arg, opts} = Keyword.pop(opts, :dtd, :all)
230+
dtd_arg = :proplists.get_value(:dtd, opts, :all)
231+
opts = :proplists.delete(:dtd, opts)
231232
opts = SweetXml.Options.handle_dtd(dtd_arg).(ets) ++ opts
232233
try do
233234
do_parse(doc, opts)
@@ -298,10 +299,9 @@ defmodule SweetXml do
298299
def stream_tags(doc, tags, options \\ []) do
299300
tags = if is_atom(tags), do: [tags], else: tags
300301

301-
{discard_tags, xmerl_options} = if options[:discard] do
302-
{options[:discard], Keyword.delete(options, :discard)}
303-
else
304-
{[], options}
302+
{discard_tags, xmerl_options} = case :proplists.lookup(:discard, options) do
303+
{:discard, tags} -> {tags, :proplists.delete(:discard, options)}
304+
:none -> {[], options}
305305
end
306306

307307
doc |> stream(fn emit ->
@@ -369,22 +369,32 @@ defmodule SweetXml do
369369
Stream.resource fn ->
370370
{parent, ref} = waiter = {self(), make_ref()}
371371
opts = options_callback.(fn e -> send(parent, {:event, ref, e}) end)
372+
373+
ets = :ets.new(nil, [:public])
374+
dtd_arg = :proplists.get_value(:dtd, opts, :all)
375+
opts = :proplists.delete(:dtd, opts)
376+
opts = SweetXml.Options.handle_dtd(dtd_arg).(ets) ++ opts
377+
372378
pid = spawn_link fn -> :xmerl_scan.string('', opts ++ continuation_opts(doc, waiter)) end
373-
{ref, pid, Process.monitor(pid)}
374-
end, fn {ref, pid, monref} = acc ->
379+
{ref, pid, Process.monitor(pid), ets}
380+
end, fn {ref, pid, monref, ets} = acc ->
375381
receive do
376382
{:DOWN, ^monref, _, _, _} ->
377-
{:halt, :parse_ended} ## !!! maybe do something when reason !== :normal
383+
{:halt, {:parse_ended, ets}} ## !!! maybe do something when reason !== :normal
378384
{:event, ^ref, event} ->
379385
{[event], acc}
380386
{:wait, ^ref} ->
381387
send(pid, {:continue, ref})
382388
{[], acc}
383389
end
384390
end, fn
385-
:parse_ended -> :ok
386-
{ref, pid, monref} ->
391+
{:parse_ended, ets} ->
392+
_ = :ets.delete(ets)
393+
:ok
394+
395+
{ref, pid, monref, ets} ->
387396
Process.demonitor(monref)
397+
_ = :ets.delete(ets)
388398
flush_halt(pid, ref)
389399
end
390400
end

mix.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ defmodule SweetXml.Mixfile do
1717

1818
def application do
1919
[
20-
applications: [:xmerl]
20+
applications: [:logger, :xmerl]
2121
]
2222
end
2323

test/issue_71_test.exs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
defmodule Issue71Test do
22
use ExUnit.Case
33

4-
test "read /etc/passwd with dtd: :none" do
4+
test "raise on reading /etc/passwd with dtd: :none" do
55
sneaky_xml = """
66
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
77
<!DOCTYPE foo [ <!ELEMENT foo ANY >
@@ -10,7 +10,7 @@ defmodule Issue71Test do
1010
"""
1111

1212
assert {:fatal, {{:error_fetching_DTD, {_, _}}, _file, _line, _col}} =
13-
catch_exit(SweetXml.parse(sneaky_xml, dtd: :none))
13+
catch_exit(SweetXml.parse(sneaky_xml, dtd: :none, quiet: true))
1414
end
1515

1616
test "raise on billion_laugh.xml with dtd: :none" do
@@ -19,4 +19,25 @@ defmodule Issue71Test do
1919
SweetXml.parse(dangerous_xml, dtd: :none)
2020
end
2121
end
22+
23+
test "stream: raise on reading /etc/passwd with dtd: :none" do
24+
sneaky_xml = """
25+
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
26+
<!DOCTYPE foo [ <!ELEMENT foo ANY >
27+
<!ENTITY xxe SYSTEM \"file:///etc/passwd\" >]>
28+
<response><result>&xxe;</result></response>
29+
"""
30+
31+
_ = Process.flag(:trap_exit, true)
32+
pid = spawn_link(fn -> Stream.run(SweetXml.stream_tags(sneaky_xml, :banana, dtd: :none, quiet: true)) end)
33+
assert_receive {:EXIT, ^pid, {:fatal, {{:error_fetching_DTD, {_, _}}, _file, _line, _col}}}
34+
end
35+
36+
test "stream: raise on billion_laugh.xml with dtd: :none" do
37+
dangerous_xml = File.read!("./test/files/billion_laugh.xml")
38+
39+
_ = Process.flag(:trap_exit, true)
40+
pid = spawn_link(fn -> Stream.run(SweetXml.stream_tags(dangerous_xml, :banana, dtd: :none, quiet: true)) end)
41+
assert_receive {:EXIT, ^pid, {%RuntimeError{}, _stacktrace}}
42+
end
2243
end

0 commit comments

Comments
 (0)