Destroy HttpPostMultipartRequestDecoder if contructor throws (#11207)

Motivation:

We need to call destroy() if the constructor of HttpPostMultipartRequestDecoder throws as otherwise we may leak memory.

Modifications:

- Call destroy() if we throw
- Add unit test

Result:

No more leaks when constructor throws

Co-authored-by: Frederic Bregier <frederic.bregier@waarp.fr>
This commit is contained in:
Norman Maurer 2021-04-28 12:27:12 +02:00
parent 4c11ce7241
commit 8636aad989
2 changed files with 38 additions and 6 deletions

View File

@ -31,6 +31,7 @@ import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.MultiPartSta
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException;
import io.netty.util.CharsetUtil;
import io.netty.util.internal.InternalThreadLocalMap;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.StringUtil;
import java.io.IOException;
@ -204,12 +205,17 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
}
currentStatus = MultiPartStatus.HEADERDELIMITER;
if (request instanceof HttpContent) {
// Offer automatically if the given request is als type of HttpContent
// See #1089
offer((HttpContent) request);
} else {
parseBody();
try {
if (request instanceof HttpContent) {
// Offer automatically if the given request is als type of HttpContent
// See #1089
offer((HttpContent) request);
} else {
parseBody();
}
} catch (Throwable e) {
destroy();
PlatformDependent.throwException(e);
}
}

View File

@ -15,11 +15,13 @@
*/
package io.netty.handler.codec.http.multipart;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.CharsetUtil;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
@ -55,4 +57,28 @@ public class HttpPostMultiPartRequestDecoderTest {
assertTrue(req.release());
}
}
@Test
public void testDecodeFullHttpRequestWithInvalidPayloadReleaseBuffer() {
String content = "\n--861fbeab-cd20-470c-9609-d40a0f704466\n" +
"Content-Disposition: form-data; name=\"image1\"; filename*=\"'some.jpeg\"\n" +
"Content-Type: image/jpeg\n" +
"Content-Length: 1\n" +
"x\n" +
"--861fbeab-cd20-470c-9609-d40a0f704466--\n";
FullHttpRequest req = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "/upload",
Unpooled.copiedBuffer(content, CharsetUtil.US_ASCII));
req.headers().set("content-type", "multipart/form-data; boundary=861fbeab-cd20-470c-9609-d40a0f704466");
req.headers().set("content-length", content.length());
try {
new HttpPostMultipartRequestDecoder(req);
fail("Was expecting an ErrorDataDecoderException");
} catch (HttpPostRequestDecoder.ErrorDataDecoderException expected) {
// expected
} finally {
assertTrue(req.release());
}
}
}