Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -267,11 +267,11 @@ HPackHeader decodeIndexedHeader(final ByteBuffer src) throws HPackException {
}

public Header decodeHeader(final ByteBuffer src) throws HPackException {
final HPackHeader header = decodeHPackHeader(src);
final HPackHeader header = decodeHPackHeader(src, true);
return header != null ? new BasicHeader(header.getName(), header.getValue(), header.isSensitive()) : null;
}

HPackHeader decodeHPackHeader(final ByteBuffer src) throws HPackException {
HPackHeader decodeHPackHeader(final ByteBuffer src, final boolean allowTableSizeUpdate) throws HPackException {
try {
while (src.hasRemaining()) {
final int b = peekByte(src);
Expand All @@ -284,6 +284,9 @@ HPackHeader decodeHPackHeader(final ByteBuffer src) throws HPackException {
} else if ((b & 0xf0) == 0x10) {
return decodeLiteralHeader(src, HPackRepresentation.NEVER_INDEXED);
} else if ((b & 0xe0) == 0x20) {
if (!allowTableSizeUpdate) {
throw new HPackException("Dynamic table size update must appear at the beginning of a header block");
}
final int maxSize = decodeInt(src, 5);
if (maxSize > this.maxTableSize) {
throw new HPackException("Requested dynamic header table size exceeds maximum size: " + maxSize);
Expand All @@ -302,13 +305,17 @@ HPackHeader decodeHPackHeader(final ByteBuffer src) throws HPackException {
public List<Header> decodeHeaders(final ByteBuffer src) throws HPackException {
final boolean enforceSizeLimit = maxListSize < Integer.MAX_VALUE;
int listSize = 0;
// RFC 7541 §4.2: dynamic table size updates are only allowed at the
// beginning of a header block (before the first header field).
boolean allowTableSizeUpdate = true;

final List<Header> list = new ArrayList<>();
while (src.hasRemaining()) {
final HPackHeader header = decodeHPackHeader(src);
final HPackHeader header = decodeHPackHeader(src, allowTableSizeUpdate);
if (header == null) {
break;
}
allowTableSizeUpdate = false;
if (enforceSizeLimit) {
listSize += header.getTotalSize();
if (listSize >= maxListSize) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1178,5 +1178,51 @@ void decoderDynamicHeaderTableMaxSizeLimitedByConfig() throws Exception {
Assertions.assertThrows(HPackException.class, () -> decoder.decodeHeaders(wrap(buf)));
}

@Test
void decoderRejectsDynamicTableSizeUpdateMidHeaderBlock() {
final InboundDynamicTable dynamicTable = new InboundDynamicTable(4096);
final HPackDecoder decoder = new HPackDecoder(dynamicTable, StandardCharsets.US_ASCII);

final ByteBuffer src = createByteBuffer(
0x82, // :method: GET
0x20 // dynamic table size update (0) - illegal after first header field
);

final HPackException ex = Assertions.assertThrows(HPackException.class, () -> decoder.decodeHeaders(src));
Assertions.assertTrue(ex.getMessage().contains("beginning of a header block"));
}

@Test
void decoderAllowsMultipleLeadingDynamicTableSizeUpdates() throws Exception {
final InboundDynamicTable dynamicTable = new InboundDynamicTable(4096);
final HPackDecoder decoder = new HPackDecoder(dynamicTable, StandardCharsets.US_ASCII);

final ByteBuffer src = createByteBuffer(
0x20, // dynamic table size update (0)
0x2a, // dynamic table size update (10)
0x82 // :method: GET
);

final List<Header> headers = decoder.decodeHeaders(src);
Assertions.assertEquals(1, headers.size());
assertHeaderEquals(new BasicHeader(":method", "GET"), headers.get(0));
Assertions.assertEquals(10, dynamicTable.getMaxSize());
}

@Test
void decoderRejectsDynamicTableSizeUpdateAfterLeadingUpdateAndHeader() {
final InboundDynamicTable dynamicTable = new InboundDynamicTable(4096);
final HPackDecoder decoder = new HPackDecoder(dynamicTable, StandardCharsets.US_ASCII);

final ByteBuffer src = createByteBuffer(
0x20, // dynamic table size update (0)
0x82, // :method: GET
0x20 // dynamic table size update (0) - illegal after first header field
);

final HPackException ex = Assertions.assertThrows(HPackException.class, () -> decoder.decodeHeaders(src));
Assertions.assertTrue(ex.getMessage().contains("beginning of a header block"));
}

}

Loading