Skip to content

Netty ProxyHandler not configured with connect timeout of vertx client #5634

@Adelrisk

Description

@Adelrisk

Version

4.5.12

Context

Due to a bad actor in an external network, my team and I have discovered that the configured ProxyHandler (from netty) does not configure the connection timeout when deploying the proxy handler:

The uncalled method setConnectTimeoutMillis: https://netty.io/4.1/api/io/netty/handler/proxy/ProxyHandler.html#setConnectTimeoutMillis-long-

As far as I know, the ProxyHandler is deployed here in ChannelProvider:

Problem

The bad actor will randomly/sometimes take 10 seconds to accept a HTTP connection. (We measured from our side of the proxy. Only this one server, and the connect takes either milliseconds, or 10 seconds plus milliseconds.)

This is unfortunate, because the default timeout in netty is 10 seconds:

https://github.com/netty/netty/blob/c269a0116d8911ac7179d4ed55108f14fe618cf4/handler-proxy/src/main/java/io/netty/handler/proxy/ProxyHandler.java#L48

This will just as consistently lead to the following exception:

jakarta.ws.rs.ProcessingException: io.netty.handler.proxy.ProxyConnectException: http, basic, /[<IPv6 address>]:7071 => <the bad actor>, timeout
	at org.jboss.resteasy.reactive.client.handlers.ClientSendRequestHandler$2.accept(ClientSendRequestHandler.java:225)
	at org.jboss.resteasy.reactive.client.handlers.ClientSendRequestHandler$2.accept(ClientSendRequestHandler.java:217)
	at io.smallrye.context.impl.wrappers.SlowContextualConsumer.accept(SlowContextualConsumer.java:21)
	at io.smallrye.mutiny.helpers.UniCallbackSubscriber.onFailure(UniCallbackSubscriber.java:62)
	at io.smallrye.mutiny.operators.uni.UniOperatorProcessor.onFailure(UniOperatorProcessor.java:55)
	at org.jboss.resteasy.reactive.client.AsyncResultUni.lambda$subscribe$1(AsyncResultUni.java:37)
	at io.vertx.core.impl.future.FutureImpl$4.onFailure(FutureImpl.java:188)
	at io.vertx.core.impl.future.FutureBase.lambda$emitFailure$1(FutureBase.java:75)
	at io.vertx.core.impl.ContextImpl.execute(ContextImpl.java:312)
	at io.vertx.core.impl.DuplicatedContext.execute(DuplicatedContext.java:168)
	at io.vertx.core.impl.future.FutureBase.emitFailure(FutureBase.java:72)
	at io.vertx.core.impl.future.FutureImpl.tryFail(FutureImpl.java:278)
	at io.vertx.core.http.impl.HttpClientImpl.lambda$doRequest$4(HttpClientImpl.java:398)
	at io.vertx.core.net.impl.pool.Endpoint.lambda$getConnection$0(Endpoint.java:52)
	at io.vertx.core.http.impl.SharedClientHttpStreamEndpoint$Request.handle(SharedClientHttpStreamEndpoint.java:162)
	at io.vertx.core.http.impl.SharedClientHttpStreamEndpoint$Request.handle(SharedClientHttpStreamEndpoint.java:123)
	at io.vertx.core.impl.ContextImpl.emit(ContextImpl.java:342)
	at io.vertx.core.impl.ContextImpl.emit(ContextImpl.java:335)
	at io.vertx.core.net.impl.pool.SimpleConnectionPool$ConnectFailed$1.run(SimpleConnectionPool.java:380)
	at io.vertx.core.net.impl.pool.Task.runNextTasks(Task.java:43)
	at io.vertx.core.net.impl.pool.CombinerExecutor.submit(CombinerExecutor.java:91)
	at io.vertx.core.net.impl.pool.SimpleConnectionPool.execute(SimpleConnectionPool.java:244)
	at io.vertx.core.net.impl.pool.SimpleConnectionPool.lambda$connect$2(SimpleConnectionPool.java:258)
	at io.vertx.core.http.impl.SharedClientHttpStreamEndpoint.lambda$connect$2(SharedClientHttpStreamEndpoint.java:104)
	at io.vertx.core.impl.future.FutureImpl$4.onFailure(FutureImpl.java:188)
	at io.vertx.core.impl.future.FutureBase.emitFailure(FutureBase.java:81)
	at io.vertx.core.impl.future.FutureImpl.tryFail(FutureImpl.java:278)
	at io.vertx.core.impl.future.Composition$1.onFailure(Composition.java:66)
	at io.vertx.core.impl.future.FutureBase.emitFailure(FutureBase.java:81)
	at io.vertx.core.impl.future.FailedFuture.addListener(FailedFuture.java:98)
	at io.vertx.core.impl.future.Composition.onFailure(Composition.java:55)
	at io.vertx.core.impl.future.FutureBase.emitFailure(FutureBase.java:81)
	at io.vertx.core.impl.future.FutureImpl.tryFail(FutureImpl.java:278)
	at io.vertx.core.impl.ContextImpl.emit(ContextImpl.java:342)
	at io.vertx.core.impl.ContextImpl.emit(ContextImpl.java:335)
	at io.vertx.core.net.impl.NetClientImpl.failed(NetClientImpl.java:351)
	at io.vertx.core.net.impl.NetClientImpl.lambda$connectInternal2$6(NetClientImpl.java:323)
	at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:603)
	at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:570)
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:505)
	at io.netty.util.concurrent.DefaultPromise.setValue0(DefaultPromise.java:649)
	at io.netty.util.concurrent.DefaultPromise.setFailure0(DefaultPromise.java:642)
	at io.netty.util.concurrent.DefaultPromise.setFailure(DefaultPromise.java:123)
	at io.vertx.core.net.impl.ChannelProvider$3$1.exceptionCaught(ChannelProvider.java:235)
	at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:346)
	at io.netty.channel.AbstractChannelHandlerContext.invokeExceptionCaught(AbstractChannelHandlerContext.java:325)
	at io.netty.channel.AbstractChannelHandlerContext.fireExceptionCaught(AbstractChannelHandlerContext.java:317)
	at io.netty.handler.proxy.ProxyHandler.failPendingWritesAndClose(ProxyHandler.java:356)
	at io.netty.handler.proxy.ProxyHandler.setConnectFailure(ProxyHandler.java:349)
	at io.netty.handler.proxy.ProxyHandler.access$100(ProxyHandler.java:41)
	at io.netty.handler.proxy.ProxyHandler$2.run(ProxyHandler.java:201)
	at io.netty.util.concurrent.PromiseTask.runTask(PromiseTask.java:98)
	at io.netty.util.concurrent.ScheduledFutureTask.run(ScheduledFutureTask.java:156)
	at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:173)
	at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:166)
	at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:569)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:998)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: io.netty.handler.proxy.ProxyConnectException: http, basic, /[<IPv6 address>]:7071 => <the bad actor>, timeout
	... 11 more

The quarkus default timeout of 15 seconds does not play a role, nor does increasing this value to 30 seconds.

https://quarkus.io/guides/rest-client#quarkus-rest-client-config_quarkus-rest-client-connect-timeout

We believe that this issue could be resolved by respecting and using the connect timeout value of the client.

Steps to reproduce

No response

Do you have a reproducer?

No response

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions