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:
parent
a9a818de84
commit
92562f90d3
@ -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) {
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user