Properly close ResponseBody when closing the InputStream

ResponseBody objects from Okhttp needs to be closed and, right now, we
just close the InputStream which is not sufficient.

I noticed that because I saw some warnings about leaked ResponseBody
instances in my logs.
This commit is contained in:
Guillaume Smet
2020-11-27 18:12:58 +01:00
parent ed4f9c8176
commit f5ad332d28

View File

@@ -14,6 +14,7 @@ import okhttp3.Protocol;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSink;
import okio.Okio;
@@ -179,7 +180,7 @@ public final class ObsoleteUrlFactory implements URLStreamHandlerFactory, Clonea
* <p>
* This code configures OkHttp to handle all HTTP and HTTPS connections created with
* {@link java.net.URL#openConnection()}:
*
*
* <pre>
* {
* &#64;code
@@ -404,7 +405,7 @@ public final class ObsoleteUrlFactory implements URLStreamHandlerFactory, Clonea
try {
Response response = getResponse(true);
if (hasBody(response) && response.code() >= HTTP_BAD_REQUEST) {
return response.body().byteStream();
return new ResponseBodyInputStream(response.body());
}
return null;
} catch (IOException e) {
@@ -486,7 +487,7 @@ public final class ObsoleteUrlFactory implements URLStreamHandlerFactory, Clonea
Response response = getResponse(false);
if (response.code() >= HTTP_BAD_REQUEST)
throw new FileNotFoundException(url.toString());
return response.body().byteStream();
return new ResponseBodyInputStream(response.body());
}
@Override
@@ -957,6 +958,7 @@ public final class ObsoleteUrlFactory implements URLStreamHandlerFactory, Clonea
initOutputStream(Okio.buffer(pipe.sink()), expectedContentLength);
}
@Override
public boolean isOneShot() {
return true;
}
@@ -1367,4 +1369,69 @@ public final class ObsoleteUrlFactory implements URLStreamHandlerFactory, Clonea
super(cause);
}
}
/**
* Make sure both the ResponseBody and the InputStream are closed when the InputStream coming from the ResponseBody
* is closed.
*/
private static final class ResponseBodyInputStream extends InputStream {
private final ResponseBody responseBody;
private final InputStream inputStream;
private ResponseBodyInputStream(ResponseBody responseBody) {
this.responseBody = responseBody;
this.inputStream = responseBody.byteStream();
}
@Override
public int read() throws IOException {
return inputStream.read();
}
@Override
public int read(byte b[]) throws IOException {
return inputStream.read(b);
}
@Override
public int read(byte b[], int off, int len) throws IOException {
return inputStream.read(b, off, len);
}
@Override
public long skip(long n) throws IOException {
return inputStream.skip(n);
}
@Override
public int available() throws IOException {
return inputStream.available();
}
@Override
public synchronized void mark(int readlimit) {
inputStream.mark(readlimit);
}
@Override
public synchronized void reset() throws IOException {
inputStream.reset();
}
@Override
public boolean markSupported() {
return inputStream.markSupported();
}
@Override
public void close() throws IOException {
try {
inputStream.close();
} finally {
responseBody.close();
}
}
}
}