This is an automated email from the ASF dual-hosted git repository.
markt pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/9.0.x by this push:
new 9fec9a8288 Make counting of active streams more robust
9fec9a8288 is described below
commit 9fec9a82887853402833a80b584e3762c7423f5f
Author: Mark Thomas <[email protected]>
AuthorDate: Wed May 8 08:36:43 2024 +0100
Make counting of active streams more robust
---
.../coyote/http2/Http2AsyncUpgradeHandler.java | 2 +-
.../org/apache/coyote/http2/Http2UpgradeHandler.java | 20 ++++++++++----------
java/org/apache/coyote/http2/Stream.java | 16 ++++++++++++++++
webapps/docs/changelog.xml | 4 ++++
4 files changed, 31 insertions(+), 11 deletions(-)
diff --git a/java/org/apache/coyote/http2/Http2AsyncUpgradeHandler.java
b/java/org/apache/coyote/http2/Http2AsyncUpgradeHandler.java
index 758b63e666..bedc8788d9 100644
--- a/java/org/apache/coyote/http2/Http2AsyncUpgradeHandler.java
+++ b/java/org/apache/coyote/http2/Http2AsyncUpgradeHandler.java
@@ -156,7 +156,7 @@ public class Http2AsyncUpgradeHandler extends
Http2UpgradeHandler {
boolean active = state.isActive();
state.sendReset();
if (active) {
- decrementActiveRemoteStreamCount();
+
decrementActiveRemoteStreamCount(getStream(se.getStreamId()));
}
}
diff --git a/java/org/apache/coyote/http2/Http2UpgradeHandler.java
b/java/org/apache/coyote/http2/Http2UpgradeHandler.java
index a50f62287d..2ac1b969b3 100644
--- a/java/org/apache/coyote/http2/Http2UpgradeHandler.java
+++ b/java/org/apache/coyote/http2/Http2UpgradeHandler.java
@@ -288,8 +288,8 @@ class Http2UpgradeHandler extends AbstractStream implements
InternalHttpUpgradeH
}
- protected void decrementActiveRemoteStreamCount() {
-
setConnectionTimeoutForStreamCount(activeRemoteStreamCount.decrementAndGet());
+ protected void decrementActiveRemoteStreamCount(Stream stream) {
+
setConnectionTimeoutForStreamCount(stream.decrementAndGetActiveRemoteStreamCount());
}
@@ -596,7 +596,7 @@ class Http2UpgradeHandler extends AbstractStream implements
InternalHttpUpgradeH
boolean active = state.isActive();
state.sendReset();
if (active) {
- decrementActiveRemoteStreamCount();
+
decrementActiveRemoteStreamCount(getStream(se.getStreamId()));
}
}
socketWrapper.write(true, rstFrame, 0, rstFrame.length);
@@ -839,7 +839,7 @@ class Http2UpgradeHandler extends AbstractStream implements
InternalHttpUpgradeH
protected void sentEndOfStream(Stream stream) {
stream.sentEndOfStream();
if (!stream.isActive()) {
- decrementActiveRemoteStreamCount();
+ decrementActiveRemoteStreamCount(stream);
}
}
@@ -1221,7 +1221,7 @@ class Http2UpgradeHandler extends AbstractStream
implements InternalHttpUpgradeH
}
- private Stream getStream(int streamId) {
+ Stream getStream(int streamId) {
Integer key = Integer.valueOf(streamId);
AbstractStream result = streams.get(key);
if (result instanceof Stream) {
@@ -1590,6 +1590,7 @@ class Http2UpgradeHandler extends AbstractStream
implements InternalHttpUpgradeH
Stream stream = getStream(streamId, false);
if (stream == null) {
stream = createRemoteStream(streamId);
+ activeRemoteStreamCount.incrementAndGet();
}
if (streamId < maxActiveRemoteStreamId) {
throw new
ConnectionException(sm.getString("upgradeHandler.stream.old",
Integer.valueOf(streamId),
@@ -1668,9 +1669,8 @@ class Http2UpgradeHandler extends AbstractStream
implements InternalHttpUpgradeH
Stream stream = (Stream) abstractNonZeroStream;
if (stream.isActive()) {
if (stream.receivedEndOfHeaders()) {
-
- if (localSettings.getMaxConcurrentStreams() <
activeRemoteStreamCount.incrementAndGet()) {
- decrementActiveRemoteStreamCount();
+ if (localSettings.getMaxConcurrentStreams() <
activeRemoteStreamCount.get()) {
+ decrementActiveRemoteStreamCount(stream);
// Ignoring maxConcurrentStreams increases the
overhead count
increaseOverheadCount(FrameType.HEADERS);
throw new StreamException(
@@ -1714,7 +1714,7 @@ class Http2UpgradeHandler extends AbstractStream
implements InternalHttpUpgradeH
private void receivedEndOfStream(Stream stream) throws ConnectionException
{
stream.receivedEndOfStream();
if (!stream.isActive()) {
- decrementActiveRemoteStreamCount();
+ decrementActiveRemoteStreamCount(stream);
}
}
@@ -1740,7 +1740,7 @@ class Http2UpgradeHandler extends AbstractStream
implements InternalHttpUpgradeH
boolean active = stream.isActive();
stream.receiveReset(errorCode);
if (active) {
- decrementActiveRemoteStreamCount();
+ decrementActiveRemoteStreamCount(stream);
}
}
}
diff --git a/java/org/apache/coyote/http2/Stream.java
b/java/org/apache/coyote/http2/Stream.java
index 1a74f3b84c..95b596a004 100644
--- a/java/org/apache/coyote/http2/Stream.java
+++ b/java/org/apache/coyote/http2/Stream.java
@@ -28,6 +28,7 @@ import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Supplier;
@@ -92,6 +93,7 @@ class Stream extends AbstractNonZeroStream implements
HeaderEmitter {
private final StreamInputBuffer inputBuffer;
private final StreamOutputBuffer streamOutputBuffer = new
StreamOutputBuffer();
private final Http2OutputBuffer http2OutputBuffer = new
Http2OutputBuffer(coyoteResponse, streamOutputBuffer);
+ private final AtomicBoolean removedFromActiveCount = new
AtomicBoolean(false);
// State machine would be too much overhead
private int headerState = HEADER_STATE_START;
@@ -883,6 +885,20 @@ class Stream extends AbstractNonZeroStream implements
HeaderEmitter {
}
+ int decrementAndGetActiveRemoteStreamCount() {
+ /*
+ * Protect against mis-counting of active streams. This method should
only be called once per stream but since
+ * the count of active streams is used to enforce the maximum
concurrent streams limit, make sure each stream is
+ * only removed from the active count exactly once.
+ */
+ if (removedFromActiveCount.compareAndSet(false, true)) {
+ return handler.activeRemoteStreamCount.decrementAndGet();
+ } else {
+ return handler.activeRemoteStreamCount.get();
+ }
+ }
+
+
private static void push(final Http2UpgradeHandler handler, final Request
request, final Stream stream)
throws IOException {
if (org.apache.coyote.Constants.IS_SECURITY_ENABLED) {
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index dce08e2919..76b0fb554b 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -165,6 +165,10 @@
<code>Connector</code> element, similar to the <code>Executor</code>
element, for consistency. (remm)
</update>
+ <fix>
+ Make counting of active HTTP/2 streams per connection more robust.
+ (markt)
+ </fix>
</changelog>
</subsection>
<subsection name="Jasper">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]