diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/multipart/MultipartOptionalInputTest.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/multipart/MultipartOptionalInputTest.java new file mode 100644 index 00000000000000..291e39433fee28 --- /dev/null +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/multipart/MultipartOptionalInputTest.java @@ -0,0 +1,78 @@ +package io.quarkus.resteasy.reactive.server.test.multipart; + +import static org.hamcrest.CoreMatchers.equalTo; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.function.Supplier; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.resteasy.reactive.server.test.multipart.other.OtherPackageFormDataBase; +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class MultipartOptionalInputTest extends AbstractMultipartTest { + + private static final Path uploadDir = Paths.get("file-uploads"); + + @RegisterExtension + static QuarkusUnitTest test = new QuarkusUnitTest() + .setArchiveProducer(new Supplier() { + @Override + public JavaArchive get() { + return ShrinkWrap.create(JavaArchive.class) + .addClasses(FormDataBase.class, OtherPackageFormDataBase.class, FormData.class, Status.class, + OtherFormData.class, FormDataSameFileName.class, + OtherFormDataBase.class, + MultipartResource.class, OtherMultipartResource.class) + .addAsResource(new StringAsset( + // keep the files around so we can assert the outcome + "quarkus.http.body.delete-uploaded-files-on-end=false\nquarkus.http.body.uploads-directory=" + + uploadDir.toString() + "\n"), + "application.properties"); + } + + }); + + private final File HTML_FILE = new File("./src/test/resources/test.html"); + + @BeforeEach + public void assertEmptyUploads() { + Assertions.assertTrue(isDirectoryEmpty(uploadDir)); + } + + @AfterEach + public void clearDirectory() { + clearDirectory(uploadDir); + } + + @Test + public void testUploadWithSomeFilesMissing() { + RestAssured.given() + .multiPart("name", "Alice") + .multiPart("active", "true") + .multiPart("num", "25") + .multiPart("status", "WORKING") + .multiPart("htmlFile", HTML_FILE, "text/html") + .accept("text/plain") + .when() + .post("/multipart/optional") + .then() + .statusCode(200) + .body(equalTo("Alice - true - 50 - WORKING - true - false - false")); + + // ensure that the 1 uploaded file was created on disk + File[] uploadedFiles = uploadDir.toFile().listFiles(); + Assertions.assertNotNull(uploadedFiles); + Assertions.assertEquals(1, uploadedFiles.length); + } +} diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/multipart/MultipartResource.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/multipart/MultipartResource.java index 904fd3cccef8a5..58edf0ceae3a72 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/multipart/MultipartResource.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/multipart/MultipartResource.java @@ -67,4 +67,18 @@ public String sameName(FormDataSameFileName formData) { + formData.xmlFiles.size(); } + @POST + @Produces(MediaType.TEXT_PLAIN) + @Consumes(MediaType.MULTIPART_FORM_DATA) + @Path("/optional") + @NonBlocking + public String optional(@MultipartForm FormData formData) { + if (BlockingOperationControl.isBlockingAllowed()) { + throw new RuntimeException("should not have dispatched"); + } + return formData.getName() + " - " + formData.active + " - " + formData.getNum() + " - " + formData.getStatus() + + " - " + (formData.getHtmlPart() != null) + " - " + (formData.xmlPart != null) + " - " + + (formData.txtFile != null); + } + } diff --git a/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/multipart/MultipartSupport.java b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/multipart/MultipartSupport.java index 6c3cd26afe4304..979fb51e18c845 100644 --- a/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/multipart/MultipartSupport.java +++ b/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/multipart/MultipartSupport.java @@ -9,6 +9,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; @@ -23,6 +24,7 @@ import org.jboss.resteasy.reactive.server.core.ServerSerialisers; import org.jboss.resteasy.reactive.server.core.multipart.DefaultFileUpload; import org.jboss.resteasy.reactive.server.core.multipart.FormData; +import org.jboss.resteasy.reactive.server.core.multipart.FormData.FormValue; import org.jboss.resteasy.reactive.server.handlers.RequestDeserializeHandler; import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyReader; @@ -98,9 +100,12 @@ public static List getFileUploads(String formName, ResteasyRe List result = new ArrayList<>(); FormData fileUploads = context.getFormData(); if (fileUploads != null) { - for (FormData.FormValue fileUpload : fileUploads.get(formName)) { - if (fileUpload.isFileItem()) { - result.add(new DefaultFileUpload(formName, fileUpload)); + Collection fileUploadsForName = fileUploads.get(formName); + if (fileUploadsForName != null) { + for (FormData.FormValue fileUpload : fileUploadsForName) { + if (fileUpload.isFileItem()) { + result.add(new DefaultFileUpload(formName, fileUpload)); + } } } }