diff --git a/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartParser.java b/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartParser.java index 0e6086221f46..e0097c036742 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartParser.java +++ b/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartParser.java @@ -540,7 +540,7 @@ else if (len < 0) { while ((prev = this.queue.pollLast()) != null) { int prevByteCount = prev.readableByteCount(); int prevLen = prevByteCount + len; - if (prevLen > 0) { + if (prevLen >= 0) { // slice body part of previous buffer, and flush it DataBuffer body = prev.split(prevLen + prev.readPosition()); DataBufferUtils.release(prev); diff --git a/spring-web/src/test/java/org/springframework/http/codec/multipart/DefaultPartHttpMessageReaderTests.java b/spring-web/src/test/java/org/springframework/http/codec/multipart/DefaultPartHttpMessageReaderTests.java index 64efd900a921..24c4af12f759 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/multipart/DefaultPartHttpMessageReaderTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/multipart/DefaultPartHttpMessageReaderTests.java @@ -301,6 +301,23 @@ void exceedHeaderLimit() throws InterruptedException { latch.await(); } + @ParameterizedDefaultPartHttpMessageReaderTest + void emptyLastPart(DefaultPartHttpMessageReader reader) throws InterruptedException { + MockServerHttpRequest request = createRequest( + new ClassPathResource("empty-part.multipart", getClass()), "LiG0chJ0k7YtLt-FzTklYFgz50i88xJCW5jD"); + + Flux result = reader.read(forClass(Part.class), request, emptyMap()); + + CountDownLatch latch = new CountDownLatch(2); + StepVerifier.create(result) + .consumeNextWith(part -> testPart(part, null, "", latch)) + .consumeNextWith(part -> testPart(part, null, "", latch)) + .verifyComplete(); + + latch.await(); + } + + private void testBrowser(DefaultPartHttpMessageReader reader, Resource resource, String boundary) throws InterruptedException { diff --git a/spring-web/src/test/resources/org/springframework/http/codec/multipart/empty-part.multipart b/spring-web/src/test/resources/org/springframework/http/codec/multipart/empty-part.multipart new file mode 100644 index 000000000000..501388b78196 --- /dev/null +++ b/spring-web/src/test/resources/org/springframework/http/codec/multipart/empty-part.multipart @@ -0,0 +1,13 @@ +--LiG0chJ0k7YtLt-FzTklYFgz50i88xJCW5jD +Content-Disposition: form-data; name="files"; filename="file17312898095703516893.tmp" +Content-Type: application/octet-stream +Content-Length: 0 + + +--LiG0chJ0k7YtLt-FzTklYFgz50i88xJCW5jD +Content-Disposition: form-data; name="files"; filename="file14790463448453253614.tmp" +Content-Type: application/octet-stream +Content-Length: 0 + + +--LiG0chJ0k7YtLt-FzTklYFgz50i88xJCW5jD-- diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/function/MultipartRouterFunctionIntegrationTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/function/MultipartRouterFunctionIntegrationTests.java index f91cbf71f177..f59892ca3033 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/function/MultipartRouterFunctionIntegrationTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/function/MultipartRouterFunctionIntegrationTests.java @@ -257,13 +257,19 @@ public Mono partData(ServerRequest request) { assertThat(data).hasSize(2); List fileData = data.get(0); - assertThat(fileData).hasSize(1); + assertThat(fileData).hasSize(2); assertThat(fileData).element(0).isInstanceOf(FilePartEvent.class); FilePartEvent filePartEvent = (FilePartEvent) fileData.get(0); assertThat(filePartEvent.name()).isEqualTo("fooPart"); assertThat(filePartEvent.filename()).isEqualTo("foo.txt"); DataBufferUtils.release(filePartEvent.content()); + assertThat(fileData).element(1).isInstanceOf(FilePartEvent.class); + filePartEvent = (FilePartEvent) fileData.get(1); + assertThat(filePartEvent.name()).isEqualTo("fooPart"); + assertThat(filePartEvent.filename()).isEqualTo("foo.txt"); + DataBufferUtils.release(filePartEvent.content()); + List fieldData = data.get(1); assertThat(fieldData).hasSize(1); assertThat(fieldData).element(0).isInstanceOf(FormPartEvent.class);