diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2FrameReader.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2FrameReader.java index 63e184bc7b..cc63b28474 100644 --- a/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2FrameReader.java +++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2FrameReader.java @@ -239,8 +239,8 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize return; } - // Get a view of the buffer for the size of the payload. - ByteBuf payload = in.readSlice(payloadLength); + // Only process up to payloadLength bytes. + int payloadEndIndex = in.readerIndex() + payloadLength; // We have consumed the data, next time we read we will be expecting to read a frame header. readingHeaders = true; @@ -248,39 +248,40 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize // Read the payload and fire the frame event to the listener. switch (frameType) { case DATA: - readDataFrame(ctx, payload, listener); + readDataFrame(ctx, in, payloadEndIndex, listener); break; case HEADERS: - readHeadersFrame(ctx, payload, listener); + readHeadersFrame(ctx, in, payloadEndIndex, listener); break; case PRIORITY: - readPriorityFrame(ctx, payload, listener); + readPriorityFrame(ctx, in, listener); break; case RST_STREAM: - readRstStreamFrame(ctx, payload, listener); + readRstStreamFrame(ctx, in, listener); break; case SETTINGS: - readSettingsFrame(ctx, payload, listener); + readSettingsFrame(ctx, in, listener); break; case PUSH_PROMISE: - readPushPromiseFrame(ctx, payload, listener); + readPushPromiseFrame(ctx, in, payloadEndIndex, listener); break; case PING: - readPingFrame(ctx, payload.readLong(), listener); + readPingFrame(ctx, in.readLong(), listener); break; case GO_AWAY: - readGoAwayFrame(ctx, payload, listener); + readGoAwayFrame(ctx, in, payloadEndIndex, listener); break; case WINDOW_UPDATE: - readWindowUpdateFrame(ctx, payload, listener); + readWindowUpdateFrame(ctx, in, listener); break; case CONTINUATION: - readContinuationFrame(payload, listener); + readContinuationFrame(in, payloadEndIndex, listener); break; default: - readUnknownFrame(ctx, payload, listener); + readUnknownFrame(ctx, in, payloadEndIndex, listener); break; } + in.readerIndex(payloadEndIndex); } private void verifyDataFrame() throws Http2Exception { @@ -408,21 +409,20 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize verifyNotProcessingHeaders(); } - private void readDataFrame(ChannelHandlerContext ctx, ByteBuf payload, + private void readDataFrame(ChannelHandlerContext ctx, ByteBuf payload, int payloadEndIndex, Http2FrameListener listener) throws Http2Exception { int padding = readPadding(payload); verifyPadding(padding); // Determine how much data there is to read by removing the trailing // padding. - int dataLength = lengthWithoutTrailingPadding(payload.readableBytes(), padding); + int dataLength = lengthWithoutTrailingPadding(payloadEndIndex - payload.readerIndex(), padding); ByteBuf data = payload.readSlice(dataLength); listener.onDataRead(ctx, streamId, data, padding, flags.endOfStream()); - payload.skipBytes(payload.readableBytes()); } - private void readHeadersFrame(final ChannelHandlerContext ctx, ByteBuf payload, + private void readHeadersFrame(final ChannelHandlerContext ctx, ByteBuf payload, int payloadEndIndex, Http2FrameListener listener) throws Http2Exception { final int headersStreamId = streamId; final Http2Flags headersFlags = flags; @@ -439,7 +439,7 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize throw streamError(streamId, PROTOCOL_ERROR, "A stream cannot depend on itself."); } final short weight = (short) (payload.readUnsignedByte() + 1); - final ByteBuf fragment = payload.readSlice(lengthWithoutTrailingPadding(payload.readableBytes(), padding)); + final int lenToRead = lengthWithoutTrailingPadding(payloadEndIndex - payload.readerIndex(), padding); // Create a handler that invokes the listener when the header block is complete. headersContinuation = new HeadersContinuation() { @@ -449,10 +449,10 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize } @Override - public void processFragment(boolean endOfHeaders, ByteBuf fragment, + public void processFragment(boolean endOfHeaders, ByteBuf fragment, int len, Http2FrameListener listener) throws Http2Exception { final HeadersBlockBuilder hdrBlockBuilder = headersBlockBuilder(); - hdrBlockBuilder.addFragment(fragment, ctx.alloc(), endOfHeaders); + hdrBlockBuilder.addFragment(fragment, len, ctx.alloc(), endOfHeaders); if (endOfHeaders) { listener.onHeadersRead(ctx, headersStreamId, hdrBlockBuilder.headers(), streamDependency, weight, exclusive, padding, headersFlags.endOfStream()); @@ -461,7 +461,7 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize }; // Process the initial fragment, invoking the listener's callback if end of headers. - headersContinuation.processFragment(flags.endOfHeaders(), fragment, listener); + headersContinuation.processFragment(flags.endOfHeaders(), payload, lenToRead, listener); resetHeadersContinuationIfEnd(flags.endOfHeaders()); return; } @@ -475,10 +475,10 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize } @Override - public void processFragment(boolean endOfHeaders, ByteBuf fragment, + public void processFragment(boolean endOfHeaders, ByteBuf fragment, int len, Http2FrameListener listener) throws Http2Exception { final HeadersBlockBuilder hdrBlockBuilder = headersBlockBuilder(); - hdrBlockBuilder.addFragment(fragment, ctx.alloc(), endOfHeaders); + hdrBlockBuilder.addFragment(fragment, len, ctx.alloc(), endOfHeaders); if (endOfHeaders) { listener.onHeadersRead(ctx, headersStreamId, hdrBlockBuilder.headers(), padding, headersFlags.endOfStream()); @@ -487,8 +487,8 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize }; // Process the initial fragment, invoking the listener's callback if end of headers. - final ByteBuf fragment = payload.readSlice(lengthWithoutTrailingPadding(payload.readableBytes(), padding)); - headersContinuation.processFragment(flags.endOfHeaders(), fragment, listener); + int len = lengthWithoutTrailingPadding(payloadEndIndex - payload.readerIndex(), padding); + headersContinuation.processFragment(flags.endOfHeaders(), payload, len, listener); resetHeadersContinuationIfEnd(flags.endOfHeaders()); } @@ -543,7 +543,7 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize } } - private void readPushPromiseFrame(final ChannelHandlerContext ctx, ByteBuf payload, + private void readPushPromiseFrame(final ChannelHandlerContext ctx, ByteBuf payload, int payloadEndIndex, Http2FrameListener listener) throws Http2Exception { final int pushPromiseStreamId = streamId; final int padding = readPadding(payload); @@ -558,9 +558,9 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize } @Override - public void processFragment(boolean endOfHeaders, ByteBuf fragment, + public void processFragment(boolean endOfHeaders, ByteBuf fragment, int len, Http2FrameListener listener) throws Http2Exception { - headersBlockBuilder().addFragment(fragment, ctx.alloc(), endOfHeaders); + headersBlockBuilder().addFragment(fragment, len, ctx.alloc(), endOfHeaders); if (endOfHeaders) { listener.onPushPromiseRead(ctx, pushPromiseStreamId, promisedStreamId, headersBlockBuilder().headers(), padding); @@ -569,8 +569,8 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize }; // Process the initial fragment, invoking the listener's callback if end of headers. - final ByteBuf fragment = payload.readSlice(lengthWithoutTrailingPadding(payload.readableBytes(), padding)); - headersContinuation.processFragment(flags.endOfHeaders(), fragment, listener); + int len = lengthWithoutTrailingPadding(payloadEndIndex - payload.readerIndex(), padding); + headersContinuation.processFragment(flags.endOfHeaders(), payload, len, listener); resetHeadersContinuationIfEnd(flags.endOfHeaders()); } @@ -583,11 +583,11 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize } } - private static void readGoAwayFrame(ChannelHandlerContext ctx, ByteBuf payload, + private static void readGoAwayFrame(ChannelHandlerContext ctx, ByteBuf payload, int payloadEndIndex, Http2FrameListener listener) throws Http2Exception { int lastStreamId = readUnsignedInt(payload); long errorCode = payload.readUnsignedInt(); - ByteBuf debugData = payload.readSlice(payload.readableBytes()); + ByteBuf debugData = payload.readSlice(payloadEndIndex - payload.readerIndex()); listener.onGoAwayRead(ctx, lastStreamId, errorCode, debugData); } @@ -601,18 +601,17 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize listener.onWindowUpdateRead(ctx, streamId, windowSizeIncrement); } - private void readContinuationFrame(ByteBuf payload, Http2FrameListener listener) + private void readContinuationFrame(ByteBuf payload, int payloadEndIndex, Http2FrameListener listener) throws Http2Exception { // Process the initial fragment, invoking the listener's callback if end of headers. - final ByteBuf continuationFragment = payload.readSlice(payload.readableBytes()); - headersContinuation.processFragment(flags.endOfHeaders(), continuationFragment, - listener); + headersContinuation.processFragment(flags.endOfHeaders(), payload, + payloadEndIndex - payload.readerIndex(), listener); resetHeadersContinuationIfEnd(flags.endOfHeaders()); } - private void readUnknownFrame(ChannelHandlerContext ctx, ByteBuf payload, Http2FrameListener listener) - throws Http2Exception { - payload = payload.readSlice(payload.readableBytes()); + private void readUnknownFrame(ChannelHandlerContext ctx, ByteBuf payload, + int payloadEndIndex, Http2FrameListener listener) throws Http2Exception { + payload = payload.readSlice(payloadEndIndex - payload.readerIndex()); listener.onUnknownFrame(ctx, frameType, streamId, flags, payload); } @@ -664,7 +663,7 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize * @param fragment the fragment of the header block to be added. * @param listener the listener to be notified if the header block is completed. */ - abstract void processFragment(boolean endOfHeaders, ByteBuf fragment, + abstract void processFragment(boolean endOfHeaders, ByteBuf fragment, int len, Http2FrameListener listener) throws Http2Exception; final HeadersBlockBuilder headersBlockBuilder() { @@ -704,33 +703,32 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize * This is used for an optimization for when the first fragment is the full * block. In that case, the buffer is used directly without copying. */ - final void addFragment(ByteBuf fragment, ByteBufAllocator alloc, boolean endOfHeaders) throws Http2Exception { + final void addFragment(ByteBuf fragment, int len, ByteBufAllocator alloc, + boolean endOfHeaders) throws Http2Exception { if (headerBlock == null) { - if (fragment.readableBytes() > headersDecoder.configuration().maxHeaderListSizeGoAway()) { + if (len > headersDecoder.configuration().maxHeaderListSizeGoAway()) { headerSizeExceeded(); } if (endOfHeaders) { // Optimization - don't bother copying, just use the buffer as-is. Need // to retain since we release when the header block is built. - headerBlock = fragment.retain(); + headerBlock = fragment.readRetainedSlice(len); } else { - headerBlock = alloc.buffer(fragment.readableBytes()); - headerBlock.writeBytes(fragment); + headerBlock = alloc.buffer(len).writeBytes(fragment, len); } return; } - if (headersDecoder.configuration().maxHeaderListSizeGoAway() - fragment.readableBytes() < + if (headersDecoder.configuration().maxHeaderListSizeGoAway() - len < headerBlock.readableBytes()) { headerSizeExceeded(); } - if (headerBlock.isWritable(fragment.readableBytes())) { + if (headerBlock.isWritable(len)) { // The buffer can hold the requested bytes, just write it directly. - headerBlock.writeBytes(fragment); + headerBlock.writeBytes(fragment, len); } else { // Allocate a new buffer that is big enough to hold the entire header block so far. - ByteBuf buf = alloc.buffer(headerBlock.readableBytes() + fragment.readableBytes()); - buf.writeBytes(headerBlock); - buf.writeBytes(fragment); + ByteBuf buf = alloc.buffer(headerBlock.readableBytes() + len); + buf.writeBytes(headerBlock).writeBytes(fragment, len); headerBlock.release(); headerBlock = buf; } diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2FrameWriter.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2FrameWriter.java index 3fa8413704..1e4cdcd937 100644 --- a/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2FrameWriter.java +++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2FrameWriter.java @@ -195,7 +195,7 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize ctx.write(lastFrame, promiseAggregator.newPromise()); // Write the payload. - lastFrame = data.readSlice(maxFrameSize); + lastFrame = data.readableBytes() != maxFrameSize ? data.readSlice(maxFrameSize) : data; data = null; ctx.write(lastFrame, promiseAggregator.newPromise()); }