Hi Team,

I have created a project with spring-cloud-gateway that runs on netty server. Please help in finding a fix for this whenever we have a request with special character server doesn't seem to accept the request http://localhost:8080/api-gateway/testendauth?userLoginId=DHARANE%& Error:'java net urisyntaxexception malformed escape pair at index 61'

Note: If I remove '%' or on encoding the server accepts the request. Please check the below trace. This is while testing spring-cloud-gateway with netty server. Only testcases where queryparam has '%' seems to fail. ReactorHttpHandlerAdapter.java seems to be failing.

Is it necessary to encode queryparam before is request sent?

TRACE:
2023-05-11 15:27:42.812 DEBUG 11396 --- [ctor-http-nio-3] r.n.http.server.HttpServerOperations     : [dfe2a8ca, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:62599] Increasing pending responses, now 1
2023-05-11 15:27:42.812 DEBUG 11396 --- [ctor-http-nio-3] reactor.netty.http.server.HttpServer     : [dfe2a8ca-3, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:62599] Handler is being applied: org.springframework.http.server.reactive.ReactorHttpHandlerAdapter@3ea5bcc5
2023-05-11 15:27:42.812 DEBUG 11396 --- [ctor-http-nio-3] o.s.h.s.r.ReactorHttpHandlerAdapter      : Failed to get request URI: Malformed escape pair at index 66: http://localhost:8080/api-gateway/testendauth?userLoginId=DHARANE%&
2023-05-11 15:27:42.812 DEBUG 11396 --- [ctor-http-nio-3] r.n.http.server.HttpServerOperations     : [dfe2a8ca-3, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:62599] Last HTTP response frame
2023-05-11 15:27:42.812 DEBUG 11396 --- [ctor-http-nio-3] r.n.http.server.HttpServerOperations     : [dfe2a8ca-3, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:62599] No sendHeaders() called before complete, sending zero-length header
2023-05-11 15:27:42.812 DEBUG 11396 --- [ctor-http-nio-3] r.n.http.server.HttpServerOperations     : [dfe2a8ca-3, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:62599] Decreasing pending responses, now 0
2023-05-11 15:27:42.812 DEBUG 11396 --- [ctor-http-nio-3] r.n.http.server.HttpServerOperations     : [dfe2a8ca-3, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:62599] Last HTTP packet was sent, terminating the channel
2023-05-11 15:27:42.812 DEBUG 11396 --- [ctor-http-nio-3] reactor.netty.channel.ChannelOperations  : [dfe2a8ca-3, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:62599] [HttpServer] Channel inbound receiver cancelled (subscription disposed).
2023-05-11 15:27:42.813 TRACE 11396 --- [ctor-http-nio-3] reactor.netty.channel.ChannelOperations  : [dfe2a8ca, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:62599] Disposing ChannelOperation from a channel

java.lang.Exception: ChannelOperation terminal stack
    at reactor.netty.channel.ChannelOperations.terminate(ChannelOperations.java:470) ~[reactor-netty-core-1.0.27.jar:1.0.27]
    at reactor.netty.http.server.HttpServerOperations.cleanHandlerTerminate(HttpServerOperations.java:785) ~[reactor-netty-http-1.1.5.jar:1.1.5]
    at reactor.netty.http.server.HttpTrafficHandler.operationComplete(HttpTrafficHandler.java:459) ~[reactor-netty-http-1.1.5.jar:1.1.5]
    at reactor.netty.http.server.HttpTrafficHandler.operationComplete(HttpTrafficHandler.java:65) ~[reactor-netty-http-1.1.5.jar:1.1.5]
    at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:590) ~[netty-common-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:557) ~[netty-common-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:492) ~[netty-common-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.util.concurrent.DefaultPromise.setValue0(DefaultPromise.java:636) ~[netty-common-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.util.concurrent.DefaultPromise.setSuccess0(DefaultPromise.java:625) ~[netty-common-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.util.concurrent.DefaultPromise.trySuccess(DefaultPromise.java:105) ~[netty-common-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.util.internal.PromiseNotificationUtil.trySuccess(PromiseNotificationUtil.java:48) ~[netty-common-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.ChannelOutboundBuffer.safeSuccess(ChannelOutboundBuffer.java:717) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.ChannelOutboundBuffer.remove(ChannelOutboundBuffer.java:272) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.ChannelOutboundBuffer.removeBytes(ChannelOutboundBuffer.java:352) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.socket.nio.NioSocketChannel.doWrite(NioSocketChannel.java:421) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannel$AbstractUnsafe.flush0(AbstractChannel.java:931) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.flush0(AbstractNioChannel.java:354) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannel$AbstractUnsafe.flush(AbstractChannel.java:895) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.DefaultChannelPipeline$HeadContext.flush(DefaultChannelPipeline.java:1372) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:921) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeFlush(AbstractChannelHandlerContext.java:907) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannelHandlerContext.flush(AbstractChannelHandlerContext.java:893) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.flush(CombinedChannelDuplexHandler.java:531) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.ChannelOutboundHandlerAdapter.flush(ChannelOutboundHandlerAdapter.java:125) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.CombinedChannelDuplexHandler.flush(CombinedChannelDuplexHandler.java:356) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:923) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeFlush(AbstractChannelHandlerContext.java:907) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannelHandlerContext.flush(AbstractChannelHandlerContext.java:893) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.ChannelDuplexHandler.flush(ChannelDuplexHandler.java:127) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:923) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeWriteAndFlush(AbstractChannelHandlerContext.java:941) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:966) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:934) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:984) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.DefaultChannelPipeline.writeAndFlush(DefaultChannelPipeline.java:1025) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannel.writeAndFlush(AbstractChannel.java:306) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at reactor.netty.http.server.HttpServerOperations.onOutboundComplete(HttpServerOperations.java:721) ~[reactor-netty-http-1.1.5.jar:1.1.5]
    at reactor.netty.channel.ChannelOperations.onComplete(ChannelOperations.java:242) ~[reactor-netty-core-1.0.27.jar:1.0.27]
    at reactor.core.publisher.Operators.complete(Operators.java:137) ~[reactor-core-3.4.26.jar:3.4.26]
    at reactor.core.publisher.MonoEmpty.subscribe(MonoEmpty.java:46) ~[reactor-core-3.4.26.jar:3.4.26]
    at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55) ~[reactor-core-3.4.26.jar:3.4.26]
    at reactor.netty.http.server.HttpServer$HttpServerHandle.onStateChange(HttpServer.java:1006) ~[reactor-netty-http-1.1.5.jar:1.1.5]
    at reactor.netty.ReactorNetty$CompositeConnectionObserver.onStateChange(ReactorNetty.java:707) ~[reactor-netty-core-1.0.27.jar:1.0.27]
    at reactor.netty.transport.ServerTransport$ChildObserver.onStateChange(ServerTransport.java:477) ~[reactor-netty-core-1.0.27.jar:1.0.27]
    at reactor.netty.http.server.HttpServerOperations.onInboundNext(HttpServerOperations.java:633) ~[reactor-netty-http-1.1.5.jar:1.1.5]
    at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:113) ~[reactor-netty-core-1.0.27.jar:1.0.27]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at reactor.netty.http.server.HttpTrafficHandler.channelRead(HttpTrafficHandler.java:228) ~[reactor-netty-http-1.1.5.jar:1.1.5]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346) ~[netty-codec-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:333) ~[netty-codec-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:454) ~[netty-codec-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:290) ~[netty-codec-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562) ~[netty-transport-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) ~[netty-common-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.87.Final.jar:4.1.87.Final]
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.87.Final.jar:4.1.87.Final]
    at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]

Comment From: snicoll

I don't know if that's an issue in Spring Framework or in Netty. To figure that out and provide you support, we need a small sample app that we can run ourselves to reproduce the issue. You can attach a zip to this issue or push the code to a GitHub repository. Make sure to upgrade your dependencies as it can also have been fixed downstream in the meantime.

Comment From: spring-projects-issues

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

Comment From: bclozel

Duplicates #30489