HTTP/2 Buffer Leak if UTF8 Conversion Fails
Motivation: Http2CodecUtil uses ByteBufUtil.writeUtf8 but does not account for it throwing an exception. If an exception is thrown because the format is not valid UTF16 encoded UTF8 then the buffer will leak. Modifications: - Make sure the buffer is released if an exception is thrown - Ensure call sites of the Http2CodecUtil.toByteBuf can tolerate and exception being thrown Result: No leak if exception data can not be converted to UTF8.
This commit is contained in:
parent
a75dcb2756
commit
7a7160f176
@ -152,7 +152,15 @@ public final class Http2CodecUtil {
|
|||||||
|
|
||||||
// Create the debug message. `* 3` because UTF-8 max character consumes 3 bytes.
|
// Create the debug message. `* 3` because UTF-8 max character consumes 3 bytes.
|
||||||
ByteBuf debugData = ctx.alloc().buffer(cause.getMessage().length() * 3);
|
ByteBuf debugData = ctx.alloc().buffer(cause.getMessage().length() * 3);
|
||||||
|
boolean shouldRelease = true;
|
||||||
|
try {
|
||||||
ByteBufUtil.writeUtf8(debugData, cause.getMessage());
|
ByteBufUtil.writeUtf8(debugData, cause.getMessage());
|
||||||
|
shouldRelease = false;
|
||||||
|
} finally {
|
||||||
|
if (shouldRelease) {
|
||||||
|
debugData.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
return debugData;
|
return debugData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ package io.netty.handler.codec.http2;
|
|||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.ByteBufUtil;
|
import io.netty.buffer.ByteBufUtil;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
import io.netty.channel.ChannelFutureListener;
|
import io.netty.channel.ChannelFutureListener;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
@ -705,7 +706,13 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
|
|||||||
*/
|
*/
|
||||||
private ChannelFuture goAway(ChannelHandlerContext ctx, Http2Exception cause) {
|
private ChannelFuture goAway(ChannelHandlerContext ctx, Http2Exception cause) {
|
||||||
long errorCode = cause != null ? cause.error().code() : NO_ERROR.code();
|
long errorCode = cause != null ? cause.error().code() : NO_ERROR.code();
|
||||||
ByteBuf debugData = Http2CodecUtil.toByteBuf(ctx, cause);
|
ByteBuf debugData = Unpooled.EMPTY_BUFFER;
|
||||||
|
try {
|
||||||
|
debugData = Http2CodecUtil.toByteBuf(ctx, cause);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
// We must continue on to prevent our internal state from becoming corrupted but we log this exception.
|
||||||
|
logger.warn("caught exception while translating " + cause + " to ByteBuf", t);
|
||||||
|
}
|
||||||
int lastKnownStream = connection().remote().lastStreamCreated();
|
int lastKnownStream = connection().remote().lastStreamCreated();
|
||||||
return goAway(ctx, lastKnownStream, errorCode, debugData, ctx.newPromise());
|
return goAway(ctx, lastKnownStream, errorCode, debugData, ctx.newPromise());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user