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 46780d5  SLING-13351 make content-type handling consistent (#86)
46780d5 is described below

commit 46780d5710c7c7aa0647f9d52b5961c09cc9df8b
Author: Jörg Hoh <[email protected]>
AuthorDate: Mon Sep 21 13:33:41 2026 +0200

    SLING-13351 make content-type handling consistent (#86)
    
    the content-type can be set also via setHeader/addHeader, so in these cases 
the logic of
    setContenType should be applied.
---
 .../impl/SlingJakartaHttpServletResponseImpl.java  | 14 ++++++
 .../impl/SlingHttpServletResponseImplTest.java     | 58 ++++++++++++++++++++++
 2 files changed, 72 insertions(+)

diff --git 
a/src/main/java/org/apache/sling/engine/impl/SlingJakartaHttpServletResponseImpl.java
 
b/src/main/java/org/apache/sling/engine/impl/SlingJakartaHttpServletResponseImpl.java
index e8a690c..be9d38e 100644
--- 
a/src/main/java/org/apache/sling/engine/impl/SlingJakartaHttpServletResponseImpl.java
+++ 
b/src/main/java/org/apache/sling/engine/impl/SlingJakartaHttpServletResponseImpl.java
@@ -59,6 +59,8 @@ public class SlingJakartaHttpServletResponseImpl extends 
HttpServletResponseWrap
 
     private static final String CALL_STACK_MESSAGE = "Call stack causing the 
content type override violation: ";
 
+    private static final String HEADER_CONTENT_TYPE = "Content-Type";
+
     private static final Logger LOG = 
LoggerFactory.getLogger(SlingJakartaHttpServletResponseImpl.class);
 
     // this regex matches TIMER_START{ followed by any characters except }, 
and then
@@ -274,6 +276,12 @@ public class SlingJakartaHttpServletResponseImpl extends 
HttpServletResponseWrap
 
     @Override
     public void addHeader(final String name, final String value) {
+        if (this.isInclude() && HEADER_CONTENT_TYPE.equalsIgnoreCase(name)) {
+            // changing the Content-Type header during an include must be 
subject
+            // to the same enforcement as setContentType (see setHeader)
+            this.setContentType(value);
+            return;
+        }
         if (!this.isProtectHeadersOnInclude()) {
             logHeaderModificationCallOnIncludeForMethod("addHeader()");
             super.addHeader(name, value);
@@ -307,6 +315,12 @@ public class SlingJakartaHttpServletResponseImpl extends 
HttpServletResponseWrap
 
     @Override
     public void setHeader(final String name, final String value) {
+        if (this.isInclude() && HEADER_CONTENT_TYPE.equalsIgnoreCase(name)) {
+            // changing the Content-Type header during an include must be 
subject
+            // to the same enforcement as setContentType (see setHeader)
+            this.setContentType(value);
+            return;
+        }
         if (!this.isProtectHeadersOnInclude()) {
             logHeaderModificationCallOnIncludeForMethod("setHeader()");
             super.setHeader(name, value);
diff --git 
a/src/test/java/org/apache/sling/engine/impl/SlingHttpServletResponseImplTest.java
 
b/src/test/java/org/apache/sling/engine/impl/SlingHttpServletResponseImplTest.java
index 51bd2b7..58ac359 100644
--- 
a/src/test/java/org/apache/sling/engine/impl/SlingHttpServletResponseImplTest.java
+++ 
b/src/test/java/org/apache/sling/engine/impl/SlingHttpServletResponseImplTest.java
@@ -374,6 +374,64 @@ public class SlingHttpServletResponseImplTest {
                                 
.collect(Collectors.joining(System.lineSeparator())))));
     }
 
+    @Test
+    public void testContentTypeOverrideEnforcedForSetHeader() {
+        final SlingJakartaHttpServletResponse orig = 
Mockito.mock(SlingJakartaHttpServletResponse.class);
+        final RequestData requestData = mock(RequestData.class);
+        final DispatchingInfo info = new 
DispatchingInfo(DispatcherType.INCLUDE);
+        final RequestProgressTracker requestProgressTracker = 
mock(RequestProgressTracker.class);
+        when(requestData.getDispatchingInfo()).thenReturn(info);
+        when(orig.getContentType()).thenReturn("text/plain");
+        
when(requestData.getRequestProgressTracker()).thenReturn(requestProgressTracker);
+        ArrayList<String> logMessagesList = new 
ArrayList<>(Arrays.asList(logMessages));
+        when(requestProgressTracker.getMessages()).thenAnswer(invocation -> 
logMessagesList.iterator());
+        info.setCheckContentTypeOnInclude(true);
+
+        final SlingRequestProcessorImpl requestProcessor = 
mock(SlingRequestProcessorImpl.class);
+        
when(requestData.getSlingRequestProcessor()).thenReturn(requestProcessor);
+        
when(requestData.getActiveServletName()).thenReturn(ACTIVE_SERVLET_NAME);
+
+        final HttpServletResponse include = new 
SlingJakartaHttpServletResponseImpl(requestData, orig);
+
+        Throwable setHeaderThrowable = null;
+        try {
+            include.setHeader("Content-Type", "text/html");
+        } catch (RuntimeException e) {
+            setHeaderThrowable = e;
+        }
+        assertNotNull("Expected setHeader(\"Content-Type\", ...) to be 
blocked.", setHeaderThrowable);
+
+        Throwable addHeaderThrowable = null;
+        try {
+            include.addHeader("content-type", "text/html");
+        } catch (RuntimeException e) {
+            addHeaderThrowable = e;
+        }
+        assertNotNull("Expected addHeader(\"content-type\", ...) to be 
blocked.", addHeaderThrowable);
+
+        Mockito.verify(orig, never()).setHeader(Mockito.anyString(), 
Mockito.anyString());
+        Mockito.verify(orig, never()).addHeader(Mockito.anyString(), 
Mockito.anyString());
+        Mockito.verify(orig, never()).setContentType(Mockito.anyString());
+    }
+
+    @Test
+    public void testUnrelatedHeadersNotRoutedThroughContentTypeCheck() {
+        final SlingJakartaHttpServletResponse orig = 
Mockito.mock(SlingJakartaHttpServletResponse.class);
+        final RequestData requestData = mock(RequestData.class);
+        final DispatchingInfo info = new 
DispatchingInfo(DispatcherType.INCLUDE);
+        when(requestData.getDispatchingInfo()).thenReturn(info);
+        
when(requestData.getRequestProgressTracker()).thenReturn(mock(RequestProgressTracker.class));
+        info.setCheckContentTypeOnInclude(true);
+
+        final HttpServletResponse include = new 
SlingJakartaHttpServletResponseImpl(requestData, orig);
+
+        include.setHeader("X-Custom", "value");
+        include.addHeader("X-Custom", "another");
+
+        Mockito.verify(orig, times(1)).setHeader("X-Custom", "value");
+        Mockito.verify(orig, times(1)).addHeader("X-Custom", "another");
+    }
+
     @Test
     public void testContentTypeOverrideDisabled() {
         final SlingJakartaHttpServletResponse orig = 
Mockito.mock(SlingJakartaHttpServletResponse.class);

Reply via email to