coobird / thumbnailator

Thumbnailator - a thumbnail generation library for Java
MIT License
5.14k stars 784 forks source link

Input streams are not closed after reading #126

Closed sagebind closed 6 years ago

sagebind commented 6 years ago

Expected behavior

Please describe what you are expecting the library to perform.

When using an InputStream as an image source, Thumbnailator should close the stream automatically when finished with reading from the stream.

Actual behavior

Please describe the actual behavior you are experiencing, including stack trace and other information which would help diagnose the issue.

When using an InputStream, the stream is never closed, resulting in possible memory or resource leaks. I am attempting to use the streamed response of an HTTP request to feed into Thumbnailator. Since the HTTP client uses connection pooling, the end result is that after making multiple requests, connections in the connection pool are still being used (even after the corresponding thumbnails are generated) and subsequent requests cause my application to hang indefinitely, waiting for connections to be closed and returned to the pool.

The reason this is happening is that Thumbnailator is never calling close() on the input streams it is given. As a workaround, I am closing the streams manually after generating the thumbnail.

Steps to reproduce the behavior

Please enter step-by-step instructions for reproducing the actual behavior. Including code can be helpful in diagnosing issue, but please keep the code to a minimal that will reproduce the behavior.

It can be reproduced with the following simple program:

import net.coobird.thumbnailator.Thumbnails;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class ResourceLeakExample {
    public static void main(String[] args) throws IOException {
        InputStream input = new FileInputStream("input.png") {
            @Override
            public void close() throws IOException {
                super.close();
                System.out.println("Resource closed");
            }
        };

        Thumbnails.of(input).outputFormat("png").size(200, 200).toFile("output.png");
    }
}

When running, notice that Resource closed is not printed. This appears to be a bug in net.coobird.thumbnailator.tasks.io.InputStreamImageSource, where adding a simple is.close() to the end of read() would fix it.

Environment

Please provide vendor and version information for the Operating System, JDK, and Thumbnailator. Please feel free to add any other information which may be pertinent.

oakit commented 6 years ago

use try with resource to be sure the inputsream is closed

try (InputStream input = new FileInputStream("input.png")) { Thumbnails.of(input).outputFormat("png").size(200, 200).toFile("output.png"); }

coobird commented 6 years ago

Sorry for the late reply.

To put it succinctly, this behavior is intended; the code that @oakit presents is a very nice way to handle InputStreams which are given to Thumbnailator.

Now, the long reason as to why this is the intended behavior comes down to Thumbnailator not being able to tell whether it should close the InputStream or not, since Thumbnailator itself does not have control over the lifecycle of that object. Since the caller is creating the InputStream, Thumbnailator shouldn't make any assumptions of whether the InputStream should be closed; the responsibility of the cleaning up after the InputStream lies with one who created the InputStream in the first place.

If Thumbnailator were making the InputStream itself, then Thumbnailator should be calling InputStream.close() but this is not the case, since Thumbnailator is merely receiving the InputStream object rather than creating it.