I'm trying to create multiple asynchronous HTTP connections using single client endpoint I have tried the multiplexing example given in Apache site
the code snippet is as follows,
final IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
.setSoTimeout(Timeout.ofSeconds(5))
.build();
final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal(
HttpVersionPolicy.FORCE_HTTP_2, H2Config.DEFAULT, null, ioReactorConfig);
client.start();
final HttpHost target = new HttpHost("localhost", 7070, "https");
final Future<AsyncClientEndpoint> leaseFuture = client.lease(target, null);
final AsyncClientEndpoint endpoint = leaseFuture.get(30, TimeUnit.SECONDS);
try {
final String[] requestUris = new String[] {"/test.html"};
final CountDownLatch latch = new CountDownLatch(requestUris.length);
for (final String requestUri: requestUris) {
final 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);
}
@Override
public void cancelled() {
latch.countDown();
System.out.println(requestUri + " cancelled");
}
});
}
latch.await();
} finally {
endpoint.releaseAndReuse();
}
System.out.println("Shutting down");
client.shutdown(ShutdownType.GRACEFUL);
This example works properly for a site which have a valid certificate, but if I want to try a site which certificate is expired/self signed, it throws the following exceptions
javax.net.ssl.SSLHandshakeException: General SSLEngine problem javax.net.ssl.SSLHandshakeException: General SSLEngine problem at sun.security.ssl.Handshaker.checkThrown(Handshaker.java:1478) at sun.security.ssl.SSLEngineImpl.checkTaskThrown(SSLEngineImpl.java:535) at sun.security.ssl.SSLEngineImpl.writeAppRecord(SSLEngineImpl.java:1214) at sun.security.ssl.SSLEngineImpl.wrap(SSLEngineImpl.java:1186) at javax.net.ssl.SSLEngine.wrap(SSLEngine.java:469) at org.apache.hc.core5.reactor.ssl.SSLIOSession.doWrap(SSLIOSession.java:256) at org.apache.hc.core5.reactor.ssl.SSLIOSession.doHandshake(SSLIOSession.java:294) at org.apache.hc.core5.reactor.ssl.SSLIOSession.isAppInputReady(SSLIOSession.java:502) at org.apache.hc.core5.reactor.InternalDataChannel.onIOEvent(InternalDataChannel.java:112) at org.apache.hc.core5.reactor.InternalChannel.handleIOEvent(InternalChannel.java:50) at org.apache.hc.core5.reactor.SingleCoreIOReactor.processEvents(SingleCoreIOReactor.java:173) at org.apache.hc.core5.reactor.SingleCoreIOReactor.doExecute(SingleCoreIOReactor.java:123) at org.apache.hc.core5.reactor.AbstractSingleCoreIOReactor.execute(AbstractSingleCoreIOReactor.java:80) at org.apache.hc.core5.reactor.IOReactorWorker.run(IOReactorWorker.java:44) at java.lang.Thread.run(Thread.java:748) Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1728) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:304) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1514) at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216) at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026) at sun.security.ssl.Handshaker$1.run(Handshaker.java:966) at sun.security.ssl.Handshaker$1.run(Handshaker.java:963) at java.security.AccessController.doPrivileged(Native Method) at sun.security.ssl.Handshaker$DelegatedTask.run(Handshaker.java:1416) at org.apache.hc.core5.reactor.ssl.SSLIOSession.doRunTask(SSLIOSession.java:274) at org.apache.hc.core5.reactor.ssl.SSLIOSession.doHandshake(SSLIOSession.java:331) ... 8 more Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:397) at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302) at sun.security.validator.Validator.validate(Validator.java:260) at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324) at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:281) at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:136) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1501) ... 16 more Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280) at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392) ... 22 more
What I have tried: I created a socket factory that trusts all certificates and tried setting in connectionManager but that creates a CloseableHttpClient and I think which cannot be used for asynchronous multiplexing, the code is as follows
SSLContext sslContext = SSLContextBuilder
.create()
.loadTrustMaterial(new TrustSelfSignedStrategy())
.build();
// we can optionally disable hostname verification.
// if you don't want to further weaken the security, you don't have to include this.
HostnameVerifier allowAllHosts = new NoopHostnameVerifier();
// create an SSL Socket Factory to use the SSLContext with the trust self signed certificate strategy
// and allow all hosts verifier.
SSLConnectionSocketFactory connectionFactory = new SSLConnectionSocketFactory(sslContext, allowAllHosts);
Registry<ConnectionSocketFactory> r = RegistryBuilder.<ConnectionSocketFactory>create().register("https", connectionFactory).build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(r);
CloseableHttpClient build = HttpClients.custom().setConnectionManager(cm).build();
Kindly let me know if there are any ways or workarounds to ignore self signed certificates in MinimalHttpAsyncClient.
First off, configure SSL context to be used by your application. It is highly advisable to make it trust only specific self-signed certificate if you absolutely have to do so, instead of trusting all certificates indiscriminately
final SSLContext sslContext = SSLContexts.custom()
.loadTrustMaterial(new TrustAllStrategy())
.build();
Create a custom connection manager with the given SSL context
final PoolingAsyncClientConnectionManager connectionManager = PoolingAsyncClientConnectionManagerBuilder.create()
.setTlsStrategy(new H2TlsStrategy(sslContext, NoopHostnameVerifier.INSTANCE))
.build();
Create a custom HttpAsyncClient
instance with the given connection manager
final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal(
HttpVersionPolicy.FORCE_HTTP_2,
H2Config.DEFAULT,
null,
ioReactorConfig,
connectionManager);
Alternatively, if you only care about HTTP/2 and do not need a client with HTTP/1.1 fall-back, consider using an HTTP/2 optimized implementations. A minimal implementation will provide essential message transport features (no state management, no authentication, no caching, no automatic redirects) with a least possible overhead.
final MinimalHttp2AsyncClient h2ClientMinimal = HttpAsyncClients.createHttp2Minimal(
H2Config.DEFAULT,
ioReactorConfig,
new H2TlsStrategy(sslContext, NoopHostnameVerifier.INSTANCE));
A full-featured implementation will provide a fully featured HTTP/2 transport with all the functionality supported by the classic HttpClient
with a sole exception of transparent content decompression:
final HttpAsyncClient h2Client = HttpAsyncClients.customHttp2()
.setIOReactorConfig(ioReactorConfig)
.setTlsStrategy(new H2TlsStrategy(sslContext, NoopHostnameVerifier.INSTANCE))
.build();
Hope this helps