From a2a10b993171880bbe719ef0361cc69da253e9d4 Mon Sep 17 00:00:00 2001 From: feijermu Date: Thu, 2 Apr 2020 20:16:01 +0800 Subject: [PATCH] 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. --- .../multipart/AbstractMemoryHttpData.java | 23 ++++++++---- .../multipart/AbstractMemoryHttpDataTest.java | 37 +++++++++++++++++-- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/multipart/AbstractMemoryHttpData.java b/codec-http/src/main/java/io/netty/handler/codec/http/multipart/AbstractMemoryHttpData.java index 04bf68b141..e53c56ca2a 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/multipart/AbstractMemoryHttpData.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/multipart/AbstractMemoryHttpData.java @@ -130,15 +130,22 @@ public abstract class AbstractMemoryHttpData extends AbstractHttpData { } checkSize(newsize); RandomAccessFile accessFile = new RandomAccessFile(file, "r"); - FileChannel fileChannel = accessFile.getChannel(); - byte[] array = new byte[(int) newsize]; - ByteBuffer byteBuffer = ByteBuffer.wrap(array); - int read = 0; - while (read < newsize) { - read += fileChannel.read(byteBuffer); + ByteBuffer byteBuffer; + try { + FileChannel fileChannel = accessFile.getChannel(); + try { + byte[] array = new byte[(int) newsize]; + 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(); if (byteBuf != null) { byteBuf.release(); diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/multipart/AbstractMemoryHttpDataTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/multipart/AbstractMemoryHttpDataTest.java index 249f7365ba..0da3b3ca09 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/multipart/AbstractMemoryHttpDataTest.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/multipart/AbstractMemoryHttpDataTest.java @@ -23,16 +23,47 @@ import io.netty.buffer.Unpooled; import org.junit.Test; import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; import java.nio.charset.Charset; import java.security.SecureRandom; import java.util.Arrays; import java.util.Random; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; import static io.netty.util.CharsetUtil.*; import static org.junit.Assert.*; /** {@link AbstractMemoryHttpData} test cases. */ 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. * @@ -45,15 +76,13 @@ public class AbstractMemoryHttpDataTest { String contentStr = "foo_test"; ByteBuf buf = Unpooled.wrappedBuffer(contentStr.getBytes(UTF_8)); int readerIndex = buf.readerIndex(); - ByteBufInputStream is = new ByteBufInputStream(buf); - try { + + try (ByteBufInputStream is = new ByteBufInputStream(buf)) { 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();