Skip to content

Commit

Permalink
HTTPCORE-707: H2 connections incorrectly enforce the frame size max l…
Browse files Browse the repository at this point in the history
…imit based on local settings instead of remote ones
  • Loading branch information
ok2c committed Jan 1, 2022
1 parent 13c7fdb commit b2a5a18
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1226,6 +1226,11 @@ private void applyRemoteSettings(final H2Config config) throws H2ConnectionExcep
final int delta = remoteConfig.getInitialWindowSize() - initOutputWinSize;
initOutputWinSize = remoteConfig.getInitialWindowSize();

final int maxFrameSize = remoteConfig.getMaxFrameSize();
if (maxFrameSize > localConfig.getMaxFrameSize()) {
outputBuffer.expand(maxFrameSize);
}

if (delta != 0) {
if (!streamMap.isEmpty()) {
for (final Iterator<Map.Entry<Integer, H2Stream>> it = streamMap.entrySet().iterator(); it.hasNext(); ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.WritableByteChannel;

import org.apache.hc.core5.http2.H2ConnectionException;
import org.apache.hc.core5.http2.H2Error;
import org.apache.hc.core5.http2.H2TransportMetrics;
import org.apache.hc.core5.http2.frame.FrameConsts;
import org.apache.hc.core5.http2.frame.RawFrame;
Expand All @@ -47,8 +45,8 @@
public final class FrameOutputBuffer {

private final BasicH2TransportMetrics metrics;
private final int maxFramePayloadSize;
private final ByteBuffer buffer;
private volatile int maxFramePayloadSize;
private volatile ByteBuffer buffer;

public FrameOutputBuffer(final BasicH2TransportMetrics metrics, final int maxFramePayloadSize) {
Args.notNull(metrics, "HTTP2 transport metrics");
Expand All @@ -62,14 +60,21 @@ public FrameOutputBuffer(final int maxFramePayloadSize) {
this(new BasicH2TransportMetrics(), maxFramePayloadSize);
}

public void expand(final int maxFramePayloadSize) {
this.maxFramePayloadSize = maxFramePayloadSize;
final ByteBuffer newBuffer = ByteBuffer.allocate(FrameConsts.HEAD_LEN + maxFramePayloadSize);
if (buffer.position() > 0) {
buffer.flip();
newBuffer.put(buffer);
}
buffer = newBuffer;
}

public void write(final RawFrame frame, final WritableByteChannel channel) throws IOException {
Args.notNull(frame, "Frame");

final ByteBuffer payload = frame.getPayload();
if (payload != null && payload.remaining() > maxFramePayloadSize) {
throw new H2ConnectionException(H2Error.FRAME_SIZE_ERROR, "Frame size exceeds maximum");
}

Args.check(payload == null || payload.remaining() <= maxFramePayloadSize, "Frame size exceeds maximum");
buffer.putInt((payload != null ? payload.remaining() << 8 : 0) | (frame.getType() & 0xff));
buffer.put((byte) (frame.getFlags() & 0xff));
buffer.putInt(frame.getStreamId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ public void testReadFrameCorruptFrame() throws Exception {
inBuffer.read(readableChannel);
}

@Test(expected = H2ConnectionException.class)
@Test(expected = IllegalArgumentException.class)
public void testWriteFrameExceedingLimit() throws Exception {
final WritableByteChannelMock writableChannel = new WritableByteChannelMock(1024);
final FrameOutputBuffer outbuffer = new FrameOutputBuffer(1024);
Expand Down

0 comments on commit b2a5a18

Please sign in to comment.