Author: markt Date: Wed Jun 10 19:43:10 2015 New Revision: 1684752 URL: http://svn.apache.org/r1684752 Log: Add the plumbing required for HTTP/2 5.1.1 and 5.1.2
Modified: tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties tomcat/trunk/java/org/apache/coyote/http2/Stream.java tomcat/trunk/java/org/apache/coyote/http2/StreamStateMachine.java Modified: tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java?rev=1684752&r1=1684751&r2=1684752&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java (original) +++ tomcat/trunk/java/org/apache/coyote/http2/Http2UpgradeHandler.java Wed Jun 10 19:43:10 2015 @@ -107,7 +107,6 @@ public class Http2UpgradeHandler extends private final ConnectionSettings remoteSettings = new ConnectionSettings(); private final ConnectionSettings localSettings = new ConnectionSettings(); - private volatile int maxRemoteStreamId = 0; private HpackDecoder hpackDecoder; private HpackEncoder hpackEncoder; @@ -118,7 +117,9 @@ public class Http2UpgradeHandler extends private long writeTimeout = 10000; private final Map<Integer,Stream> streams = new HashMap<>(); - private int maxStreamId = -1; + private volatile int activeRemoteStreamCount = 0; + private volatile int maxRemoteStreamId = 0; + private volatile int maxActiveRemoteStreamId = 0; // Tracking for when the connection is blocked (windowSize < 1) private final Object backLogLock = new Object(); @@ -140,6 +141,7 @@ public class Http2UpgradeHandler extends Stream stream = new Stream(key, this, coyoteRequest); streams.put(key, stream); maxRemoteStreamId = 1; + activeRemoteStreamCount = 1; } } @@ -632,7 +634,8 @@ public class Http2UpgradeHandler extends Stream result = streams.get(key); if (result == null && unknownIsError) { // Stream has been closed and removed from the map - throw new ConnectionException(sm.getString("upgradeHandler.stream.closed", key), Http2Error.PROTOCOL_ERROR); + throw new ConnectionException(sm.getString("upgradeHandler.stream.closed", key), + Http2Error.PROTOCOL_ERROR); } return result; } @@ -651,6 +654,8 @@ public class Http2UpgradeHandler extends Integer.valueOf(maxRemoteStreamId)), Http2Error.PROTOCOL_ERROR); } + // TODO Implement periodic pruning of closed streams + Stream result = new Stream(key, this); streams.put(key, result); maxRemoteStreamId = streamId; @@ -761,9 +766,6 @@ public class Http2UpgradeHandler extends @Override public ByteBuffer getInputByteBuffer(int streamId, int payloadSize) throws Http2Exception { Stream stream = getStream(streamId, true); - if (stream == null) { - return null; - } stream.checkState(FrameType.DATA); return stream.getInputByteBuffer(); } @@ -772,9 +774,10 @@ public class Http2UpgradeHandler extends @Override public void receiveEndOfStream(int streamId) throws ConnectionException { Stream stream = getStream(streamId, true); - if (stream != null) { - stream.receivedEndOfStream(); + if (stream.isActive()) { + activeRemoteStreamCount--; } + stream.receivedEndOfStream(); } @@ -786,10 +789,29 @@ public class Http2UpgradeHandler extends } stream.checkState(FrameType.HEADERS); stream.receivedStartOfHeaders(); + closeIdleStreams(streamId); + if (localSettings.getMaxConcurrentStreams() > activeRemoteStreamCount) { + activeRemoteStreamCount++; + } else { + throw new StreamException(sm.getString("upgradeHandler.tooManyRemoteStreams", + Long.toString(localSettings.getMaxConcurrentStreams())), + Http2Error.REFUSED_STREAM, streamId); + } return stream; } + private void closeIdleStreams(int newMaxActiveRemoteStreamId) throws Http2Exception { + for (int i = maxActiveRemoteStreamId + 2; i < newMaxActiveRemoteStreamId; i += 2) { + Stream stream = getStream(newMaxActiveRemoteStreamId, false); + if (stream != null) { + stream.closeIfIdle(); + } + } + maxActiveRemoteStreamId = newMaxActiveRemoteStreamId; + } + + @Override public void reprioritise(int streamId, int parentStreamId, boolean exclusive, int weight) throws Http2Exception { @@ -820,10 +842,8 @@ public class Http2UpgradeHandler extends @Override public void reset(int streamId, long errorCode) throws Http2Exception { Stream stream = getStream(streamId, true); - if (stream != null) { - stream.checkState(FrameType.RST); - stream.reset(errorCode); - } + stream.checkState(FrameType.RST); + stream.reset(errorCode); } @@ -869,9 +889,6 @@ public class Http2UpgradeHandler extends log.debug(sm.getString("upgradeHandler.goaway.debug", connectionId, Integer.toString(lastStreamId), Long.toHexString(errorCode), debugData)); } - - // TODO: Do more than just record this - maxStreamId = lastStreamId; } 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=1684752&r1=1684751&r2=1684752&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties (original) +++ tomcat/trunk/java/org/apache/coyote/http2/LocalStrings.properties Wed Jun 10 19:43:10 2015 @@ -72,6 +72,7 @@ upgradeHandler.socketCloseFailed=Error c upgradeHandler.stream.closed=Stream [{0}] has been closed for some time upgradeHandler.stream.even=A new remote stream ID of [{0}] was requested but all remote streams must use odd identifiers upgradeHandler.stream.old=A new remote stream ID of [{0}] was requested but the most recent stream was [{1}] +upgradeHandler.tooManyRemoteStreams=The client attempted to use more than [{0}] active streams upgradeHandler.swallow.eos=End of stream found while trying to swallow [{0}] bytes upgradeHandler.unexpectedEos=Unexpected end of stream upgradeHandler.unexpectedStatus=An unexpected value of status ([{0}]) was passed to this method Modified: tomcat/trunk/java/org/apache/coyote/http2/Stream.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/Stream.java?rev=1684752&r1=1684751&r2=1684752&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http2/Stream.java (original) +++ tomcat/trunk/java/org/apache/coyote/http2/Stream.java Wed Jun 10 19:43:10 2015 @@ -38,11 +38,12 @@ public class Stream extends AbstractStre private volatile int weight = Constants.DEFAULT_WEIGHT; private final Http2UpgradeHandler handler; + private final StreamStateMachine state; + // TODO: Only create these objects if needed and null them when finished private final Request coyoteRequest; private final Response coyoteResponse = new Response(); private final StreamInputBuffer inputBuffer; private final StreamOutputBuffer outputBuffer = new StreamOutputBuffer(); - private final StreamStateMachine state; public Stream(Integer identifier, Http2UpgradeHandler handler) { @@ -260,6 +261,16 @@ public class Stream extends AbstractStre } + boolean isActive() { + return state.isActive(); + } + + + void closeIfIdle() { + state.closeIfIdle(); + } + + class StreamOutputBuffer implements OutputBuffer { private final ByteBuffer buffer = ByteBuffer.allocate(8 * 1024); 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=1684752&r1=1684751&r2=1684752&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http2/StreamStateMachine.java (original) +++ tomcat/trunk/java/org/apache/coyote/http2/StreamStateMachine.java Wed Jun 10 19:43:10 2015 @@ -130,6 +130,13 @@ public class StreamStateMachine { } + public synchronized void closeIfIdle() { + if (state == State.IDLE) { + state = State.CLOSED_FINAL; + } + } + + private enum State { IDLE (false, true, Http2Error.PROTOCOL_ERROR, FrameType.HEADERS, FrameType.PRIORITY), --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org