final int lastStreamId = conn.local().lastStreamKnownByPeer(); if (lastStreamId < 0 || // Did not receive a GOAWAY yet or
stream.isResetSent() ? "RST_STREAM sent." : ("Stream created after GOAWAY sent. Last known stream by peer " + connection.remote().lastStreamKnownByPeer()));
@Override public void onStreamClosed(Http2Stream stream) { goAwayHandler.onStreamClosed(channel(), stream); final HttpResponseWrapper res = getResponse(streamIdToId(stream.id()), true); if (res == null) { return; } if (!goAwayHandler.receivedGoAway()) { res.close(ClosedSessionException.get()); return; } final int lastStreamId = conn.local().lastStreamKnownByPeer(); if (stream.id() > lastStreamId) { res.close(UnprocessedRequestException.get()); } else { res.close(ClosedSessionException.get()); } // Send a GOAWAY frame if the connection has been scheduled for disconnection and // it did not receive or send a GOAWAY frame. if (needsToDisconnectNow() && !goAwayHandler.sentGoAway() && !goAwayHandler.receivedGoAway()) { channel().close(); } }
if (lastStreamId == connection().remote().lastStreamKnownByPeer()) { if (lastStreamId > connection.remote().lastStreamKnownByPeer()) { throw connectionError(PROTOCOL_ERROR, "Last stream identifier must not increase between " + "sending multiple GOAWAY frames (was '%d', is '%d').", connection.remote().lastStreamKnownByPeer(), lastStreamId);
stream.isResetSent() ? "RST_STREAM sent." : ("Stream created after GOAWAY sent. Last known stream by peer " + connection.remote().lastStreamKnownByPeer()));
/** * Helper method to determine if a frame that has the semantics of headers or data should be ignored for the * {@code stream} (which may be {@code null}) associated with {@code streamId}. */ private boolean shouldIgnoreHeadersOrDataFrame(ChannelHandlerContext ctx, int streamId, Http2Stream stream, String frameName) throws Http2Exception { if (stream == null) { if (streamCreatedAfterGoAwaySent(streamId)) { logger.info("{} ignoring {} frame for stream {}. Stream sent after GOAWAY sent", ctx.channel(), frameName, streamId); return true; } // If the stream could have existed in the past we assume this is a frame sent by the remote // after a RST_STREAM has been sent. Since we don't retain metadata about streams that have been // reset we can't know this for sure. verifyStreamMayHaveExisted(streamId); return true; } else if (stream.isResetSent() || streamCreatedAfterGoAwaySent(streamId)) { if (logger.isInfoEnabled()) { logger.info("{} ignoring {} frame for stream {} {}", ctx.channel(), frameName, stream.isResetSent() ? "RST_STREAM sent." : ("Stream created after GOAWAY sent. Last known stream by peer " + connection.remote().lastStreamKnownByPeer())); } return true; } return false; }
/** * Helper method to determine if a frame that has the semantics of headers or data should be ignored for the * {@code stream} (which may be {@code null}) associated with {@code streamId}. */ private boolean shouldIgnoreHeadersOrDataFrame(ChannelHandlerContext ctx, int streamId, Http2Stream stream, String frameName) throws Http2Exception { if (stream == null) { if (streamCreatedAfterGoAwaySent(streamId)) { logger.info("{} ignoring {} frame for stream {}. Stream sent after GOAWAY sent", ctx.channel(), frameName, streamId); return true; } // Its possible that this frame would result in stream ID out of order creation (PROTOCOL ERROR) and its // also possible that this frame is received on a CLOSED stream (STREAM_CLOSED after a RST_STREAM is // sent). We don't have enough information to know for sure, so we choose the lesser of the two errors. throw streamError(streamId, STREAM_CLOSED, "Received %s frame for an unknown stream %d", frameName, streamId); } else if (stream.isResetSent() || streamCreatedAfterGoAwaySent(streamId)) { if (logger.isInfoEnabled()) { logger.info("{} ignoring {} frame for stream {} {}", ctx.channel(), frameName, stream.isResetSent() ? "RST_STREAM sent." : ("Stream created after GOAWAY sent. Last known stream by peer " + connection.remote().lastStreamKnownByPeer())); } return true; } return false; }
/** * Helper method to determine if a frame that has the semantics of headers or data should be ignored for the * {@code stream} (which may be {@code null}) associated with {@code streamId}. */ private boolean shouldIgnoreHeadersOrDataFrame(ChannelHandlerContext ctx, int streamId, Http2Stream stream, String frameName) throws Http2Exception { if (stream == null) { if (streamCreatedAfterGoAwaySent(streamId)) { logger.info("{} ignoring {} frame for stream {}. Stream sent after GOAWAY sent", ctx.channel(), frameName, streamId); return true; } // If the stream could have existed in the past we assume this is a frame sent by the remote // after a RST_STREAM has been sent. Since we don't retain metadata about streams that have been // reset we can't know this for sure. verifyStreamMayHaveExisted(streamId); return true; } else if (stream.isResetSent() || streamCreatedAfterGoAwaySent(streamId)) { if (logger.isInfoEnabled()) { logger.info("{} ignoring {} frame for stream {} {}", ctx.channel(), frameName, stream.isResetSent() ? "RST_STREAM sent." : ("Stream created after GOAWAY sent. Last known stream by peer " + connection.remote().lastStreamKnownByPeer())); } return true; } return false; }
/** * Helper method for determining whether or not to ignore inbound frames. A stream is considered to be created * after a {@code GOAWAY} is sent if the following conditions hold: * <p/> * <ul> * <li>A {@code GOAWAY} must have been sent by the local endpoint</li> * <li>The {@code streamId} must identify a legitimate stream id for the remote endpoint to be creating</li> * <li>{@code streamId} is greater than the Last Known Stream ID which was sent by the local endpoint * in the last {@code GOAWAY} frame</li> * </ul> * <p/> */ private boolean streamCreatedAfterGoAwaySent(int streamId) { Endpoint<?> remote = connection.remote(); return connection.goAwaySent() && remote.isValidStreamId(streamId) && streamId > remote.lastStreamKnownByPeer(); }
/** * Helper method for determining whether or not to ignore inbound frames. A stream is considered to be created * after a {@code GOAWAY} is sent if the following conditions hold: * <p/> * <ul> * <li>A {@code GOAWAY} must have been sent by the local endpoint</li> * <li>The {@code streamId} must identify a legitimate stream id for the remote endpoint to be creating</li> * <li>{@code streamId} is greater than the Last Known Stream ID which was sent by the local endpoint * in the last {@code GOAWAY} frame</li> * </ul> * <p/> */ private boolean streamCreatedAfterGoAwaySent(int streamId) { Endpoint<?> remote = connection.remote(); return connection.goAwaySent() && remote.isValidStreamId(streamId) && streamId > remote.lastStreamKnownByPeer(); }
/** * Helper method for determining whether or not to ignore inbound frames. A stream is considered to be created * after a {@code GOAWAY} is sent if the following conditions hold: * <p/> * <ul> * <li>A {@code GOAWAY} must have been sent by the local endpoint</li> * <li>The {@code streamId} must identify a legitimate stream id for the remote endpoint to be creating</li> * <li>{@code streamId} is greater than the Last Known Stream ID which was sent by the local endpoint * in the last {@code GOAWAY} frame</li> * </ul> * <p/> */ private boolean streamCreatedAfterGoAwaySent(int streamId) { Endpoint<?> remote = connection.remote(); return connection.goAwaySent() && remote.isValidStreamId(streamId) && streamId > remote.lastStreamKnownByPeer(); }
/** * Helper method for determining whether or not to ignore inbound frames. A stream is considered to be created * after a {@code GOAWAY} is sent if the following conditions hold: * <p/> * <ul> * <li>A {@code GOAWAY} must have been sent by the local endpoint</li> * <li>The {@code streamId} must identify a legitimate stream id for the remote endpoint to be creating</li> * <li>{@code streamId} is greater than the Last Known Stream ID which was sent by the local endpoint * in the last {@code GOAWAY} frame</li> * </ul> * <p/> */ private boolean streamCreatedAfterGoAwaySent(int streamId) { Endpoint<?> remote = connection.remote(); return connection.goAwaySent() && remote.isValidStreamId(streamId) && streamId > remote.lastStreamKnownByPeer(); }
void onGoAwayRead0(ChannelHandlerContext ctx, int lastStreamId, long errorCode, ByteBuf debugData) throws Http2Exception { if (connection.goAwayReceived() && connection.local().lastStreamKnownByPeer() < lastStreamId) { throw connectionError(PROTOCOL_ERROR, "lastStreamId MUST NOT increase. Current value: %d new value: %d", connection.local().lastStreamKnownByPeer(), lastStreamId); } listener.onGoAwayRead(ctx, lastStreamId, errorCode, debugData); connection.goAwayReceived(lastStreamId, errorCode, debugData); }
void onGoAwayRead0(ChannelHandlerContext ctx, int lastStreamId, long errorCode, ByteBuf debugData) throws Http2Exception { if (connection.goAwayReceived() && connection.local().lastStreamKnownByPeer() < lastStreamId) { throw connectionError(PROTOCOL_ERROR, "lastStreamId MUST NOT increase. Current value: %d new value: %d", connection.local().lastStreamKnownByPeer(), lastStreamId); } listener.onGoAwayRead(ctx, lastStreamId, errorCode, debugData); connection.goAwayReceived(lastStreamId, errorCode, debugData); }
void onGoAwayRead0(ChannelHandlerContext ctx, int lastStreamId, long errorCode, ByteBuf debugData) throws Http2Exception { if (connection.goAwayReceived() && connection.local().lastStreamKnownByPeer() < lastStreamId) { throw connectionError(PROTOCOL_ERROR, "lastStreamId MUST NOT increase. Current value: %d new value: %d", connection.local().lastStreamKnownByPeer(), lastStreamId); } listener.onGoAwayRead(ctx, lastStreamId, errorCode, debugData); connection.goAwayReceived(lastStreamId, errorCode, debugData); }
/** * Helper method for determining whether or not to ignore inbound frames. A stream is considered to be created * after a {@code GOAWAY} is sent if the following conditions hold: * <p/> * <ul> * <li>A {@code GOAWAY} must have been sent by the local endpoint</li> * <li>The {@code streamId} must identify a legitimate stream id for the remote endpoint to be creating</li> * <li>{@code streamId} is greater than the Last Known Stream ID which was sent by the local endpoint * in the last {@code GOAWAY} frame</li> * </ul> * <p/> */ private boolean streamCreatedAfterGoAwaySent(int streamId) { Endpoint<?> remote = connection.remote(); return connection.goAwaySent() && remote.isValidStreamId(streamId) && streamId > remote.lastStreamKnownByPeer(); }