Hi folks,
We found that this particular piece of code in okhttp 3.x: https://github.com/square/okhttp/blob/okhttp_3.14.x/okhttp/src/main/java/okhttp3/internal/platform/Jdk9Platform.java#L81-L94 breaks.
This checks for setApplicationProtocols and getApplicationProtocol which are JDK 9. however, these ones got backported to Zulu 8.0.252 causing OkHttp believing that is running on jdk9 and initializing a Jdk9Platform which breaks projects
Wondering if a patch could be released for 3.x since there are several libraries and projects out there that haven't migrated to 4.x
Thanks
Can you explain more about why it breaks projects. If these methods are here, isn't it correct to use this Platform? What do you want it to do?
Do you want it to use alpn-boot library, or just not support http/2 via ALPN?
Those methods are being used to detect Java 9 ALPN support however they're now available on Java 8, but ALPN support is not, so cause runtime failures due to the Jdk9Platform being used:
java.lang.AssertionError: failed to get ALPN selected protocol
at okhttp3.internal.platform.Jdk9Platform.getSelectedProtocol(Jdk9Platform.java:68) ~[carson-0.461.0-all.jar:0.461.0]
a41361efcb0d4ed2e7f09313c9e9fcc3d72e837b is what makes >4.3.0 work with 8u252
@DanielThomas Do you have the root cause exception? Maybe the right fix is to make it work correctly here?
throw new AssertionError("failed to get ALPN selected protocol", e);
I'm also curious why this was backported in what was presumably a very recent release https://docs.azul.com/zulu/zulurelnotes/ZuluReleaseNotes/CA_What'sNew.htm
a41361e is what makes >4.3.0 work with 8u252
Yep, but the reflection in 3.14 and the directly compiled code in 4.x should act the same.
Here's the upstream change https://hg.openjdk.java.net/jdk8u/jdk8u41/jdk/rev/b26b096d4c89
Full stack trace:
java.lang.AssertionError: failed to get ALPN selected protocol
at okhttp3.internal.platform.Jdk9Platform.getSelectedProtocol(Jdk9Platform.java:68) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:363) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:300) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:185) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.java:224) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.java:108) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.java:88) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.internal.connection.Transmitter.newExchange(Transmitter.java:169) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:41) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:94) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:88) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:223) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117) ~[carson-0.461.0-all.jar:0.461.0]
at com.netflix.engtools.carson.JenkinsClient$userAgentUpdate$1.invoke(JenkinsClient.kt:32) ~[carson-0.461.0-all.jar:0.461.0]
at com.netflix.engtools.carson.JenkinsClient$userAgentUpdate$1.invoke(JenkinsClient.kt:19) ~[carson-0.461.0-all.jar:0.461.0]
at com.netflix.engtools.carson.JenkinsClient$sam$okhttp3_Interceptor$0.intercept(JenkinsClient.kt) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:229) ~[carson-0.461.0-all.jar:0.461.0]
at okhttp3.RealCall.execute(RealCall.java:81) ~[carson-0.461.0-all.jar:0.461.0]
at retrofit2.OkHttpCall.execute(OkHttpCall.java:190) ~[carson-0.461.0-all.jar:0.461.0]
...
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_252]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_252]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_252]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_252]
at okhttp3.internal.platform.Jdk9Platform.getSelectedProtocol(Jdk9Platform.java:58) ~[carson-0.461.0-all.jar:0.461.0]
... 37 more
Caused by: java.lang.UnsupportedOperationException
at javax.net.ssl.SSLSocket.getApplicationProtocol(SSLSocket.java:691) ~[?:1.8.0_252]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_252]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_252]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_252]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_252]
at okhttp3.internal.platform.Jdk9Platform.getSelectedProtocol(Jdk9Platform.java:58) ~[carson-0.461.0-all.jar:0.461.0]
... 37 more
Why would anyone do that????
public String getApplicationProtocol() {
throw new UnsupportedOperationException();
}
It's part of the contract for that method:
https://docs.oracle.com/javase/9/docs/api/javax/net/ssl/SSLSocket.html#getApplicationProtocol--
FWIW it's exactly how SSLSocket looks on Java 9 onwards too, but SSLSocketImpl implements it.
Fair point, probably need two fixes then.
1) This fix to avoid using this on JDK8.
2) Catch UnsupportedOperationException and return null here.
The first point could possibly be optional if you don't mind ALPN not working on zulu JDK8. Do you actively support the alpn-boot mechanism?
Yeah, we have a few applications that install the native modules required for JDK 8 ALPN support.
Hmmmm.... alpn-boot says it isn't needed on 252+
https://www.eclipse.org/jetty/documentation/current/alpn-chapter.html
1.8.0u242 | 8.1.13.v20181017
-- | --
1.8.0u252 and later | NOT NECESSARY
If you use OpenJDK 8u251/8u252 or later, you must NOT add the Jetty ALPN boot jar to the bootclasspath.
Oh yeah, interesting. I wonder what SSLSocketImpl we're getting at runtime...
Yeah, OpenJDK seems to support this see SSLSocketImpl in https://hg.openjdk.java.net/jdk8u/jdk8u41/jdk/rev/b26b096d4c89
Oh yeah, interesting. I wonder what
SSLSocketImplwe're getting at runtime...
OpenJSSE? https://docs.azul.com/openjsse/Title.htm
We're not opting in, and org.openjsse.sun.security.ssl.SSLSocketImpl implements getApplicationProtocol. Going to try and get an easily reproducible case here to see what impl we're actually getting.
Thanks, I don't think the fix is to avoid JDK9Platform. But probably to catch that exception and continue. Since we can't fallback to alpn-boot in this case anyway.
Ah! It's the combination of the JDK 9 platform activation our internal mTLS wrapper that delegates to the underlying impl that's breaking this on our end - it doesn't implement those methods causing those calls to fall through to SslSocket and hit the UnsupportedOperationException. Guess we'll have to conditionally drop in the right wrapper depending on the method availability.
Guess u252 and upwards still needs a leg up on OkHttp 3 and 4 so the built-in ALPN support _does_ activate there. Seems like OkHttp 3 will work by default, OkHttp 4 will not activate built-in ALPN support in this release.
Thanks for raising it and the discussion.
@rpalcolea or @DanielThomas Are you able to test with a local snapshot build?
@DanielThomas can we track the fix in your "internal mTLS wrapper" somewhere? That should reenable HTTP/2 on Zulu also.
Sure can - let us know where to pickup your snapshots and we'll give it a try.
Our wrapper is fixed, we switched to a javaassist generated proxy, so we should be good to go there.
@DanielThomas No easy option off the branches unfortunately so
$ git clone https://github.com/square/okhttp
$ git checkout okhttp_3.14.x
$ mvn package
$ cp okhttp/target/okhttp-3.14.8-SNAPSHOT.jar ...
Looks great! JDK 9 platform activates and the fallback for UnsupportedOperationException for our incompatible SslSocket wrapper successfully falls back to HTTP/1.