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

box / box-java-sdk / #4518

11 Mar 2025 09:58AM UTC coverage: 72.057% (-0.006%) from 72.063%
#4518

Pull #1297

github

web-flow
Merge 8d4b48676 into 7f4944302
Pull Request #1297: fix: trim `content-length` header value

1 of 3 new or added lines in 1 file covered. (33.33%)

6 existing lines in 1 file now uncovered.

8221 of 11409 relevant lines covered (72.06%)

0.72 hits per line

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

73.33
/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
                try {
104
                    length = Long.parseLong(headerValue.trim());
1✔
105
                } catch (NumberFormatException e) {
×
NEW
106
                    throw new RuntimeException("Invalid content length: " + headerValue.trim() + " with: "
×
NEW
107
                        + headerValue.trim().length() + " number of characters.");
×
108
                }
1✔
109
            }
110
        }
111

112
        return length;
1✔
113
    }
114

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

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

150
    static void writeStreamTo(InputStream input, OutputStream output, long expectedLength) {
151
        long totalBytesRead = 0;
1✔
152
        if (expectedLength < 0) {
1✔
UNCOV
153
            throw new RuntimeException("Expected content length should not be negative: " + expectedLength);
×
154
        }
155
        try {
156
            byte[] buffer = new byte[BUFFER_SIZE];
1✔
157
            for (int n = input.read(buffer); n != -1; n = input.read(buffer)) {
1✔
158
                output.write(buffer, 0, n);
1✔
159
                totalBytesRead += n;  // Track the total bytes read
1✔
160
            }
161
            if (totalBytesRead != expectedLength) {
1✔
UNCOV
162
                throw new IOException("Stream ended prematurely. Expected "
×
163
                    + expectedLength + " bytes, but read " + totalBytesRead + " bytes.");
164
            }
UNCOV
165
        } catch (IOException e) {
×
166
            throw new RuntimeException("Error during streaming: " + e.getMessage(), e);
×
167
        } finally {
168
            try {
169
                input.close();
1✔
170
                output.close();
1✔
UNCOV
171
            } catch (IOException closeException) {
×
172
                throw new RuntimeException("IOException during stream close", closeException);
×
173
            }
1✔
174
        }
175
    }
1✔
176
}
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

© 2025 Coveralls, Inc