Skip to content

Commit 912fa76

Browse files
committed
Improve invalid Content-Type handling in WebFlux
Closes gh-29565
1 parent 525fc7a commit 912fa76

File tree

3 files changed

+31
-4
lines changed

3 files changed

+31
-4
lines changed

spring-web/src/main/java/org/springframework/http/HttpHeaders.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -984,7 +984,8 @@ public void setContentType(@Nullable MediaType mediaType) {
984984
/**
985985
* Return the {@linkplain MediaType media type} of the body, as specified
986986
* by the {@code Content-Type} header.
987-
* <p>Returns {@code null} when the content-type is unknown.
987+
* <p>Returns {@code null} when the {@code Content-Type} header is not set.
988+
* @throws InvalidMediaTypeException if the media type value cannot be parsed
988989
*/
989990
@Nullable
990991
public MediaType getContentType() {

spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@
3535
import org.springframework.core.codec.Hints;
3636
import org.springframework.core.io.buffer.DataBuffer;
3737
import org.springframework.core.io.buffer.DataBufferUtils;
38+
import org.springframework.http.HttpHeaders;
3839
import org.springframework.http.HttpMethod;
3940
import org.springframework.http.HttpStatus;
41+
import org.springframework.http.InvalidMediaTypeException;
4042
import org.springframework.http.MediaType;
4143
import org.springframework.http.codec.HttpMessageReader;
4244
import org.springframework.http.server.reactive.ServerHttpRequest;
@@ -146,7 +148,16 @@ protected Mono<Object> readBody(MethodParameter bodyParam, @Nullable MethodParam
146148
ServerHttpRequest request = exchange.getRequest();
147149
ServerHttpResponse response = exchange.getResponse();
148150

149-
MediaType contentType = request.getHeaders().getContentType();
151+
MediaType contentType;
152+
HttpHeaders headers = request.getHeaders();
153+
try {
154+
contentType = headers.getContentType();
155+
}
156+
catch (InvalidMediaTypeException ex) {
157+
throw new UnsupportedMediaTypeStatusException(
158+
"Can't parse Content-Type [" + headers.getFirst("Content-Type") + "]: " + ex.getMessage());
159+
}
160+
150161
MediaType mediaType = (contentType != null ? contentType : MediaType.APPLICATION_OCTET_STREAM);
151162
Object[] hints = extractValidationHints(bodyParam);
152163

spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestBodyMethodArgumentResolverTests.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,14 @@
4141
import org.springframework.web.reactive.BindingContext;
4242
import org.springframework.web.server.ServerWebExchange;
4343
import org.springframework.web.server.ServerWebInputException;
44+
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
4445
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
4546
import org.springframework.web.testfixture.method.ResolvableMethod;
4647
import org.springframework.web.testfixture.server.MockServerWebExchange;
4748

4849
import static org.assertj.core.api.Assertions.assertThat;
4950
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
51+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
5052
import static org.springframework.web.testfixture.method.MvcAnnotationPredicates.requestBody;
5153

5254
/**
@@ -214,14 +216,26 @@ public void emptyBodyWithCompletableFuture() {
214216
});
215217
}
216218

219+
@Test // gh-29565
220+
public void invalidContentType() {
221+
MethodParameter parameter = this.testMethod.annot(requestBody()).arg(String.class);
222+
223+
ServerWebExchange exchange = MockServerWebExchange.from(
224+
MockServerHttpRequest.post("/path").header("Content-Type", "invalid").build());
225+
226+
assertThatThrownBy(() -> this.resolver.readBody(parameter, true, new BindingContext(), exchange))
227+
.isInstanceOf(UnsupportedMediaTypeStatusException.class);
228+
}
229+
217230
@SuppressWarnings("unchecked")
218231
private <T> T resolveValue(MethodParameter param, String body) {
219232
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.post("/path").body(body));
220233
Mono<Object> result = this.resolver.readBody(param, true, new BindingContext(), exchange);
221234
Object value = result.block(Duration.ofSeconds(5));
222235

223236
assertThat(value).isNotNull();
224-
assertThat(param.getParameterType().isAssignableFrom(value.getClass())).as("Unexpected return value type: " + value).isTrue();
237+
assertThat(param.getParameterType().isAssignableFrom(value.getClass()))
238+
.as("Unexpected return value type: " + value).isTrue();
225239

226240
//no inspection unchecked
227241
return (T) value;
@@ -234,7 +248,8 @@ private <T> T resolveValueWithEmptyBody(MethodParameter param) {
234248
Object value = result.block(Duration.ofSeconds(5));
235249

236250
if (value != null) {
237-
assertThat(param.getParameterType().isAssignableFrom(value.getClass())).as("Unexpected parameter type: " + value).isTrue();
251+
assertThat(param.getParameterType().isAssignableFrom(value.getClass()))
252+
.as("Unexpected parameter type: " + value).isTrue();
238253
}
239254

240255
//no inspection unchecked

0 commit comments

Comments
 (0)