Skip to content

Commit 026ea6d

Browse files
committed
Don't keep slices around that could be overwritten
1 parent c49430d commit 026ea6d

File tree

4 files changed

+78
-2
lines changed

4 files changed

+78
-2
lines changed

multipart-core/src/main/java/io/netty/contrib/multipart/MultipartDecoder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ public Event next() {
204204
if (normal == 0) {
205205
return null;
206206
}
207-
undecodedPartData = buffer.readRetainedSlice(normal);
207+
undecodedPartData = buffer.readBytes(normal);
208208
addReceivedLength(normal);
209209
return Event.CONTENT;
210210
}

multipart-core/src/main/java/io/netty/contrib/multipart/UrlEncodedDecoder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ public Event next() {
130130
} else if (valueEnd == buffer.readerIndex()) {
131131
return null;
132132
} else {
133-
undecodedContent = buffer.readRetainedSlice(valueEnd - buffer.readerIndex());
133+
undecodedContent = buffer.readBytes(valueEnd - buffer.readerIndex());
134134
}
135135
if (quirks.contains(DecoderQuirk.EARLY_CRLF_CHECK) && buffer != null) {
136136
earlyEolCheck(buffer.readerIndex());

multipart-core/src/test/java/io/netty/contrib/multipart/MultipartDecoderTest.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,14 @@
2121
import org.junit.jupiter.api.Assertions;
2222
import org.junit.jupiter.api.Test;
2323

24+
import java.io.ByteArrayOutputStream;
25+
import java.io.IOException;
2426
import java.nio.charset.StandardCharsets;
27+
import java.util.ArrayList;
28+
import java.util.List;
29+
import java.util.concurrent.ThreadLocalRandom;
30+
31+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
2532

2633
class MultipartDecoderTest {
2734

@@ -193,4 +200,56 @@ private static int findDelimiter(int readerOffset, String input, String delimite
193200
b.release();
194201
}
195202
}
203+
204+
@Test
205+
public void bufferCompaction() throws IOException {
206+
byte[] fullData = new byte[10 * 1024 * 1024];
207+
ThreadLocalRandom.current().nextBytes(fullData);
208+
209+
bufferCompaction(PostBodyDecoder.builder().forMultipartBoundary("a"), "--a\r\n\r\n", fullData, "\r\n--a--");
210+
}
211+
212+
static void bufferCompaction(PostBodyDecoder decoder, String before, byte[] fullData, String after) throws IOException {
213+
// this test verifies that buffers returned by decodedContent remain unchanged over time. This tests for a bug
214+
// caused by incorrect discardSomeReadBytes calls
215+
216+
List<ByteBuf> readData = new ArrayList<>();
217+
218+
try (decoder) {
219+
decoder.add(Unpooled.copiedBuffer(before, StandardCharsets.UTF_8));
220+
221+
for (int i = 0; i < fullData.length / 1024; i++) {
222+
decoder.add(Unpooled.copiedBuffer(fullData, i * 1024, 1024));
223+
224+
while (true) {
225+
PostBodyDecoder.Event event = decoder.next();
226+
if (event == null) {
227+
break;
228+
} else if (event == PostBodyDecoder.Event.CONTENT) {
229+
readData.add(decoder.decodedContent());
230+
}
231+
}
232+
}
233+
234+
decoder.add(Unpooled.copiedBuffer(after, StandardCharsets.UTF_8));
235+
decoder.endInput();
236+
237+
while (true) {
238+
PostBodyDecoder.Event event = decoder.next();
239+
if (event == null) {
240+
break;
241+
} else if (event == PostBodyDecoder.Event.CONTENT) {
242+
readData.add(decoder.decodedContent());
243+
}
244+
}
245+
}
246+
247+
ByteArrayOutputStream combined = new ByteArrayOutputStream(fullData.length);
248+
for (ByteBuf buf : readData) {
249+
buf.readBytes(combined, buf.readableBytes());
250+
buf.release();
251+
}
252+
253+
assertArrayEquals(fullData, combined.toByteArray());
254+
}
196255
}

multipart-core/src/test/java/io/netty/contrib/multipart/UrlEncodedDecoderTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import org.junit.jupiter.api.Assertions;
66
import org.junit.jupiter.api.Test;
77

8+
import java.io.IOException;
89
import java.nio.charset.StandardCharsets;
10+
import java.util.concurrent.ThreadLocalRandom;
911

1012
class UrlEncodedDecoderTest {
1113
private void expectField(PostBodyDecoder decoder, String name, String value) {
@@ -101,4 +103,19 @@ public void spacesValue() {
101103
Assertions.assertNull(decoder.next());
102104
}
103105
}
106+
107+
@Test
108+
public void bufferCompaction() throws IOException {
109+
byte[] fullData = new byte[10 * 1024 * 1024];
110+
for (int i = 0; i < fullData.length; i++) {
111+
// avoid *valid* escape sequences, but we still need some invalid ones to trigger buffering behavior
112+
int c = ThreadLocalRandom.current().nextInt('f', 'z' + 1);
113+
if (c == 'f') {
114+
c = '%';
115+
}
116+
fullData[i] = (byte) c;
117+
}
118+
119+
MultipartDecoderTest.bufferCompaction(PostBodyDecoder.builder().forUrlEncodedData(), "xyz=", fullData, "");
120+
}
104121
}

0 commit comments

Comments
 (0)