This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch 11.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 7774a01d9ccaf1d3d45b6061c5c9490403427801 Author: opencode <[email protected]> AuthorDate: Wed Oct 7 16:48:49 2026 +0200 Ignore malformed Accept-Encoding q-values in DefaultServlet precompressed handling Double.parseDouble() of the q-value in getBestPrecompressedResource() was unprotected, so a client header such as Accept-Encoding: br;q=abc triggered a NumberFormatException and the request failed with a 500 whenever a precompressed variant of the requested resource existed. Skip a preference with an unparsable q-value instead, consistent with treating it as not expressed. --- .../apache/catalina/servlets/DefaultServlet.java | 7 ++- .../catalina/servlets/TestDefaultServlet.java | 65 ++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/java/org/apache/catalina/servlets/DefaultServlet.java b/java/org/apache/catalina/servlets/DefaultServlet.java index 4e9b38b7bc..5a30cf9514 100644 --- a/java/org/apache/catalina/servlets/DefaultServlet.java +++ b/java/org/apache/catalina/servlets/DefaultServlet.java @@ -1502,7 +1502,12 @@ public class DefaultServlet extends HttpServlet { if (equalsIdx == -1) { continue; } - quality = Double.parseDouble(preference.substring(equalsIdx + 1).trim()); + try { + quality = Double.parseDouble(preference.substring(equalsIdx + 1).trim()); + } catch (NumberFormatException nfe) { + // Invalid q-value: ignore this preference + continue; + } } if (quality >= bestResourceQuality) { String encoding = preference; diff --git a/test/org/apache/catalina/servlets/TestDefaultServlet.java b/test/org/apache/catalina/servlets/TestDefaultServlet.java index 6f9701ce1b..8bc83645b8 100644 --- a/test/org/apache/catalina/servlets/TestDefaultServlet.java +++ b/test/org/apache/catalina/servlets/TestDefaultServlet.java @@ -381,6 +381,71 @@ public class TestDefaultServlet extends TomcatBaseTest { Assert.assertTrue(responseHeaders.contains("vary: accept-encoding")); } + /* + * Verify that a malformed q-value in Accept-Encoding does not fail the + * request and only causes the affected preference to be ignored. + */ + @Test + public void testMalformedPrecompressedQValue() throws Exception { + + Tomcat tomcat = getTomcatInstance(); + + File appDir = new File("test/webapp"); + + long gzSize = new File(appDir, "index.html.gz").length(); + long indexSize = new File(appDir, "index.html").length(); + + // app dir is relative to server home + Context ctxt = tomcat.addContext("", appDir.getAbsolutePath()); + Wrapper defaultServlet = Tomcat.addServlet(ctxt, "default", + DefaultServlet.class.getName()); + defaultServlet.addInitParameter("precompressed", "br=.br,gzip=.gz"); + defaultServlet.addInitParameter("fileEncoding", "ISO-8859-1"); + + ctxt.addServletMapping("/", "default"); + ctxt.addMimeMapping("html", "text/html"); + + tomcat.start(); + + TestCompressedClient client = new TestCompressedClient(getPort()); + + client.reset(); + // @formatter:off + client.setRequest(new String[] { + "GET /index.html HTTP/1.1" + CRLF + + "Host: localhost" + CRLF + + "Connection: Close" + CRLF + + "Accept-Encoding: br;q=abc" + CRLF + + CRLF + }); + // @formatter:on + client.connect(); + client.processRequest(); + Assert.assertTrue(client.isResponse200()); + List<String> responseHeaders = client.getResponseHeaders(); + Assert.assertFalse(responseHeaders.contains("Content-Encoding")); + Assert.assertTrue(responseHeaders.contains("Content-Length: " + indexSize)); + Assert.assertTrue(responseHeaders.contains("vary: accept-encoding")); + + client.reset(); + // @formatter:off + client.setRequest(new String[] { + "GET /index.html HTTP/1.1" + CRLF + + "Host: localhost" + CRLF + + "Connection: Close" + CRLF + + "Accept-Encoding: br;q=abc,gzip" + CRLF + + CRLF + }); + // @formatter:on + client.connect(); + client.processRequest(); + Assert.assertTrue(client.isResponse200()); + responseHeaders = client.getResponseHeaders(); + Assert.assertTrue(responseHeaders.contains("Content-Encoding: gzip")); + Assert.assertTrue(responseHeaders.contains("Content-Length: " + gzSize)); + Assert.assertTrue(responseHeaders.contains("vary: accept-encoding")); + } + /* * Verify preferring of brotli in default configuration for actual Firefox and Chrome requests. */ --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
