This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/main by this push: new dc53d09311 RFC 9110 - units in range specifiers are case insensitive dc53d09311 is described below commit dc53d093118bc020f8fcbc73e5350cf37e0063ae Author: Mark Thomas <ma...@apache.org> AuthorDate: Tue Aug 2 10:02:26 2022 +0100 RFC 9110 - units in range specifiers are case insensitive Added test cases for: - case insensitivity - expanding code coverage for Ranges class to 100% Expanded code coverage identified several optimisations - exit earlier when required syntax is not present - remove check make unnecessary by earlier exits --- .../org/apache/tomcat/util/http/parser/Ranges.java | 13 +- .../apache/tomcat/util/http/parser/TestRanges.java | 138 +++++++++++++++++++++ webapps/docs/changelog.xml | 4 + 3 files changed, 147 insertions(+), 8 deletions(-) diff --git a/java/org/apache/tomcat/util/http/parser/Ranges.java b/java/org/apache/tomcat/util/http/parser/Ranges.java index 15bdbbf4bf..eadbc56a2a 100644 --- a/java/org/apache/tomcat/util/http/parser/Ranges.java +++ b/java/org/apache/tomcat/util/http/parser/Ranges.java @@ -21,6 +21,7 @@ import java.io.StringReader; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Locale; public class Ranges { @@ -29,7 +30,8 @@ public class Ranges { public Ranges(String units, List<Entry> entries) { - this.units = units; + // Units are lower case (RFC 9110, section 14.1) + this.units = units.toLowerCase(Locale.ENGLISH); this.entries = Collections.unmodifiableList(entries); } @@ -84,7 +86,7 @@ public class Ranges { } // Must be followed by '=' - if (HttpParser.skipConstant(input, "=") == SkipResult.NOT_FOUND) { + if (HttpParser.skipConstant(input, "=") != SkipResult.FOUND) { return null; } @@ -95,7 +97,7 @@ public class Ranges { do { long start = HttpParser.readLong(input); // Must be followed by '-' - if (HttpParser.skipConstant(input, "-") == SkipResult.NOT_FOUND) { + if (HttpParser.skipConstant(input, "-") != SkipResult.FOUND) { return null; } long end = HttpParser.readLong(input); @@ -114,11 +116,6 @@ public class Ranges { } } while (skipResult == SkipResult.FOUND); - // There must be at least one entry - if (entries.size() == 0) { - return null; - } - return new Ranges(units, entries); } } diff --git a/test/org/apache/tomcat/util/http/parser/TestRanges.java b/test/org/apache/tomcat/util/http/parser/TestRanges.java new file mode 100644 index 0000000000..7de9dba29b --- /dev/null +++ b/test/org/apache/tomcat/util/http/parser/TestRanges.java @@ -0,0 +1,138 @@ +/* + * 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.tomcat.util.http.parser; + +import java.io.IOException; +import java.io.StringReader; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + +import org.apache.tomcat.util.http.parser.Ranges.Entry; + +public class TestRanges { + + @Test + public void testCaseInsensitive() throws Exception { + Ranges lower = parse("bytes=1-10"); + Ranges upper = parse("Bytes=1-10"); + + compareRanges(lower, upper); + } + + + @Test + public void testInvalid01() throws Exception { + doTestInvalid(""); + } + + + @Test + public void testInvalid02() throws Exception { + doTestInvalid("=1-10"); + } + + + @Test + public void testInvalid03() throws Exception { + doTestInvalid("bytes"); + } + + + @Test + public void testInvalid04() throws Exception { + doTestInvalid("bytes=1"); + } + + + @Test + public void testInvalid05() throws Exception { + doTestInvalid("bytes=-"); + } + + + @Test + public void testInvalid06() throws Exception { + doTestInvalid("bytes=1-10 a"); + } + + + @Test + public void testValid01() throws Exception { + Ranges r = parse("bytes=1-10,21-30"); + Assert.assertEquals("bytes", r.getUnits()); + List<Entry> l = r.getEntries(); + Assert.assertEquals(2, l.size()); + Entry e1 = l.get(0); + Assert.assertEquals(1, e1.getStart()); + Assert.assertEquals(10, e1.getEnd()); + Entry e2 = l.get(1); + Assert.assertEquals(21, e2.getStart()); + Assert.assertEquals(30, e2.getEnd()); + } + + + @Test + public void testValid02() throws Exception { + Ranges r = parse("bytes=-20"); + List<Entry> l = r.getEntries(); + Assert.assertEquals(1, l.size()); + Entry e1 = l.get(0); + Assert.assertEquals(-1, e1.getStart()); + Assert.assertEquals(20, e1.getEnd()); + } + + + @Test + public void testValid03() throws Exception { + Ranges r = parse("bytes=21-"); + List<Entry> l = r.getEntries(); + Assert.assertEquals(1, l.size()); + Entry e1 = l.get(0); + Assert.assertEquals(21, e1.getStart()); + Assert.assertEquals(-1, e1.getEnd()); + } + + + private void doTestInvalid(String s) throws IOException { + Ranges r = parse(s); + Assert.assertNull(r); + } + + + private Ranges parse(String s) throws IOException { + return Ranges.parse(new StringReader(s)); + } + + + private void compareRanges(Ranges r1, Ranges r2) { + Assert.assertEquals(r1.getUnits(), r2.getUnits()); + + List<Entry> l1 = r1.getEntries(); + List<Entry> l2 = r2.getEntries(); + + Assert.assertEquals(l1.size(), l2.size()); + for (int i = 0; i < l1.size(); i++) { + Entry e1 = l1.get(i); + Entry e2 = l2.get(i); + + Assert.assertEquals(e1.getStart(), e2.getStart()); + Assert.assertEquals(e1.getEnd(), e2.getEnd()); + } + } +} diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index d414f93bad..a1e0ce9e02 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -115,6 +115,10 @@ Implement the requirements of RFC 7231 and do not include sensitive headers in responses to HTTP TRACE requests. (markt) </fix> + <fix> + Implement the clarification in RFC 9110 that the units in HTTP range + specifiers are case insensitive. (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