Author: markt Date: Tue Oct 13 16:25:44 2015 New Revision: 1708458 URL: http://svn.apache.org/viewvc?rev=1708458&view=rev Log: Start to refactor reset and error handling. Add flags to each state for: - able to read (request body) - able to write (response body) - able to reset stream Ensure that a stream is only reset once.
Modified: tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties tomcat/trunk/java/org/apache/coyote/http2/StreamStateMachine.java Modified: tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties?rev=1708458&r1=1708457&r2=1708458&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties (original) +++ tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties Tue Oct 13 16:25:44 2015 @@ -81,6 +81,7 @@ streamProcessor.ssl.error=Unable to retr streamStateMachine.debug.change=Connection [{0}], Stream [{1}], State changed from [{2}] to [{3}] streamStateMachine.invalidFrame=Connection [{0}], Stream [{1}], State [{2}], Frame type [{3}] +streamStateMachine.invalidReset=Connection [{0}], Stream [{1}], State [{2}], Reset is not permitted in this state upgradeHandler.allocate.debug=Connection [{0}], Stream [{1}], allocated [{2}] bytes upgradeHandler.allocate.left=Connection [{0}], Stream [{1}], [{2}] bytes unallocated - trying to allocate to children Modified: tomcat/trunk/java/org/apache/coyote/http2/StreamStateMachine.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/StreamStateMachine.java?rev=1708458&r1=1708457&r2=1708458&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http2/StreamStateMachine.java (original) +++ tomcat/trunk/java/org/apache/coyote/http2/StreamStateMachine.java Tue Oct 13 16:25:44 2015 @@ -82,8 +82,30 @@ public class StreamStateMachine { } - public synchronized void sendReset() { - stateChange(state, State.CLOSED_RST_TX); + /** + * Marks the stream as reset. This method will not change the stream state + * if: + * <ul> + * <li>The stream is already reset</li> + * <li>The stream is already closed</li> + * + * @return <code>true</code> if a reset frame needs to be sent to the peer, + * otherwise <code>false</code> + * + * @throws IllegalStateException If the stream is in a state that does not + * permit resets + */ + public synchronized boolean sendReset() { + if (state == State.IDLE) { + throw new IllegalStateException(sm.getString("streamStateMachine.debug.change", + stream.getConnectionId(), stream.getIdentifier(), state)); + } + if (state.canReset()) { + stateChange(state, State.CLOSED_RST_TX); + return true; + } else { + return false; + } } @@ -130,6 +152,16 @@ public class StreamStateMachine { } + public synchronized boolean canRead() { + return state.canRead(); + } + + + public synchronized boolean canWrite() { + return state.canWrite(); + } + + public synchronized boolean isClosedFinal() { return state == State.CLOSED_FINAL; } @@ -140,50 +172,66 @@ public class StreamStateMachine { private enum State { - IDLE (false, true, Http2Error.PROTOCOL_ERROR, FrameType.HEADERS, - FrameType.PRIORITY), - OPEN (true, true, Http2Error.PROTOCOL_ERROR, FrameType.DATA, - FrameType.HEADERS, - FrameType.PRIORITY, - FrameType.RST, - FrameType.PUSH_PROMISE, - FrameType.WINDOW_UPDATE), - RESERVED_LOCAL (false, true, Http2Error.PROTOCOL_ERROR, FrameType.PRIORITY, - FrameType.RST, - FrameType.WINDOW_UPDATE), - RESERVED_REMOTE (false, true, Http2Error.PROTOCOL_ERROR, FrameType.HEADERS, - FrameType.PRIORITY, - FrameType.RST), - HALF_CLOSED_LOCAL (true, true, Http2Error.PROTOCOL_ERROR, FrameType.DATA, - FrameType.HEADERS, - FrameType.PRIORITY, - FrameType.RST, - FrameType.PUSH_PROMISE, - FrameType.WINDOW_UPDATE), - HALF_CLOSED_REMOTE (true, true, Http2Error.STREAM_CLOSED, FrameType.PRIORITY, - FrameType.RST, - FrameType.WINDOW_UPDATE), - CLOSED_RX (false, true, Http2Error.STREAM_CLOSED, FrameType.PRIORITY), - CLOSED_TX (false, true, Http2Error.STREAM_CLOSED, FrameType.PRIORITY, - FrameType.RST, - FrameType.WINDOW_UPDATE), - CLOSED_RST_RX (false, false, Http2Error.STREAM_CLOSED, FrameType.PRIORITY), - CLOSED_RST_TX (false, false, Http2Error.STREAM_CLOSED, FrameType.DATA, - FrameType.HEADERS, - FrameType.PRIORITY, - FrameType.RST, - FrameType.PUSH_PROMISE, - FrameType.WINDOW_UPDATE), - CLOSED_FINAL (false, true, Http2Error.PROTOCOL_ERROR, FrameType.PRIORITY); - - private final boolean active; + IDLE (false, false, false, true, + Http2Error.PROTOCOL_ERROR, FrameType.HEADERS, + FrameType.PRIORITY), + OPEN (true, true, true, true, + Http2Error.PROTOCOL_ERROR, FrameType.DATA, + FrameType.HEADERS, + FrameType.PRIORITY, + FrameType.RST, + FrameType.PUSH_PROMISE, + FrameType.WINDOW_UPDATE), + RESERVED_LOCAL (false, false, true, true, + Http2Error.PROTOCOL_ERROR, FrameType.PRIORITY, + FrameType.RST, + FrameType.WINDOW_UPDATE), + RESERVED_REMOTE (false, false, true, true, + Http2Error.PROTOCOL_ERROR, FrameType.HEADERS, + FrameType.PRIORITY, + FrameType.RST), + HALF_CLOSED_LOCAL (true, false, true, true, + Http2Error.PROTOCOL_ERROR, FrameType.DATA, + FrameType.HEADERS, + FrameType.PRIORITY, + FrameType.RST, + FrameType.PUSH_PROMISE, + FrameType.WINDOW_UPDATE), + HALF_CLOSED_REMOTE (false, true, true, true, + Http2Error.STREAM_CLOSED, FrameType.PRIORITY, + FrameType.RST, + FrameType.WINDOW_UPDATE), + CLOSED_RX (false, false, false, true, + Http2Error.STREAM_CLOSED, FrameType.PRIORITY), + CLOSED_TX (false, false, false, true, + Http2Error.STREAM_CLOSED, FrameType.PRIORITY, + FrameType.RST, + FrameType.WINDOW_UPDATE), + CLOSED_RST_RX (false, false, false, false, + Http2Error.STREAM_CLOSED, FrameType.PRIORITY), + CLOSED_RST_TX (false, false, false, false, + Http2Error.STREAM_CLOSED, FrameType.DATA, + FrameType.HEADERS, + FrameType.PRIORITY, + FrameType.RST, + FrameType.PUSH_PROMISE, + FrameType.WINDOW_UPDATE), + CLOSED_FINAL (false, false, false, false, + Http2Error.PROTOCOL_ERROR, FrameType.PRIORITY); + + private final boolean canRead; + private final boolean canWrite; + private final boolean canReset; private final boolean connectionErrorForInvalidFrame; private final Http2Error errorCodeForInvalidFrame; private final Set<FrameType> frameTypesPermitted = new HashSet<>(); - private State(boolean active, boolean connectionErrorForInvalidFrame, - Http2Error errorCode, FrameType... frameTypes) { - this.active = active; + private State(boolean canRead, boolean canWrite, boolean canReset, + boolean connectionErrorForInvalidFrame, Http2Error errorCode, + FrameType... frameTypes) { + this.canRead = canRead; + this.canWrite = canWrite; + this.canReset = canReset; this.connectionErrorForInvalidFrame = connectionErrorForInvalidFrame; this.errorCodeForInvalidFrame = errorCode; for (FrameType frameType : frameTypes) { @@ -192,7 +240,19 @@ public class StreamStateMachine { } public boolean isActive() { - return active; + return canWrite || canRead; + } + + public boolean canRead() { + return canRead; + } + + public boolean canWrite() { + return canWrite; + } + + public boolean canReset() { + return canReset; } public boolean isFrameTypePermitted(FrameType frameType) { --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org