Skip to content
This repository was archived by the owner on May 28, 2018. It is now read-only.

Commit bb99db4

Browse files
author
alessandro.gherardi
committed
Properly close the Apache response so that connections can be reused
1 parent 88c6d7d commit bb99db4

File tree

2 files changed

+49
-17
lines changed

2 files changed

+49
-17
lines changed

connectors/apache-connector/src/main/java/org/glassfish/jersey/apache/connector/ApacheConnector.java

+8-15
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ public ClientResponse apply(final ClientRequest clientRequest) throws Processing
486486
}
487487

488488
try {
489-
responseContext.setEntityStream(new HttpClientResponseInputStream(getInputStream(response)));
489+
responseContext.setEntityStream(getInputStream(response));
490490
} catch (final IOException e) {
491491
LOGGER.log(Level.SEVERE, null, e);
492492
}
@@ -625,18 +625,6 @@ private static Map<String, String> writeOutBoundHeaders(final MultivaluedMap<Str
625625
return stringHeaders;
626626
}
627627

628-
private static final class HttpClientResponseInputStream extends FilterInputStream {
629-
630-
HttpClientResponseInputStream(final InputStream inputStream) throws IOException {
631-
super(inputStream);
632-
}
633-
634-
@Override
635-
public void close() throws IOException {
636-
super.close();
637-
}
638-
}
639-
640628
private static InputStream getInputStream(final CloseableHttpResponse response) throws IOException {
641629

642630
final InputStream inputStream;
@@ -655,8 +643,13 @@ private static InputStream getInputStream(final CloseableHttpResponse response)
655643
return new FilterInputStream(inputStream) {
656644
@Override
657645
public void close() throws IOException {
658-
response.close();
659-
super.close();
646+
try {
647+
super.close();
648+
} catch (IOException ex) {
649+
// Ignore
650+
} finally {
651+
response.close();
652+
}
660653
}
661654
};
662655
}

connectors/apache-connector/src/test/java/org/glassfish/jersey/apache/connector/StreamingTest.java

+41-2
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,13 @@
4949
import javax.ws.rs.client.WebTarget;
5050
import javax.ws.rs.core.Application;
5151
import javax.ws.rs.core.MediaType;
52-
52+
import javax.ws.rs.core.Response;
5353
import javax.inject.Singleton;
5454

55+
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
56+
5557
import org.glassfish.jersey.client.ClientConfig;
58+
import org.glassfish.jersey.client.ClientProperties;
5659
import org.glassfish.jersey.server.ChunkedOutput;
5760
import org.glassfish.jersey.server.ResourceConfig;
5861
import org.glassfish.jersey.test.JerseyTest;
@@ -64,14 +67,16 @@
6467
* @author Petr Janouch (petr.janouch at oracle.com)
6568
*/
6669
public class StreamingTest extends JerseyTest {
70+
private PoolingHttpClientConnectionManager connectionManager;
6771

6872
/**
6973
* Test that a data stream can be terminated from the client side.
7074
*/
7175
@Test
7276
public void clientCloseTest() throws IOException {
7377
// start streaming
74-
InputStream inputStream = target().path("/streamingEndpoint").request().get(InputStream.class);
78+
InputStream inputStream = target().path("/streamingEndpoint").request()
79+
.property(ClientProperties.READ_TIMEOUT, 1_000).get(InputStream.class);
7580

7681
WebTarget sendTarget = target().path("/streamingEndpoint/send");
7782
// trigger sending 'A' to the stream; OK is sent if everything on the server was OK
@@ -85,8 +90,35 @@ public void clientCloseTest() throws IOException {
8590
assertEquals("NOK", sendTarget.request().get().readEntity(String.class));
8691
}
8792

93+
/**
94+
* Tests that closing a response after completely reading the entity reuses the connection
95+
*/
96+
@Test
97+
public void reuseConnectionTest() throws IOException {
98+
Response response = target().path("/streamingEndpoint/get").request().get();
99+
InputStream is = response.readEntity(InputStream.class);
100+
byte[] buf = new byte[8192];
101+
is.read(buf);
102+
is.close();
103+
response.close();
104+
105+
assertEquals(1, connectionManager.getTotalStats().getAvailable());
106+
assertEquals(0, connectionManager.getTotalStats().getLeased());
107+
}
108+
109+
/**
110+
* Tests that closing a request without reading the entity does not throw an exception.
111+
*/
112+
@Test
113+
public void clientCloseThrowsNoExceptionTest() throws IOException {
114+
Response response = target().path("/streamingEndpoint/get").request().get();
115+
response.close();
116+
}
117+
88118
@Override
89119
protected void configureClient(ClientConfig config) {
120+
connectionManager = new PoolingHttpClientConnectionManager();
121+
config.property(ApacheClientProperties.CONNECTION_MANAGER, connectionManager);
90122
config.connectorProvider(new ApacheConnectorProvider());
91123
}
92124

@@ -118,5 +150,12 @@ public String sendEvent() {
118150
public ChunkedOutput<String> get() {
119151
return output;
120152
}
153+
154+
@GET
155+
@Path("get")
156+
@Produces(MediaType.TEXT_PLAIN)
157+
public String getString() {
158+
return "OK";
159+
}
121160
}
122161
}

0 commit comments

Comments
 (0)