spring-cloud / spring-cloud/spring-cloud-gateway
ResponseBodyModification filter interferes with other filters that modify response.
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 4.9k
- Forks
- 3.5k
- Avg merge
- 20h 57m
- Merged PRs (30d)
- 8
Description
Describe the bug
Response body modification filter can interfere with other filters that are potentially modifying response body and as the result fail the request. (full reproducer and error details below).
For example we have a ModifyResponseBody filter that accepts Map and returns Map. Also prior to that we set up a caching filter that can potentially prevent request from going further and just return existing(cached) value for that request. In that case ModifyResponseBody filter shouldn't be called at all since the response is being written prior to that in a different filter. However response is being written via response.writeWith call, which is being overriden by response body modification filter and that call will fail with exception below.
Sample
Reproducer here: https://github.com/korektur/spring-cloud-gateway/blob/filter_modify_body/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyResponseBodyGatewayFilterTests.java
Route:
.route("modify_response_java_test_with_filter",
r -> r.path("/withFilterAndModifier")
.filters(f -> f.setPath("/httpbin/")
.filter(cacheGatewayFilter)
.modifyResponseBody(Map.class, Map.class,
(webExchange, originalResponse) -> {
Map<String, Object> modifiedResponse = new HashMap<>();
modifiedResponse.put("value",
originalResponse);
modifiedResponse.put("length",
originalResponse
.size());
return Mono
.just(modifiedResponse);
}))
.uri(uri))
.build();
Intercepting filter:
return (exchange, chain) -> {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.OK);
DataBufferFactory dataBufferFactory = response.bufferFactory();
DataBuffer wrap = dataBufferFactory.wrap(
"{\"value\": \"intercepted\"}".getBytes(StandardCharsets.UTF_8));
return response.writeWith(Mono.just(wrap))
.doOnSuccess(v -> response.setComplete());
};
Error:
org.springframework.web.reactive.function.UnsupportedMediaTypeException: Content type 'application/octet-stream' not supported for bodyType=java.util.Map<?, ?>
at org.springframework.web.reactive.function.BodyExtractors.lambda$readWithMessageReaders$12(BodyExtractors.java:201) ~[spring-webflux-5.2.6.BUILD-20200420.134351-81.jar:5.2.6.BUILD-SNAPSHOT]
Error goes away if first parameter of .modifyResponseBody is set to String.class, however in that case body is modifyed twice, once in caching layer and then in modifyResponseBody filter.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyResponseBodyGatewayFilterTests.java and run the reproducer for the cache filter followed by ModifyResponseBody. Trace the response-writing and body-decoding behavior shown in the test; done means the cached response completes without the UnsupportedMediaTypeException and is not modified twice.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring, spring-boot
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100