Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Safely close compressor stream after failure #160

Closed
fredrikekre opened this issue Oct 31, 2023 · 0 comments · Fixed by #182
Closed

Safely close compressor stream after failure #160

fredrikekre opened this issue Oct 31, 2023 · 0 comments · Fixed by #182
Labels

Comments

@fredrikekre
Copy link

fredrikekre commented Oct 31, 2023

This is perhaps not a bug report, but looking for input on how to improve.

HTTP.jl uses the following pattern for decompressing request bodies (see https://github.com/JuliaWeb/HTTP.jl/blob/master/src/clientlayers/StreamRequest.jl#L122-L140):

using SimpleBufferStream, CodecZlib

# Create a dummy file to read from, this is the compressed HTTP body
file = "no-gzip"
write(file, "this is not gzipped")
io = open(file)

# Intermediate bufferstream so that we can read/write in chunks
buf = SimpleBufferStream.BufferStream()
decompressor = GzipDecompressorStream(buf)

# Write body into the decompressor, which decompresses into buf
tsk = @async begin
    try
        write(decompressor, io) # Doesn't throw
    finally
        close(decompressor) # This throws *before* closing buf
    end
end

write(stderr, buf) # Deadlocks because buf is never closed
wait(tsk)

The problem here is that there is a deadlock if the content can't be decompressed, e.g. if the content isn't gzipped to begin with. What happens is that write(decompressor, io) works, but then changemode! inside of close(decompressor) errors. Specifically,

stopped = stream.state.mode == :stop
is false, meaning that https://github.com/JuliaIO/TranscodingStreams.jl/blob/master/src/stream.jl#L186-L188 is never executed.

Ultimately this means that tsk fails, but since buf is still open, write(stderr, buf) deadlocks.

I found that using something like

tsk = @async begin
    try
        write(decompressor, io)
    finally
        try
            close(decompressor)
        catch
            close(buf) # explicity close buf in case of errors in close(decompressor)
            rethrow()
        end
    end
end

mitigates the issue but doesn't really seem like a satisfactory solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants