Discussion:
JerseClient SSL/TLS connection reuse
Roger Nordquist
2014-09-22 15:44:06 UTC
Permalink
Ok, it seems I found the reason why the connection reuse doesn’t work.
Jersey HttpUrlConnector always recreates the SSLSocketFactory for the HttpsURLConnection on each request.
I’m not sure why this is needed, if it has something to do with client reuse for different hosts or so?

However, I think there should be a possibility to configure this. My suggestion is to add a property that makes Jersey client reuse the global sslSocketFactory set by: HttpsURLConnection.setDefaultSSLSocketFactory.
Something like this:
if (request.resolveProperty(ClientProperties.USE_GLOBAL_SSL_SOCKET_FACTORY, false)) {
suc.setSSLSocketFactory(HttpsURLConnection.getDefaultSSLSocketFactory());
} else {
suc.setSSLSocketFactory(client.getSslContext().getSocketFactory());
}

What do you think? Any feedback is welcome!
I will probably come up with a pull request in the next couple of days.

Regards,
Roger

From: Roger Nordquist <roger.nordquist-7+TMkytGX/LLoDKTGw+***@public.gmane.org<mailto:***@valtech.se>>
Reply-To: "users-ywjJWXFEILO43ww/***@public.gmane.org<mailto:users-ywjJWXFEILO43ww/***@public.gmane.org>" <***@jersey.java.net<mailto:users-ywjJWXFEILO43ww/***@public.gmane.org>>
Date: Friday 19 September 2014 12:39
To: "users-ywjJWXFEILO43ww/***@public.gmane.org<mailto:users-ywjJWXFEILO43ww/***@public.gmane.org>" <users-***@public.gmane.orga.net<mailto:users-ywjJWXFEILO43ww/***@public.gmane.org>>
Subject: [Jersey] JerseClient SSL/TLS connection reuse

(New subject)

Hello,

I’m in need of help to get JerseyClient to reuse connections when using SSL.
We use a client certificate with a truststore (see SSL config code in forwarded mail below)
The application we’ve built integrates with a system on the other side of the Atlantic and the latency is too high if the SSL handshake needs to take place each and every time a request is made.

I’ve looked through all guides and recommendations I’ve found on the internet in configuring the client correctly and checked with this page that we do it correctly.
http://docs.oracle.com/javase/8/docs/technotes/guides/net/http-keepalive.html

The question is if Jersey follows all that specification?

The server we access returns Connection: Keep-Alive and Keep-Alive: timeout=15, max=100 but the client recreates the connection anyway.
The response code is 200 and we read the response fully.

We have managed to get the reuse working with ApacheConnector (after some minor modification) but we haven’t found anyway of doing it with “vanilla” Jersey as we would like it to be.

Thanks,
Roger

From: Roger Nordquist <roger.nordquist-7+TMkytGX/LLoDKTGw+***@public.gmane.org<mailto:***@valtech.se>>
Date: Wednesday 10 September 2014 14:30
To: "users-ywjJWXFEILO43ww/***@public.gmane.org<mailto:users-ywjJWXFEILO43ww/***@public.gmane.org>" <users-***@public.gmane.orga.net<mailto:users-ywjJWXFEILO43ww/***@public.gmane.org>>
Subject: JettyConnector using Proxy over SSL/TLS

Hello,

I am trying to use JettyConnectorProvider in Jersey 2.8 to make requests to a resource behind a proxy using SSL.
The reason why I chosen to replace the default provider is because the default one doesn’t seem to reuse connections according to the setting in the Keep-Alive header as we need it to do.
It’s for performance reasons really, but I can’t get it to work through the proxy.

Here is my setup:
SslConfigurator sslConfig = SslConfigurator
.newInstance()
.trustStore(config.getTrustStore())
.trustManagerFactoryAlgorithm(“SunX509")
.keyPassword(config.getKeystorePass())
.keyManagerFactoryAlgorithm(“SunX509")
.keyStore(keyStore);

ClientConfig clientConfig = new ClientConfig();
clientConfig.connectorProvider(new JettyConnectorProvider());
clientConfig.property(JettyClientProperties.SSL_CONFIG, sslConfig);
clientConfig.property(ClientProperties.CONNECT_TIMEOUT, config.getConnectTimeout());
clientConfig.property(ClientProperties.READ_TIMEOUT, config.getReadTimeout());

if (config.usingHttpProxy()) {
clientConfig.property(ClientProperties.PROXY_URI, String.format("http://%s:%s", config.getHttpProxyHost(), config.getHttpProxyPort()));
}

return ClientBuilder.newBuilder()
.withConfig(clientConfig)
.build()
.register(getJacksonConfiguration())
.register(new LoggingFilter())
.register(new CharacterSetFilter())
.register(new RequestTimeLogging());

The exception I get when using the proxy is the following:

java.nio.channels.ReadPendingException: null
at org.eclipse.jetty.io.FillInterest.register(FillInterest.java:62) ~[jetty-io-9.1.1.v20140108.jar:3.19.0-SNAPSHOT]
at org.eclipse.jetty.io.AbstractEndPoint.fillInterested(AbstractEndPoint.java:119) ~[jetty-io-9.1.1.v20140108.jar:3.19.0-SNAPSHOT]
at org.eclipse.jetty.io.AbstractConnection$FillInterestedState.onEnter(AbstractConnection.java:269) ~[jetty-io-9.1.1.v20140108.jar:3.19.0-SNAPSHOT]
at org.eclipse.jetty.io.AbstractConnection.next(AbstractConnection.java:238) ~[jetty-io-9.1.1.v20140108.jar:3.19.0-SNAPSHOT]
at org.eclipse.jetty.io.AbstractConnection$1.run(AbstractConnection.java:512) ~[jetty-io-9.1.1.v20140108.jar:3.19.0-SNAPSHOT]
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:607) ~[jetty-util-9.1.1.v20140108.jar:3.19.0-SNAPSHOT]
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:536) ~[jetty-util-9.1.1.v20140108.jar:3.19.0-SNAPSHOT]
at java.lang.Thread.run(Unknown Source) [na:1.8.0_05]
2014-09-09 18:02:51,131 ExceptionMapper:24:ERROR - Uncaught exception occurred. - POST /resource …
javax.ws.rs.ProcessingException: java.util.concurrent.ExecutionException: java.io.EOFException
at org.glassfish.jersey.jetty.connector.JettyConnector.apply(JettyConnector.java:277) ~[jersey-jetty-connector-2.8.jar:na]
at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:224) ~[jersey-client-2.8.jar:na]
at org.glassfish.jersey.client.JerseyInvocation$1.call(JerseyInvocation.java:655) ~[jersey-client-2.8.jar:na]
at org.glassfish.jersey.client.JerseyInvocation$1.call(JerseyInvocation.java:652) ~[jersey-client-2.8.jar:na]
at org.glassfish.jersey.internal.Errors.process(Errors.java:315) [jersey-common-2.8.jar:na]
at org.glassfish.jersey.internal.Errors.process(Errors.java:297) [jersey-common-2.8.jar:na]
at org.glassfish.jersey.internal.Errors.process(Errors.java:228) [jersey-common-2.8.jar:na]
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:424) [jersey-common-2.8.jar:na]
at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:652) ~[jersey-client-2.8.jar:na]
at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:412) ~[jersey-client-2.8.jar:na]
at org.glassfish.jersey.client.JerseyInvocation$Builder.post(JerseyInvocation.java:321) ~[jersey-client-2.8.jar:na]
...
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_05]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_05]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_05]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_05]
at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81) ~[jersey-server-2.8.jar:na]
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:151) ~[jersey-server-2.8.jar:na]
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:171) ~[jersey-server-2.8.jar:na]
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:152) ~[jersey-server-2.8.jar:na]
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:104) ~[jersey-server-2.8.jar:na]
at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:387) ~[jersey-server-2.8.jar:na]
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:331) ~[jersey-server-2.8.jar:na]
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:103) ~[jersey-server-2.8.jar:na]
at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:269) ~[jersey-server-2.8.jar:na]
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271) [jersey-common-2.8.jar:na]
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267) [jersey-common-2.8.jar:na]
at org.glassfish.jersey.internal.Errors.process(Errors.java:315) [jersey-common-2.8.jar:na]
at org.glassfish.jersey.internal.Errors.process(Errors.java:297) [jersey-common-2.8.jar:na]
at org.glassfish.jersey.internal.Errors.process(Errors.java:267) [jersey-common-2.8.jar:na]
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:297) [jersey-common-2.8.jar:na]
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:252) [jersey-server-2.8.jar:na]
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1023) [jersey-server-2.8.jar:na]
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:372) [jersey-container-servlet-core-2.8.jar:na]
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:382) [jersey-container-servlet-core-2.8.jar:na]
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:345) [jersey-container-servlet-core-2.8.jar:na]
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:220) [jersey-container-servlet-core-2.8.jar:na]
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:751) []
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1666) []
...
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1645) []
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:564) []
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) []
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:578) []
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:221) []
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1111) []
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:498) []
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:183) []
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1045) []
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) []
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:98) []
at org.eclipse.jetty.server.Server.handle(Server.java:461) []
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:284) []
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:244) []
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:534) []
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:607) []
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:536) []
at java.lang.Thread.run(Unknown Source) [na:1.8.0_05]
Caused by: java.util.concurrent.ExecutionException: java.io.EOFException
at org.eclipse.jetty.client.util.FutureResponseListener.getResult(FutureResponseListener.java:118) ~[jetty-client-9.1.1.v20140108.jar:9.1.1.v20140108]
at org.eclipse.jetty.client.util.FutureResponseListener.get(FutureResponseListener.java:110) ~[jetty-client-9.1.1.v20140108.jar:9.1.1.v20140108]
at org.eclipse.jetty.client.HttpRequest.send(HttpRequest.java:579) ~[jetty-client-9.1.1.v20140108.jar:9.1.1.v20140108]
at org.glassfish.jersey.jetty.connector.JettyConnector.apply(JettyConnector.java:259) ~[jersey-jetty-connector-2.8.jar:na]
... 68 common frames omitted
Caused by: java.io.EOFException: null
at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.earlyEOF(HttpReceiverOverHTTP.java:203) ~[]
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:1261) ~[]
at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.shutdown(HttpReceiverOverHTTP.java:129) ~[]
at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.receive(HttpReceiverOverHTTP.java:91) ~[]
at org.eclipse.jetty.client.http.HttpChannelOverHTTP.receive(HttpChannelOverHTTP.java:75) ~[]
at org.eclipse.jetty.client.http.HttpConnectionOverHTTP.onFillable(HttpConnectionOverHTTP.java:103) ~[]
at org.eclipse.jetty.io.AbstractConnection$1.run(AbstractConnection.java:505) ~[]
... 3 common frames omitted

It looks like it cannot read the response properly but it only happens with the JettyConnector, not the default so I think the proxy is correctly configured.

When not using the proxy it looks like it works perfectly and connections are reused as I want them to, but I can’t say for sure for those tests were only made from my local computer, not the environment I get this exception on.

And btw, we are not using any asynchronous calls so this exception is kinda confusing :S

Is some additional configuration needed that I’m not aware of?
Any ideaŽs and pointers are welcome as I’m pretty stuck right now! :)

Thanks!

/Roger

Loading...