Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ClientResponse's body ignored on UnsupportedMediaTypeException [SPR-17054] #21592

Closed
spring-projects-issues opened this issue Jul 17, 2018 · 0 comments
Assignees
Labels
type: bug
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

@spring-projects-issues spring-projects-issues commented Jul 17, 2018

Denys Ivano opened SPR-17054 and commented

When remote service responses with Content-Type that can't be read by HttpMessageReader, an instance of UnsupportedMediaTypeException is being thrown (see BodyExtractors.readWithMessageReaders()). But ClientResponse's body is being ignored in this case.

From ClientResponse's Javadoc:

* <p><strong>NOTE:</strong> When given access to a {@link ClientResponse},
* through the {@code WebClient}
* {@link WebClient.RequestHeadersSpec#exchange() exchange()} method,
* you must always use one of the body or toEntity methods to ensure resources
* are released and avoid potential issues with HTTP connection pooling.
* You can use {@code bodyToMono(Void.class)} if no response content is
* expected. However keep in mind that if the response does have content, the
* connection will be closed and will not be placed back in the pool.

So in order to release resources and avoid potential issues with HTTP connection pool, the response body must be consumed.

I've created a test that reproduces this issue:

@Test
public void shouldConsumeBodyOnUnsupportedMediaTypeException() {
    AtomicBoolean bodyConsumed = new AtomicBoolean();
    ExchangeFunction exchangeFunction = mock(ExchangeFunction.class);
    ClientResponse response = ClientResponse.create(HttpStatus.OK)
            .header(HttpHeaders.CONTENT_TYPE, "application/unknown")
//                .header(HttpHeaders.CONTENT_TYPE, "application/json")
            .body(Flux.defer(() -> {
                DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                return Flux.just("{\"name\": \"Hello World!\"}").
                        map(s -> {
                            bodyConsumed.set(true);
                            byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
                            return dataBufferFactory.wrap(bytes);
                        });
            }))
            .build();

    when(exchangeFunction.exchange(any())).thenReturn(Mono.just(response));

    WebClient webClient = WebClient.builder()
            .exchangeFunction(exchangeFunction)
            .build();

    Mono<String> result = webClient.get()
            .retrieve()
            .bodyToMono(TestResponse.class)
            .map(TestResponse::getName);

    StepVerifier.create(result)
            .expectError(UnsupportedMediaTypeException.class)
//                .expectNext("Hello World!")
//                .expectComplete()
            .verify(Duration.ZERO);

    assertTrue("Response body wasn't consumed", bodyConsumed.get());
}

private static class TestResponse {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Issue Links:

  • #21563 DataBufferUtils#join could leak buffers in case of error from the source
  • #22014 WebClient throws "Only one connection receive subscriber allowed" when response has content but no Content-Type header

Referenced from: commits a410d90, d0ada56

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug
Projects
None yet
Development

No branches or pull requests

2 participants