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

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

commit 6b16104ca3aad0e135d454e1a9b78dfa28d122df
Author: Joerg Hoh <[email protected]>
AuthorDate: Wed Sep 16 11:40:49 2026 +0200

    SLING-13352 support log/fail also for newer Servlet Versions
    
    add support for these methods
    * sendRedirect(String, int)
    * sendRedirect(String, boolean)
    * sendRedirect(String, int, boolean)
    * setTrailerFields(Supplier<Map<String,String>>)
---
 .../impl/SlingJakartaHttpServletResponseImpl.java  | 58 ++++++++++++++++++++++
 .../impl/SlingHttpServletResponseImplTest.java     | 38 ++++++++++++++
 2 files changed, 96 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 5ed609b..9784007 100644
--- 
a/src/main/java/org/apache/sling/engine/impl/SlingJakartaHttpServletResponseImpl.java
+++ 
b/src/main/java/org/apache/sling/engine/impl/SlingJakartaHttpServletResponseImpl.java
@@ -28,7 +28,9 @@ import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Optional;
+import java.util.function.Supplier;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
@@ -297,6 +299,62 @@ public class SlingJakartaHttpServletResponseImpl extends 
HttpServletResponseWrap
         }
     }
 
+    /**
+     * Overridden to apply the same include protection as
+     * {@link #sendRedirect(String)}. Since Servlet API 6.1
+     * {@code HttpServletResponseWrapper} overrides every {@code sendRedirect}
+     * variant with a direct delegation to the wrapped response, so each new
+     * overload must be gated here explicitly - none of them dispatches
+     * through another override on this wrapper.
+     */
+    @Override
+    public void sendRedirect(final String location, final int sc) throws 
IOException {
+        if (!this.isProtectHeadersOnInclude()) {
+            logHeaderModificationCallOnIncludeForMethod("sendRedirect()");
+            this.committedReason = CommitReason.SEND_REDIRECT;
+            super.sendRedirect(location, sc);
+        }
+    }
+
+    /**
+     * Overridden to apply the same include protection as
+     * {@link #sendRedirect(String)}, see {@link #sendRedirect(String, int)}.
+     */
+    @Override
+    public void sendRedirect(final String location, final boolean clearBuffer) 
throws IOException {
+        if (!this.isProtectHeadersOnInclude()) {
+            logHeaderModificationCallOnIncludeForMethod("sendRedirect()");
+            this.committedReason = CommitReason.SEND_REDIRECT;
+            super.sendRedirect(location, clearBuffer);
+        }
+    }
+
+    /**
+     * Overridden to apply the same include protection as
+     * {@link #sendRedirect(String)}, see {@link #sendRedirect(String, int)}.
+     */
+    @Override
+    public void sendRedirect(final String location, final int sc, final 
boolean clearBuffer) throws IOException {
+        if (!this.isProtectHeadersOnInclude()) {
+            logHeaderModificationCallOnIncludeForMethod("sendRedirect()");
+            this.committedReason = CommitReason.SEND_REDIRECT;
+            super.sendRedirect(location, sc, clearBuffer);
+        }
+    }
+
+    /**
+     * Overridden to apply the include header protection: response trailer
+     * fields are headers as well and must not be settable by included
+     * servlets when header protection is enabled.
+     */
+    @Override
+    public void setTrailerFields(final Supplier<Map<String, String>> supplier) 
{
+        if (!this.isProtectHeadersOnInclude()) {
+            logHeaderModificationCallOnIncludeForMethod("setTrailerFields()");
+            super.setTrailerFields(supplier);
+        }
+    }
+
     @Override
     public void setDateHeader(final String name, final long value) {
         if (!this.isProtectHeadersOnInclude()) {
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 fd658f5..06c845b 100644
--- 
a/src/test/java/org/apache/sling/engine/impl/SlingHttpServletResponseImplTest.java
+++ 
b/src/test/java/org/apache/sling/engine/impl/SlingHttpServletResponseImplTest.java
@@ -141,6 +141,44 @@ public class SlingHttpServletResponseImplTest {
         Mockito.verify(spyInclude, 
never()).checkContentTypeOverride(Mockito.any());
     }
 
+    @Test
+    public void testSendRedirectOverloadsProtectedOnInclude() throws 
IOException {
+        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);
+        info.setProtectHeadersOnInclude(true);
+
+        final HttpServletResponse include = new 
SlingJakartaHttpServletResponseImpl(requestData, orig);
+
+        include.sendRedirect("/target");
+        include.sendRedirect("/target", 
HttpServletResponse.SC_MOVED_PERMANENTLY);
+        include.sendRedirect("/target", false);
+        include.sendRedirect("/target", 
HttpServletResponse.SC_MOVED_PERMANENTLY, false);
+        include.setTrailerFields(java.util.Collections::emptyMap);
+
+        Mockito.verifyNoInteractions(orig);
+    }
+
+    @Test
+    public void testSendRedirectOverloadsDelegateWhenNotProtected() throws 
IOException {
+        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));
+
+        final HttpServletResponse include = new 
SlingJakartaHttpServletResponseImpl(requestData, orig);
+
+        include.sendRedirect("/target", 
HttpServletResponse.SC_MOVED_PERMANENTLY);
+        include.sendRedirect("/target", true);
+        include.sendRedirect("/target", 
HttpServletResponse.SC_MOVED_PERMANENTLY, false);
+
+        Mockito.verify(orig, times(1)).sendRedirect("/target", 
HttpServletResponse.SC_MOVED_PERMANENTLY);
+        Mockito.verify(orig, times(1)).sendRedirect("/target", true);
+        Mockito.verify(orig, times(1)).sendRedirect("/target", 
HttpServletResponse.SC_MOVED_PERMANENTLY, false);
+    }
+
     @Test
     public void testNoViolationChecksOnCommittedResponseWhenSendError() throws 
IOException {
         final SlingJakartaHttpServletResponse orig = 
Mockito.mock(SlingJakartaHttpServletResponse.class);

Reply via email to