Close the file in case of an IOException in AbstractMemoryHttpData.renameTo. (#10163)

Motivation:

An `IOException` may be thrown from `FileChannel.write` or `FileChannel.force`, and cause the fd leak.

Modification:

Close the file in a finally block.

Result:

Avoid fd leak.
This commit is contained in:
feijermu 2020-04-06 16:12:46 +08:00 committed by GitHub
parent 363c4ecc7f
commit 3ebf3d7705
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 58 additions and 15 deletions

View File

@ -237,24 +237,29 @@ public abstract class AbstractMemoryHttpData extends AbstractHttpData {
return true;
}
int length = byteBuf.readableBytes();
RandomAccessFile accessFile = new RandomAccessFile(dest, "rw");
FileChannel fileChannel = accessFile.getChannel();
int written = 0;
if (byteBuf.nioBufferCount() == 1) {
ByteBuffer byteBuffer = byteBuf.nioBuffer();
while (written < length) {
written += fileChannel.write(byteBuffer);
}
} else {
ByteBuffer[] byteBuffers = byteBuf.nioBuffers();
while (written < length) {
written += fileChannel.write(byteBuffers);
RandomAccessFile accessFile = new RandomAccessFile(dest, "rw");
try {
FileChannel fileChannel = accessFile.getChannel();
try {
if (byteBuf.nioBufferCount() == 1) {
ByteBuffer byteBuffer = byteBuf.nioBuffer();
while (written < length) {
written += fileChannel.write(byteBuffer);
}
} else {
ByteBuffer[] byteBuffers = byteBuf.nioBuffers();
while (written < length) {
written += fileChannel.write(byteBuffers);
}
}
fileChannel.force(false);
} finally {
fileChannel.close();
}
} finally {
accessFile.close();
}
fileChannel.force(false);
fileChannel.close();
accessFile.close();
return written == length;
}

View File

@ -25,6 +25,7 @@ import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.charset.Charset;
import java.security.SecureRandom;
@ -64,6 +65,43 @@ public class AbstractMemoryHttpDataTest {
test.delete();
}
}
@Test
public void testRenameTo() throws Exception {
TestHttpData test = new TestHttpData("test", UTF_8, 0);
try {
File tmpFile = File.createTempFile(UUID.randomUUID().toString(), ".tmp");
tmpFile.deleteOnExit();
final int totalByteCount = 4096;
byte[] bytes = new byte[totalByteCount];
PlatformDependent.threadLocalRandom().nextBytes(bytes);
ByteBuf content = Unpooled.wrappedBuffer(bytes);
test.setContent(content);
boolean succ = test.renameTo(tmpFile);
assertTrue(succ);
FileInputStream fis = new FileInputStream(tmpFile);
try {
byte[] buf = new byte[totalByteCount];
int count = 0;
int offset = 0;
int size = totalByteCount;
while ((count = fis.read(buf, offset, size)) > 0) {
offset += count;
size -= count;
if (offset >= totalByteCount || size <= 0) {
break;
}
}
assertArrayEquals(bytes, buf);
assertEquals(0, fis.available());
} finally {
fis.close();
}
} finally {
//release the ByteBuf in AbstractMemoryHttpData
test.delete();
}
}
/**
* Provide content into HTTP data with input stream.
*