Skip to content

Commit

Permalink
Improve invalid Content-Type handling in WebFlux
Browse files Browse the repository at this point in the history
Closes gh-29565
  • Loading branch information
rstoyanchev committed Dec 5, 2022
1 parent 4a555aa commit 9131638
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 4 deletions.
Expand Up @@ -990,7 +990,8 @@ public void setContentType(@Nullable MediaType mediaType) {
/**
* Return the {@linkplain MediaType media type} of the body, as specified
* by the {@code Content-Type} header.
* <p>Returns {@code null} when the content-type is unknown.
* <p>Returns {@code null} when the {@code Content-Type} header is not set.
* @throws InvalidMediaTypeException if the media type value cannot be parsed
*/
@Nullable
public MediaType getContentType() {
Expand Down
Expand Up @@ -34,8 +34,10 @@
import org.springframework.core.codec.Hints;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.InvalidMediaTypeException;
import org.springframework.http.MediaType;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.server.reactive.ServerHttpRequest;
Expand Down Expand Up @@ -145,7 +147,16 @@ protected Mono<Object> readBody(MethodParameter bodyParam, @Nullable MethodParam
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();

MediaType contentType = request.getHeaders().getContentType();
MediaType contentType;
HttpHeaders headers = request.getHeaders();
try {
contentType = headers.getContentType();
}
catch (InvalidMediaTypeException ex) {
throw new UnsupportedMediaTypeStatusException(
"Can't parse Content-Type [" + headers.getFirst("Content-Type") + "]: " + ex.getMessage());
}

MediaType mediaType = (contentType != null ? contentType : MediaType.APPLICATION_OCTET_STREAM);
Object[] hints = extractValidationHints(bodyParam);

Expand Down
Expand Up @@ -41,12 +41,14 @@
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerWebInputException;
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
import org.springframework.web.testfixture.method.ResolvableMethod;
import org.springframework.web.testfixture.server.MockServerWebExchange;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.springframework.web.testfixture.method.MvcAnnotationPredicates.requestBody;

/**
Expand Down Expand Up @@ -214,14 +216,26 @@ public void emptyBodyWithCompletableFuture() {
});
}

@Test // gh-29565
public void invalidContentType() {
MethodParameter parameter = this.testMethod.annot(requestBody()).arg(String.class);

ServerWebExchange exchange = MockServerWebExchange.from(
MockServerHttpRequest.post("/path").header("Content-Type", "invalid").build());

assertThatThrownBy(() -> this.resolver.readBody(parameter, true, new BindingContext(), exchange))
.isInstanceOf(UnsupportedMediaTypeStatusException.class);
}

@SuppressWarnings("unchecked")
private <T> T resolveValue(MethodParameter param, String body) {
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.post("/path").body(body));
Mono<Object> result = this.resolver.readBody(param, true, new BindingContext(), exchange);
Object value = result.block(Duration.ofSeconds(5));

assertThat(value).isNotNull();
assertThat(param.getParameterType().isAssignableFrom(value.getClass())).as("Unexpected return value type: " + value).isTrue();
assertThat(param.getParameterType().isAssignableFrom(value.getClass()))
.as("Unexpected return value type: " + value).isTrue();

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

if (value != null) {
assertThat(param.getParameterType().isAssignableFrom(value.getClass())).as("Unexpected parameter type: " + value).isTrue();
assertThat(param.getParameterType().isAssignableFrom(value.getClass()))
.as("Unexpected parameter type: " + value).isTrue();
}

//no inspection unchecked
Expand Down

0 comments on commit 9131638

Please sign in to comment.