http2: count pad length field toward flow control. Fixes #5434

Motivation:
The HTTP/2 specification requires the pad length field of DATA, HEADERS and PUSH_PROMISE frames to be counted towards the flow control window. The current implementation doesn't do so (See #5434).

Furthermore, it's currently not possible to add one byte padding, as this would add the one byte pad length field as well as append one padding byte to the end of the frame.

Modifications:
Include the one byte pad length field in the padding parameter of the API. Thereby extending the allowed value range by one byte to 256 (inclusive). On the wire, a one byte padding is encoded with a pad length field with value zero and a 256 byte padding is encoded with a pad length field with value 255 and 255 bytes append to the end of the frame.

Result:
More correct padding.
This commit is contained in:
buchgr 2016-06-23 14:09:23 +02:00 committed by Scott Mitchell
parent 731f52fdf7
commit 73c4ad5f0a
10 changed files with 105 additions and 66 deletions

View File

@ -20,6 +20,7 @@ import io.netty.buffer.Unpooled;
import io.netty.util.IllegalReferenceCountException;
import io.netty.util.internal.UnstableApi;
import static io.netty.handler.codec.http2.Http2CodecUtil.verifyPadding;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
/**
@ -64,14 +65,13 @@ public final class DefaultHttp2DataFrame extends AbstractHttp2StreamFrame implem
*
* @param content non-{@code null} payload
* @param endStream whether this data should terminate the stream
* @param padding additional bytes that should be added to obscure the true content size
* @param padding additional bytes that should be added to obscure the true content size. Must be between 0 and
* 256 (inclusive).
*/
public DefaultHttp2DataFrame(ByteBuf content, boolean endStream, int padding) {
this.content = checkNotNull(content, "content");
this.endStream = endStream;
if (padding < 0 || padding > Http2CodecUtil.MAX_UNSIGNED_BYTE) {
throw new IllegalArgumentException("padding must be non-negative and less than 256");
}
verifyPadding(padding);
this.padding = padding;
}

View File

@ -396,11 +396,11 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize
private void readDataFrame(ChannelHandlerContext ctx, ByteBuf payload,
Http2FrameListener listener) throws Http2Exception {
short padding = readPadding(payload);
int padding = readPadding(payload);
// Determine how much data there is to read by removing the trailing
// padding.
int dataLength = payload.readableBytes() - padding;
int dataLength = lengthWithoutTrailingPadding(payload.readableBytes(), padding);
if (dataLength < 0) {
throw streamError(streamId, FRAME_SIZE_ERROR,
"Frame payload too small for padding.");
@ -424,7 +424,7 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize
final boolean exclusive = (word1 & 0x80000000L) != 0;
final int streamDependency = (int) (word1 & 0x7FFFFFFFL);
final short weight = (short) (payload.readUnsignedByte() + 1);
final ByteBuf fragment = payload.readSlice(payload.readableBytes() - padding);
final ByteBuf fragment = payload.readSlice(lengthWithoutTrailingPadding(payload.readableBytes(), padding));
// Create a handler that invokes the listener when the header block is complete.
headersContinuation = new HeadersContinuation() {
@ -471,7 +471,7 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize
};
// Process the initial fragment, invoking the listener's callback if end of headers.
final ByteBuf fragment = payload.readSlice(payload.readableBytes() - padding);
final ByteBuf fragment = payload.readSlice(lengthWithoutTrailingPadding(payload.readableBytes(), padding));
headersContinuation.processFragment(flags.endOfHeaders(), fragment, listener);
}
@ -542,7 +542,7 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize
};
// Process the initial fragment, invoking the listener's callback if end of headers.
final ByteBuf fragment = payload.readSlice(payload.readableBytes() - padding);
final ByteBuf fragment = payload.readSlice(lengthWithoutTrailingPadding(payload.readableBytes(), padding));
headersContinuation.processFragment(flags.endOfHeaders(), fragment, listener);
}
@ -589,13 +589,24 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize
}
/**
* If padding is present in the payload, reads the next byte as padding. Otherwise, returns zero.
* If padding is present in the payload, reads the next byte as padding. The padding also includes the one byte
* width of the pad length field. Otherwise, returns zero.
*/
private short readPadding(ByteBuf payload) {
private int readPadding(ByteBuf payload) {
if (!flags.paddingPresent()) {
return 0;
}
return payload.readUnsignedByte();
return payload.readUnsignedByte() + 1;
}
/**
* The padding parameter consists of the 1 byte pad length field and the trailing padding bytes. This method
* returns the number of readable bytes without the trailing padding.
*/
private static int lengthWithoutTrailingPadding(int readableBytes, int padding) {
return padding == 0
? readableBytes
: readableBytes - (padding - 1);
}
/**

View File

@ -46,6 +46,7 @@ import static io.netty.handler.codec.http2.Http2CodecUtil.WINDOW_UPDATE_FRAME_LE
import static io.netty.handler.codec.http2.Http2CodecUtil.isMaxFrameSizeValid;
import static io.netty.handler.codec.http2.Http2CodecUtil.writeFrameHeaderInternal;
import static io.netty.handler.codec.http2.Http2CodecUtil.writeUnsignedInt;
import static io.netty.handler.codec.http2.Http2CodecUtil.verifyPadding;
import static io.netty.handler.codec.http2.Http2CodecUtil.writeUnsignedShort;
import static io.netty.handler.codec.http2.Http2Error.FRAME_SIZE_ERROR;
import static io.netty.handler.codec.http2.Http2Exception.connectionError;
@ -71,7 +72,7 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
private static final String STREAM_ID = "Stream ID";
private static final String STREAM_DEPENDENCY = "Stream Dependency";
/**
* This buffer is allocated to the maximum padding size needed, and filled with padding.
* This buffer is allocated to the maximum size of the padding field, and filled with zeros.
* When padding is needed it can be taken as a slice of this buffer. Users should call {@link ByteBuf#retain()}
* before using their slice.
*/
@ -163,8 +164,8 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
ctx.write(lastFrame ? frameData : frameData.retain(), promiseAggregator.newPromise());
// Write the frame padding.
if (framePaddingBytes > 0) {
ctx.write(ZERO_BUFFER.slice(0, framePaddingBytes), promiseAggregator.newPromise());
if (paddingBytes(framePaddingBytes) > 0) {
ctx.write(ZERO_BUFFER.slice(0, paddingBytes(framePaddingBytes)), promiseAggregator.newPromise());
}
} while (!lastFrame);
} catch (Throwable t) {
@ -302,7 +303,7 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
// Read the first fragment (possibly everything).
Http2Flags flags = new Http2Flags().paddingPresent(padding > 0);
// INT_FIELD_LENGTH is for the length of the promisedStreamId
int nonFragmentLength = INT_FIELD_LENGTH + padding + flags.getPaddingPresenceFieldLength();
int nonFragmentLength = INT_FIELD_LENGTH + padding;
int maxFragmentLength = maxFrameSize - nonFragmentLength;
ByteBuf fragment = headerBlock.readRetainedSlice(min(headerBlock.readableBytes(), maxFragmentLength));
@ -320,8 +321,9 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
// Write the first fragment.
ctx.write(fragment, promiseAggregator.newPromise());
if (padding > 0) { // Write out the padding, if any.
ctx.write(ZERO_BUFFER.slice(0, padding), promiseAggregator.newPromise());
// Write out the padding, if any.
if (paddingBytes(padding) > 0) {
ctx.write(ZERO_BUFFER.slice(0, paddingBytes(padding)), promiseAggregator.newPromise());
}
if (!flags.endOfHeaders()) {
@ -426,7 +428,7 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
new Http2Flags().endOfStream(endStream).priorityPresent(hasPriority).paddingPresent(padding > 0);
// Read the first fragment (possibly everything).
int nonFragmentBytes = padding + flags.getNumPriorityBytes() + flags.getPaddingPresenceFieldLength();
int nonFragmentBytes = padding + flags.getNumPriorityBytes();
int maxFragmentLength = maxFrameSize - nonFragmentBytes;
ByteBuf fragment = headerBlock.readRetainedSlice(min(headerBlock.readableBytes(), maxFragmentLength));
@ -450,8 +452,9 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
// Write the first fragment.
ctx.write(fragment, promiseAggregator.newPromise());
if (padding > 0) { // Write out the padding, if any.
ctx.write(ZERO_BUFFER.slice(0, padding), promiseAggregator.newPromise());
// Write out the padding, if any.
if (paddingBytes(padding) > 0) {
ctx.write(ZERO_BUFFER.slice(0, paddingBytes(padding)), promiseAggregator.newPromise());
}
if (!flags.endOfHeaders()) {
@ -473,8 +476,7 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
private ChannelFuture writeContinuationFrames(ChannelHandlerContext ctx, int streamId,
ByteBuf headerBlock, int padding, SimpleChannelPromiseAggregator promiseAggregator) {
Http2Flags flags = new Http2Flags().paddingPresent(padding > 0);
int nonFragmentLength = padding + flags.getPaddingPresenceFieldLength();
int maxFragmentLength = maxFrameSize - nonFragmentLength;
int maxFragmentLength = maxFrameSize - padding;
// TODO: same padding is applied to all frames, is this desired?
if (maxFragmentLength <= 0) {
return promiseAggregator.setFailure(new IllegalArgumentException(
@ -484,7 +486,7 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
if (headerBlock.isReadable()) {
// The frame header (and padding) only changes on the last frame, so allocate it once and re-use
int fragmentReadableBytes = min(headerBlock.readableBytes(), maxFragmentLength);
int payloadLength = fragmentReadableBytes + nonFragmentLength;
int payloadLength = fragmentReadableBytes + padding;
ByteBuf buf = ctx.alloc().buffer(CONTINUATION_FRAME_HEADER_LENGTH);
writeFrameHeaderInternal(buf, payloadLength, CONTINUATION, flags, streamId);
writePaddingLength(buf, padding);
@ -493,7 +495,7 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
fragmentReadableBytes = min(headerBlock.readableBytes(), maxFragmentLength);
ByteBuf fragment = headerBlock.readRetainedSlice(fragmentReadableBytes);
payloadLength = fragmentReadableBytes + nonFragmentLength;
payloadLength = fragmentReadableBytes + padding;
if (headerBlock.isReadable()) {
ctx.write(buf.retain(), promiseAggregator.newPromise());
} else {
@ -509,18 +511,28 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
ctx.write(fragment, promiseAggregator.newPromise());
// Write out the padding, if any.
if (padding > 0) {
ctx.write(ZERO_BUFFER.slice(0, padding), promiseAggregator.newPromise());
if (paddingBytes(padding) > 0) {
ctx.write(ZERO_BUFFER.slice(0, paddingBytes(padding)), promiseAggregator.newPromise());
}
} while(headerBlock.isReadable());
}
return promiseAggregator;
}
private static void writePaddingLength(ByteBuf buf, int paddingLength) {
if (paddingLength > 0) {
/**
* Returns the number of padding bytes that should be appended to the end of a frame.
*/
private static int paddingBytes(int padding) {
// The padding parameter contains the 1 byte pad length field as well as the trailing padding bytes.
// Subtract 1, so to only get the number of padding bytes that need to be appended to the end of a frame.
return padding - 1;
}
private static void writePaddingLength(ByteBuf buf, int padding) {
if (padding > 0) {
// It is assumed that the padding length has been bounds checked before this
buf.writeByte(paddingLength);
// Minus 1, as the pad length field is included in the padding parameter and is 1 byte wide.
buf.writeByte(padding - 1);
}
}
@ -536,12 +548,6 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
}
}
private static void verifyPadding(int padding) {
if (padding < 0 || padding > MAX_UNSIGNED_BYTE) {
throw new IllegalArgumentException("Invalid padding value: " + padding);
}
}
private static void verifyWeight(short weight) {
if (weight < MIN_WEIGHT || weight > MAX_WEIGHT) {
throw new IllegalArgumentException("Invalid weight: " + weight);
@ -601,7 +607,7 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
flags.endOfStream(endOfStream);
frameHeader = buffer.readSlice(DATA_FRAME_HEADER_LENGTH).writerIndex(0);
int payloadLength = data + padding + flags.getPaddingPresenceFieldLength();
int payloadLength = data + padding;
writeFrameHeaderInternal(frameHeader, payloadLength, DATA, flags, streamId);
writePaddingLength(frameHeader, padding);
}

View File

@ -17,6 +17,7 @@ package io.netty.handler.codec.http2;
import io.netty.util.internal.UnstableApi;
import static io.netty.handler.codec.http2.Http2CodecUtil.verifyPadding;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
/**
@ -51,14 +52,13 @@ public final class DefaultHttp2HeadersFrame extends AbstractHttp2StreamFrame imp
*
* @param headers the non-{@code null} headers to send
* @param endStream whether these headers should terminate the stream
* @param padding additional bytes that should be added to obscure the true content size
* @param padding additional bytes that should be added to obscure the true content size. Must be between 0 and
* 256 (inclusive).
*/
public DefaultHttp2HeadersFrame(Http2Headers headers, boolean endStream, int padding) {
this.headers = checkNotNull(headers, "headers");
this.endStream = endStream;
if (padding < 0 || padding > Http2CodecUtil.MAX_UNSIGNED_BYTE) {
throw new IllegalArgumentException("padding must be non-negative and less than 256");
}
verifyPadding(padding);
this.padding = padding;
}

View File

@ -46,6 +46,11 @@ public final class Http2CodecUtil {
public static final int PING_FRAME_PAYLOAD_LENGTH = 8;
public static final short MAX_UNSIGNED_BYTE = 0xFF;
/**
* The maximum number of padding bytes. That is the 255 padding bytes appended to the end of a frame and the 1 byte
* pad length field.
*/
public static final int MAX_PADDING = 256;
public static final int MAX_UNSIGNED_SHORT = 0xFFFF;
public static final long MAX_UNSIGNED_INT = 0xFFFFFFFFL;
public static final int FRAME_HEADER_LENGTH = 9;
@ -340,5 +345,11 @@ public final class Http2CodecUtil {
}
}
public static void verifyPadding(int padding) {
if (padding < 0 || padding > MAX_PADDING) {
throw new IllegalArgumentException(String.format("Invalid padding '%d'. Padding must be between 0 and " +
"%d (inclusive).", padding, MAX_PADDING));
}
}
private Http2CodecUtil() { }
}

View File

@ -32,7 +32,10 @@ public interface Http2DataWriter {
* @param ctx the context to use for writing.
* @param streamId the stream for which to send the frame.
* @param data the payload of the frame. This will be released by this method.
* @param padding the amount of padding to be added to the end of the frame
* @param padding additional bytes that should be added to obscure the true content size. Must be between 0 and
* 256 (inclusive). A 1 byte padding is encoded as just the pad length field with value 0.
* A 256 byte padding is encoded as the pad length field with value 255 and 255 padding bytes
* appended to the end of the frame.
* @param endStream indicates if this is the last frame to be sent for the stream.
* @param promise the promise for the write.
* @return the future for the write.

View File

@ -30,7 +30,8 @@ public interface Http2FrameListener {
* @param ctx the context from the handler where the frame was read.
* @param streamId the subject stream for the frame.
* @param data payload buffer for the frame. This buffer will be released by the codec.
* @param padding the number of padding bytes found at the end of the frame.
* @param padding additional bytes that should be added to obscure the true content size. Must be between 0 and
* 256 (inclusive).
* @param endOfStream Indicates whether this is the last frame to be sent from the remote endpoint for this stream.
* @return the number of bytes that have been processed by the application. The returned bytes are used by the
* inbound flow controller to determine the appropriate time to expand the inbound flow control window (i.e. send
@ -60,7 +61,8 @@ public interface Http2FrameListener {
* @param ctx the context from the handler where the frame was read.
* @param streamId the subject stream for the frame.
* @param headers the received headers.
* @param padding the number of padding bytes found at the end of the frame.
* @param padding additional bytes that should be added to obscure the true content size. Must be between 0 and
* 256 (inclusive).
* @param endOfStream Indicates whether this is the last frame to be sent from the remote endpoint
* for this stream.
*/
@ -89,7 +91,8 @@ public interface Http2FrameListener {
* connection.
* @param weight the new weight for the stream.
* @param exclusive whether or not the stream should be the exclusive dependent of its parent.
* @param padding the number of padding bytes found at the end of the frame.
* @param padding additional bytes that should be added to obscure the true content size. Must be between 0 and
* 256 (inclusive).
* @param endOfStream Indicates whether this is the last frame to be sent from the remote endpoint
* for this stream.
*/
@ -176,7 +179,8 @@ public interface Http2FrameListener {
* @param streamId the stream the frame was sent on.
* @param promisedStreamId the ID of the promised stream.
* @param headers the received headers.
* @param padding the number of padding bytes found at the end of the frame.
* @param padding additional bytes that should be added to obscure the true content size. Must be between 0 and
* 256 (inclusive).
*/
void onPushPromiseRead(ChannelHandlerContext ctx, int streamId, int promisedStreamId,
Http2Headers headers, int padding) throws Http2Exception;

View File

@ -51,7 +51,8 @@ public interface Http2FrameWriter extends Http2DataWriter, Closeable {
* @param ctx the context to use for writing.
* @param streamId the stream for which to send the frame.
* @param headers the headers to be sent.
* @param padding the amount of padding to be added to the end of the frame
* @param padding additional bytes that should be added to obscure the true content size. Must be between 0 and
* 256 (inclusive).
* @param endStream indicates if this is the last frame to be sent for the stream.
* @param promise the promise for the write.
* @return the future for the write.
@ -69,7 +70,8 @@ public interface Http2FrameWriter extends Http2DataWriter, Closeable {
* depend on the connection.
* @param weight the weight for this stream.
* @param exclusive whether this stream should be the exclusive dependant of its parent.
* @param padding the amount of padding to be added to the end of the frame
* @param padding additional bytes that should be added to obscure the true content size. Must be between 0 and
* 256 (inclusive).
* @param endStream indicates if this is the last frame to be sent for the stream.
* @param promise the promise for the write.
* @return the future for the write.
@ -145,7 +147,8 @@ public interface Http2FrameWriter extends Http2DataWriter, Closeable {
* @param streamId the stream for which to send the frame.
* @param promisedStreamId the ID of the promised stream.
* @param headers the headers to be sent.
* @param padding the amount of padding to be added to the end of the frame
* @param padding additional bytes that should be added to obscure the true content size. Must be between 0 and
* 256 (inclusive).
* @param promise the promise for the write.
* @return the future for the write.
*/

View File

@ -42,7 +42,8 @@ public interface Http2LocalFlowController extends Http2FlowController {
* stream} is {@code null} or closed, flow control should only be applied to the connection window and the bytes are
* immediately consumed.
* @param data payload buffer for the frame.
* @param padding the number of padding bytes found at the end of the frame.
* @param padding additional bytes that should be added to obscure the true content size. Must be between 0 and
* 256 (inclusive).
* @param endOfStream Indicates whether this is the last frame to be sent from the remote endpoint for this stream.
* @throws Http2Exception if any flow control errors are encountered.
*/

View File

@ -39,7 +39,7 @@ import java.util.LinkedList;
import java.util.List;
import static io.netty.buffer.Unpooled.EMPTY_BUFFER;
import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_MAX_HEADER_SIZE;
import static io.netty.handler.codec.http2.Http2CodecUtil.*;
import static io.netty.handler.codec.http2.Http2TestUtil.randomString;
import static io.netty.util.CharsetUtil.UTF_8;
import static java.lang.Math.min;
@ -148,17 +148,17 @@ public class Http2FrameRoundtripTest {
@Test
public void dataShouldMatch() throws Exception {
final ByteBuf data = data(10);
writer.writeData(ctx, STREAM_ID, data.slice(), 0, false, ctx.newPromise());
writer.writeData(ctx, STREAM_ID, data.slice(), 1, false, ctx.newPromise());
readFrames();
verify(listener).onDataRead(eq(ctx), eq(STREAM_ID), eq(data), eq(0), eq(false));
verify(listener).onDataRead(eq(ctx), eq(STREAM_ID), eq(data), eq(1), eq(false));
}
@Test
public void dataWithPaddingShouldMatch() throws Exception {
final ByteBuf data = data(10);
writer.writeData(ctx, STREAM_ID, data.slice(), 0xFF, true, ctx.newPromise());
writer.writeData(ctx, STREAM_ID, data.slice(), MAX_PADDING, true, ctx.newPromise());
readFrames();
verify(listener).onDataRead(eq(ctx), eq(STREAM_ID), eq(data), eq(0xFF), eq(true));
verify(listener).onDataRead(eq(ctx), eq(STREAM_ID), eq(data), eq(MAX_PADDING), eq(true));
}
@Test
@ -210,9 +210,9 @@ public class Http2FrameRoundtripTest {
@Test
public void emptyHeadersWithPaddingShouldMatch() throws Exception {
final Http2Headers headers = EmptyHttp2Headers.INSTANCE;
writer.writeHeaders(ctx, STREAM_ID, headers, 0xFF, true, ctx.newPromise());
writer.writeHeaders(ctx, STREAM_ID, headers, MAX_PADDING, true, ctx.newPromise());
readFrames();
verify(listener).onHeadersRead(eq(ctx), eq(STREAM_ID), eq(headers), eq(0xFF), eq(true));
verify(listener).onHeadersRead(eq(ctx), eq(STREAM_ID), eq(headers), eq(MAX_PADDING), eq(true));
}
@Test
@ -243,18 +243,18 @@ public class Http2FrameRoundtripTest {
@Test
public void headersWithPaddingWithoutPriorityShouldMatch() throws Exception {
final Http2Headers headers = headers();
writer.writeHeaders(ctx, STREAM_ID, headers, 0xFF, true, ctx.newPromise());
writer.writeHeaders(ctx, STREAM_ID, headers, MAX_PADDING, true, ctx.newPromise());
readFrames();
verify(listener).onHeadersRead(eq(ctx), eq(STREAM_ID), eq(headers), eq(0xFF), eq(true));
verify(listener).onHeadersRead(eq(ctx), eq(STREAM_ID), eq(headers), eq(MAX_PADDING), eq(true));
}
@Test
public void headersWithPaddingWithPriorityShouldMatch() throws Exception {
final Http2Headers headers = headers();
writer.writeHeaders(ctx, STREAM_ID, headers, 2, (short) 3, true, 0xFF, true, ctx.newPromise());
writer.writeHeaders(ctx, STREAM_ID, headers, 2, (short) 3, true, 1, true, ctx.newPromise());
readFrames();
verify(listener).onHeadersRead(eq(ctx), eq(STREAM_ID), eq(headers), eq(2), eq((short) 3), eq(true),
eq(0xFF), eq(true));
eq(1), eq(true));
}
@Test
@ -269,16 +269,16 @@ public class Http2FrameRoundtripTest {
@Test
public void continuedHeadersWithPaddingShouldMatch() throws Exception {
final Http2Headers headers = largeHeaders();
writer.writeHeaders(ctx, STREAM_ID, headers, 2, (short) 3, true, 0xFF, true, ctx.newPromise());
writer.writeHeaders(ctx, STREAM_ID, headers, 2, (short) 3, true, MAX_PADDING, true, ctx.newPromise());
readFrames();
verify(listener).onHeadersRead(eq(ctx), eq(STREAM_ID), eq(headers), eq(2), eq((short) 3), eq(true),
eq(0xFF), eq(true));
eq(MAX_PADDING), eq(true));
}
@Test
public void headersThatAreTooBigShouldFail() throws Exception {
final Http2Headers headers = headersOfSize(DEFAULT_MAX_HEADER_SIZE + 1);
writer.writeHeaders(ctx, STREAM_ID, headers, 2, (short) 3, true, 0xFF, true, ctx.newPromise());
writer.writeHeaders(ctx, STREAM_ID, headers, 2, (short) 3, true, MAX_PADDING, true, ctx.newPromise());
try {
readFrames();
fail();
@ -308,9 +308,9 @@ public class Http2FrameRoundtripTest {
@Test
public void pushPromiseWithPaddingShouldMatch() throws Exception {
final Http2Headers headers = headers();
writer.writePushPromise(ctx, STREAM_ID, 2, headers, 0xFF, ctx.newPromise());
writer.writePushPromise(ctx, STREAM_ID, 2, headers, MAX_PADDING, ctx.newPromise());
readFrames();
verify(listener).onPushPromiseRead(eq(ctx), eq(STREAM_ID), eq(2), eq(headers), eq(0xFF));
verify(listener).onPushPromiseRead(eq(ctx), eq(STREAM_ID), eq(2), eq(headers), eq(MAX_PADDING));
}
@Test