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: [email protected]
For additional commands, e-mail: [email protected]