Skip to content

Commit

Permalink
Handle premature stream halt gracefully
Browse files Browse the repository at this point in the history
  • Loading branch information
akash-akya committed Jul 3, 2024
1 parent 689a1ca commit 3ec7da7
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 9 deletions.
28 changes: 19 additions & 9 deletions lib/unzip.ex
Original file line number Diff line number Diff line change
Expand Up @@ -175,17 +175,26 @@ defmodule Unzip do
end)
end

@end_of_stream :__end__

defp decompress(stream, 0x8) do
stream
|> Stream.concat([@end_of_stream])
|> Stream.transform(
fn ->
z = :zlib.open()
:ok = :zlib.inflateInit(z, -15)
z
end,
fn data, z -> {[:zlib.inflate(z, data)], z} end,
fn
@end_of_stream, z ->
:zlib.inflateEnd(z)
{[@end_of_stream], z}

data, z ->
{[:zlib.inflate(z, data)], z}
end,
fn z ->
:zlib.inflateEnd(z)
:zlib.close(z)
end
)
Expand All @@ -198,16 +207,17 @@ defmodule Unzip do
end

defp crc_check(stream, expected_crc) do
stream
|> Stream.transform(
fn -> :erlang.crc32(<<>>) end,
fn data, crc -> {[data], :erlang.crc32(crc, data)} end,
fn crc ->
Stream.transform(stream, :erlang.crc32(<<>>), fn
@end_of_stream, crc ->
unless crc == expected_crc do
raise Error, message: "CRC mismatch. expected: #{expected_crc} got: #{crc}"
end
end
)

{[], :ok}

data, crc ->
{[data], :erlang.crc32(crc, data)}
end)
end

defp read_cd_entries(zip, eocd) do
Expand Down
22 changes: 22 additions & 0 deletions test/unzip_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,28 @@ defmodule UnzipTest do
assert File.read!(Path.join(@fixture_path, "file-sample_1MB.doc")) == result
end

test "premature termination of stream" do
{:ok, file} = Unzip.new(local_zip("deflate.zip"))

assert_raise RuntimeError, "some error", fn ->
file
|> Unzip.file_stream!("file-sample_1MB.doc")
|> Enum.each(fn _ ->
raise "some error"
end)
end
end

test "CRC mismatch" do

Check failure on line 119 in test/unzip_test.exs

View workflow job for this annotation

GitHub Actions / Linux OTP 24.x / Elixir 1.14.x

test CRC mismatch (UnzipTest)

Check failure on line 119 in test/unzip_test.exs

View workflow job for this annotation

GitHub Actions / Linux OTP 25.x / Elixir 1.15.x

test CRC mismatch (UnzipTest)

Check failure on line 119 in test/unzip_test.exs

View workflow job for this annotation

GitHub Actions / Linux OTP 26.x / Elixir 1.15.x

test CRC mismatch (UnzipTest)

Check failure on line 119 in test/unzip_test.exs

View workflow job for this annotation

GitHub Actions / Linux OTP 26.x / Elixir 1.16.x

test CRC mismatch (UnzipTest)
{:ok, file} = Unzip.new(local_zip("crc_mismatch.zip"))

assert_raise Unzip.Error, "CRC mismatch. expected: 2912544069 got: 2912478533", fn ->
file
|> Unzip.file_stream!("file.txt")
|> Stream.run()
end
end

test "decompression for store" do
{:ok, file} = Unzip.new(local_zip("stored.zip"))

Expand Down

0 comments on commit 3ec7da7

Please sign in to comment.