diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/multipart/MultiByteFileTest.java b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/multipart/MultiByteFileTest.java index 2b7207f02fa15..ee6e94b1544a8 100644 --- a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/multipart/MultiByteFileTest.java +++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/multipart/MultiByteFileTest.java @@ -15,6 +15,7 @@ import jakarta.inject.Inject; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.HeaderParam; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import jakarta.ws.rs.core.MediaType; @@ -139,6 +140,17 @@ void shouldSendFromMultiEmittingOutsideEventLoop() { assertThat(result).isEqualTo("myFile"); } + @Test + public void shouldPropertySetContentType() { + Client client = RestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class); + + ClientForm form = new ClientForm(); + form.file = Multi.createBy().repeating().supplier(() -> (byte) 4).atMost(100); + + assertThat(client.postMultipartToType(form)).startsWith("multipart/form-data"); + assertThat(client.postMultipartMixedToType(form)).startsWith("multipart/mixed"); + } + private void delayedEmit(AtomicLong i, MultiEmitter em) { vertx.setTimer(100, id -> { long index = i.getAndIncrement(); @@ -190,6 +202,12 @@ public String uploadEmpty(@MultipartForm FormWithTwoFiles form) { + verifyFile(form.file2, 100, position -> (byte) 7); } + @Path("type") + @POST + public String contentType(@HeaderParam("Content-Type") String contentType) { + return contentType; + } + private String verifyFile(FileUpload upload, int expectedSize, Function expectedByte) { var uploadedFile = upload.uploadedFile(); int size; @@ -270,6 +288,16 @@ public interface Client { @POST @Consumes(MediaType.MULTIPART_FORM_DATA) String postEmpty(@MultipartForm ClientForm form); + + @Path("/type") + @POST + @Consumes(MediaType.MULTIPART_FORM_DATA) + String postMultipartToType(@MultipartForm ClientForm clientForm); + + @Path("/type") + @POST + @Consumes("multipart/mixed") + String postMultipartMixedToType(@MultipartForm ClientForm clientForm); } public static class ClientForm { diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/handlers/ClientSendRequestHandler.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/handlers/ClientSendRequestHandler.java index 6120fc1bad74f..16fb90acd0cf6 100644 --- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/handlers/ClientSendRequestHandler.java +++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/handlers/ClientSendRequestHandler.java @@ -39,6 +39,7 @@ import org.jboss.resteasy.reactive.common.core.Serialisers; import org.jboss.resteasy.reactive.common.util.MultivaluedTreeMap; +import io.netty.handler.codec.http.HttpHeaderValues; import io.netty.handler.codec.http.LastHttpContent; import io.netty.handler.codec.http.multipart.InterfaceHttpData; import io.smallrye.mutiny.Multi; @@ -484,6 +485,19 @@ private QuarkusMultipartFormUpload setMultipartHeadersAndPrepareBody(HttpClientR headerMap.put(multipartHeader, multipartHeaders.getAll(multipartHeader)); } + if (state.getEntity().getVariant() != null) { + Variant v = state.getEntity().getVariant(); + String variantContentType = v.getMediaType().toString(); + String multipartContentType = headerMap.getFirst(HttpHeaders.CONTENT_TYPE); + if (multipartContentType.startsWith(HttpHeaderValues.MULTIPART_FORM_DATA.toString()) + && !variantContentType.startsWith(HttpHeaderValues.MULTIPART_FORM_DATA.toString())) { + // this is a total hack whose purpose is to allow the @Consumes annotation to override the media type + int semicolonIndex = multipartContentType.indexOf(';'); + headerMap.put(HttpHeaders.CONTENT_TYPE, + List.of(variantContentType + multipartContentType.substring(semicolonIndex))); + } + } + setVertxHeaders(httpClientRequest, headerMap); return multipartFormUpload; }