• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

box / box-java-sdk / #4529

11 Mar 2025 04:41PM UTC coverage: 72.055% (-0.008%) from 72.063%
#4529

push

github

web-flow
fix: trim `content-length` header value (#1297)

2 of 4 new or added lines in 1 file covered. (50.0%)

1 existing line in 1 file now uncovered.

8215 of 11401 relevant lines covered (72.06%)

0.72 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

73.77
/src/main/java/com/box/sdk/BinaryBodyUtils.java
1
package com.box.sdk;
2

3
import com.box.sdk.http.HttpHeaders;
4
import java.io.IOException;
5
import java.io.InputStream;
6
import java.io.OutputStream;
7

8
/**
9
 * Utility class to help writing binary data to output stream.
10
 */
11
final class BinaryBodyUtils {
12
    private static final int BUFFER_SIZE = 8192;
13

14
    private BinaryBodyUtils() {
15
        // utility class has no public constructor
16
    }
17

18
    /**
19
     * Writes response body bytes to output stream. After all closes the input stream.
20
     *
21
     * @param response Response that is going to be written.
22
     * @param output   Output stream.
23
     */
24
    static void writeStream(BoxAPIResponse response, OutputStream output) {
25
        writeStream(response, output, null);
1✔
26
    }
1✔
27

28
    /**
29
     * Writes response body bytes to output stream. After all closes the input stream.
30
     *
31
     * @param response Response that is going to be written.
32
     * @param output   Output stream.
33
     * @param listener Listener that will be notified on writing response. Can be null.
34
     */
35

36
    static void writeStream(BoxAPIResponse response, OutputStream output, ProgressListener listener) {
37
        try {
38
            InputStream input;
39
            if (listener != null) {
1✔
40
                input = response.getBody(listener);
1✔
41
            } else {
42
                input = response.getBody();
1✔
43
            }
44
            writeStreamTo(input, output);
1✔
45
        } finally {
46
            response.close();
1✔
47
        }
48
    }
1✔
49

50
    /**
51
     * Writes response body bytes to output stream. After all closes the input stream.
52
     *
53
     * @param response Response that is going to be written.
54
     * @param output   Output stream.
55
     */
56

57
    static void writeStreamWithContentLength(BoxAPIResponse response, OutputStream output) {
58
        writeStreamWithContentLength(response, output, null);
1✔
59
    }
1✔
60

61
    /**
62
     * Writes response body bytes to output stream. After all closes the input stream.
63
     *
64
     * @param response Response that is going to be written.
65
     * @param output   Output stream.
66
     * @param listener Listener that will be notified on writing response. Can be null.
67
     */
68

69
    static void writeStreamWithContentLength(BoxAPIResponse response, OutputStream output, ProgressListener listener) {
70
        try {
71
            InputStream input;
72
            if (listener != null) {
1✔
73
                input = response.getBody(listener);
×
74
            } else {
75
                input = response.getBody();
1✔
76
            }
77
            writeStreamTo(input, output, getContentLengthFromAPIResponse(response));
1✔
78
        } finally {
79
            response.close();
1✔
80
        }
81
    }
1✔
82

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();
1✔
94
        if (length == -1) {
1✔
95
            String headerValue = null;
1✔
96
            if (response.getHeaders().containsKey(HttpHeaders.CONTENT_LENGTH)) {
1✔
97
                headerValue = response.getHeaders().get(HttpHeaders.CONTENT_LENGTH).get(0);
1✔
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) {
1✔
103
                String trimmedHeaderValue = headerValue.trim();
1✔
104
                try {
105
                    length = Long.parseLong(trimmedHeaderValue);
1✔
106
                } catch (NumberFormatException e) {
×
NEW
107
                    throw new RuntimeException("Invalid content length: " + trimmedHeaderValue + " with: "
×
NEW
108
                        + trimmedHeaderValue.length() + " number of characters.");
×
109
                }
1✔
110
            }
111
        }
112

113
        return length;
1✔
114
    }
115

116
    /**
117
     * Writes content of input stream to provided output.
118
     *
119
     * @param input  Input that will be read.
120
     * @param output Output stream.
121
     */
122
    static void writeStreamTo(InputStream input, OutputStream output) {
123
        try {
124
            byte[] buffer = new byte[BUFFER_SIZE];
1✔
125
            int n = input.read(buffer);
1✔
126
            while (n != -1) {
1✔
127
                output.write(buffer, 0, n);
1✔
128
                n = input.read(buffer);
1✔
129
            }
130
        } catch (IOException e) {
×
131
            throw new RuntimeException(e);
×
132
        } finally {
133
            try {
134
                input.close();
1✔
135
                output.close();
1✔
136
            } catch (IOException e) {
×
137
                throw new RuntimeException(e);
×
138
            }
1✔
139
        }
140
    }
1✔
141

142
    /**
143
     * Writes the content of the input stream to the provided output stream, ensuring the exact number of bytes specified
144
     * by the expected length is written. If the stream ends prematurely an exception is thrown.
145
     *
146
     * @param input          The input stream to be read.
147
     * @param output         The output stream where data will be written.
148
     * @param expectedLength The expected number of bytes to be transferred.
149
     */
150

151
    static void writeStreamTo(InputStream input, OutputStream output, long expectedLength) {
152
        long totalBytesRead = 0;
1✔
153
        if (expectedLength < 0) {
1✔
154
            throw new RuntimeException("Expected content length should not be negative: " + expectedLength);
×
155
        }
156
        try {
157
            byte[] buffer = new byte[BUFFER_SIZE];
1✔
158
            for (int n = input.read(buffer); n != -1; n = input.read(buffer)) {
1✔
159
                output.write(buffer, 0, n);
1✔
160
                totalBytesRead += n;  // Track the total bytes read
1✔
161
            }
162
            if (totalBytesRead != expectedLength) {
1✔
163
                throw new IOException("Stream ended prematurely. Expected "
×
164
                    + expectedLength + " bytes, but read " + totalBytesRead + " bytes.");
165
            }
166
        } catch (IOException e) {
×
167
            throw new RuntimeException("Error during streaming: " + e.getMessage(), e);
×
168
        } finally {
169
            try {
170
                input.close();
1✔
171
                output.close();
1✔
172
            } catch (IOException closeException) {
×
173
                throw new RuntimeException("IOException during stream close", closeException);
×
174
            }
1✔
175
        }
176
    }
1✔
177
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc