Skip to content

Commit 0b9b9b4

Browse files
committed
Avoid overreading of InputStream in copyRange
Closes gh-32695
1 parent 40596d4 commit 0b9b9b4

File tree

2 files changed

+36
-16
lines changed

2 files changed

+36
-16
lines changed

spring-core/src/main/java/org/springframework/util/StreamUtils.java

+8-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -177,18 +177,13 @@ public static long copyRange(InputStream in, OutputStream out, long start, long
177177
long bytesToCopy = end - start + 1;
178178
byte[] buffer = new byte[(int) Math.min(StreamUtils.BUFFER_SIZE, bytesToCopy)];
179179
while (bytesToCopy > 0) {
180-
int bytesRead = in.read(buffer);
180+
int bytesRead = (bytesToCopy < buffer.length ? in.read(buffer, 0, (int) bytesToCopy) :
181+
in.read(buffer));
181182
if (bytesRead == -1) {
182183
break;
183184
}
184-
else if (bytesRead <= bytesToCopy) {
185-
out.write(buffer, 0, bytesRead);
186-
bytesToCopy -= bytesRead;
187-
}
188-
else {
189-
out.write(buffer, 0, (int) bytesToCopy);
190-
bytesToCopy = 0;
191-
}
185+
out.write(buffer, 0, bytesRead);
186+
bytesToCopy -= bytesRead;
192187
}
193188
return (end - start + 1 - bytesToCopy);
194189
}
@@ -202,7 +197,9 @@ else if (bytesRead <= bytesToCopy) {
202197
* @since 4.3
203198
*/
204199
public static int drain(@Nullable InputStream in) throws IOException {
205-
Assert.notNull(in, "No InputStream specified");
200+
if (in == null) {
201+
return 0;
202+
}
206203
return (int) in.transferTo(OutputStream.nullOutputStream());
207204
}
208205

spring-core/src/test/java/org/springframework/util/StreamUtilsTests.java

+28-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -38,13 +38,15 @@
3838
* Tests for {@link StreamUtils}.
3939
*
4040
* @author Phillip Webb
41+
* @author Juergen Hoeller
4142
*/
4243
class StreamUtilsTests {
4344

4445
private byte[] bytes = new byte[StreamUtils.BUFFER_SIZE + 10];
4546

4647
private String string = "";
4748

49+
4850
@BeforeEach
4951
void setup() {
5052
new Random().nextBytes(bytes);
@@ -53,6 +55,7 @@ void setup() {
5355
}
5456
}
5557

58+
5659
@Test
5760
void copyToByteArray() throws Exception {
5861
InputStream inputStream = new ByteArrayInputStream(bytes);
@@ -91,11 +94,30 @@ void copyStream() throws Exception {
9194
}
9295

9396
@Test
94-
void copyRange() throws Exception {
97+
void copyRangeWithinBuffer() throws Exception {
98+
ByteArrayOutputStream out = new ByteArrayOutputStream();
99+
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
100+
StreamUtils.copyRange(in, out, 0, 100);
101+
assertThat(in.available()).isEqualTo(bytes.length - 101);
102+
assertThat(out.toByteArray()).isEqualTo(Arrays.copyOfRange(bytes, 0, 101));
103+
}
104+
105+
@Test
106+
void copyRangeBeyondBuffer() throws Exception {
95107
ByteArrayOutputStream out = new ByteArrayOutputStream();
96-
StreamUtils.copyRange(new ByteArrayInputStream(bytes), out, 0, 100);
97-
byte[] range = Arrays.copyOfRange(bytes, 0, 101);
98-
assertThat(out.toByteArray()).isEqualTo(range);
108+
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
109+
StreamUtils.copyRange(in, out, 0, 8200);
110+
assertThat(in.available()).isEqualTo(1);
111+
assertThat(out.toByteArray()).isEqualTo(Arrays.copyOfRange(bytes, 0, 8201));
112+
}
113+
114+
@Test
115+
void copyRangeBeyondAvailable() throws Exception {
116+
ByteArrayOutputStream out = new ByteArrayOutputStream();
117+
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
118+
StreamUtils.copyRange(in, out, 0, 8300);
119+
assertThat(in.available()).isEqualTo(0);
120+
assertThat(out.toByteArray()).isEqualTo(Arrays.copyOfRange(bytes, 0, 8202));
99121
}
100122

101123
@Test
@@ -127,4 +149,5 @@ void nonClosingOutputStream() throws Exception {
127149
ordered.verify(source).write(bytes, 1, 2);
128150
ordered.verify(source, never()).close();
129151
}
152+
130153
}

0 commit comments

Comments
 (0)