Skip to content

Commit

Permalink
Update BodyPart to return Optional instead of a nullable String (#6101)
Browse files Browse the repository at this point in the history
* Update BodyPart to return Optional instead of a nullable String
Also add a new method isNamed to test the control name.

Fixes #2833
  • Loading branch information
romain-grecourt authored Feb 7, 2023
1 parent 179d24f commit b6bbd5f
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import java.util.Map;
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;
Expand Down Expand Up @@ -67,10 +68,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 {
Expand Down
2 changes: 1 addition & 1 deletion examples/media/multipart/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <http://localhost:8080/ui> in your browser.
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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;
Expand Down Expand Up @@ -81,10 +82,13 @@ 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[]")) {
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 {
Expand Down
7 changes: 6 additions & 1 deletion reactive/media/multipart/pom.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
Expand Down Expand Up @@ -113,5 +113,10 @@
<artifactId>reactive-streams-tck-flow</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.helidon.common.testing</groupId>
<artifactId>helidon-common-testing-junit5</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -15,6 +15,8 @@
*/
package io.helidon.reactive.media.multipart;

import java.util.Optional;

import io.helidon.reactive.media.common.MessageBodyContent;

/**
Expand All @@ -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<String> 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<String> filename() {
return headers().contentDisposition().filename();
}
}
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -30,10 +30,11 @@

import org.junit.jupiter.api.Test;

import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty;
import static io.helidon.common.testing.junit5.OptionalMatcher.optionalValue;
import static io.helidon.reactive.media.multipart.MultiPartDecoderTest.chunksPublisher;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.fail;
Expand Down Expand Up @@ -122,8 +123,8 @@ public void testName() {
.build())
.entity("abc")
.build();
assertThat(bodyPart.name(), is(equalTo("foo")));
assertThat(bodyPart.filename(), is(nullValue()));
assertThat(bodyPart.name(), optionalValue(is("foo")));
assertThat(bodyPart.filename(), is(optionalEmpty()));
}

@Test
Expand All @@ -136,8 +137,8 @@ public void testFilename() {
.build())
.entity("abc")
.build();
assertThat(bodyPart.filename(), is(equalTo("foo.txt")));
assertThat(bodyPart.name(), is(nullValue()));
assertThat(bodyPart.filename(), optionalValue(is("foo.txt")));
assertThat(bodyPart.name(), is(optionalEmpty()));
}

static MessageBodyReadableContent readableContent(Publisher<DataChunk> chunks) {
Expand Down

0 comments on commit b6bbd5f

Please sign in to comment.