From 8dee7d8fb6311c5ac92db36fa1c197bae5492bd5 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Fri, 13 Jun 2025 16:45:46 +0200 Subject: [PATCH] Use concrete form-data type when reading request body Prior to this commit, the WebFlux server support would try reading form-data from the request by: * first, checking that request content-type is compatible with a form-data content-type * then by selecting a message reader that is compatible with the given request content-type This approach is flawed because if the content-type provided by the request is too broad, another message reader could be selected that's not meant to be used for reading form-data. Typically, a JSON message reader could be selected and would fail when reading the request. This problem was previously hidden because message readers would not support `MultiValueMap` as a target type. Now that some readers support this type, this can lead to deserialization errors. This commit now ensures that in all cases, we attempt to read form-data with a message reader that supports the "application/x-www-form-urlencoded" media type. Fixes gh-34660 --- .../server/adapter/DefaultServerWebExchange.java | 2 +- .../adapter/DefaultServerWebExchangeTests.java | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/server/adapter/DefaultServerWebExchange.java b/spring-web/src/main/java/org/springframework/web/server/adapter/DefaultServerWebExchange.java index 0c84ef9d005..d457c6039a0 100644 --- a/spring-web/src/main/java/org/springframework/web/server/adapter/DefaultServerWebExchange.java +++ b/spring-web/src/main/java/org/springframework/web/server/adapter/DefaultServerWebExchange.java @@ -153,7 +153,7 @@ public class DefaultServerWebExchange implements ServerWebExchange { return EMPTY_FORM_DATA; } - HttpMessageReader> reader = getReader(configurer, contentType, FORM_DATA_TYPE); + HttpMessageReader> reader = getReader(configurer, MediaType.APPLICATION_FORM_URLENCODED, FORM_DATA_TYPE); if (reader == null) { return Mono.error(new IllegalStateException("No HttpMessageReader for " + contentType)); } diff --git a/spring-web/src/test/java/org/springframework/web/server/adapter/DefaultServerWebExchangeTests.java b/spring-web/src/test/java/org/springframework/web/server/adapter/DefaultServerWebExchangeTests.java index 2c5f4d332b7..077d22df62c 100644 --- a/spring-web/src/test/java/org/springframework/web/server/adapter/DefaultServerWebExchangeTests.java +++ b/spring-web/src/test/java/org/springframework/web/server/adapter/DefaultServerWebExchangeTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,10 @@ package org.springframework.web.server.adapter; import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; import org.springframework.http.codec.ServerCodecConfigurer; +import org.springframework.util.MultiValueMap; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.i18n.AcceptHeaderLocaleContextResolver; import org.springframework.web.server.session.DefaultWebSessionManager; @@ -56,6 +59,17 @@ class DefaultServerWebExchangeTests { assertThat(exchange.transformUrl("/foo")).isEqualTo("/foo;p=abc?q=123"); } + @Test // gh-34660 + void useFormDataMessageReaderWhenAllContentType() { + MockServerHttpRequest request = MockServerHttpRequest + .post("https://example.com") + .header(HttpHeaders.CONTENT_TYPE, MediaType.ALL_VALUE) + .body("project=spring"); + ServerWebExchange exchange = createExchange(request); + MultiValueMap body = exchange.getFormData().block(); + assertThat(body.get("project")).contains("spring"); + } + private DefaultServerWebExchange createExchange() { MockServerHttpRequest request = MockServerHttpRequest.get("https://example.com").build();