@Override public State state() { Http2Stream stream = this.stream; return stream == null ? State.IDLE : stream.state(); }
@Override public State state() { Http2Stream stream = this.stream; return stream == null ? State.IDLE : stream.state(); }
private static boolean isClosed(Http2Stream stream) { return stream.state() == Http2Stream.State.CLOSED; }
@Override public State state() { Http2Stream stream = this.stream; return stream == null ? State.IDLE : stream.state(); }
@Override public void onStreamHalfClosed(Http2Stream stream) { if (HALF_CLOSED_LOCAL == stream.state()) { /** * When this method is called there should not be any * pending frames left if the API is used correctly. However, * it is possible that a erroneous application can sneak * in a frame even after having already written a frame with the * END_STREAM flag set, as the stream state might not transition * immediately to HALF_CLOSED_LOCAL / CLOSED due to flow control * delaying the write. * * This is to cancel any such illegal writes. */ state(stream).cancel(STREAM_CLOSED, null); } } });
@Override public void onStreamClosed(Http2Stream stream) { // Any pending frames can never be written, cancel and // write errors for any pending frames. state(stream).cancel(STREAM_CLOSED, null); }
@Override public void onStreamActive(Http2Stream stream) { state(stream).setStreamReservedOrActivated(); // wasStreamReservedOrActivated is part of the comparator for stateOnlyRemovalQueue there is no need to // reprioritize here because it will not be in stateOnlyRemovalQueue. }
@Override public void onStreamActive(Http2Stream stream) { // If the object was previously created, but later activated then we have to ensure the proper // initialWindowSize is used. monitor.windowSize(state(stream), initialWindowSize); }
@Override public void onStreamClosed(Http2Stream stream) { state(stream).close(); }
public void onStreamClosed(Channel channel, Http2Stream stream) { if (stream.id() == 1) { logger.debug("{} HTTP/2 upgrade stream closed: {}", channel, stream.state()); } } }
private static boolean isWritable(Http2Stream stream) { switch (stream.state()) { case OPEN: case HALF_CLOSED_REMOTE: return !stream.isHeadersSent(); default: return false; } }
/** * Closes the local side of the given stream. If this causes the stream to be closed, adds a * hook to close the channel after the given future completes. * * @param stream the stream to be half closed. * @param future If closing, the future after which to close the channel. */ @Override public void closeStreamLocal(Http2Stream stream, ChannelFuture future) { switch (stream.state()) { case HALF_CLOSED_LOCAL: case OPEN: stream.closeLocalSide(); break; default: closeStream(stream, future); break; } }
/** * Closes the remote side of the given stream. If this causes the stream to be closed, adds a * hook to close the channel after the given future completes. * * @param stream the stream to be half closed. * @param future If closing, the future after which to close the channel. */ @Override public void closeStreamRemote(Http2Stream stream, ChannelFuture future) { switch (stream.state()) { case HALF_CLOSED_REMOTE: case OPEN: stream.closeRemoteSide(); break; default: closeStream(stream, future); break; } }
/** * Returns {@code true} if the stream with the given {@code streamId} has been created and is writable. * Note that this method will return {@code false} for the stream which was not created yet. */ private boolean isStreamPresentAndWritable(int streamId) { final Http2Stream stream = encoder.connection().stream(streamId); if (stream == null) { return false; } switch (stream.state()) { case RESERVED_LOCAL: case OPEN: case HALF_CLOSED_REMOTE: return true; default: // The response has been sent already. return false; } }
@Override public ChannelFuture writeData(final ChannelHandlerContext ctx, final int streamId, ByteBuf data, int padding, final boolean endOfStream, ChannelPromise promise) { final Http2Stream stream; try { stream = requireStream(streamId); // Verify that the stream is in the appropriate state for sending DATA frames. switch (stream.state()) { case OPEN: case HALF_CLOSED_REMOTE: // Allowed sending DATA frames in these states. break; default: throw new IllegalStateException("Stream " + stream.id() + " in unexpected state " + stream.state()); } } catch (Throwable e) { data.release(); return promise.setFailure(e); } // Hand control of the frame to the flow controller. flowController().addFlowControlled(stream, new FlowControlledData(stream, data, padding, endOfStream, promise)); return promise; }
@Override public void onWindowUpdateRead(ChannelHandlerContext ctx, int streamId, int windowSizeIncrement) throws Http2Exception { Http2Stream stream = connection.stream(streamId); if (stream == null || stream.state() == CLOSED || streamCreatedAfterGoAwaySent(streamId)) { // Ignore this frame. verifyStreamMayHaveExisted(streamId); return; } // Update the outbound flow control window. encoder.flowController().incrementWindowSize(stream, windowSizeIncrement); listener.onWindowUpdateRead(ctx, streamId, windowSizeIncrement); }
@Override public void onRstStreamRead(ChannelHandlerContext ctx, int streamId, long errorCode) throws Http2Exception { Http2Stream stream = connection.stream(streamId); if (stream == null) { verifyStreamMayHaveExisted(streamId); return; } switch(stream.state()) { case IDLE: throw connectionError(PROTOCOL_ERROR, "RST_STREAM received for IDLE stream %d", streamId); case CLOSED: return; // RST_STREAM frames must be ignored for closed streams. default: break; } listener.onRstStreamRead(ctx, streamId, errorCode); lifecycleManager.closeStream(stream, ctx.newSucceededFuture()); }
@Override public void onStreamAdded(Http2Stream stream) { State state = stateOnlyMap.remove(stream.id()); if (state == null) { state = new State(stream); // Only the stream which was just added will change parents. So we only need an array of size 1. List<ParentChangedEvent> events = new ArrayList<ParentChangedEvent>(1); connectionState.takeChild(state, false, events); notifyParentChanged(events); } else { stateOnlyRemovalQueue.removeTyped(state); state.stream = stream; } switch (stream.state()) { case RESERVED_REMOTE: case RESERVED_LOCAL: state.setStreamReservedOrActivated(); // wasStreamReservedOrActivated is part of the comparator for stateOnlyRemovalQueue there is no // need to reprioritize here because it will not be in stateOnlyRemovalQueue. break; default: break; } stream.setProperty(stateKey, state); }
@Override public DefaultStream reservePushStream(int streamId, Http2Stream parent) throws Http2Exception { if (parent == null) { throw connectionError(PROTOCOL_ERROR, "Parent stream missing"); } if (isLocal() ? !parent.state().localSideOpen() : !parent.state().remoteSideOpen()) { throw connectionError(PROTOCOL_ERROR, "Stream %d is not open for sending push promise", parent.id()); } if (!opposite().allowPushTo()) { throw connectionError(PROTOCOL_ERROR, "Server push not allowed to opposite endpoint"); } State state = isLocal() ? RESERVED_LOCAL : RESERVED_REMOTE; checkNewStreamAllowed(streamId, state); // Create and initialize the stream. DefaultStream stream = new DefaultStream(streamId, state); incrementExpectedStreamId(streamId); // Register the stream. addStream(stream); return stream; }
@Override public void onStreamRemoved(Http2Stream stream) { // The stream has been removed from the connection. We can no longer rely on the stream's property // storage to track the State. If we have room, and the precedence of the stream is sufficient, we // should retain the State in the stateOnlyMap. State state = state(stream); // Typically the stream is set to null when the stream is closed because it is no longer needed to write // data. However if the stream was not activated it may not be closed (reserved streams) so we ensure // the stream reference is set to null to avoid retaining a reference longer than necessary. state.stream = null; if (WeightedFairQueueByteDistributor.this.maxStateOnlySize == 0) { state.parent.removeChild(state); return; } if (stateOnlyRemovalQueue.size() == WeightedFairQueueByteDistributor.this.maxStateOnlySize) { State stateToRemove = stateOnlyRemovalQueue.peek(); if (StateOnlyComparator.INSTANCE.compare(stateToRemove, state) >= 0) { // The "lowest priority" stream is a "higher priority" than the stream being removed, so we // just discard the state. state.parent.removeChild(state); return; } stateOnlyRemovalQueue.poll(); stateToRemove.parent.removeChild(stateToRemove); stateOnlyMap.remove(stateToRemove.streamId); } stateOnlyRemovalQueue.add(state); stateOnlyMap.put(state.streamId, state); } });