Browse Source

Support multipart/mixed and related in DefaultServerWebExchange

See gh-29671
pull/29969/head
Ronny Perinke 2 years ago committed by rstoyanchev
parent
commit
67df0756cd
  1. 10
      framework-docs/src/docs/asciidoc/web/webflux.adoc
  2. 6
      spring-web/src/main/java/org/springframework/web/server/adapter/DefaultServerWebExchange.java
  3. 31
      spring-web/src/test/java/org/springframework/http/server/reactive/MultipartHttpHandlerIntegrationTests.java

10
framework-docs/src/docs/asciidoc/web/webflux.adoc

@ -613,8 +613,8 @@ The `DefaultServerWebExchange` uses the configured `HttpMessageReader` to parse @@ -613,8 +613,8 @@ The `DefaultServerWebExchange` uses the configured `HttpMessageReader` to parse
----
The `DefaultServerWebExchange` uses the configured
`HttpMessageReader<MultiValueMap<String, Part>>` to parse `multipart/form-data` content
into a `MultiValueMap`.
`HttpMessageReader<MultiValueMap<String, Part>>` to parse `multipart/form-data`,
`multipart/mixed` and `multipart/related` content into a `MultiValueMap`.
By default, this is the `DefaultPartHttpMessageReader`, which does not have any third-party
dependencies.
Alternatively, the `SynchronossPartHttpMessageReader` can be used, which is based on the
@ -805,9 +805,9 @@ consistently for access to the cached form data versus reading from the raw requ @@ -805,9 +805,9 @@ consistently for access to the cached form data versus reading from the raw requ
==== Multipart
`MultipartHttpMessageReader` and `MultipartHttpMessageWriter` support decoding and
encoding "multipart/form-data" content. In turn `MultipartHttpMessageReader` delegates to
another `HttpMessageReader` for the actual parsing to a `Flux<Part>` and then simply
collects the parts into a `MultiValueMap`.
encoding "multipart/form-data", "multipart/mixed" and "multipart/related" content.
In turn `MultipartHttpMessageReader` delegates to another `HttpMessageReader`
for the actual parsing to a `Flux<Part>` and then simply collects the parts into a `MultiValueMap`.
By default, the `DefaultPartHttpMessageReader` is used, but this can be changed through the
`ServerCodecConfigurer`.
For more information about the `DefaultPartHttpMessageReader`, refer to the

6
spring-web/src/main/java/org/springframework/web/server/adapter/DefaultServerWebExchange.java

@ -163,9 +163,11 @@ public class DefaultServerWebExchange implements ServerWebExchange { @@ -163,9 +163,11 @@ public class DefaultServerWebExchange implements ServerWebExchange {
try {
MediaType contentType = request.getHeaders().getContentType();
if (MediaType.MULTIPART_FORM_DATA.isCompatibleWith(contentType)) {
if (MediaType.MULTIPART_FORM_DATA.isCompatibleWith(contentType) ||
MediaType.MULTIPART_MIXED.isCompatibleWith(contentType) ||
MediaType.MULTIPART_RELATED.isCompatibleWith(contentType)) {
return ((HttpMessageReader<MultiValueMap<String, Part>>) configurer.getReaders().stream()
.filter(reader -> reader.canRead(MULTIPART_DATA_TYPE, MediaType.MULTIPART_FORM_DATA))
.filter(reader -> reader.canRead(MULTIPART_DATA_TYPE, contentType))
.findFirst()
.orElseThrow(() -> new IllegalStateException("No multipart HttpMessageReader.")))
.readMono(MULTIPART_DATA_TYPE, request, Hints.from(Hints.LOG_PREFIX_HINT, logPrefix))

31
spring-web/src/test/java/org/springframework/http/server/reactive/MultipartHttpHandlerIntegrationTests.java

@ -32,6 +32,7 @@ import org.springframework.http.ResponseEntity; @@ -32,6 +32,7 @@ import org.springframework.http.ResponseEntity;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.http.codec.multipart.FormFieldPart;
import org.springframework.http.codec.multipart.Part;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
@ -55,14 +56,38 @@ class MultipartHttpHandlerIntegrationTests extends AbstractHttpHandlerIntegratio @@ -55,14 +56,38 @@ class MultipartHttpHandlerIntegrationTests extends AbstractHttpHandlerIntegratio
}
@ParameterizedHttpServerTest
void getFormParts(HttpServer httpServer) throws Exception {
void getFormPartsFormdata(HttpServer httpServer) throws Exception {
performTest(httpServer, MediaType.MULTIPART_FORM_DATA);
}
@ParameterizedHttpServerTest
void getFormPartsMixed(HttpServer httpServer) throws Exception {
performTest(httpServer, MediaType.MULTIPART_MIXED);
}
@ParameterizedHttpServerTest
void getFormPartsRelated(HttpServer httpServer) throws Exception {
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().stream()
.filter(FormHttpMessageConverter.class::isInstance)
.map(FormHttpMessageConverter.class::cast)
.findFirst()
.orElseThrow()
.addSupportedMediaTypes(MediaType.MULTIPART_RELATED);
performTest(httpServer, MediaType.MULTIPART_RELATED, restTemplate);
}
private void performTest(HttpServer httpServer, MediaType mediaType) throws Exception {
performTest(httpServer, mediaType, new RestTemplate());
}
private void performTest(HttpServer httpServer, MediaType mediaType, RestTemplate restTemplate) throws Exception {
startServer(httpServer);
@SuppressWarnings("resource")
RestTemplate restTemplate = new RestTemplate();
RequestEntity<MultiValueMap<String, Object>> request = RequestEntity
.post(URI.create("http://localhost:" + port + "/form-parts"))
.contentType(MediaType.MULTIPART_FORM_DATA)
.contentType(mediaType)
.body(generateBody());
ResponseEntity<Void> response = restTemplate.exchange(request, Void.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);

Loading…
Cancel
Save