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

joerghoh pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-engine.git


The following commit(s) were added to refs/heads/master by this push:
     new 68b028f  SLING-13360 all log directives should handle CR/LF escaping 
(#91)
68b028f is described below

commit 68b028ffe29ad8dc56a1792a3427915a8614aa76
Author: Jörg Hoh <[email protected]>
AuthorDate: Wed Sep 23 19:17:07 2026 +0200

    SLING-13360 all log directives should handle CR/LF escaping (#91)
---
 .../sling/engine/impl/log/CustomLogFormat.java     | 11 ++--
 .../sling/engine/impl/log/CustomLogFormatTest.java | 60 ++++++++++++++++++++++
 2 files changed, 67 insertions(+), 4 deletions(-)

diff --git 
a/src/main/java/org/apache/sling/engine/impl/log/CustomLogFormat.java 
b/src/main/java/org/apache/sling/engine/impl/log/CustomLogFormat.java
index 8d353b5..e67b119 100644
--- a/src/main/java/org/apache/sling/engine/impl/log/CustomLogFormat.java
+++ b/src/main/java/org/apache/sling/engine/impl/log/CustomLogFormat.java
@@ -547,7 +547,7 @@ class CustomLogFormat {
         }
 
         protected String getValue(RequestLoggerRequest request) {
-            return Thread.currentThread().getName();
+            return escape(Thread.currentThread().getName());
         }
 
         protected String getValue(RequestLoggerResponse response) {
@@ -561,7 +561,7 @@ class CustomLogFormat {
         }
 
         protected String getValue(RequestLoggerRequest request) {
-            return request.getParameter(this.getParParam());
+            return escape(request.getParameter(this.getParParam()));
         }
 
         protected String getValue(RequestLoggerResponse response) {
@@ -705,7 +705,7 @@ class CustomLogFormat {
         }
 
         protected String getValue(RequestLoggerRequest request) {
-            return request.getRemoteHost();
+            return escape(request.getRemoteHost());
         }
 
         protected String getValue(RequestLoggerResponse response) {
@@ -763,7 +763,10 @@ class CustomLogFormat {
         protected String getValue(RequestLoggerRequest request) {
             final Object resourcePath = 
request.getAttribute(RequestData.REQUEST_RESOURCE_PATH_ATTR);
             if (resourcePath instanceof String) {
-                return (String) resourcePath;
+                // the resolved resource path is derived from the decoded 
request
+                // path and may contain control characters (e.g. for 
non-existing
+                // resources), so it must be escaped like other request data
+                return escape((String) resourcePath);
             }
             return null;
         }
diff --git 
a/src/test/java/org/apache/sling/engine/impl/log/CustomLogFormatTest.java 
b/src/test/java/org/apache/sling/engine/impl/log/CustomLogFormatTest.java
index 1553e88..404e9cf 100644
--- a/src/test/java/org/apache/sling/engine/impl/log/CustomLogFormatTest.java
+++ b/src/test/java/org/apache/sling/engine/impl/log/CustomLogFormatTest.java
@@ -19,6 +19,8 @@
 package org.apache.sling.engine.impl.log;
 
 import junit.framework.TestCase;
+import org.apache.sling.engine.impl.request.RequestData;
+import org.mockito.Mockito;
 
 /**
  * The <code>CustomLogFormatTest</code> class tests the
@@ -69,4 +71,62 @@ public class CustomLogFormatTest extends TestCase {
                 "This is a special character \\u1234",
                 CustomLogFormat.HeaderParameter.escape("This is a special 
character \u1234"));
     }
+
+    public void testRequestParameterValueEscaped() {
+        final RequestLoggerRequest request = 
Mockito.mock(RequestLoggerRequest.class);
+        Mockito.when(request.getParameter("ref"))
+                .thenReturn("x\r\n192.168.1.1 - admin \"POST /system/console 
HTTP/1.1\" 200");
+
+        final CustomLogFormat.ParamParameter param = new 
CustomLogFormat.ParamParameter("ref");
+        final String value = param.getValue(request);
+
+        // no raw CR/LF may end up in the log line
+        assertFalse(value.contains("\r"));
+        assertFalse(value.contains("\n"));
+        assertEquals("x\\r\\n192.168.1.1 - admin \\\"POST /system/console 
HTTP/1.1\\\" 200", value);
+    }
+
+    public void testContentPathEscaped() {
+        final RequestLoggerRequest request = 
Mockito.mock(RequestLoggerRequest.class);
+        
Mockito.when(request.getAttribute(RequestData.REQUEST_RESOURCE_PATH_ATTR))
+                .thenReturn("/content/foo\r\nFORGED LINE");
+
+        final CustomLogFormat.ContentPathParameter param = new 
CustomLogFormat.ContentPathParameter();
+        final String value = param.getValue(request);
+
+        assertFalse(value.contains("\r"));
+        assertFalse(value.contains("\n"));
+        assertEquals("/content/foo\\r\\nFORGED LINE", value);
+    }
+
+    public void testRemoteHostEscaped() {
+        final RequestLoggerRequest request = 
Mockito.mock(RequestLoggerRequest.class);
+        
Mockito.when(request.getRemoteHost()).thenReturn("evil\nhost.example.com");
+
+        final CustomLogFormat.RemoteHostParameter param = new 
CustomLogFormat.RemoteHostParameter();
+        final String value = param.getValue(request);
+
+        assertFalse(value.contains("\n"));
+        assertEquals("evil\\nhost.example.com", value);
+    }
+
+    public void testThreadNameEscaped() {
+        // %P (ThreadParameter) does not read from the request but from the
+        // name of the thread handling it, and the threadname can contain the
+        // requested path
+        final Thread currentThread = Thread.currentThread();
+        final String originalName = currentThread.getName();
+        currentThread.setName("/content/\r\nfoo");
+        try {
+            final RequestLoggerRequest request = 
Mockito.mock(RequestLoggerRequest.class);
+            final CustomLogFormat.ThreadParameter param = new 
CustomLogFormat.ThreadParameter(null);
+            final String value = param.getValue(request);
+
+            assertFalse(value.contains("\r"));
+            assertFalse(value.contains("\n"));
+            assertEquals("/content/\\r\\nfoo", value);
+        } finally {
+            currentThread.setName(originalName);
+        }
+    }
 }

Reply via email to