How to upload multipart/form-data to AmazonS3 using java sdk and web-flux?

Viewed 1535

I have a java spring-boot project with spring-boot-starter-webflux. I have a rest controller:

import software.amazon.awssdk.services.s3.S3AsyncClient;
import software.amazon.awssdk.core.async.AsyncRequestBody;
...
@PostMapping(path = "/path", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = APPLICATION_JSON_VALUE)
    public Mono<String> submitMultipartInstance(@RequestPart Flux<FilePart> partFlux) {
        String bucketName = ...
        String key = ...

        PutObjectRequest request = PutObjectRequest.builder()
                .bucket(bucketName)
                .key(key)
                .build();

        CompletableFuture<PutObjectResponse> completableFuture = s3AsyncClient.putObject(request, createAsyncBody(partFlux));

        return Mono.defer(() -> Mono.fromFuture(completableFuture))
                .map(PutObjectResponse::toString)
    }

private AsyncRequestBody createAsyncBody(Flux<FilePart> part) {
    return new AsyncRequestBody() {
        @Override
        public Optional<Long> contentLength() {
            return Optional.empty(); // what value to return from here?
        }

        @Override
        public void subscribe(Subscriber<? super ByteBuffer> s) {
            part.flatMap(FilePart::content).map(toByteBuffer()).subscribe(s);
        }

        private Function<DataBuffer, ByteBuffer> toByteBuffer() {
            return (buffer) -> {
                byte[] bytes = new byte[buffer.asByteBuffer().remaining()];
                try {
                    return ByteBuffer.wrap(bytes);
                } finally {
                    DataBufferUtils.release(buffer.read(bytes));
                }
            };
        }
    };
}

and I receive message (expectedly)

Caused by: software.amazon.awssdk.services.s3.model.S3Exception: You must provide the Content-Length HTTP header. (Service: S3, Status Code: 411, Request ID: ...)

How to upload multipart to s3 in reactive style?

1 Answers
Related