This is an automated email from the ASF dual-hosted git repository.
ChristopherSchultz 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 5ee0bc24b2 Fix handling of quoted literals and escaped 's
5ee0bc24b2 is described below
commit 5ee0bc24b2e6dfb485218e096066e2539f1b956d
Author: Christopher Schultz <[email protected]>
AuthorDate: Thu May 21 11:02:46 2026 -0400
Fix handling of quoted literals and escaped 's
---
java/org/apache/juli/DateFormatCache.java | 35 ++++++++++------
test/org/apache/juli/TestDateFormatCache.java | 57 +++++++++++++++++++++++++++
webapps/docs/changelog.xml | 4 ++
3 files changed, 84 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'"
+ )
+ );
+ }
}
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 656615e4e9..7d78aa5f63 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -164,6 +164,10 @@
Remove exception swallowing in <code>DataSourceStore</code> to align
it with <code>FileStore</code> and avoid session loss on errors. (remm)
</fix>
+ <fix>
+ Add support for single-quote escaped literal as well as quoted literals
+ in <code>DateFormatCache</code>. (schultz)
+ </fix>
</changelog>
</subsection>
<subsection name="Coyote">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]