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:
parent
8ed4807360
commit
85fecba770
@ -828,6 +828,7 @@ public class HttpPostRequestEncoder implements ChunkedInput<HttpContent> {
|
|||||||
int length = currentBuffer.readableBytes();
|
int length = currentBuffer.readableBytes();
|
||||||
if (length > HttpPostBodyUtil.chunkSize) {
|
if (length > HttpPostBodyUtil.chunkSize) {
|
||||||
ByteBuf slice = currentBuffer.slice(currentBuffer.readerIndex(), HttpPostBodyUtil.chunkSize);
|
ByteBuf slice = currentBuffer.slice(currentBuffer.readerIndex(), HttpPostBodyUtil.chunkSize);
|
||||||
|
currentBuffer.retain();
|
||||||
currentBuffer.skipBytes(HttpPostBodyUtil.chunkSize);
|
currentBuffer.skipBytes(HttpPostBodyUtil.chunkSize);
|
||||||
return slice;
|
return slice;
|
||||||
} else {
|
} else {
|
||||||
|
@ -16,8 +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.SlicedByteBuf;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
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.HttpMethod;
|
||||||
import io.netty.handler.codec.http.HttpVersion;
|
import io.netty.handler.codec.http.HttpVersion;
|
||||||
import io.netty.handler.codec.http.multipart.HttpPostRequestEncoder.EncoderMode;
|
import io.netty.handler.codec.http.multipart.HttpPostRequestEncoder.EncoderMode;
|
||||||
@ -26,6 +28,7 @@ import io.netty.util.internal.StringUtil;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static io.netty.handler.codec.http.HttpHeaderNames.*;
|
import static io.netty.handler.codec.http.HttpHeaderNames.*;
|
||||||
@ -187,6 +190,38 @@ public class HttpPostRequestEncoderTest {
|
|||||||
assertEquals(expected, content);
|
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 {
|
private static String getRequestBody(HttpPostRequestEncoder encoder) throws Exception {
|
||||||
encoder.finalizeRequest();
|
encoder.finalizeRequest();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user