Skip to content

ResponseBodyModification filter interferes with other filters that modify response. #1682

Open
@korektur

Description

@korektur

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions