-
Bug
-
Resolution: Unresolved
-
Major
-
None
-
21.0.0.Final, 21.0.1.Final, 21.0.2.Final
-
None
-
-
Compatibility/Configuration
-
Workaround Exists
-
-
Undefined
-
---
-
---
I have a Wildfly 21.0.0.Final running a Spring Boot REST application and I encountered a strange behaviour with GET requests containing | (pipe) character in the query parameters.
| (pipe) character is unsafe according to the RFC1738 specification of HTTP, while RFC3986 allows for the encoding of Unicode characters.
However, Wildfly (Undertow) has an option on http-listener and https-listener entries to allow-unescaped-characters-in-url.
Full standalone.xml here with masked sensitive info.
The application is running on 127.0.0.1:443, and is exposed to the outside world as https://myappname.company.com via a PulseSecure load balancer, where myappname is a CNAME registered on company.com DNS, pointing to the load balancers VIP.
The allow-unescaped-characters-in-url="true" bit works fine in these cases (so when the request containing | doesn't go through the Windows hosts file, but goes through the load balancer).
However, when I add an entry to the Windows hosts file to bypass the load balancer, such as:
127.0.0.1 myappname.company.com
…then the GET request containing | in its query parameter won't work - in fact it looks like it is not even hitting the server, as if Wildfly/Undertow's allow-unescaped-characters-in-url="true" setting wouldn't even be there.
Now this causes issues with our local testing. Is there any change we can make so that allow-unescaped-characters-in-url="true" would be always respected?
We know that ideally | should be encoded to %7D, but we would be interested in a solution (ideally on Wildfly level) that would make allow-unescaped-characters-in-url="true" work every time, irrespective whether the requests is going through hosts file or the load balancer.
The very strange this is that it was working fine in Wildfly 20.0.0.Final, even without allow-unescaped-characters-in-url="true" being in standalone.xml.
Full request source:
GET /rest/v3/news/_lite?mql=customerId=1212090,caseId=1078841||caseId=null HTTP/1.1 Host: myappname.company.com Connection: keep-alive Pragma: no-cache Cache-Control: no-cache sec-ch-ua: "Google Chrome";v="87", " Not;A Brand";v="99", "Chromium";v="87" Accept: application/json, text/plain, */* Authorization: Bearer masked sec-ch-ua-mobile: ?0 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Sec-Fetch-Site: same-origin Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Referer: https://myappname.company.com/anotherPage Accept-Encoding: gzip, deflate, br Accept-Language: en-GB,en;q=0.9 Cookie: JSESSIONID=masked; _ga=GA1.2.1926489359.1609961117; _gid=masked; _gat_gtag_UA_112487518_3=1
Server log excerpt with TRACE level logging attached. The faulty request is /rest/v3/news/_lite - it can be seen in one of the TRACE logs with | (pipe) symbol in its query string, but then it doesn't get "deeper", doesn't get processed at all, doesn't get logged by io.undertow.request.dump either.
The error I get on DEBUG level:
2021-01-08 01:32:20,660 DEBUG [io.undertow.request.io] (default I/O-7) Sending rststream on channel Http2Channel peer /127.0.0.1:50355 local /127.0.0.1:443[ No Receiver [] -- [] -- []] stream 1: java.nio.channels.ClosedChannelException at io.undertow.core@2.2.2.Final//io.undertow.protocols.http2.Http2Channel.sendRstStream(Http2Channel.java:1059) at io.undertow.core@2.2.2.Final//io.undertow.server.protocol.http2.Http2ReceiveListener.handleRequests(Http2ReceiveListener.java:135) at io.undertow.core@2.2.2.Final//io.undertow.server.protocol.http2.Http2ReceiveListener.handleEvent(Http2ReceiveListener.java:115) at io.undertow.core@2.2.2.Final//io.undertow.server.protocol.http2.Http2ReceiveListener.handleEvent(Http2ReceiveListener.java:73) at org.jboss.xnio@3.8.2.Final//org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92) at io.undertow.core@2.2.2.Final//io.undertow.server.protocol.framed.AbstractFramedChannel$FrameReadListener.handleEvent(AbstractFramedChannel.java:952) at io.undertow.core@2.2.2.Final//io.undertow.server.protocol.framed.AbstractFramedChannel$FrameReadListener.handleEvent(AbstractFramedChannel.java:932) at org.jboss.xnio@3.8.2.Final//org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92) at io.undertow.core@2.2.2.Final//io.undertow.server.protocol.framed.AbstractFramedChannel$FrameReadListener$1.run(AbstractFramedChannel.java:963) at io.undertow.core@2.2.2.Final//io.undertow.server.protocol.framed.AbstractFramedChannel$FrameReadListener.handleEvent(AbstractFramedChannel.java:939) at io.undertow.core@2.2.2.Final//io.undertow.server.protocol.framed.AbstractFramedChannel$FrameReadListener.handleEvent(AbstractFramedChannel.java:932) at org.jboss.xnio@3.8.2.Final//org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92) at org.jboss.xnio@3.8.2.Final//org.xnio.conduits.ReadReadyHandler$ChannelListenerHandler.readReady(ReadReadyHandler.java:66) at io.undertow.core@2.2.2.Final//io.undertow.protocols.ssl.SslConduit$SslReadReadyHandler.readReady(SslConduit.java:1211) at io.undertow.core@2.2.2.Final//io.undertow.protocols.ssl.SslConduit$1.run(SslConduit.java:180) at io.undertow.core@2.2.2.Final//io.undertow.protocols.ssl.SslConduit$2.run(SslConduit.java:195) at org.jboss.xnio.nio@3.8.2.Final//org.xnio.nio.WorkerThread.safeRun(WorkerThread.java:612) at org.jboss.xnio.nio@3.8.2.Final//org.xnio.nio.WorkerThread.run(WorkerThread.java:479)