This is an automated email from the ASF dual-hosted git repository. cziegeler pushed a commit to branch sling-13421-header-only-media-ranges in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-api.git
commit d7609ee823f86e4589c9a108904093e48ea23c5c Author: Carsten Ziegeler <[email protected]> AuthorDate: Wed Nov 11 13:08:03 2026 +0100 SLING-13421 Add header-only Jakarta media range parsing Co-authored-by: Copilot <[email protected]> --- .../api/request/header/JakartaMediaRangeList.java | 40 ++++++++++++++++++++++ .../sling/api/request/header/package-info.java | 2 +- .../request/header/JakartaMediaRangeListTest.java | 31 +++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/apache/sling/api/request/header/JakartaMediaRangeList.java b/src/main/java/org/apache/sling/api/request/header/JakartaMediaRangeList.java index bc7bf5d..3b6dbe6 100644 --- a/src/main/java/org/apache/sling/api/request/header/JakartaMediaRangeList.java +++ b/src/main/java/org/apache/sling/api/request/header/JakartaMediaRangeList.java @@ -25,6 +25,7 @@ import java.util.Set; import java.util.TreeSet; import jakarta.servlet.http.HttpServletRequest; +import org.jetbrains.annotations.NotNull; import org.osgi.annotation.versioning.ConsumerType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,13 +38,40 @@ import org.slf4j.LoggerFactory; @ConsumerType public class JakartaMediaRangeList extends TreeSet<JakartaMediaRangeList.MediaRange> { + /** + * The HTTP header name for the Accept header. + */ public static final String HEADER_ACCEPT = "Accept"; + + /** + * The request parameter name for the Accept header override. + * @deprecated Use {@link #HEADER_ACCEPT} instead. + */ + @Deprecated public static final String PARAM_ACCEPT = ":http-equiv-accept"; + + /** + * The wildcard character for media ranges. + */ public static final String WILDCARD = "*"; + boolean matchesAll = false; private static final Logger log = LoggerFactory.getLogger(JakartaMediaRangeList.class); + /** + * Creates a <code>MediaRangeList</code> from the {@link #HEADER_ACCEPT} header of the supplied request. + * Request parameters, including {@link #PARAM_ACCEPT}, are ignored. + * If the header is missing or empty, the client is assumed to accept all media types. + * + * @param request The request to read the Accept header from + * @return The media ranges accepted by the client + * @since 1.2.0 + */ + public static @NotNull JakartaMediaRangeList fromRequest(@NotNull HttpServletRequest request) { + return new JakartaMediaRangeList(request.getHeader(HEADER_ACCEPT)); + } + /** * Constructs a <code>MediaRangeList</code> using information from the supplied <code>HttpServletRequest</code>. * if the request contains a {@link #PARAM_ACCEPT} query parameter, the query parameter value overrides any @@ -52,7 +80,10 @@ public class JakartaMediaRangeList extends TreeSet<JakartaMediaRangeList.MediaRa * {@link #HEADER_ACCEPT} is used. If both values are missing, it is assumed that the client accepts all media types, * as per the RFC. See also {@link #JakartaMediaRangeList(java.lang.String)} * @param request The <code>HttpServletRequest</code> to extract a <code>MediaRangeList</code> from + * @deprecated Use {@link #fromRequest(HttpServletRequest)} to read only the Accept header without + * allowing request parameters to override it. */ + @Deprecated public JakartaMediaRangeList(HttpServletRequest request) { String queryParam = request.getParameter(PARAM_ACCEPT); if (queryParam != null && queryParam.trim().length() != 0) { @@ -106,6 +137,15 @@ public class JakartaMediaRangeList extends TreeSet<JakartaMediaRangeList.MediaRa } } + /** + * Whether this <code>MediaRangeList</code> matches all media types. + * @return <code>true</code> if this <code>MediaRangeList</code> matches all media types, <code>false</code> otherwise + * @since 1.2.0 + */ + public boolean matchesAll() { + return this.matchesAll; + } + /** * Determines if this MediaRangeList contains a given media type. * @param mediaType A string on the form <code>type/subtype</code>. Neither <code>type</code> diff --git a/src/main/java/org/apache/sling/api/request/header/package-info.java b/src/main/java/org/apache/sling/api/request/header/package-info.java index a7085e2..09b8624 100644 --- a/src/main/java/org/apache/sling/api/request/header/package-info.java +++ b/src/main/java/org/apache/sling/api/request/header/package-info.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -@Version("1.1.0") +@Version("1.2.0") package org.apache.sling.api.request.header; import org.osgi.annotation.versioning.Version; diff --git a/src/test/java/org/apache/sling/api/request/header/JakartaMediaRangeListTest.java b/src/test/java/org/apache/sling/api/request/header/JakartaMediaRangeListTest.java index c30034f..954d67d 100644 --- a/src/test/java/org/apache/sling/api/request/header/JakartaMediaRangeListTest.java +++ b/src/test/java/org/apache/sling/api/request/header/JakartaMediaRangeListTest.java @@ -22,6 +22,7 @@ import junit.framework.TestCase; import org.apache.sling.api.SlingJakartaHttpServletRequest; import org.mockito.Mockito; +@SuppressWarnings("deprecation") public class JakartaMediaRangeListTest extends TestCase { protected JakartaMediaRangeList rangeList; @@ -55,6 +56,36 @@ public class JakartaMediaRangeListTest extends TestCase { assertFalse("Contained media type from overridden Accept header", rangeList.contains("text/plain")); } + public void testFromRequestIgnoresHttpEquivParam() { + SlingJakartaHttpServletRequest req = Mockito.mock(SlingJakartaHttpServletRequest.class); + Mockito.when(req.getHeader(JakartaMediaRangeList.HEADER_ACCEPT)) + .thenReturn("text/plain;q=0.8, application/json"); + Mockito.when(req.getParameter(JakartaMediaRangeList.PARAM_ACCEPT)).thenReturn("text/html"); + + JakartaMediaRangeList rangeList = JakartaMediaRangeList.fromRequest(req); + + assertEquals("text/plain", rangeList.prefer("text/plain")); + assertTrue(rangeList.contains("application/json")); + assertFalse(rangeList.contains("text/html")); + assertEquals("application/json", rangeList.prefer("text/plain", "application/json")); + Mockito.verify(req, Mockito.never()).getParameter(Mockito.anyString()); + } + + public void testFromRequestWithoutAcceptHeader() { + for (String header : new String[] {null, "", " "}) { + SlingJakartaHttpServletRequest req = Mockito.mock(SlingJakartaHttpServletRequest.class); + Mockito.when(req.getHeader(JakartaMediaRangeList.HEADER_ACCEPT)).thenReturn(header); + Mockito.when(req.getParameter(JakartaMediaRangeList.PARAM_ACCEPT)).thenReturn("text/html"); + + JakartaMediaRangeList rangeList = JakartaMediaRangeList.fromRequest(req); + + assertEquals(1, rangeList.size()); + assertTrue(rangeList.contains("text/plain")); + assertTrue(rangeList.contains("application/json")); + Mockito.verify(req, Mockito.never()).getParameter(Mockito.anyString()); + } + } + public void testInvalidJdkAcceptHeader() { // This header is sent by Java client which make use of URLConnection on Oracle JDK // See acceptHeader at
