Improve invalid Content-Type handling in WebFlux

Closes gh-29565
This commit is contained in:
rstoyanchev 2022-12-05 09:19:15 +00:00
parent 4a555aaef1
commit 913163884a
3 changed files with 31 additions and 4 deletions

View File

@ -990,7 +990,8 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
/**
* 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() {

View File

@ -34,8 +34,10 @@ import org.springframework.core.codec.DecodingException;
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;
@ -145,7 +147,16 @@ public abstract class AbstractMessageReaderArgumentResolver extends HandlerMetho
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);

View File

@ -41,12 +41,14 @@ import org.springframework.web.bind.annotation.RequestBody;
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;
/**
@ -214,6 +216,17 @@ public class RequestBodyMethodArgumentResolverTests {
});
}
@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));
@ -221,7 +234,8 @@ public class RequestBodyMethodArgumentResolverTests {
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;
@ -234,7 +248,8 @@ public class RequestBodyMethodArgumentResolverTests {
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