Java 带有jdk8的Conscrypt可为http2启用ALPN
我一直在研究如何使用jdk8的Conscrypt-openjdk-uber-1.4.1.jar实现ConscryptSSL提供程序,以支持ALPN生成http2(使用apachehttpclient 5)连接到服务器时,默认情况下jdk8不支持ALPN,或者另一种解决方案是迁移到jdk9(或更高版本),这在目前是不可行的,因为我们的产品严重依赖jdk8 我一直在广泛地搜索一些要实现的文档或示例,但找不到 我尝试将conscrypt provider作为默认提供程序插入,我的程序将其作为默认提供程序,但它仍然无法连接到http2服务器,我的示例如下:Java 带有jdk8的Conscrypt可为http2启用ALPN,java,apache-httpclient-4.x,http2,alpn,apache-httpclient-5.x,Java,Apache Httpclient 4.x,Http2,Alpn,Apache Httpclient 5.x,我一直在研究如何使用jdk8的Conscrypt-openjdk-uber-1.4.1.jar实现ConscryptSSL提供程序,以支持ALPN生成http2(使用apachehttpclient 5)连接到服务器时,默认情况下jdk8不支持ALPN,或者另一种解决方案是迁移到jdk9(或更高版本),这在目前是不可行的,因为我们的产品严重依赖jdk8 我一直在广泛地搜索一些要实现的文档或示例,但找不到 我尝试将conscrypt provider作为默认提供程序插入,我的程序将其作为默认提供程
public static void main(final String[] args) throws Exception {
Security.insertProviderAt(new OpenSSLProvider(), 1);
final SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(new TrustAllStrategy()).build();
final PoolingAsyncClientConnectionManager connectionManager = PoolingAsyncClientConnectionManagerBuilder.create().setTlsStrategy(new H2TlsStrategy(sslContext, NoopHostnameVerifier.INSTANCE)).build();
final IOReactorConfig ioReactorConfig = IOReactorConfig.custom().setSoTimeout(Timeout.ofSeconds(5)).build();
final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal(HttpVersionPolicy.FORCE_HTTP_2, H2Config.DEFAULT, null, ioReactorConfig, connectionManager);
client.start();
final HttpHost target = new HttpHost("localhost", 8082, "https");
final Future<AsyncClientEndpoint> leaseFuture = client.lease(target, null);
final AsyncClientEndpoint endpoint = leaseFuture.get(10, TimeUnit.SECONDS);
try {
String[] requestUris = new String[] {"/"};
CountDownLatch latch = new CountDownLatch(requestUris.length);
for (final String requestUri: requestUris) {
SimpleHttpRequest request = SimpleHttpRequest.get(target, requestUri);
endpoint.execute(SimpleRequestProducer.create(request), SimpleResponseConsumer.create(), new FutureCallback<SimpleHttpResponse>() {
@Override
public void completed(final SimpleHttpResponse response) {
latch.countDown();
System.out.println(requestUri + "->" + response.getCode());
System.out.println(response.getBody());
}
@Override
public void failed(final Exception ex) {
latch.countDown();
System.out.println(requestUri + "->" + ex);
ex.printStackTrace();
}
@Override
public void cancelled() {
latch.countDown();
System.out.println(requestUri + " cancelled");
}
});
}
latch.await();
} catch (Exception e) {
e.printStackTrace();
}finally {
endpoint.releaseAndReuse();
}
client.shutdown(ShutdownType.GRACEFUL);
}
publicstaticvoidmain(最终字符串[]args)引发异常{
insertProviderAt(新的OpenSSLProvider(),1);
最终SSLContext SSLContext=SSLContexts.custom().loadTrustMaterial(新的TrustAllStrategy()).build();
最终PoolgasSyncClient连接管理器connectionManager=PoolgasSyncClient连接管理器builder.create().SettlesStrategy(新的H2TlsStrategy(sslContext,NoopHostnameVerifier.INSTANCE)).build();
最终IOReactorConfig IOReactorConfig=IOReactorConfig.custom().setSoTimeout(Timeout.ofSeconds(5)).build();
final MinimalHttpAsyncClient客户端=HttpAsyncClients.createMinimal(HttpVersionPolicy.FORCE_HTTP_2,H2Config.DEFAULT,null,ioReactorConfig,connectionManager);
client.start();
最终HttpHost目标=新HttpHost(“localhost”,8082,“https”);
最终未来租赁未来=client.lease(target,null);
最终AsyncClientEndpoint端点=leaseFuture.get(10,TimeUnit.SECONDS);
试一试{
String[]requestUris=新字符串[]{”/“};
CountDownLatch闩锁=新的CountDownLatch(requestUris.length);
for(最终字符串requestUri:requestUris){
SimpleHttpRequest请求=SimpleHttpRequest.get(目标,请求URI);
execute(SimpleRequestProducer.create(请求)、SimpleResponseConsumer.create()、new FutureCallback()){
@凌驾
公共作废已完成(最终SimpleHttpResponse响应){
倒计时();
System.out.println(requestUri+“->”+response.getCode());
System.out.println(response.getBody());
}
@凌驾
公共作废失败(最终例外情况除外){
倒计时();
System.out.println(requestUri+“->”+ex);
例如printStackTrace();
}
@凌驾
公众假期取消(){
倒计时();
System.out.println(requestUri+“已取消”);
}
});
}
satch.wait();
}捕获(例外e){
e、 printStackTrace();
}最后{
endpoint.releaseAndReuse();
}
client.shutdown(ShutdownType.优雅);
}
该程序将输出为
org.apache.hc.core5.http.ConnectionClosedException:连接已关闭
org.apache.hc.core5.http.ConnectionClosedException:连接已关闭
位于org.apache.hc.core5.http2.impl.nio.FrameInputBuffer.read(FrameInputBuffer.java:146)
位于org.apache.hc.core5.http2.impl.nio.AbstractHttp2StreamMultiplexer.onInput(AbstractHttp2StreamMultiplexer.java:415)
位于org.apache.hc.core5.http2.impl.nio.AbstractHttp2IOEventHandler.inputReady(AbstractHttp2IOEventHandler.java:63)
位于org.apache.hc.core5.http2.impl.nio.clienthttpp2ioeventhandler.inputReady(clienthttpp2ioeventhandler.java:38)
位于org.apache.hc.core5.reactor.InternalDataChannel.onIOEvent(InternalDataChannel.java:117)
在org.apache.hc.core5.reactor.InternalChannel.handleIOEvent(InternalChannel.java:50)上
位于org.apache.hc.core5.reactor.SingleCoreiorreactor.processEvents(singleCoreiorreactor.java:173)
在org.apache.hc.core5.reactor.SingleCoreiorreactor.doExecute(singleCoreiorreactor.java:123)
位于org.apache.hc.core5.reactor.AbstractSingleCoreIOReactor.execute(AbstractSingleCoreIOReactor.java:80)
位于org.apache.hc.core5.reactor.IOReactorWorker.run(IOReactorWorker.java:44)
运行(Thread.java:748)
如果我将提供程序和版本打印为Conscrypt version 1.0和JDK 1.8.0¢,但它仍然无法连接到http2端点
如果我使用jdk9和默认提供程序进行连接,同样的代码块可以完美地工作,我在conscrypt配置中缺少了什么
谢谢你的帮助
提前感谢仅用Conscrypt替换默认的JSSE提供程序是不够的。我们还需要一个定制的
TlsStrategy
,它可以利用Conscrypt API
这就是我在Java1.8和Conscrypt1.4.1中的工作原理
static class ConscriptClientTlsStrategy implements TlsStrategy {
private final SSLContext sslContext;
public ConscriptClientTlsStrategy(final SSLContext sslContext) {
this.sslContext = Args.notNull(sslContext, "SSL context");
}
@Override
public boolean upgrade(
final TransportSecurityLayer tlsSession,
final HttpHost host,
final SocketAddress localAddress,
final SocketAddress remoteAddress,
final Object attachment) {
final String scheme = host != null ? host.getSchemeName() : null;
if (URIScheme.HTTPS.same(scheme)) {
tlsSession.startTls(
sslContext,
host,
SSLBufferMode.STATIC,
(endpoint, sslEngine) -> {
final SSLParameters sslParameters = sslEngine.getSSLParameters();
sslParameters.setProtocols(H2TlsSupport.excludeBlacklistedProtocols(sslParameters.getProtocols()));
sslParameters.setCipherSuites(H2TlsSupport.excludeBlacklistedCiphers(sslParameters.getCipherSuites()));
H2TlsSupport.setEnableRetransmissions(sslParameters, false);
final HttpVersionPolicy versionPolicy = attachment instanceof HttpVersionPolicy ?
(HttpVersionPolicy) attachment : HttpVersionPolicy.NEGOTIATE;
final String[] appProtocols;
switch (versionPolicy) {
case FORCE_HTTP_1:
appProtocols = new String[] { ApplicationProtocols.HTTP_1_1.id };
break;
case FORCE_HTTP_2:
appProtocols = new String[] { ApplicationProtocols.HTTP_2.id };
break;
default:
appProtocols = new String[] { ApplicationProtocols.HTTP_2.id, ApplicationProtocols.HTTP_1_1.id };
}
if (Conscrypt.isConscrypt(sslEngine)) {
sslEngine.setSSLParameters(sslParameters);
Conscrypt.setApplicationProtocols(sslEngine, appProtocols);
} else {
H2TlsSupport.setApplicationProtocols(sslParameters, appProtocols);
sslEngine.setSSLParameters(sslParameters);
}
},
(endpoint, sslEngine) -> {
if (Conscrypt.isConscrypt(sslEngine)) {
return new TlsDetails(sslEngine.getSession(), Conscrypt.getApplicationProtocol(sslEngine));
}
return null;
});
return true;
}
return false;
}
}
public static void main(String[] args) throws Exception {
final SSLContext sslContext = SSLContexts.custom()
.setProvider(Conscrypt.newProvider())
.build();
final PoolingAsyncClientConnectionManager cm = PoolingAsyncClientConnectionManagerBuilder.create()
.setTlsStrategy(new ConscriptClientTlsStrategy(sslContext))
.build();
try (CloseableHttpAsyncClient client = HttpAsyncClients.custom()
.setVersionPolicy(HttpVersionPolicy.NEGOTIATE)
.setConnectionManager(cm)
.build()) {
client.start();
final HttpHost target = new HttpHost("nghttp2.org", 443, "https");
final String requestUri = "/httpbin";
final HttpClientContext clientContext = HttpClientContext.create();
final SimpleHttpRequest request = SimpleHttpRequests.GET.create(target, requestUri);
final Future<SimpleHttpResponse> future = client.execute(
SimpleRequestProducer.create(request),
SimpleResponseConsumer.create(),
clientContext,
new FutureCallback<SimpleHttpResponse>() {
@Override
public void completed(final SimpleHttpResponse response) {
System.out.println(requestUri + "->" + response.getCode() + " " +
clientContext.getProtocolVersion());
System.out.println(response.getBody());
final SSLSession sslSession = clientContext.getSSLSession();
if (sslSession != null) {
System.out.println("SSL protocol " + sslSession.getProtocol());
System.out.println("SSL cipher suite " + sslSession.getCipherSuite());
}
}
@Override
public void failed(final Exception ex) {
System.out.println(requestUri + "->" + ex);
}
@Override
public void cancelled() {
System.out.println(requestUri + " cancelled");
}
});
future.get();
System.out.println("Shutting down");
client.shutdown(CloseMode.GRACEFUL);
}
}
静态类ConscriptClientTlsStrategy实现TlsStrategy{
专用最终SSLContext SSLContext;
公共征兵客户策略(最终SSLContext SSLContext){
this.sslContext=Args.notNull(sslContext,“SSL上下文”);
}
@凌驾
公共布尔升级(
最终传输安全层tlsSession,
最终HttpHost主机,
最终SocketAddress本地地址,
最终SocketAddress远程地址,
最终对象(附件){
最后一个字符串scheme=host!=null?host.getSchemeName():null;
if(URIScheme.HTTPS.same(scheme)){
tlsSession.startTls(
sslContext,
主办
SSLBufferMode.STATIC,
(端点,sslEngine)->{
最终SSLParameters SSLParameters=sslEng