This is an automated email from the ASF dual-hosted git repository. remm 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 a17e3c056d Return 400 for content and range mismatch a17e3c056d is described below commit a17e3c056db314f57b5108a0a401c2c59446d2bf Author: remm <r...@apache.org> AuthorDate: Wed Mar 5 11:31:02 2025 +0100 Return 400 for content and range mismatch Still hacked together since the existing DefaultServlet executePartialPut method signature is not appropriate. As suggested in PR#810. --- .../apache/catalina/servlets/DefaultServlet.java | 21 +++++++++++++++++---- .../catalina/servlets/LocalStrings.properties | 1 + .../catalina/servlets/TestDefaultServletPut.java | 5 +++++ webapps/docs/changelog.xml | 8 ++++++++ 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/java/org/apache/catalina/servlets/DefaultServlet.java b/java/org/apache/catalina/servlets/DefaultServlet.java index 7523158add..c2f333a384 100644 --- a/java/org/apache/catalina/servlets/DefaultServlet.java +++ b/java/org/apache/catalina/servlets/DefaultServlet.java @@ -635,10 +635,12 @@ public class DefaultServlet extends HttpServlet { resourceInputStream = req.getInputStream(); } else { tempContentFile = executePartialPut(req, range, path); - resourceInputStream = new FileInputStream(tempContentFile); + if (tempContentFile != null) { + resourceInputStream = new FileInputStream(tempContentFile); + } } - if (resources.write(path, resourceInputStream, true)) { + if (resourceInputStream != null && resources.write(path, resourceInputStream, true)) { if (resource.exists()) { resp.setStatus(HttpServletResponse.SC_NO_CONTENT); } else { @@ -646,7 +648,8 @@ public class DefaultServlet extends HttpServlet { } } else { try { - resp.sendError(HttpServletResponse.SC_CONFLICT); + resp.sendError(resourceInputStream != null ? + HttpServletResponse.SC_CONFLICT : HttpServletResponse.SC_BAD_REQUEST); } catch (IllegalStateException e) { // Already committed, ignore } @@ -710,12 +713,22 @@ public class DefaultServlet extends HttpServlet { // Append data in request input stream to contentFile randAccessContentFile.seek(range.getStart()); + long received = 0; int numBytesRead; byte[] transferBuffer = new byte[BUFFER_SIZE]; try (BufferedInputStream requestBufInStream = new BufferedInputStream(req.getInputStream(), BUFFER_SIZE)) { while ((numBytesRead = requestBufInStream.read(transferBuffer)) != -1) { + received += numBytesRead; + if (received > range.getEnd() - range.getStart()) { + throw new IllegalStateException(sm.getString("defaultServlet.wrongByteCountForRange", + String.valueOf(received), String.valueOf(range.getEnd() - range.getStart()))); + } randAccessContentFile.write(transferBuffer, 0, numBytesRead); } + if (received < range.getEnd() - range.getStart()) { + throw new IllegalStateException(sm.getString("defaultServlet.wrongByteCountForRange", + String.valueOf(received), String.valueOf(range.getEnd() - range.getStart()))); + } } } catch (IOException | RuntimeException | Error e) { @@ -723,7 +736,7 @@ public class DefaultServlet extends HttpServlet { if (!contentFile.delete()) { log(sm.getString("defaultServlet.deleteTempFileFailed", contentFile.getAbsolutePath())); } - throw e; + return null; } return contentFile; diff --git a/java/org/apache/catalina/servlets/LocalStrings.properties b/java/org/apache/catalina/servlets/LocalStrings.properties index d2e6a16c33..5a3158afd3 100644 --- a/java/org/apache/catalina/servlets/LocalStrings.properties +++ b/java/org/apache/catalina/servlets/LocalStrings.properties @@ -54,6 +54,7 @@ defaultServlet.resource.name=Name defaultServlet.resource.size=Size defaultServlet.skipfail=Read failed because only [{0}] bytes were available but needed to skip [{1}] bytes to reach the start of the requested range defaultServlet.unknownBomConfig=Unrecognised value of [{0}] provided for useBomIfPresent initialization parameter +defaultServlet.wrongByteCountForRange=An invalid amount [{0}] of bytes were received for range with length [{1}] defaultServlet.xslError=XSL transformer error webdavservlet.dataSourceStore.error=Error processing [{0}] on dead properties for path [{1}] diff --git a/test/org/apache/catalina/servlets/TestDefaultServletPut.java b/test/org/apache/catalina/servlets/TestDefaultServletPut.java index d19b95684d..55a04b79d6 100644 --- a/test/org/apache/catalina/servlets/TestDefaultServletPut.java +++ b/test/org/apache/catalina/servlets/TestDefaultServletPut.java @@ -86,6 +86,11 @@ public class TestDefaultServletPut extends TomcatBaseTest { // Valid partial PUT but partial PUT is disabled parameterSets.add(new Object[] { "Content-Range: bytes 0-" + PATCH_LEN + "/" + START_LEN + CRLF, Boolean.TRUE, START_TEXT, Boolean.FALSE }); + // Errors due to incorrect length + parameterSets.add(new Object[] { + "Content-Range: bytes 0-1/" + PATCH_LEN + CRLF, Boolean.FALSE, START_TEXT, Boolean.TRUE }); + parameterSets.add(new Object[] { + "Content-Range: bytes 0-19/20" + CRLF, Boolean.FALSE, START_TEXT, Boolean.TRUE }); return parameterSets; } diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 9d1606b2ef..44a7ac5a90 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -105,6 +105,14 @@ issues do not "pop up" wrt. others). --> <section name="Tomcat 10.1.40 (schultz)" rtext="in development"> + <subsection name="Catalina"> + <changelog> + <fix> + Return 400 if the amount of content sent for a partial PUT is + inconsistent with the range that was specified. (remm) + </fix> + </changelog> + </subsection> </section> <section name="Tomcat 10.1.39 (schultz)" rtext="release in progress"> </section> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org