This is an automated email from the ASF dual-hosted git repository.
ChristopherSchultz pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/main by this push:
new 8bb32b3de0 Fix handling of quoted literals and escaped 's
8bb32b3de0 is described below
commit 8bb32b3de0428136ba64f1ea70b3bf9cdb8a564a
Author: Christopher Schultz <[email protected]>
AuthorDate: Thu May 21 10:59:06 2026 -0400
Fix handling of quoted literals and escaped 's
---
java/org/apache/juli/DateFormatCache.java | 35 ++++++++++------
test/org/apache/juli/TestDateFormatCache.java | 57 +++++++++++++++++++++++++++
2 files changed, 80 insertions(+), 12 deletions(-)
diff --git a/java/org/apache/juli/DateFormatCache.java
b/java/org/apache/juli/DateFormatCache.java
index 054f92265d..e40e8e3550 100644
--- a/java/org/apache/juli/DateFormatCache.java
+++ b/java/org/apache/juli/DateFormatCache.java
@@ -63,22 +63,33 @@ public class DateFormatCache {
* formatted time stamps cacheable. Our consumer might choose to replace
the dummy chars with the actual
* milliseconds because that's relatively cheap.
*/
- private String tidyFormat(String format) {
- boolean escape = false;
+ protected static String tidyFormat(String format) {
+ final int length = format.length();
StringBuilder result = new StringBuilder();
- int len = format.length();
- char x;
- for (int i = 0; i < len; i++) {
- x = format.charAt(i);
- if (escape || x != 'S') {
- result.append(x);
- } else {
- result.append(MSEC_PATTERN);
+ boolean literalMode = false;
+
+ for (int i = 0; i < length; i++) {
+ char c = format.charAt(i);
+
+ if (c == '\'') {
+ // Handle escaped quote ('') which isn't the same as entering
literal-mode
+ if (i + 1 < length && format.charAt(i + 1) == '\'') {
+ result.append("''");
+ i++; // consume second quote
+ } else {
+ literalMode = !literalMode;
+ result.append(c);
+ }
+ continue;
}
- if (x == '\'') {
- escape = !escape;
+
+ if (!literalMode && c == 'S') {
+ result.append(MSEC_PATTERN);
+ } else {
+ result.append(c);
}
}
+
return result.toString();
}
diff --git a/test/org/apache/juli/TestDateFormatCache.java
b/test/org/apache/juli/TestDateFormatCache.java
index 9205364042..46a6e3a898 100644
--- a/test/org/apache/juli/TestDateFormatCache.java
+++ b/test/org/apache/juli/TestDateFormatCache.java
@@ -106,4 +106,61 @@ public class TestDateFormatCache {
return sdf.format(new Date(secs * 1000));
}
+ @Test
+ public void replacesUnquotedS() {
+ Assert.assertEquals(
+ "HH:mm:ss.###",
+ DateFormatCache.tidyFormat("HH:mm:ss.SSS")
+ );
+ }
+
+ @Test
+ public void doesNotReplaceQuotedS() {
+ Assert.assertEquals(
+ "HH:mm:ss.'SSS'",
+ DateFormatCache.tidyFormat("HH:mm:ss.'SSS'")
+ );
+ }
+
+ @Test
+ public void handlesEscapedQuoteInsideLiteral() {
+ Assert.assertEquals(
+ "'o''clock' ###",
+ DateFormatCache.tidyFormat("'o''clock' SSS")
+ );
+ }
+
+ @Test
+ public void doesNotReplaceSInsideLiteralAfterEscapedQuote() {
+ Assert.assertEquals(
+ "'abc''SSS'",
+ DateFormatCache.tidyFormat("'abc''SSS'")
+ );
+ }
+
+ @Test
+ public void handlesMultipleLiteralSections() {
+ Assert.assertEquals(
+ "'foo' ### 'bar'",
+ DateFormatCache.tidyFormat("'foo' SSS 'bar'")
+ );
+ }
+
+ @Test
+ public void handlesEscapedQuoteOutsideLiteral() {
+ Assert.assertEquals(
+ "'' ###",
+ DateFormatCache.tidyFormat("'' SSS")
+ );
+ }
+
+ @Test
+ public void complexQuoteScenario() {
+ Assert.assertEquals(
+ "'Start' ### 'o''clock' ### '' 'End'",
+ DateFormatCache.tidyFormat(
+ "'Start' SSS 'o''clock' SSS '' 'End'"
+ )
+ );
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]