This is an automated email from the ASF dual-hosted git repository.

rmaucher 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 c2d2d6319a Avoid some scenarios of expiration of never expire sessions
c2d2d6319a is described below

commit c2d2d6319ada57de84c62f37fdaec7da5e7c2dbf
Author: remm <[email protected]>
AuthorDate: Fri Aug 28 11:44:55 2026 +0200

    Avoid some scenarios of expiration of never expire sessions
    
    Tests written by OpenCode.
---
 .../apache/catalina/session/DataSourceStore.java   |  1 +
 java/org/apache/catalina/session/StoreBase.java    |  3 +-
 .../org/apache/catalina/session/TestFileStore.java | 34 ++++++++++++++++++
 .../TestPersistentManagerDataSourceStore.java      | 42 ++++++++++++++++++++++
 4 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/java/org/apache/catalina/session/DataSourceStore.java 
b/java/org/apache/catalina/session/DataSourceStore.java
index 5bca390cab..c15dcb3e70 100644
--- a/java/org/apache/catalina/session/DataSourceStore.java
+++ b/java/org/apache/catalina/session/DataSourceStore.java
@@ -357,6 +357,7 @@ public class DataSourceStore extends StoreBase {
     private String[] keys(boolean expiredOnly) throws IOException {
         String sqlTmp = "SELECT " + sessionIdCol + " FROM " + sessionTable + " 
WHERE " + sessionAppCol + " = ?";
         if (expiredOnly) {
+            sqlTmp += " AND " + sessionMaxInactiveCol + " >= 0";
             sqlTmp += " AND (" + sessionLastAccessedCol + " + " + 
sessionMaxInactiveCol + " * 1000 < ?)";
         }
         final String keysSql = sqlTmp;
diff --git a/java/org/apache/catalina/session/StoreBase.java 
b/java/org/apache/catalina/session/StoreBase.java
index eaa4ab56b5..ee5a7d9dc5 100644
--- a/java/org/apache/catalina/session/StoreBase.java
+++ b/java/org/apache/catalina/session/StoreBase.java
@@ -160,7 +160,8 @@ public abstract class StoreBase extends LifecycleBase 
implements Store {
                     continue;
                 }
                 int timeIdle = (int) ((timeNow - 
session.getThisAccessedTime()) / 1000L);
-                if (timeIdle < session.getMaxInactiveInterval()) {
+                int maxInactive = session.getMaxInactiveInterval();
+                if (maxInactive < 0 || timeIdle < maxInactive) {
                     continue;
                 }
                 if (manager.getContext().getLogger().isTraceEnabled()) {
diff --git a/test/org/apache/catalina/session/TestFileStore.java 
b/test/org/apache/catalina/session/TestFileStore.java
index e2109a9dda..67a878a0fb 100644
--- a/test/org/apache/catalina/session/TestFileStore.java
+++ b/test/org/apache/catalina/session/TestFileStore.java
@@ -102,6 +102,40 @@ public class TestFileStore {
         Assert.assertEquals(1, fileStore.getSize());
     }
 
+    @Test
+    public void processExpiresNeverExpiringSession() throws Exception {
+        // Use a separate store and directory so this test does not
+        // interfere with the fixtures used by the other tests.
+        FileStore expireStore = new FileStore();
+        expireStore.setManager(manager);
+        expireStore.setDirectory(new File(dir, "expire").getAbsolutePath());
+        expireStore.start();
+        try {
+            // A session that is idle longer than its max inactive interval
+            // but that must never expire.
+            StandardSession neverExpiring = (StandardSession) 
manager.createSession("never-expiring");
+            neverExpiring.setManager(manager);
+            neverExpiring.setMaxInactiveInterval(-1);
+            neverExpiring.setCreationTime(System.currentTimeMillis() - 
60_000L);
+            expireStore.save(neverExpiring);
+
+            // A session that is idle longer than its max inactive interval
+            // and that must be expired.
+            StandardSession expiring = (StandardSession) 
manager.createSession("expiring");
+            expiring.setManager(manager);
+            expiring.setMaxInactiveInterval(1);
+            expiring.setCreationTime(System.currentTimeMillis() - 60_000L);
+            expireStore.save(expiring);
+
+            expireStore.processExpires();
+
+            Assert.assertArrayEquals(new String[] { "never-expiring" }, 
expireStore.keys());
+        } finally {
+            expireStore.clear();
+            expireStore.stop();
+        }
+    }
+
     @Test
     public void pathTraversalSessionId() throws Exception {
         File storageDir = dir.getAbsoluteFile();
diff --git 
a/test/org/apache/catalina/session/TestPersistentManagerDataSourceStore.java 
b/test/org/apache/catalina/session/TestPersistentManagerDataSourceStore.java
index c8770b086a..1896480eab 100644
--- a/test/org/apache/catalina/session/TestPersistentManagerDataSourceStore.java
+++ b/test/org/apache/catalina/session/TestPersistentManagerDataSourceStore.java
@@ -38,6 +38,8 @@ import org.apache.catalina.Session;
 import org.apache.catalina.startup.Tomcat;
 import org.apache.catalina.startup.TomcatBaseTest;
 import org.apache.tomcat.util.compat.JreCompat;
+import org.apache.tomcat.unittest.TesterContext;
+import org.apache.tomcat.unittest.TesterServletContext;
 
 public class TestPersistentManagerDataSourceStore extends TomcatBaseTest {
 
@@ -148,6 +150,46 @@ public class TestPersistentManagerDataSourceStore extends 
TomcatBaseTest {
         store.clear();
     }
 
+    @Test
+    public void testExpiredKeysNeverExpiringSessions() throws Exception {
+        StandardManager manager = new StandardManager();
+        TesterContext testerContext = new TesterContext();
+        testerContext.setServletContext(new TesterServletContext());
+        manager.setContext(testerContext);
+
+        DerbyDataSourceStore store = new DerbyDataSourceStore("expiredkeys");
+        store.setSessionTable("tomcatsessions");
+        store.setManager(manager);
+        store.start();
+        try {
+            // A session that must never expire.
+            StandardSession neverExpiring = (StandardSession) 
manager.createSession("never-expiring");
+            neverExpiring.setManager(manager);
+            neverExpiring.setMaxInactiveInterval(-1);
+            store.save(neverExpiring);
+
+            // A session with a 1 second max inactive interval.
+            StandardSession expiring = (StandardSession) 
manager.createSession("expiring");
+            expiring.setManager(manager);
+            expiring.setMaxInactiveInterval(1);
+            store.save(expiring);
+
+            // Make both saved sessions idle for 60 seconds so that the
+            // "expiring" session is well past its max inactive interval.
+            String dbUrl = "jdbc:derby:" + 
getTemporaryDirectory().getAbsolutePath() +
+                    "/store-expiredkeys";
+            try (Connection conn = DriverManager.getConnection(dbUrl);
+                    Statement statement = conn.createStatement()) {
+                statement.execute("update tomcatsessions set lastaccess = 
lastaccess - 60000");
+            }
+
+            Assert.assertArrayEquals(new String[] { "expiring" }, 
store.expiredKeys());
+        } finally {
+            store.clear();
+            store.stop();
+        }
+    }
+
     private static class DummyServlet extends HttpServlet {
 
         private static final long serialVersionUID = -3696433049266123995L;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to