diff --git a/src/main/java/com/box/sdk/BinaryBodyUtils.java b/src/main/java/com/box/sdk/BinaryBodyUtils.java index 58c4bcb24..9f34db3f7 100644 --- a/src/main/java/com/box/sdk/BinaryBodyUtils.java +++ b/src/main/java/com/box/sdk/BinaryBodyUtils.java @@ -46,6 +46,28 @@ static void writeStream(BoxAPIResponse response, OutputStream output, ProgressLi } } + /** + * Writes response body bytes to output stream. After all closes the input stream. + * + * @param response Response that is going to be written. + * @param output Output stream. + * @param listener Listener that will be notified on writing response. Can be null. + */ + + static void writeStreamWithContentLength(BoxAPIResponse response, OutputStream output, ProgressListener listener) { + try { + InputStream input; + if (listener != null) { + input = response.getBody(listener); + } else { + input = response.getBody(); + } + writeStreamTo(input, output, response.getContentLength()); + } finally { + response.close(); + } + } + /** * Writes content of input stream to provided output. Method is NOT closing input stream. * @@ -71,4 +93,31 @@ static void writeStreamTo(InputStream input, OutputStream output) { } } } + + static void writeStreamTo(InputStream input, OutputStream output, long expectedLength) { + long totalBytesRead = 0; + if (expectedLength < 0) { + throw new RuntimeException("No Data bytes in stream"); + } + try { + byte[] buffer = new byte[8192]; + for (int n = input.read(buffer); n != -1; n = input.read(buffer)) { + output.write(buffer, 0, n); + totalBytesRead += n; // Track the total bytes read + } + if (totalBytesRead != expectedLength) { + throw new IOException("Stream ended prematurely. Expected " + expectedLength + + " bytes, but read " + totalBytesRead + " bytes."); + } + } catch (IOException e) { + throw new RuntimeException("Error during streaming: " + e.getMessage(), e); + } finally { + try { + input.close(); + output.close(); + } catch (IOException closeException) { + throw new RuntimeException("IOException during stream close", closeException); + } + } + } } diff --git a/src/main/java/com/box/sdk/BoxFile.java b/src/main/java/com/box/sdk/BoxFile.java index bcb62cf15..d0dad40b5 100644 --- a/src/main/java/com/box/sdk/BoxFile.java +++ b/src/main/java/com/box/sdk/BoxFile.java @@ -1,6 +1,7 @@ package com.box.sdk; import static com.box.sdk.BinaryBodyUtils.writeStream; +import static com.box.sdk.BinaryBodyUtils.writeStreamWithContentLength; import static com.box.sdk.http.ContentType.APPLICATION_JSON; import static com.box.sdk.http.ContentType.APPLICATION_JSON_PATCH; import static com.eclipsesource.json.Json.NULL; @@ -602,7 +603,7 @@ private void makeRepresentationContentRequest( URL repURL = new URL(representationURLTemplate.replace("{+asset_path}", assetPath)); BoxAPIRequest repContentReq = new BoxAPIRequest(this.getAPI(), repURL, HttpMethod.GET); BoxAPIResponse response = repContentReq.send(); - writeStream(response, output); + writeStreamWithContentLength(response, output, null); } catch (MalformedURLException ex) { throw new BoxAPIException("Could not generate representation content URL"); diff --git a/src/test/java/com/box/sdk/BoxFileTest.java b/src/test/java/com/box/sdk/BoxFileTest.java index 6d642c638..62f7479bb 100644 --- a/src/test/java/com/box/sdk/BoxFileTest.java +++ b/src/test/java/com/box/sdk/BoxFileTest.java @@ -433,6 +433,7 @@ public void testGetThumbnailSucceeds() { )) .willReturn(WireMock.aResponse() .withHeader("Content-Type", "image/jpg") + .withHeader("Content-Length", String.valueOf(13)) .withBody("This is a JPG") .withStatus(200)) ); @@ -517,6 +518,7 @@ public void testGetRepresentationContentSuccess() { )) .willReturn(WireMock.aResponse() .withHeader("Content-Type", "image/jpg") + .withHeader("Content-Length", String.valueOf(13)) .withBody("This is a JPG") .withStatus(200)) );