Skip to content

HTTPS urls cause NPE when using Jetty Reactor #16810

@Sineaggi

Description

@Sineaggi

Affects: 5.1.x, 5.2.x


This code

@Autowired
private WebClient.Builder builder;
public void run(String... args) {
    String result = builder.build().get().uri("https://www.google.com").retrieve().bodyToMono(String.class).block();
}

using a dependency list like

dependencies {
    compile("org.springframework.boot:spring-boot-starter")
    compile("org.springframework.boot:spring-boot-starter-webflux") {
        exclude group: "org.springframework.boot", module: "spring-boot-starter-reactor-netty"
    }
    compile("org.springframework.boot:spring-boot-starter-jetty")
    compile("org.eclipse.jetty:jetty-reactive-httpclient")
    compile("org.springframework:spring-webflux")
}

causes exceptions due to a missing SslContextFactory

2019-05-02 12:48:31.061 ERROR 6144 --- [           main] o.s.boot.SpringApplication               : Application run failed

java.lang.IllegalStateException: Failed to execute CommandLineRunner
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:816) ~[spring-boot-2.1.4.RELEASE.jar:2.1.4.RELEASE]
	at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:797) ~[spring-boot-2.1.4.RELEASE.jar:2.1.4.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:324) ~[spring-boot-2.1.4.RELEASE.jar:2.1.4.RELEASE]
	at bnf.App.main(App.java:26) [classes/:na]
Caused by: java.lang.NullPointerException: Missing SslContextFactory
	at java.util.Objects.requireNonNull(Objects.java:228) ~[na:1.8.0_202]
	at org.eclipse.jetty.io.ssl.SslClientConnectionFactory.<init>(SslClientConnectionFactory.java:55) ~[jetty-io-9.4.15.v20190215.jar:9.4.15.v20190215]
	at org.eclipse.jetty.client.HttpClient.newSslClientConnectionFactory(HttpClient.java:1170) ~[jetty-client-9.4.15.v20190215.jar:9.4.15.v20190215]
	at org.eclipse.jetty.client.HttpDestination.newSslClientConnectionFactory(HttpDestination.java:137) ~[jetty-client-9.4.15.v20190215.jar:9.4.15.v20190215]
	at org.eclipse.jetty.client.HttpDestination.<init>(HttpDestination.java:94) ~[jetty-client-9.4.15.v20190215.jar:9.4.15.v20190215]
	at org.eclipse.jetty.client.PoolingHttpDestination.<init>(PoolingHttpDestination.java:25) ~[jetty-client-9.4.15.v20190215.jar:9.4.15.v20190215]
	at org.eclipse.jetty.client.http.HttpDestinationOverHTTP.<init>(HttpDestinationOverHTTP.java:32) ~[jetty-client-9.4.15.v20190215.jar:9.4.15.v20190215]
	at org.eclipse.jetty.client.http.HttpClientTransportOverHTTP.newHttpDestination(HttpClientTransportOverHTTP.java:51) ~[jetty-client-9.4.15.v20190215.jar:9.4.15.v20190215]
	at org.eclipse.jetty.client.HttpClient.destinationFor(HttpClient.java:542) ~[jetty-client-9.4.15.v20190215.jar:9.4.15.v20190215]
	at org.eclipse.jetty.client.HttpClient.send(HttpClient.java:575) ~[jetty-client-9.4.15.v20190215.jar:9.4.15.v20190215]
	at org.eclipse.jetty.client.HttpRequest.send(HttpRequest.java:726) ~[jetty-client-9.4.15.v20190215.jar:9.4.15.v20190215]
	at org.eclipse.jetty.client.HttpRequest.send(HttpRequest.java:718) ~[jetty-client-9.4.15.v20190215.jar:9.4.15.v20190215]
	at org.eclipse.jetty.reactive.client.internal.ResponseListenerPublisher.send(ResponseListenerPublisher.java:137) ~[jetty-reactive-httpclient-1.0.3.jar:na]
	at org.eclipse.jetty.reactive.client.internal.ResponseListenerPublisher.onRequest(ResponseListenerPublisher.java:123) ~[jetty-reactive-httpclient-1.0.3.jar:na]
	at org.eclipse.jetty.reactive.client.internal.AbstractSinglePublisher.request(AbstractSinglePublisher.java:91) ~[jetty-reactive-httpclient-1.0.3.jar:na]
	at reactor.core.publisher.MonoNext$NextSubscriber.request(MonoNext.java:102) ~[reactor-core-3.2.8.RELEASE.jar:3.2.8.RELEASE]
	at reactor.core.publisher.MonoIgnoreThen$ThenAcceptInner.onSubscribe(MonoIgnoreThen.java:285) ~[reactor-core-3.2.8.RELEASE.jar:3.2.8.RELEASE]
	at reactor.core.publisher.MonoNext$NextSubscriber.onSubscribe(MonoNext.java:64) ~[reactor-core-3.2.8.RELEASE.jar:3.2.8.RELEASE]
	at org.eclipse.jetty.reactive.client.internal.AbstractSinglePublisher.subscribe(AbstractSinglePublisher.java:63) ~[jetty-reactive-httpclient-1.0.3.jar:na]
	at reactor.core.publisher.MonoFromPublisher.subscribe(MonoFromPublisher.java:43) ~[reactor-core-3.2.8.RELEASE.jar:3.2.8.RELEASE]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.drain(MonoIgnoreThen.java:153) ~[reactor-core-3.2.8.RELEASE.jar:3.2.8.RELEASE]
	at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:56) ~[reactor-core-3.2.8.RELEASE.jar:3.2.8.RELEASE]
	at reactor.core.publisher.MonoPeekFuseable.subscribe(MonoPeekFuseable.java:74) ~[reactor-core-3.2.8.RELEASE.jar:3.2.8.RELEASE]
	at reactor.core.publisher.MonoPeekFuseable.subscribe(MonoPeekFuseable.java:74) ~[reactor-core-3.2.8.RELEASE.jar:3.2.8.RELEASE]
	at reactor.core.publisher.MonoMapFuseable.subscribe(MonoMapFuseable.java:59) ~[reactor-core-3.2.8.RELEASE.jar:3.2.8.RELEASE]
	at reactor.core.publisher.MonoSwitchIfEmpty.subscribe(MonoSwitchIfEmpty.java:44) ~[reactor-core-3.2.8.RELEASE.jar:3.2.8.RELEASE]
	at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:60) ~[reactor-core-3.2.8.RELEASE.jar:3.2.8.RELEASE]
	at reactor.core.publisher.Mono.block(Mono.java:1493) ~[reactor-core-3.2.8.RELEASE.jar:3.2.8.RELEASE]
	at bnf.App.run(App.java:32) [classes/:na]
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:813) ~[spring-boot-2.1.4.RELEASE.jar:2.1.4.RELEASE]
	... 3 common frames omitted

as far as I can tell, the SslContextFactory being initialized to null due to the constructors used by org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorConfiguration.JettyClient:73

@Bean
public JettyClientHttpConnector jettyClientHttpConnector(
		JettyResourceFactory jettyResourceFactory) {
	return new JettyClientHttpConnector(jettyResourceFactory, (httpClient) -> {
	});
}

I was able to work around this in my code by registering my own JettyClientHttpConnector with with an SslContextFactory

@Bean
fun jettyClientHttpConnector(): JettyClientHttpConnector {
    val resourceFactory = JettyResourceFactory()
    val ssl = SslContextFactory()
    val httpClient = HttpClient(ssl).apply {
        executor = resourceFactory.executor
        byteBufferPool = resourceFactory.byteBufferPool
        scheduler = resourceFactory.scheduler
    }
    return JettyClientHttpConnector(httpClient)
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions