Fix behavior of ClientResponse#bodyTo** with Void

Prior to this commit, asking for a `Void` type using any of the
`ClientResponse#bodyTo*` methods would immediately return an empty
`Publisher` without consuming the response body.

Not doing so can lead to HTTP connection pool inconsistencies and/or
memory leaks, since:

* a connection that still has a response body being written to it cannot
be properly recycled in the connection pool
* incoming `DataBuffer` might not be released

This commit detects when `Void` types are asked as body types and in
those cases does the following:

1. Subscribe to the response body `Publisher` to allow the connection to
be returned to the connection pool
2. `cancel()` the body `Publisher` if the response body is not empty; in
that case, we choose to close the connection vs. consume the whole
response body

Those changes imply that `ClientHttpResponse` and other related
contracts don't need a `close()` method anymore.

Issue: SPR-16018
This commit is contained in:
Brian Clozel
2017-09-27 23:08:30 +02:00
parent ec345bf162
commit 126ac849e5
11 changed files with 122 additions and 152 deletions

View File

@@ -16,8 +16,6 @@
package org.springframework.http.client.reactive;
import java.io.Closeable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ReactiveHttpInputMessage;
import org.springframework.http.ResponseCookie;
@@ -30,7 +28,7 @@ import org.springframework.util.MultiValueMap;
* @author Brian Clozel
* @since 5.0
*/
public interface ClientHttpResponse extends ReactiveHttpInputMessage, Closeable {
public interface ClientHttpResponse extends ReactiveHttpInputMessage {
/**
* Return the HTTP status as an {@link HttpStatus} enum value.
@@ -42,16 +40,4 @@ public interface ClientHttpResponse extends ReactiveHttpInputMessage, Closeable
*/
MultiValueMap<String, ResponseCookie> getCookies();
/**
* Close this response and the underlying HTTP connection.
* <p>This non-blocking method has to be called if its body isn't going
* to be consumed. Not doing so might result in HTTP connection pool
* inconsistencies or memory leaks.
* <p>This shouldn't be called if the response body is read,
* because it would prevent connections to be reused and cancel
* the benefits of using a connection pooling.
*/
@Override
void close();
}

View File

@@ -70,11 +70,6 @@ public class ClientHttpResponseDecorator implements ClientHttpResponse {
return this.delegate.getBody();
}
@Override
public void close() {
this.delegate.close();
}
@Override
public String toString() {
return getClass().getSimpleName() + " [delegate=" + getDelegate() + "]";

View File

@@ -89,11 +89,6 @@ public class ReactorClientHttpResponse implements ClientHttpResponse {
return CollectionUtils.unmodifiableMultiValueMap(result);
}
@Override
public void close() {
this.response.dispose();
}
@Override
public String toString() {
return "ReactorClientHttpResponse{" +