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);
