Release the ByteBuf when IOException occurs in AbstractMemoryHttpData. (#10133)

Motivation:

An IOException may be thrown from InputStream.read or checkSize method, and cause the ByteBuf leak.

Modification:

Release the ByteBuf when IOException occurs.

Result:
Avoid ByteBuf leak.
This commit is contained in:
feijermu 2020-03-30 17:26:03 +08:00 committed by Norman Maurer
parent a9a818de84
commit 92562f90d3
2 changed files with 34 additions and 7 deletions

View File

@ -65,18 +65,24 @@ public abstract class AbstractMemoryHttpData extends AbstractHttpData {
@Override @Override
public void setContent(InputStream inputStream) throws IOException { public void setContent(InputStream inputStream) throws IOException {
requireNonNull(inputStream, "inputStream"); requireNonNull(inputStream, "inputStream");
ByteBuf buffer = buffer();
byte[] bytes = new byte[4096 * 4]; byte[] bytes = new byte[4096 * 4];
int read = inputStream.read(bytes); ByteBuf buffer = buffer();
int written = 0; int written = 0;
while (read > 0) { try {
buffer.writeBytes(bytes, 0, read); int read = inputStream.read(bytes);
written += read; while (read > 0) {
checkSize(written); buffer.writeBytes(bytes, 0, read);
read = inputStream.read(bytes); written += read;
checkSize(written);
read = inputStream.read(bytes);
}
} catch (IOException e) {
buffer.release();
throw e;
} }
size = written; size = written;
if (definedSize > 0 && definedSize < size) { if (definedSize > 0 && definedSize < size) {
buffer.release();
throw new IOException("Out of size: " + size + " > " + definedSize); throw new IOException("Out of size: " + size + " > " + definedSize);
} }
if (byteBuf != null) { if (byteBuf != null) {

View File

@ -16,6 +16,10 @@
package io.netty.handler.codec.http.multipart; package io.netty.handler.codec.http.multipart;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import org.junit.Test; import org.junit.Test;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -36,6 +40,22 @@ public class AbstractMemoryHttpDataTest {
*/ */
@Test @Test
public void testSetContentFromStream() throws Exception { public void testSetContentFromStream() throws Exception {
// definedSize=0
TestHttpData test = new TestHttpData("test", UTF_8, 0);
String contentStr = "foo_test";
ByteBuf buf = Unpooled.wrappedBuffer(contentStr.getBytes(UTF_8));
int readerIndex = buf.readerIndex();
ByteBufInputStream is = new ByteBufInputStream(buf);
try {
test.setContent(is);
assertFalse(buf.isReadable());
assertEquals(test.getString(UTF_8), contentStr);
buf.readerIndex(readerIndex);
assertTrue(ByteBufUtil.equals(buf, test.getByteBuf()));
} finally {
is.close();
}
Random random = new SecureRandom(); Random random = new SecureRandom();
for (int i = 0; i < 20; i++) { for (int i = 0; i < 20; i++) {
@ -56,6 +76,7 @@ public class AbstractMemoryHttpDataTest {
assertEquals(0, buffer.readerIndex()); assertEquals(0, buffer.readerIndex());
assertEquals(bytes.length, buffer.writerIndex()); assertEquals(bytes.length, buffer.writerIndex());
assertArrayEquals(bytes, Arrays.copyOf(buffer.array(), bytes.length)); assertArrayEquals(bytes, Arrays.copyOf(buffer.array(), bytes.length));
assertArrayEquals(bytes, data.get());
} }
} }