Fix for Issue #3308 related to slice missing retain

Motivations:
It seems that slicing a buffer and using this slice to write to CTX will
decrease the initial refCnt to 0, while the original buffer is not yet
fully used (not empty).

Modifications:
As suggested in the ticket and tested, when the currentBuffer is sliced
since it will still be used later on, the currentBuffer is retained.

Add a test case for this issue.

Result:
The currentBuffer still has its correct refCnt when reaching the last
write (not sliced) of 1 and therefore will be released correctly.
The exception does no more occur.

This fix should be applied to all branches >= 4.0.
This commit is contained in:
Frederic Bregier 2015-01-06 09:32:13 +01:00 committed by Norman Maurer
parent 8ed4807360
commit 85fecba770
2 changed files with 36 additions and 0 deletions

View File

@ -828,6 +828,7 @@ public class HttpPostRequestEncoder implements ChunkedInput<HttpContent> {
int length = currentBuffer.readableBytes();
if (length > HttpPostBodyUtil.chunkSize) {
ByteBuf slice = currentBuffer.slice(currentBuffer.readerIndex(), HttpPostBodyUtil.chunkSize);
currentBuffer.retain();
currentBuffer.skipBytes(HttpPostBodyUtil.chunkSize);
return slice;
} else {

View File

@ -16,8 +16,10 @@
package io.netty.handler.codec.http.multipart;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.SlicedByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.multipart.HttpPostRequestEncoder.EncoderMode;
@ -26,6 +28,7 @@ import io.netty.util.internal.StringUtil;
import org.junit.Test;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import static io.netty.handler.codec.http.HttpHeaderNames.*;
@ -187,6 +190,38 @@ public class HttpPostRequestEncoderTest {
assertEquals(expected, content);
}
@Test
public void testHttpPostRequestEncoderSlicedBuffer() throws Exception {
DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1,
HttpMethod.POST, "http://localhost");
HttpPostRequestEncoder encoder = new HttpPostRequestEncoder(request, true);
// add Form attribute
encoder.addBodyAttribute("getform", "POST");
encoder.addBodyAttribute("info", "first value");
encoder.addBodyAttribute("secondinfo", "secondvalue a&");
encoder.addBodyAttribute("thirdinfo", "short text");
int length = 100000;
char[] array = new char[length];
Arrays.fill(array, 'a');
String longText = new String(array);
encoder.addBodyAttribute("fourthinfo", longText.substring(0, 7470));
File file1 = new File(getClass().getResource("/file-01.txt").toURI());
encoder.addBodyFileUpload("myfile", file1, "application/x-zip-compressed", false);
encoder.finalizeRequest();
while (! encoder.isEndOfInput()) {
HttpContent httpContent = encoder.readChunk(null);
if (httpContent.content() instanceof SlicedByteBuf) {
assertEquals(2, httpContent.content().refCnt());
} else {
assertEquals(1, httpContent.content().refCnt());
}
httpContent.release();
}
encoder.cleanFiles();
encoder.close();
}
private static String getRequestBody(HttpPostRequestEncoder encoder) throws Exception {
encoder.finalizeRequest();