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

rmaucher pushed a commit to branch 11.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 3341e7f1b1942055d2bd7a7089090a989f604feb
Author: opencode <[email protected]>
AuthorDate: Thu Oct 8 14:19:01 2026 +0200

    Fix SSI built-in date variables always resolving to null
    
    The mediator stored the built-in variables DATE_GMT, DATE_LOCAL and
    LAST_MODIFIED as external variables using names starting with its own
    fully qualified class name, and looked them up the same way. The servlet
    resolver rejects names under the reserved prefixes, and since
    org.apache.catalina.ssi.SSIMediator falls under the
    org.apache.catalina. prefix added when the reserved list was extended,
    both the store and the lookup silently did nothing and the variables
    always rendered as (none).
    
    Hold the built-in variables in the mediator itself, as per-document
    values that do not need to live in the external resolver, and resolve
    them there after the external lookup, preserving the ability of the
    document to override them via #set. The cross-mediator alreadyset guard
    was dead (it used the same rejected names) and has no meaning with
    per-mediator storage; with it gone, the fromConstructor parameter of
    setConfigTimeFmt() and setDateVariables() is no longer needed and is
    removed.
---
 java/org/apache/catalina/ssi/SSIMediator.java    | 67 ++++++++++--------------
 test/org/apache/catalina/ssi/TestSsiServlet.java |  3 ++
 webapps/docs/changelog.xml                       | 12 +++++
 3 files changed, 43 insertions(+), 39 deletions(-)

diff --git a/java/org/apache/catalina/ssi/SSIMediator.java 
b/java/org/apache/catalina/ssi/SSIMediator.java
index bac7bb4a48..7f82a64a49 100644
--- a/java/org/apache/catalina/ssi/SSIMediator.java
+++ b/java/org/apache/catalina/ssi/SSIMediator.java
@@ -20,8 +20,10 @@ import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.Collection;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Set;
 import java.util.TimeZone;
 import java.util.regex.Matcher;
@@ -100,6 +102,12 @@ public class SSIMediator {
      * Number of regex match groups from the last match operation.
      */
     protected int lastMatchCount = 0;
+    /**
+     * Built-in variables supplied by this mediator, keyed by upper-case name. 
These are held
+     * locally rather than in the external resolver since the resolver rejects 
names under the
+     * reserved prefixes, which included the names historically used for these 
variables.
+     */
+    private final Map<String, String> builtinVariables = new HashMap<>();
 
 
     /**
@@ -111,7 +119,7 @@ public class SSIMediator {
     public SSIMediator(SSIExternalResolver ssiExternalResolver, long 
lastModifiedDate) {
         this.ssiExternalResolver = ssiExternalResolver;
         this.lastModifiedDate = lastModifiedDate;
-        setConfigTimeFmt(DEFAULT_CONFIG_TIME_FMT, true);
+        setConfigTimeFmt(DEFAULT_CONFIG_TIME_FMT);
     }
 
 
@@ -131,24 +139,13 @@ public class SSIMediator {
      * @param configTimeFmt the time format string
      */
     public void setConfigTimeFmt(String configTimeFmt) {
-        setConfigTimeFmt(configTimeFmt, false);
-    }
-
-
-    /**
-     * Sets the time format string and updates date variables accordingly.
-     *
-     * @param configTimeFmt    the time format string
-     * @param fromConstructor true if called from the constructor
-     */
-    public void setConfigTimeFmt(String configTimeFmt, boolean 
fromConstructor) {
         this.configTimeFmt = configTimeFmt;
         this.strftime = new Strftime(configTimeFmt, Locale.US);
         /*
          * Variables like DATE_LOCAL, DATE_GMT, and LAST_MODIFIED need to be 
updated when the timefmt changes. This is
          * what Apache SSI does.
          */
-        setDateVariables(fromConstructor);
+        setDateVariables();
     }
 
 
@@ -308,8 +305,7 @@ public class SSIMediator {
             // Try getting it externally first, if it fails, try getting the 
'built-in' value
             variableValue = ssiExternalResolver.getVariableValue(variableName);
             if (variableValue == null) {
-                variableName = variableName.toUpperCase(Locale.ENGLISH);
-                variableValue = ssiExternalResolver.getVariableValue(className 
+ "." + variableName);
+                variableValue = 
builtinVariables.get(variableName.toUpperCase(Locale.ENGLISH));
             }
             if (variableValue != null) {
                 variableValue = encode(variableValue, encoding);
@@ -517,30 +513,23 @@ public class SSIMediator {
 
     /**
      * Updates the built-in date variables (DATE_GMT, DATE_LOCAL, 
LAST_MODIFIED).
-     *
-     * @param fromConstructor true if called from the constructor
-     */
-    protected void setDateVariables(boolean fromConstructor) {
-        boolean alreadySet = ssiExternalResolver.getVariableValue(className + 
".alreadyset") != null;
-        // skip this if we are being called from the constructor, and this has 
already been set
-        if (!(fromConstructor && alreadySet)) {
-            ssiExternalResolver.setVariableValue(className + ".alreadyset", 
"true");
-            Date date = new Date();
-            TimeZone timeZone = TimeZone.getTimeZone("GMT");
-            String retVal = formatDate(date, timeZone);
-            /*
-             * If we are setting on of the date variables, we want to remove 
them from the user defined list of
-             * variables, because this is what Apache does.
-             */
-            setVariableValue("DATE_GMT", null);
-            ssiExternalResolver.setVariableValue(className + ".DATE_GMT", 
retVal);
-            retVal = formatDate(date, null);
-            setVariableValue("DATE_LOCAL", null);
-            ssiExternalResolver.setVariableValue(className + ".DATE_LOCAL", 
retVal);
-            retVal = formatDate(new Date(lastModifiedDate), null);
-            setVariableValue("LAST_MODIFIED", null);
-            ssiExternalResolver.setVariableValue(className + ".LAST_MODIFIED", 
retVal);
-        }
+     */
+    protected void setDateVariables() {
+        Date date = new Date();
+        TimeZone timeZone = TimeZone.getTimeZone("GMT");
+        String retVal = formatDate(date, timeZone);
+        /*
+         * If we are setting on of the date variables, we want to remove them 
from the user defined list of variables,
+         * because this is what Apache does.
+         */
+        setVariableValue("DATE_GMT", null);
+        builtinVariables.put("DATE_GMT", retVal);
+        retVal = formatDate(date, null);
+        setVariableValue("DATE_LOCAL", null);
+        builtinVariables.put("DATE_LOCAL", retVal);
+        retVal = formatDate(new Date(lastModifiedDate), null);
+        setVariableValue("LAST_MODIFIED", null);
+        builtinVariables.put("LAST_MODIFIED", retVal);
     }
 
 
diff --git a/test/org/apache/catalina/ssi/TestSsiServlet.java 
b/test/org/apache/catalina/ssi/TestSsiServlet.java
index 009caa5f3c..28e8fa6337 100644
--- a/test/org/apache/catalina/ssi/TestSsiServlet.java
+++ b/test/org/apache/catalina/ssi/TestSsiServlet.java
@@ -67,6 +67,9 @@ public class TestSsiServlet extends TomcatBaseTest {
         Assert.assertTrue(body.contains("path is relative"));
         Assert.assertTrue(body.contains("1k"));
         Assert.assertTrue(body.contains("SERVER_PROTOCOL"));
+        // Any undefined variable renders as "(none)". The page only echoes
+        // variables that must be defined, including the built-in date 
variables.
+        Assert.assertFalse(body.contains("(none)"));
 
     }
 }
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 4975384ef6..c98f19f0cd 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -1915,6 +1915,18 @@
         evaluation of existing documents using unparenthesized mixed
         <code>&amp;&amp;</code> and <code>||</code> chains. (remm)
       </fix>
+      <fix>
+        Fix the built-in SSI variables <code>DATE_GMT</code>,
+        <code>DATE_LOCAL</code> and <code>LAST_MODIFIED</code> always
+        resolving to <code>null</code> and rendering as
+        <code>(none)</code>. The mediator stored and looked them up as
+        external variables using names starting with its own fully qualified
+        class name, which the servlet resolver rejects since those names fall
+        under the reserved <code>org.apache.catalina.</code> prefix. Hold the
+        built-in variables in the mediator itself and resolve them there, as
+        they are per-document values that do not need to be stored in the
+        external resolver. (remm)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Coyote">


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

Reply via email to