This is an automated email from the ASF dual-hosted git repository. joerghoh pushed a commit to branch SLING-13322 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-engine.git
commit 6f5be528c8a7ab48474831dc046a5e856a4df4bd Author: Joerg Hoh <[email protected]> AuthorDate: Wed Aug 26 18:34:34 2026 +0200 SLING-13322 warnings on non-spec compliant behavior log warnings when during an include a header-modifying operation is tried, which is not allowed by the Servlet spec. --- .../impl/SlingJakartaHttpServletResponseImpl.java | 35 ++++++++++++++++++++++ .../impl/SlingHttpServletResponseImplTest.java | 2 ++ 2 files changed, 37 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 4c197d4..b62826b 100644 --- a/src/main/java/org/apache/sling/engine/impl/SlingJakartaHttpServletResponseImpl.java +++ b/src/main/java/org/apache/sling/engine/impl/SlingJakartaHttpServletResponseImpl.java @@ -210,6 +210,7 @@ public class SlingJakartaHttpServletResponseImpl extends HttpServletResponseWrap explanation); } } else { // response is not yet committed, so the statuscode can be changed + logHeaderModificationCallOnIncludeForMethod("setStatus"); super.setStatus(sc); } } @@ -217,6 +218,9 @@ public class SlingJakartaHttpServletResponseImpl extends HttpServletResponseWrap @Override public void reset() { if (!this.isProtectHeadersOnInclude() || isError()) { + if (!this.isProtectHeadersOnInclude()) { + logHeaderModificationCallOnIncludeForMethod("reset"); + } super.reset(); } else { // ignore if not committed: because we want the exception to be thrown when the @@ -231,6 +235,7 @@ public class SlingJakartaHttpServletResponseImpl extends HttpServletResponseWrap @Override public void setContentLength(final int len) { if (!this.isProtectHeadersOnInclude()) { + logHeaderModificationCallOnIncludeForMethod("setContentLength()"); super.setContentLength(len); } } @@ -238,6 +243,7 @@ public class SlingJakartaHttpServletResponseImpl extends HttpServletResponseWrap @Override public void setContentLengthLong(final long len) { if (!this.isProtectHeadersOnInclude()) { + logHeaderModificationCallOnIncludeForMethod("setContentLengthLong()"); super.setContentLengthLong(len); } } @@ -245,6 +251,7 @@ public class SlingJakartaHttpServletResponseImpl extends HttpServletResponseWrap @Override public void setLocale(final Locale loc) { if (!this.isProtectHeadersOnInclude()) { + logHeaderModificationCallOnIncludeForMethod("setLocale()"); super.setLocale(loc); } } @@ -252,6 +259,7 @@ public class SlingJakartaHttpServletResponseImpl extends HttpServletResponseWrap @Override public void addCookie(final Cookie cookie) { if (!this.isProtectHeadersOnInclude()) { + logHeaderModificationCallOnIncludeForMethod("addCookie()"); super.addCookie(cookie); } } @@ -259,6 +267,7 @@ public class SlingJakartaHttpServletResponseImpl extends HttpServletResponseWrap @Override public void addDateHeader(final String name, final long value) { if (!this.isProtectHeadersOnInclude()) { + logHeaderModificationCallOnIncludeForMethod("addDateHeader()"); super.addDateHeader(name, value); } } @@ -266,6 +275,7 @@ public class SlingJakartaHttpServletResponseImpl extends HttpServletResponseWrap @Override public void addHeader(final String name, final String value) { if (!this.isProtectHeadersOnInclude()) { + logHeaderModificationCallOnIncludeForMethod("addHeader()"); super.addHeader(name, value); } } @@ -273,6 +283,7 @@ public class SlingJakartaHttpServletResponseImpl extends HttpServletResponseWrap @Override public void addIntHeader(final String name, final int value) { if (!this.isProtectHeadersOnInclude()) { + logHeaderModificationCallOnIncludeForMethod("addIntHeader()"); super.addIntHeader(name, value); } } @@ -280,6 +291,7 @@ public class SlingJakartaHttpServletResponseImpl extends HttpServletResponseWrap @Override public void sendRedirect(final String location) throws IOException { if (!this.isProtectHeadersOnInclude()) { + logHeaderModificationCallOnIncludeForMethod("sendRedirect"); this.committedReason = CommitReason.SEND_REDIRECT; super.sendRedirect(location); } @@ -288,6 +300,7 @@ public class SlingJakartaHttpServletResponseImpl extends HttpServletResponseWrap @Override public void setDateHeader(final String name, final long value) { if (!this.isProtectHeadersOnInclude()) { + logHeaderModificationCallOnIncludeForMethod("setDateHeader()"); super.setDateHeader(name, value); } } @@ -295,6 +308,7 @@ public class SlingJakartaHttpServletResponseImpl extends HttpServletResponseWrap @Override public void setHeader(final String name, final String value) { if (!this.isProtectHeadersOnInclude()) { + logHeaderModificationCallOnIncludeForMethod("setHeader()"); super.setHeader(name, value); } } @@ -302,6 +316,7 @@ public class SlingJakartaHttpServletResponseImpl extends HttpServletResponseWrap @Override public void setIntHeader(final String name, final int value) { if (!this.isProtectHeadersOnInclude()) { + logHeaderModificationCallOnIncludeForMethod("setIntHeader()"); super.setIntHeader(name, value); } } @@ -492,6 +507,25 @@ public class SlingJakartaHttpServletResponseImpl extends HttpServletResponseWrap allMessages); } + /** + * log a message for calling a header-modifying API when called as part of an include + * @param method the name of the method + */ + private void logHeaderModificationCallOnIncludeForMethod(String method) { + if (isInclude()) { + String msg = String.format( + "Calling '%s' within an include is not compliant to the Servlet spec (see SLING-13222)", method); + requestData.getRequestProgressTracker().log("WARN:" + msg); + if (!LOG.isDebugEnabled()) { + String s = String.format("%s; enable DEBUG logging to get the full stacktrace", msg); + // we log on WARN level intentionally, so the log message is symmetric to the one below + LOG.warn(s); + } else { + LOG.warn(msg + "; call trace: " + getCurrentStackTrace()); + } + } + } + private static class ContentTypeChangeException extends SlingException { protected ContentTypeChangeException(String text) { super(text); @@ -510,6 +544,7 @@ public class SlingJakartaHttpServletResponseImpl extends HttpServletResponseWrap @Override public void sendError(int status, String message) throws IOException { if (!this.isProtectHeadersOnInclude()) { + logHeaderModificationCallOnIncludeForMethod("setError()"); checkCommitted(); this.committedReason = CommitReason.SEND_ERROR; 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 88845c7..b14bc5b 100644 --- a/src/test/java/org/apache/sling/engine/impl/SlingHttpServletResponseImplTest.java +++ b/src/test/java/org/apache/sling/engine/impl/SlingHttpServletResponseImplTest.java @@ -94,6 +94,7 @@ public class SlingHttpServletResponseImplTest { 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 SlingJakartaHttpServletResponseImpl include = new SlingJakartaHttpServletResponseImpl(requestData, orig); SlingJakartaHttpServletResponseImpl spyInclude = Mockito.spy(include); @@ -113,6 +114,7 @@ public class SlingHttpServletResponseImplTest { final DispatchingInfo info = new DispatchingInfo(DispatcherType.INCLUDE); when(requestData.getDispatchingInfo()).thenReturn(info); when(requestData.getSlingRequestProcessor()).thenReturn(mock(SlingRequestProcessorImpl.class)); + when(requestData.getRequestProgressTracker()).thenReturn(mock(RequestProgressTracker.class)); final SlingJakartaHttpServletResponseImpl include = new SlingJakartaHttpServletResponseImpl(requestData, orig); SlingJakartaHttpServletResponseImpl spyInclude = Mockito.spy(include);
