Close the file when IOException occurs in AbstractMemoryHttpData. (#10157)

Motivation:

An IOException may be thrown from FileChannel.read, and cause the fd leak.

Modification:

Close the file when IOException occurs.

Result:
Avoid fd leak.
This commit is contained in:
feijermu 2020-04-02 20:16:01 +08:00 committed by Norman Maurer
parent dc69c04434
commit a2a10b9931
2 changed files with 48 additions and 12 deletions

View File

@ -130,15 +130,22 @@ public abstract class AbstractMemoryHttpData extends AbstractHttpData {
} }
checkSize(newsize); checkSize(newsize);
RandomAccessFile accessFile = new RandomAccessFile(file, "r"); RandomAccessFile accessFile = new RandomAccessFile(file, "r");
FileChannel fileChannel = accessFile.getChannel(); ByteBuffer byteBuffer;
byte[] array = new byte[(int) newsize]; try {
ByteBuffer byteBuffer = ByteBuffer.wrap(array); FileChannel fileChannel = accessFile.getChannel();
int read = 0; try {
while (read < newsize) { byte[] array = new byte[(int) newsize];
read += fileChannel.read(byteBuffer); byteBuffer = ByteBuffer.wrap(array);
int read = 0;
while (read < newsize) {
read += fileChannel.read(byteBuffer);
}
} finally {
fileChannel.close();
}
} finally {
accessFile.close();
} }
fileChannel.close();
accessFile.close();
byteBuffer.flip(); byteBuffer.flip();
if (byteBuf != null) { if (byteBuf != null) {
byteBuf.release(); byteBuf.release();

View File

@ -23,16 +23,47 @@ import io.netty.buffer.Unpooled;
import org.junit.Test; import org.junit.Test;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.Arrays; import java.util.Arrays;
import java.util.Random; import java.util.Random;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import static io.netty.util.CharsetUtil.*; import static io.netty.util.CharsetUtil.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
/** {@link AbstractMemoryHttpData} test cases. */ /** {@link AbstractMemoryHttpData} test cases. */
public class AbstractMemoryHttpDataTest { public class AbstractMemoryHttpDataTest {
@Test
public void testSetContentFromFile() throws Exception {
TestHttpData test = new TestHttpData("test", UTF_8, 0);
try {
File tmpFile = File.createTempFile(UUID.randomUUID().toString(), ".tmp");
tmpFile.deleteOnExit();
FileOutputStream fos = new FileOutputStream(tmpFile);
byte[] bytes = new byte[4096];
ThreadLocalRandom.current().nextBytes(bytes);
try {
fos.write(bytes);
fos.flush();
} finally {
fos.close();
}
test.setContent(tmpFile);
ByteBuf buf = test.getByteBuf();
assertEquals(buf.readerIndex(), 0);
assertEquals(buf.writerIndex(), bytes.length);
assertArrayEquals(bytes, test.get());
assertArrayEquals(bytes, ByteBufUtil.getBytes(buf));
} finally {
//release the ByteBuf
test.delete();
}
}
/** /**
* Provide content into HTTP data with input stream. * Provide content into HTTP data with input stream.
* *
@ -45,15 +76,13 @@ public class AbstractMemoryHttpDataTest {
String contentStr = "foo_test"; String contentStr = "foo_test";
ByteBuf buf = Unpooled.wrappedBuffer(contentStr.getBytes(UTF_8)); ByteBuf buf = Unpooled.wrappedBuffer(contentStr.getBytes(UTF_8));
int readerIndex = buf.readerIndex(); int readerIndex = buf.readerIndex();
ByteBufInputStream is = new ByteBufInputStream(buf);
try { try (ByteBufInputStream is = new ByteBufInputStream(buf)) {
test.setContent(is); test.setContent(is);
assertFalse(buf.isReadable()); assertFalse(buf.isReadable());
assertEquals(test.getString(UTF_8), contentStr); assertEquals(test.getString(UTF_8), contentStr);
buf.readerIndex(readerIndex); buf.readerIndex(readerIndex);
assertTrue(ByteBufUtil.equals(buf, test.getByteBuf())); assertTrue(ByteBufUtil.equals(buf, test.getByteBuf()));
} finally {
is.close();
} }
Random random = new SecureRandom(); Random random = new SecureRandom();