This is an automated email from the ASF dual-hosted git repository.
markt-asf pushed a commit to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/10.1.x by this push:
new 825a2a3d6e Validate sendAllSessionsSize in DeltaManager (#1042)
825a2a3d6e is described below
commit 825a2a3d6ef32b7a872fbd1e9bafe31baebb6e37
Author: lihongyi87 <[email protected]>
AuthorDate: Tue Aug 18 16:18:44 2026 +0800
Validate sendAllSessionsSize in DeltaManager (#1042)
Reject a sendAllSessionsSize of zero or less with an
IllegalArgumentException in the setter and document that the value
must be a positive integer. Previously a non-positive value caused
an infinite loop or a NegativeArraySizeException in the batching
loop of handleGET_ALL_SESSIONS.
Clean-up by markt
---
.../apache/catalina/ha/session/DeltaManager.java | 8 +-
.../catalina/ha/session/LocalStrings.properties | 1 +
.../catalina/ha/session/TestDeltaManagerBatch.java | 137 +++++++++++++++++++++
webapps/docs/changelog.xml | 11 ++
webapps/docs/config/cluster-manager.xml | 2 +
5 files changed, 158 insertions(+), 1 deletion(-)
diff --git a/java/org/apache/catalina/ha/session/DeltaManager.java b/java/org/apache/catalina/ha/session/DeltaManager.java
index 371bbded20..1b77b5e54b 100644
--- a/java/org/apache/catalina/ha/session/DeltaManager.java
+++ b/java/org/apache/catalina/ha/session/DeltaManager.java
@@ -438,9 +438,15 @@ public class DeltaManager extends ClusterManagerBase {
/**
* Set the batch size for sending all sessions.
*
- * @param sendAllSessionsSize The batch size value
+ * @param sendAllSessionsSize The batch size value. Must be a positive integer.
+ *
+ * @throws IllegalArgumentException if the batch size is not a positive integer
*/
public void setSendAllSessionsSize(int sendAllSessionsSize) {
+ if (sendAllSessionsSize <= 0) {
+ throw new IllegalArgumentException(
+ sm.getString("deltaManager.sendAllSessionsSize.invalid", Integer.valueOf(sendAllSessionsSize)));
+ }
this.sendAllSessionsSize = sendAllSessionsSize;
}
diff --git a/java/org/apache/catalina/ha/session/LocalStrings.properties b/java/org/apache/catalina/ha/session/LocalStrings.properties
index b42e83d5fe..eb54b36ba7 100644
--- a/java/org/apache/catalina/ha/session/LocalStrings.properties
+++ b/java/org/apache/catalina/ha/session/LocalStrings.properties
@@ -60,6 +60,7 @@ deltaManager.receiveMessage.unloadingAfter=Manager [{0}]: unloading sessions com
deltaManager.receiveMessage.unloadingBegin=Manager [{0}]: start unloading sessions
deltaManager.registerCluster=Register manager [{0}] to cluster element [{1}] with name [{2}]
deltaManager.sendMessage.newSession=Manager [{0}] send new session [{1}]
+deltaManager.sendAllSessionsSize.invalid=The sendAllSessionsSize value [{0}] is invalid. It must be a positive integer.
deltaManager.sessionReceived=Manager [{0}]; session state sent at [{1}] received in [{2}] ms.
deltaManager.startClustering=Starting clustering manager at [{0}]
deltaManager.stopped=Manager [{0}] is stopping
diff --git a/test/org/apache/catalina/ha/session/TestDeltaManagerBatch.java b/test/org/apache/catalina/ha/session/TestDeltaManagerBatch.java
new file mode 100644
index 0000000000..43efd94eef
--- /dev/null
+++ b/test/org/apache/catalina/ha/session/TestDeltaManagerBatch.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.catalina.ha.session;
+
+import java.io.IOException;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.catalina.Session;
+import org.apache.catalina.ha.CatalinaCluster;
+import org.apache.catalina.tribes.Member;
+import org.easymock.EasyMock;
+
+
+/**
+ * Tests for the <code>sendAllSessionsSize</code> validation in
+ * {@link DeltaManager} and the batched session sending in
+ * {@link DeltaManager#handleGET_ALL_SESSIONS}.
+ */
+public class TestDeltaManagerBatch {
+
+ /**
+ * Tracks how many times {@link #sendSessions(Member, Session[], long)} is
+ * invoked and what payloads it receives.
+ */
+ private static class TesterDeltaManager extends DeltaManager {
+
+ private int sendCount;
+ private int lastBatchSize = -1;
+ private final Session[] sessions;
+
+ TesterDeltaManager(Session[] sessions) {
+ this.sessions = sessions;
+ }
+
+ @Override
+ public Session[] findSessions() {
+ return sessions;
+ }
+
+ @Override
+ protected void sendSessions(Member sender, Session[] currentSessions, long sendTimestamp)
+ throws IOException {
+ sendCount++;
+ lastBatchSize = currentSessions.length;
+ }
+ }
+
+ private static Session[] createSessions(int count) {
+ Session[] result = new Session[count];
+ TesterDeltaManager manager = new TesterDeltaManager(new Session[0]);
+ for (int i = 0; i < count; i++) {
+ result[i] = new DeltaSession(manager);
+ }
+ return result;
+ }
+
+ private static TesterDeltaManager createManager(Session[] sessions, boolean sendAllSessions,
+ int sendAllSessionsSize) {
+ TesterDeltaManager manager = new TesterDeltaManager(sessions);
+ manager.setSendAllSessions(sendAllSessions);
+ manager.setSendAllSessionsSize(sendAllSessionsSize);
+ // Avoid the inter-batch sleep in the batching loop so the test does not
+ // depend on the default sendAllSessionsWaitTime.
+ manager.setSendAllSessionsWaitTime(0);
+
+ // The send operations at the end of handleGET_ALL_SESSIONS require a
+ // cluster reference. Use a mock so no real cluster is needed.
+ CatalinaCluster cluster = EasyMock.createNiceMock(CatalinaCluster.class);
+ EasyMock.replay(cluster);
+ manager.setCluster(cluster);
+ return manager;
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testSendAllSessionsSizeZeroRejected() {
+ new TesterDeltaManager(new Session[0]).setSendAllSessionsSize(0);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testSendAllSessionsSizeNegativeRejected() {
+ new TesterDeltaManager(new Session[0]).setSendAllSessionsSize(-5);
+ }
+
+ @Test
+ public void testSendAllSessionsSizePositiveAccepted() {
+ TesterDeltaManager manager = new TesterDeltaManager(new Session[0]);
+ manager.setSendAllSessionsSize(1);
+ Assert.assertEquals(1, manager.getSendAllSessionsSize());
+ }
+
+ @Test
+ public void testPositiveBatchSizeSplitsSessions() throws Exception {
+ TesterDeltaManager manager = createManager(createSessions(5), false, 2);
+
+ manager.handleGET_ALL_SESSIONS(null, null);
+
+ // 5 sessions in batches of 2 => 2+2+1 = 3 sends
+ Assert.assertEquals(3, manager.sendCount);
+ }
+
+ @Test
+ public void testSendAllSessionsIgnoresBatchSize() throws Exception {
+ TesterDeltaManager manager = createManager(createSessions(3), true, 1);
+
+ manager.handleGET_ALL_SESSIONS(null, null);
+
+ // sendAllSessions is true so all sessions are sent in a single batch
+ Assert.assertEquals(1, manager.sendCount);
+ Assert.assertEquals(3, manager.lastBatchSize);
+ }
+
+ @Test
+ public void testNoSessionsNotSent() throws Exception {
+ TesterDeltaManager manager = createManager(createSessions(0), false, 2);
+
+ manager.handleGET_ALL_SESSIONS(null, null);
+
+ // No sessions means the batching loop body never runs
+ Assert.assertEquals(0, manager.sendCount);
+ }
+}
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 14f4313953..b22186c697 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -120,6 +120,17 @@
</fix>
</changelog>
</subsection>
+ <subsection name="Cluster">
+ <changelog>
+ <fix>
+ Validate that the <code>DeltaManager</code> attribute
+ <code>sendAllSessionsSize</code> is a positive integer. Zero or negative
+ values previously caused an infinite loop or a
+ <code>NegativeArraySizeException</code> during session state transfer.
+ Pull request <pr>1042</pr> provided by lihongyi87. (markt)
+ </fix>
+ </changelog>
+ </subsection>
<subsection name="WebSocket">
<changelog>
<fix>
diff --git a/webapps/docs/config/cluster-manager.xml b/webapps/docs/config/cluster-manager.xml
index 1125ac7ad6..f9f768d1cb 100644
--- a/webapps/docs/config/cluster-manager.xml
+++ b/webapps/docs/config/cluster-manager.xml
@@ -158,6 +158,8 @@
<attribute name="sendAllSessionsSize" required="false">
The number of sessions in a session block message. This value is
effective only when <code>sendAllSessions</code> is <code>false</code>.
+ It must be a positive integer; any other value is rejected with an
+ <code>IllegalArgumentException</code> during configuration.
Default is <code>1000</code>.
</attribute>
<attribute name="sendAllSessionsWaitTime" required="false">
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.