Skip to content

Commit 0cfff66

Browse files
authored
Merge pull request #3861 from agherardi/properlyClose
Properly close the Apache response so that connections can be reused
2 parents e0d0c7c + 8078b7d commit 0cfff66

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

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ public ClientResponse apply(final ClientRequest clientRequest) throws Processing
462462
}
463463

464464
try {
465-
responseContext.setEntityStream(new HttpClientResponseInputStream(getInputStream(response)));
465+
responseContext.setEntityStream(getInputStream(response));
466466
} catch (final IOException e) {
467467
LOGGER.log(Level.SEVERE, null, e);
468468
}
@@ -601,18 +601,6 @@ private static Map<String, String> writeOutBoundHeaders(final MultivaluedMap<Str
601601
return stringHeaders;
602602
}
603603

604-
private static final class HttpClientResponseInputStream extends FilterInputStream {
605-
606-
HttpClientResponseInputStream(final InputStream inputStream) throws IOException {
607-
super(inputStream);
608-
}
609-
610-
@Override
611-
public void close() throws IOException {
612-
super.close();
613-
}
614-
}
615-
616604
private static InputStream getInputStream(final CloseableHttpResponse response) throws IOException {
617605

618606
final InputStream inputStream;
@@ -631,8 +619,13 @@ private static InputStream getInputStream(final CloseableHttpResponse response)
631619
return new FilterInputStream(inputStream) {
632620
@Override
633621
public void close() throws IOException {
634-
response.close();
635-
super.close();
622+
try {
623+
super.close();
624+
} catch (IOException ex) {
625+
// Ignore
626+
} finally {
627+
response.close();
628+
}
636629
}
637630
};
638631
}

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

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,13 @@
2525
import javax.ws.rs.client.WebTarget;
2626
import javax.ws.rs.core.Application;
2727
import javax.ws.rs.core.MediaType;
28-
28+
import javax.ws.rs.core.Response;
2929
import javax.inject.Singleton;
3030

31+
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
32+
3133
import org.glassfish.jersey.client.ClientConfig;
34+
import org.glassfish.jersey.client.ClientProperties;
3235
import org.glassfish.jersey.server.ChunkedOutput;
3336
import org.glassfish.jersey.server.ResourceConfig;
3437
import org.glassfish.jersey.test.JerseyTest;
@@ -40,14 +43,16 @@
4043
* @author Petr Janouch (petr.janouch at oracle.com)
4144
*/
4245
public class StreamingTest extends JerseyTest {
46+
private PoolingHttpClientConnectionManager connectionManager;
4347

4448
/**
4549
* Test that a data stream can be terminated from the client side.
4650
*/
4751
@Test
4852
public void clientCloseTest() throws IOException {
4953
// start streaming
50-
InputStream inputStream = target().path("/streamingEndpoint").request().get(InputStream.class);
54+
InputStream inputStream = target().path("/streamingEndpoint").request()
55+
.property(ClientProperties.READ_TIMEOUT, 1_000).get(InputStream.class);
5156

5257
WebTarget sendTarget = target().path("/streamingEndpoint/send");
5358
// trigger sending 'A' to the stream; OK is sent if everything on the server was OK
@@ -61,8 +66,35 @@ public void clientCloseTest() throws IOException {
6166
assertEquals("NOK", sendTarget.request().get().readEntity(String.class));
6267
}
6368

69+
/**
70+
* Tests that closing a response after completely reading the entity reuses the connection
71+
*/
72+
@Test
73+
public void reuseConnectionTest() throws IOException {
74+
Response response = target().path("/streamingEndpoint/get").request().get();
75+
InputStream is = response.readEntity(InputStream.class);
76+
byte[] buf = new byte[8192];
77+
is.read(buf);
78+
is.close();
79+
response.close();
80+
81+
assertEquals(1, connectionManager.getTotalStats().getAvailable());
82+
assertEquals(0, connectionManager.getTotalStats().getLeased());
83+
}
84+
85+
/**
86+
* Tests that closing a request without reading the entity does not throw an exception.
87+
*/
88+
@Test
89+
public void clientCloseThrowsNoExceptionTest() throws IOException {
90+
Response response = target().path("/streamingEndpoint/get").request().get();
91+
response.close();
92+
}
93+
6494
@Override
6595
protected void configureClient(ClientConfig config) {
96+
connectionManager = new PoolingHttpClientConnectionManager();
97+
config.property(ApacheClientProperties.CONNECTION_MANAGER, connectionManager);
6698
config.connectorProvider(new ApacheConnectorProvider());
6799
}
68100

@@ -94,5 +126,12 @@ public String sendEvent() {
94126
public ChunkedOutput<String> get() {
95127
return output;
96128
}
129+
130+
@GET
131+
@Path("get")
132+
@Produces(MediaType.TEXT_PLAIN)
133+
public String getString() {
134+
return "OK";
135+
}
97136
}
98137
}

0 commit comments

Comments
 (0)