From 59e7cdb9ebdef01cb09e1c1be3f3cef1476dc1a4 Mon Sep 17 00:00:00 2001 From: Romain Grecourt Date: Mon, 6 Feb 2023 18:08:55 -0800 Subject: [PATCH 1/6] Update BodyPart to return Optional instead of a nullable String Also add a new method isNamed to test the control name. Fixes #2833 --- .../reactive/media/multipart/BodyPart.java | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/reactive/media/multipart/src/main/java/io/helidon/reactive/media/multipart/BodyPart.java b/reactive/media/multipart/src/main/java/io/helidon/reactive/media/multipart/BodyPart.java index 605b5e4d83d..33ee88a1388 100644 --- a/reactive/media/multipart/src/main/java/io/helidon/reactive/media/multipart/BodyPart.java +++ b/reactive/media/multipart/src/main/java/io/helidon/reactive/media/multipart/BodyPart.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022 Oracle and/or its affiliates. + * Copyright (c) 2020, 2023 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,8 @@ */ package io.helidon.reactive.media.multipart; +import java.util.Optional; + import io.helidon.reactive.media.common.MessageBodyContent; /** @@ -27,33 +29,46 @@ public interface BodyPart { /** * Get the reactive representation of the part content. + * * @return {@link io.helidon.reactive.media.common.MessageBodyContent}, never {@code null} */ MessageBodyContent content(); /** * Returns HTTP part headers. + * * @return BodyPartHeaders, never {@code null} */ BodyPartHeaders headers(); + /** + * Test the control name. + * + * @param name the name to test + * @return {@code true} if the {@code name} parameter of the {@code Content-Disposition} header matches, + * {@code false} otherwise + */ + default boolean isNamed(String name) { + return name().map(name::equals).orElse(false); + } + /** * Get the control name. * * @return the {@code name} parameter of the {@code Content-Disposition} - * header, or {@code null} if not present. + * header. */ - default String name() { - return headers().contentDisposition().contentName().orElse(null); + default Optional name() { + return headers().contentDisposition().contentName(); } /** * Get the file name. * * @return the {@code filename} parameter of the {@code Content-Disposition} - * header, or {@code null} if not present. + * header. */ - default String filename() { - return headers().contentDisposition().filename().orElse(null); + default Optional filename() { + return headers().contentDisposition().filename(); } } From c33eeb4f400bb79684c9641127a454ccdfc53805 Mon Sep 17 00:00:00 2001 From: Romain Grecourt Date: Mon, 6 Feb 2023 18:36:18 -0800 Subject: [PATCH 2/6] Update multipart example --- examples/media/multipart/README.md | 2 +- .../helidon/examples/media/multipart/FileService.java | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/examples/media/multipart/README.md b/examples/media/multipart/README.md index cbe0e9fb682..206a630c045 100644 --- a/examples/media/multipart/README.md +++ b/examples/media/multipart/README.md @@ -17,7 +17,7 @@ mvn package First, start the server: ``` -java -jar target/helidon-examples-microprofile-multipart.jar +java -jar target/helidon-examples-media-multipart.jar ``` Then open in your browser. diff --git a/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/FileService.java b/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/FileService.java index cc85a0fd113..31cf1838044 100644 --- a/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/FileService.java +++ b/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/FileService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022 Oracle and/or its affiliates. + * Copyright (c) 2020, 2023 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import java.util.concurrent.ExecutorService; import io.helidon.common.configurable.ThreadPoolSupplier; +import io.helidon.common.http.BadRequestException; import io.helidon.common.http.ContentDisposition; import io.helidon.common.http.DataChunk; import io.helidon.common.http.Http; @@ -81,10 +82,12 @@ private void download(ServerRequest req, ServerResponse res) { private void upload(ServerRequest req, ServerResponse res) { req.content().asStream(ReadableBodyPart.class) .forEach(part -> { - if ("file[]".equals(part.name())) { - part.content().map(DataChunk::data) + if (part.isNamed("file[]")) { + part.content() + .map(DataChunk::data) .flatMapIterable(Arrays::asList) - .to(IoMulti.writeToFile(storage.create(part.filename())) + .to(IoMulti.writeToFile(storage.create(part.filename() + .orElseThrow(() -> new BadRequestException("Missing filename")))) .executor(executor) .build()); } else { From 207c40850fe7838dfbf701ad9e7422b7ff79d54c Mon Sep 17 00:00:00 2001 From: Romain Grecourt Date: Mon, 6 Feb 2023 18:50:43 -0800 Subject: [PATCH 3/6] fix checkstyle error --- .../io/helidon/examples/media/multipart/FileService.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/FileService.java b/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/FileService.java index 31cf1838044..b757d8b0741 100644 --- a/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/FileService.java +++ b/examples/media/multipart/src/main/java/io/helidon/examples/media/multipart/FileService.java @@ -83,11 +83,12 @@ private void upload(ServerRequest req, ServerResponse res) { req.content().asStream(ReadableBodyPart.class) .forEach(part -> { if (part.isNamed("file[]")) { + String filename = part.filename() + .orElseThrow(() -> new BadRequestException("Missing filename")); part.content() .map(DataChunk::data) .flatMapIterable(Arrays::asList) - .to(IoMulti.writeToFile(storage.create(part.filename() - .orElseThrow(() -> new BadRequestException("Missing filename")))) + .to(IoMulti.writeToFile(storage.create(filename)) .executor(executor) .build()); } else { From 01e2cff70555f7f10b6647824b8cd4d7aae2d2cc Mon Sep 17 00:00:00 2001 From: Romain Grecourt Date: Mon, 6 Feb 2023 19:08:51 -0800 Subject: [PATCH 4/6] Fix archetype --- .../java/__pkg__/FileService.java.multipart.mustache | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/archetypes/helidon/src/main/archetype/se/custom/files/src/main/java/__pkg__/FileService.java.multipart.mustache b/archetypes/helidon/src/main/archetype/se/custom/files/src/main/java/__pkg__/FileService.java.multipart.mustache index c4cbcd21ed6..7c2d36f4fb9 100644 --- a/archetypes/helidon/src/main/archetype/se/custom/files/src/main/java/__pkg__/FileService.java.multipart.mustache +++ b/archetypes/helidon/src/main/archetype/se/custom/files/src/main/java/__pkg__/FileService.java.multipart.mustache @@ -67,10 +67,13 @@ public final class FileService implements Service { private void upload(ServerRequest req, ServerResponse res) { req.content().asStream(ReadableBodyPart.class) .forEach(part -> { - if ("file[]".equals(part.name())) { - part.content().map(DataChunk::data) + if (part.isNamed("file[]")) { + String filename = part.filename() + .orElseThrow(() -> new BadRequestException("Missing filename")); + part.content() + .map(DataChunk::data) .flatMapIterable(Arrays::asList) - .to(IoMulti.writeToFile(storage.create(part.filename())) + .to(IoMulti.writeToFile(storage.create(filename)) .executor(executor) .build()); } else { From 6f4eff9433ebca561c65f90334787e494b356a3c Mon Sep 17 00:00:00 2001 From: Romain Grecourt Date: Mon, 6 Feb 2023 21:09:43 -0800 Subject: [PATCH 5/6] Fix unit test --- reactive/media/multipart/pom.xml | 7 ++++++- .../reactive/media/multipart/BodyPartTest.java | 13 +++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/reactive/media/multipart/pom.xml b/reactive/media/multipart/pom.xml index 37f6a7646d7..b82d4991339 100644 --- a/reactive/media/multipart/pom.xml +++ b/reactive/media/multipart/pom.xml @@ -1,6 +1,6 @@