This is an automated email from the ASF dual-hosted git repository.
markt-asf pushed a commit to branch 11.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/11.0.x by this push:
new b2471fdbc9 Review "Fix TIME_MON and TIME_WDAY values in the rewrite
valve"
b2471fdbc9 is described below
commit b2471fdbc95caa3f4d6963621fb0a9a72e960708
Author: Mark Thomas <[email protected]>
AuthorDate: Thu Oct 29 17:28:25 2026 +0000
Review "Fix TIME_MON and TIME_WDAY values in the rewrite valve"
Further align behaviour with mod_rewrite
- zero pad time components where required
- user correct time format
---
.../catalina/valves/rewrite/ResolverImpl.java | 30 +++++++++++++++-------
.../catalina/valves/rewrite/TestRewriteValve.java | 20 +++++++++++++--
webapps/docs/changelog.xml | 8 ++++++
3 files changed, 47 insertions(+), 11 deletions(-)
diff --git a/java/org/apache/catalina/valves/rewrite/ResolverImpl.java
b/java/org/apache/catalina/valves/rewrite/ResolverImpl.java
index b91811db64..6a410092ea 100644
--- a/java/org/apache/catalina/valves/rewrite/ResolverImpl.java
+++ b/java/org/apache/catalina/valves/rewrite/ResolverImpl.java
@@ -22,6 +22,8 @@ import java.nio.charset.Charset;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
@@ -35,7 +37,6 @@ import org.apache.catalina.WebResource;
import org.apache.catalina.WebResourceRoot;
import org.apache.catalina.connector.Request;
import org.apache.juli.logging.Log;
-import org.apache.tomcat.util.http.FastHttpDateFormat;
import org.apache.tomcat.util.http.RequestUtil;
import org.apache.tomcat.util.net.SSLSupport;
import org.apache.tomcat.util.net.jsse.PEMFile;
@@ -51,6 +52,11 @@ public class ResolverImpl extends Resolver {
private static final StringManager sm =
StringManager.getManager(ResolverImpl.class);
+ /**
+ * Format of the TIME variable, as used by mod_rewrite.
+ */
+ private static final DateTimeFormatter TIME_FORMAT =
DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
+
/**
* The request being processed.
*/
@@ -138,15 +144,16 @@ public class ResolverImpl extends Resolver {
case "REQUEST_FILENAME" -> request.getPathTranslated();
case "HTTPS" -> request.isSecure() ? "on" : "off";
case "TIME_YEAR" ->
String.valueOf(Calendar.getInstance().get(Calendar.YEAR));
- // Like mod_rewrite, TIME_MON is 1-12 and TIME_WDAY is 0-6 with
Sunday first,
- // unlike the zero-based Calendar.MONTH and one-based Sunday-first
Calendar.DAY_OF_WEEK
- case "TIME_MON" ->
String.valueOf(Calendar.getInstance().get(Calendar.MONTH) + 1);
- case "TIME_DAY" ->
String.valueOf(Calendar.getInstance().get(Calendar.DAY_OF_MONTH));
- case "TIME_HOUR" ->
String.valueOf(Calendar.getInstance().get(Calendar.HOUR_OF_DAY));
- case "TIME_MIN" ->
String.valueOf(Calendar.getInstance().get(Calendar.MINUTE));
- case "TIME_SEC" ->
String.valueOf(Calendar.getInstance().get(Calendar.SECOND));
+ // Like mod_rewrite, TIME_MON is 01-12, TIME_WDAY is 0-6 with
Sunday first and the other time values
+ // are zero padded to two digits, unlike the zero-based
Calendar.MONTH and the one-based Sunday-first
+ // Calendar.DAY_OF_WEEK
+ case "TIME_MON" ->
twoDigits(Calendar.getInstance().get(Calendar.MONTH) + 1);
+ case "TIME_DAY" ->
twoDigits(Calendar.getInstance().get(Calendar.DAY_OF_MONTH));
+ case "TIME_HOUR" ->
twoDigits(Calendar.getInstance().get(Calendar.HOUR_OF_DAY));
+ case "TIME_MIN" ->
twoDigits(Calendar.getInstance().get(Calendar.MINUTE));
+ case "TIME_SEC" ->
twoDigits(Calendar.getInstance().get(Calendar.SECOND));
case "TIME_WDAY" ->
String.valueOf(Calendar.getInstance().get(Calendar.DAY_OF_WEEK) - 1);
- case "TIME" -> FastHttpDateFormat.getCurrentDate();
+ case "TIME" -> TIME_FORMAT.format(LocalDateTime.now());
default -> null;
};
}
@@ -420,6 +427,11 @@ public class ResolverImpl extends Resolver {
}
}
+ private static String twoDigits(int value) {
+ return value < 10 ? "0" + value : String.valueOf(value);
+ }
+
+
private static String emptyStringIfNull(String value) {
return Objects.requireNonNullElse(value, "");
}
diff --git a/test/org/apache/catalina/valves/rewrite/TestRewriteValve.java
b/test/org/apache/catalina/valves/rewrite/TestRewriteValve.java
index ce8dc0af7b..aa3153ba7b 100644
--- a/test/org/apache/catalina/valves/rewrite/TestRewriteValve.java
+++ b/test/org/apache/catalina/valves/rewrite/TestRewriteValve.java
@@ -344,9 +344,9 @@ public class TestRewriteValve extends TomcatBaseTest {
@Test
public void testRewriteTimeMonModRewriteNumbering() throws Exception {
- // mod_rewrite numbering: 1-12; two tokens in one rule also cover
+ // mod_rewrite numbering: 01-12; two tokens in one rule also cover
// concatenation parsing
- String expected = String.valueOf(LocalDate.now().getMonthValue());
+ String expected = String.format("%02d",
Integer.valueOf(LocalDate.now().getMonthValue()));
doTestRewrite("RewriteRule ^/c/x$ -
[E=X-Test:%{TIME_MON}-%{TIME_MON}]",
"/c/x", "/c/x", null, expected + "-" + expected);
}
@@ -360,6 +360,22 @@ public class TestRewriteValve extends TomcatBaseTest {
"/c/x", "/c/x", null, expected + "TUE" + expected);
}
+ @Test
+ public void testRewriteTimeValuesModRewriteFormat() throws Exception {
+ // The time values are zero padded to two digits (the year and the
+ // weekday are not) and TIME is yyyyMMddHHmmss. Matching the format
+ // rather than a value keeps the test independent of the clock.
+ doTestRewrite("RewriteCond %{TIME_YEAR} ^[0-9]{4}$\n" +
+ "RewriteCond %{TIME_MON} ^(0[1-9]|1[0-2])$\n" +
+ "RewriteCond %{TIME_DAY} ^(0[1-9]|[12][0-9]|3[01])$\n" +
+ "RewriteCond %{TIME_HOUR} ^([01][0-9]|2[0-3])$\n" +
+ "RewriteCond %{TIME_MIN} ^[0-5][0-9]$\n" +
+ "RewriteCond %{TIME_SEC} ^[0-5][0-9]$\n" +
+ "RewriteCond %{TIME_WDAY} ^[0-6]$\n" +
+ "RewriteCond %{TIME} ^[0-9]{14}$\n" +
+ "RewriteRule ^/c/x$ /c/ok", "/c/x", "/c/ok");
+ }
+
@Test
public void testRemoteIdentIsNotTheRemoteUser() throws Exception {
// REMOTE_IDENT is the RFC 931 ident protocol user name, which Tomcat
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index a40cf6e03c..b6e5396d20 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -300,6 +300,14 @@
Ensure that requests cannot try to start asynchronous processing and
the
HTTP upgrade process on the same request. (markt)
</fix>
+ <fix>
+ Align the format of the <code>TIME_MON</code>, <code>TIME_DAY</code>,
+ <code>TIME_HOUR</code>, <code>TIME_MIN</code>, <code>TIME_SEC</code>
+ and <code>TIME</code> server variables in the rewrite valve with
+ mod_rewrite. The first five are now zero padded to two digits and
+ <code>TIME</code> is now of the form <code>yyyyMMddHHmmss</code>
+ rather than an HTTP date.
+ </fix>
</changelog>
</subsection>
<subsection name="Coyote">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]