Skip to content

Commit b1d5371

Browse files
authored
fix: Correctly calculate Content-Length when reading from a stream (#1277)
1 parent 26b05bd commit b1d5371

File tree

4 files changed

+64
-6
lines changed

4 files changed

+64
-6
lines changed

src/intTest/java/com/box/sdk/BoxFileIT.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,27 @@ public void getRepresentationContentSucceeds() throws InterruptedException {
146146
}
147147
}
148148

149+
@Test
150+
public void getRepresentationContentWithExtractedTextSucceeds() throws InterruptedException {
151+
BoxAPIConnection api = jwtApiForServiceAccount();
152+
String fileName = "text.pdf";
153+
BoxFile file = null;
154+
try {
155+
file = uploadSampleFileToUniqueFolder(api, fileName);
156+
final String fileId = file.getID();
157+
String representationHint = "[extracted_text]";
158+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
159+
Retry.retry(() -> {
160+
new BoxFile(api, fileId).getRepresentationContent(representationHint, outputStream);
161+
byte[] downloadedRepresentationContent = outputStream.toByteArray();
162+
String text = new String(downloadedRepresentationContent, StandardCharsets.UTF_8);
163+
assertTrue(text.contains("Lorem ipsum"));
164+
}, 5, 100);
165+
} finally {
166+
deleteFile(file);
167+
}
168+
}
169+
149170
@Test
150171
public void uploadFileStreamSucceeds() {
151172
BoxAPIConnection api = jwtApiForServiceAccount();
@@ -156,7 +177,7 @@ public void uploadFileStreamSucceeds() {
156177

157178
BoxFile uploadedFile = null;
158179
try {
159-
InputStream uploadStream = new ByteArrayInputStream(fileContent);
180+
InputStream uploadStream = new ByteArrayInputStream(fileContent);
160181
BoxFile.Info uploadedFileInfo = folder.uploadFile(uploadStream, BoxFileIT.generateString());
161182
uploadedFile = uploadedFileInfo.getResource();
162183

@@ -552,11 +573,11 @@ public void canPaginateOverListOfVersions() {
552573

553574
byte[] fileBytes = "Version 2".getBytes(StandardCharsets.UTF_8);
554575
uploadedFile.uploadNewVersion(
555-
new ByteArrayInputStream(fileBytes), null, fileBytes.length, mock(ProgressListener.class));
576+
new ByteArrayInputStream(fileBytes), null, fileBytes.length, mock(ProgressListener.class));
556577

557578
fileBytes = "Version 3".getBytes(StandardCharsets.UTF_8);
558579
uploadedFile.uploadNewVersion(
559-
new ByteArrayInputStream(fileBytes), null, fileBytes.length, mock(ProgressListener.class));
580+
new ByteArrayInputStream(fileBytes), null, fileBytes.length, mock(ProgressListener.class));
560581

561582
Collection<BoxFileVersion> versionsPart1 = uploadedFile.getVersionsRange(0, 1);
562583
assertThat(versionsPart1.size(), is(1));

src/main/java/com/box/sdk/BinaryBodyUtils.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.box.sdk;
22

3+
import com.box.sdk.http.HttpHeaders;
34
import java.io.IOException;
45
import java.io.InputStream;
56
import java.io.OutputStream;
@@ -73,12 +74,43 @@ static void writeStreamWithContentLength(BoxAPIResponse response, OutputStream o
7374
} else {
7475
input = response.getBody();
7576
}
76-
writeStreamTo(input, output, response.getContentLength());
77+
writeStreamTo(input, output, getContentLengthFromAPIResponse(response));
7778
} finally {
7879
response.close();
7980
}
8081
}
8182

83+
/**
84+
* Get the content length from the API response.
85+
* In some cases, the Content-Length is not provided in the response headers.
86+
* This could happen when getting the content representation for a compressed data.
87+
* In that case the API will switch to chunk mode and provide the length in the "X-Original-Content-Length" header.
88+
*
89+
* @param response API response.
90+
* @return Content length.
91+
*/
92+
private static long getContentLengthFromAPIResponse(BoxAPIResponse response) {
93+
long length = response.getContentLength();
94+
if (length == -1) {
95+
String headerValue = null;
96+
if (response.getHeaders().containsKey(HttpHeaders.CONTENT_LENGTH)) {
97+
headerValue = response.getHeaders().get(HttpHeaders.CONTENT_LENGTH).get(0);
98+
} else if (response.getHeaders().containsKey(HttpHeaders.X_ORIGINAL_CONTENT_LENGTH)) {
99+
headerValue = response.getHeaders().get(HttpHeaders.X_ORIGINAL_CONTENT_LENGTH).get(0);
100+
}
101+
102+
if (headerValue != null) {
103+
try {
104+
length = Integer.parseInt(headerValue);
105+
} catch (NumberFormatException e) {
106+
throw new RuntimeException("Invalid content length: " + headerValue);
107+
}
108+
}
109+
}
110+
111+
return length;
112+
}
113+
82114
/**
83115
* Writes content of input stream to provided output.
84116
*
@@ -126,8 +158,8 @@ static void writeStreamTo(InputStream input, OutputStream output, long expectedL
126158
totalBytesRead += n; // Track the total bytes read
127159
}
128160
if (totalBytesRead != expectedLength) {
129-
throw new IOException("Stream ended prematurely. Expected " + expectedLength
130-
+ " bytes, but read " + totalBytesRead + " bytes.");
161+
throw new IOException("Stream ended prematurely. Expected "
162+
+ expectedLength + " bytes, but read " + totalBytesRead + " bytes.");
131163
}
132164
} catch (IOException e) {
133165
throw new RuntimeException("Error during streaming: " + e.getMessage(), e);

src/main/java/com/box/sdk/http/HttpHeaders.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ public final class HttpHeaders {
1010
*/
1111
public static final String CONTENT_LENGTH = "Content-Length";
1212

13+
/**
14+
* HTTP header key X-Original-Content-Length.
15+
*/
16+
public static final String X_ORIGINAL_CONTENT_LENGTH = "X-Original-Content-Length";
17+
1318
/**
1419
* HTTP header key Content-Type.
1520
*/
11.1 KB
Binary file not shown.

0 commit comments

Comments
 (0)