This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 10.1.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/10.1.x by this push: new 012ec1f085 fix: MUST ignore Range header field if method is out-of-range-support 012ec1f085 is described below commit 012ec1f085e1940cc04a4f22a68bd64cd0142029 Author: Chenjp <ch...@msn.com> AuthorDate: Sat Nov 30 00:38:39 2024 +0800 fix: MUST ignore Range header field if method is out-of-range-support per RFC 9110 - Section 14, currently GET is the only method. --- .../apache/catalina/servlets/DefaultServlet.java | 8 +- .../TestDefaultServletRfc9110Section14.java | 104 +++++++++++++++++++++ webapps/docs/changelog.xml | 5 + 3 files changed, 114 insertions(+), 3 deletions(-) diff --git a/java/org/apache/catalina/servlets/DefaultServlet.java b/java/org/apache/catalina/servlets/DefaultServlet.java index a1decc334b..95633e7bc4 100644 --- a/java/org/apache/catalina/servlets/DefaultServlet.java +++ b/java/org/apache/catalina/servlets/DefaultServlet.java @@ -1454,9 +1454,11 @@ public class DefaultServlet extends HttpServlet { protected Ranges parseRange(HttpServletRequest request, HttpServletResponse response, WebResource resource) throws IOException { - // Range headers are only valid on GET requests. That implies they are - // also valid on HEAD requests. This method is only called by doGet() - // and doHead() so no need to check the request method. + if (!"GET".equals(request.getMethod())) { + // RFC 9110 - Section 14.2: GET is the only method for which range handling is defined. + // Otherwise MUST ignore a Range header field + return FULL; + } // Checking If-Range String headerValue = request.getHeader("If-Range"); diff --git a/test/org/apache/catalina/servlets/TestDefaultServletRfc9110Section14.java b/test/org/apache/catalina/servlets/TestDefaultServletRfc9110Section14.java new file mode 100644 index 0000000000..b6f996fe80 --- /dev/null +++ b/test/org/apache/catalina/servlets/TestDefaultServletRfc9110Section14.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.servlets; + +import java.io.File; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import jakarta.servlet.http.HttpServletResponse; + +import org.junit.Assert; +import org.junit.Test; + +import org.apache.catalina.Context; +import org.apache.catalina.Wrapper; +import org.apache.catalina.startup.Tomcat; +import org.apache.catalina.startup.TomcatBaseTest; +import org.apache.tomcat.util.buf.ByteChunk; + +public class TestDefaultServletRfc9110Section14 extends TomcatBaseTest { + + @Test + public void testRangeHandlingDefinedMethods() throws Exception { + // GET is the only method for which range handling is defined. + + Tomcat tomcat = getTomcatInstance(); + + File appDir = new File("test/webapp"); + Context ctxt = tomcat.addContext("", appDir.getAbsolutePath()); + + Wrapper w = Tomcat.addServlet(ctxt, "default", DefaultServlet.class.getName()); + w.addInitParameter("useAcceptRanges", "true"); + ctxt.addServletMappingDecoded("/", "default"); + + tomcat.start(); + + String path = "http://localhost:" + getPort() + "/index.html"; + ByteChunk responseBody = new ByteChunk(); + Map<String,List<String>> responseHeaders = new HashMap<>(); + Map<String,List<String>> requestHeaders = new HashMap<>(); + + String rangeHeader = "bytes=0-10"; + // Get and Head + + requestHeaders.computeIfAbsent("Range", (k) -> List.of(rangeHeader)); + int rc = getUrl(path, responseBody, requestHeaders, responseHeaders); + Assert.assertEquals("Range requests is turn on, SC_PARTIAL_CONTENT of GET is expected", + HttpServletResponse.SC_PARTIAL_CONTENT, rc); + Assert.assertTrue("Range requests is turn on, header `Accept-Ranges: bytes` is expected", + responseHeaders.containsKey("Accept-Ranges") && responseHeaders.get("Accept-Ranges").contains("bytes")); + + rc = methodUrl(path, responseBody, DEFAULT_CLIENT_TIMEOUT_MS, requestHeaders, responseHeaders, "HEAD"); + Assert.assertEquals("Range requests is turn on, SC_OK of HEAD is expected", HttpServletResponse.SC_OK, rc); + Assert.assertTrue("Range requests is turn on, header `Accept-Ranges: bytes` is expected", + responseHeaders.containsKey("Accept-Ranges") && responseHeaders.get("Accept-Ranges").contains("bytes")); + + tomcat.stop(); + } + + @Test + public void testUnsupportedRangeUnit() throws Exception { + Tomcat tomcat = getTomcatInstance(); + + File appDir = new File("test/webapp"); + Context ctxt = tomcat.addContext("", appDir.getAbsolutePath()); + + Wrapper w = Tomcat.addServlet(ctxt, "default", DefaultServlet.class.getName()); + w.addInitParameter("useAcceptRanges", "true"); + ctxt.addServletMappingDecoded("/", "default"); + + tomcat.start(); + + String path = "http://localhost:" + getPort() + "/index.html"; + ByteChunk responseBody = new ByteChunk(); + Map<String,List<String>> responseHeaders = new HashMap<>(); + Map<String,List<String>> requestHeaders = new HashMap<>(); + + String rangeHeader = "Chars=0-10"; + // Get and Head + + requestHeaders.computeIfAbsent("Range", (k) -> List.of(rangeHeader)); + int rc = getUrl(path, responseBody, requestHeaders, responseHeaders); + Assert.assertEquals( + "RFC 9110 - 14.2: An origin server MUST ignore a Range header field that contains a range unit it does not understand. `Chars` is not a understandable RangeUnit, SC_OK is expected", + HttpServletResponse.SC_OK, rc); + + tomcat.stop(); + } +} diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index ed3ac5b2b6..bd81c9b236 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -212,6 +212,11 @@ to optionally avoid the <code>comp/env</code> prefix which is usually not used there. (remm) </fix> + <fix> + As required by RFC 9110, the HTTP <code>Range</code> header will now + only be processed for <code>GET</code> requests. Based on pull request + <pr>790</pr> provided by Chenjp. (markt) + </fix> </changelog> </subsection> <subsection name="Coyote"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org