From f5ad332d287630e8eefc3660ce5088b70ca7204f Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Fri, 27 Nov 2020 18:12:58 +0100 Subject: [PATCH] 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. --- .../extras/okhttp3/ObsoleteUrlFactory.java | 73 ++++++++++++++++++- 1 file changed, 70 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/kohsuke/github/extras/okhttp3/ObsoleteUrlFactory.java b/src/main/java/org/kohsuke/github/extras/okhttp3/ObsoleteUrlFactory.java index 0849a74098..54091b42cb 100644 --- a/src/main/java/org/kohsuke/github/extras/okhttp3/ObsoleteUrlFactory.java +++ b/src/main/java/org/kohsuke/github/extras/okhttp3/ObsoleteUrlFactory.java @@ -14,6 +14,7 @@ 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 @@ HttpURLConnection open(URL url, @Nullable Proxy proxy) { *

* This code configures OkHttp to handle all HTTP and HTTPS connections created with * {@link java.net.URL#openConnection()}: - * + * *

      * {
      *     @code
@@ -404,7 +405,7 @@ public InputStream getErrorStream() {
             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 InputStream getInputStream() throws IOException {
             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 @@ static final class StreamedRequestBody extends OutputStreamRequestBody {
             initOutputStream(Okio.buffer(pipe.sink()), expectedContentLength);
         }
 
+        @Override
         public boolean isOneShot() {
             return true;
         }
@@ -1367,4 +1369,69 @@ static final class UnexpectedException extends IOException {
             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();
+            }
+        }
+    }
 }