Skip to content

Commit ccb7b49

Browse files
committed
Improved H2 connection termination in case of the opposite endpoint failing to send GOAWAY frame
1 parent a202086 commit ccb7b49

File tree

3 files changed

+25
-6
lines changed

3 files changed

+25
-6
lines changed

httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractH2StreamMultiplexer.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,11 @@ public final void onInput(final ByteBuffer src) throws HttpException, IOExceptio
442442
for (;;) {
443443
final RawFrame frame = inputBuffer.read(src, ioSession);
444444
if (frame == null) {
445+
if (inputBuffer.isEndOfStream() && connState == ConnectionHandshake.ACTIVE) {
446+
connState = ConnectionHandshake.SHUTDOWN;
447+
final RawFrame goAway = frameFactory.createGoAway(processedRemoteStreamId, H2Error.NO_ERROR, "Unexpected end of stream");
448+
commitFrame(goAway);
449+
}
445450
break;
446451
}
447452
if (streamListener != null) {

httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/FrameInputBuffer.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import java.nio.ByteBuffer;
3131
import java.nio.channels.ReadableByteChannel;
3232

33-
import org.apache.hc.core5.http.ConnectionClosedException;
3433
import org.apache.hc.core5.http2.H2ConnectionException;
3534
import org.apache.hc.core5.http2.H2CorruptFrameException;
3635
import org.apache.hc.core5.http2.H2Error;
@@ -61,6 +60,8 @@ enum State { HEAD_EXPECTED, PAYLOAD_EXPECTED }
6160
private int flags;
6261
private int streamId;
6362

63+
private boolean endOfStream;
64+
6465
FrameInputBuffer(final BasicH2TransportMetrics metrics, final int bufferLen, final int maxFramePayloadSize) {
6566
Args.notNull(metrics, "HTTP2 transport metrics");
6667
Args.positive(maxFramePayloadSize, "Maximum payload size");
@@ -70,6 +71,7 @@ enum State { HEAD_EXPECTED, PAYLOAD_EXPECTED }
7071
this.buffer = ByteBuffer.wrap(bytes);
7172
this.buffer.flip();
7273
this.state = State.HEAD_EXPECTED;
74+
this.endOfStream = false;
7375
}
7476

7577
public FrameInputBuffer(final BasicH2TransportMetrics metrics, final int maxFramePayloadSize) {
@@ -174,11 +176,13 @@ public RawFrame read(final ByteBuffer src, final ReadableByteChannel channel) th
174176
}
175177
if (bytesRead == 0) {
176178
break;
177-
} else if (bytesRead < 0) {
179+
}
180+
if (bytesRead == -1) {
178181
if (state != State.HEAD_EXPECTED || buffer.hasRemaining()) {
179182
throw new H2CorruptFrameException("Corrupt or incomplete HTTP2 frame");
180183
} else {
181-
throw new ConnectionClosedException();
184+
endOfStream = true;
185+
break;
182186
}
183187
}
184188
}
@@ -199,10 +203,18 @@ public RawFrame read(final ReadableByteChannel channel) throws IOException {
199203
public void reset() {
200204
buffer.compact();
201205
state = State.HEAD_EXPECTED;
206+
endOfStream = false;
202207
}
203208

204209
public H2TransportMetrics getMetrics() {
205210
return metrics;
206211
}
207212

213+
/**
214+
* @since 5.4
215+
*/
216+
public boolean isEndOfStream() {
217+
return endOfStream;
218+
}
219+
208220
}

httpcore5-h2/src/test/java/org/apache/hc/core5/http2/impl/nio/TestFrameInOutBuffers.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929

3030
import java.nio.ByteBuffer;
3131

32-
import org.apache.hc.core5.http.ConnectionClosedException;
3332
import org.apache.hc.core5.http2.H2ConnectionException;
3433
import org.apache.hc.core5.http2.H2CorruptFrameException;
3534
import org.apache.hc.core5.http2.ReadableByteChannelMock;
@@ -255,8 +254,11 @@ void testReadFrameConnectionClosed() throws Exception {
255254
final ReadableByteChannelMock readableChannel = new ReadableByteChannelMock(new byte[] {});
256255

257256
Assertions.assertNull(inBuffer.read(readableChannel));
258-
Assertions.assertThrows(ConnectionClosedException.class, () ->
259-
inBuffer.read(readableChannel));
257+
Assertions.assertFalse(inBuffer.isEndOfStream());
258+
Assertions.assertNull(inBuffer.read(readableChannel));
259+
Assertions.assertTrue(inBuffer.isEndOfStream());
260+
Assertions.assertNull(inBuffer.read(readableChannel));
261+
Assertions.assertTrue(inBuffer.isEndOfStream());
260262
}
261263

262264
@Test

0 commit comments

Comments
 (0)