Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Special characters in HTTP headers break an application within shinyproxy #533

Open
LDSamson opened this issue Oct 25, 2024 · 3 comments
Open
Milestone

Comments

@LDSamson
Copy link

To reproduce:

  - id: 01_hello
    display-name: Hello Application
    description: Application which demonstrates the basics of a Shiny app
    container-cmd: ["R", "-e", "shinyproxy::run_01_hello()"]
    container-image: openanalytics/shinyproxy-demo
    container-network: sp-example-net
    http_headers:
       test_header: "Ťěšťůšěř Főřáťěšť"
  • build the docker image and run it as described in the example.

Now, the app named 'Hello Application' cannot be started anymore.

I stumbled upon this issue when users with special characters in their name tried to start an application but failed to do so. In our production version, I am extracting the name (witrh special characters) from an OpenID connect claim, but below shows the issue also occurs in shinyproxy with the demo shiny applications and simple login.

These are the ShinyProxy error logs:

2024-10-25T15:05:50.668Z  INFO 1 --- [ProxyService-16] e.o.containerproxy.service.ProxyService  : [user=jack proxyId=63da50cb-eda5-4fd6-a2fa-7b3a53d854e0 specId=01_hello] Proxy activated
2024-10-25T15:05:50.726Z ERROR 1 --- [   XNIO-1 I/O-1] io.undertow.proxy                        : UT005028: Proxy request to /proxy_endpoint/63da50cb-eda5-4fd6-a2fa-7b3a53d854e0/ failed

java.io.IOException: UT001000: Connection closed
        at io.undertow.client.http.HttpClientConnection$ClientReadListener.handleEvent(HttpClientConnection.java:600) ~[undertow-core-2.3.13.Final.jar!/:2.3.13.Final]
        at io.undertow.client.http.HttpClientConnection$ClientReadListener.handleEvent(HttpClientConnection.java:535) ~[undertow-core-2.3.13.Final.jar!/:2.3.13.Final]
        at org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92) ~[xnio-api-3.8.8.Final.jar!/:3.8.8.Final]
        at org.xnio.conduits.ReadReadyHandler$ChannelListenerHandler.readReady(ReadReadyHandler.java:66) ~[xnio-api-3.8.8.Final.jar!/:3.8.8.Final]
        at org.xnio.nio.NioSocketConduit.handleReady(NioSocketConduit.java:89) ~[xnio-nio-3.8.8.Final.jar!/:3.8.8.Final]
        at org.xnio.nio.WorkerThread.run(WorkerThread.java:591) ~[xnio-nio-3.8.8.Final.jar!/:3.8.8.Final]

2024-10-25T15:05:50.741Z ERROR 1 --- [   XNIO-1 I/O-1] io.undertow.proxy                        : UT005028: Proxy request to /proxy_endpoint/63da50cb-eda5-4fd6-a2fa-7b3a53d854e0/ failed

java.nio.channels.ClosedChannelException: null
        at io.undertow.client.http.HttpClientConnection$5.handleEvent(HttpClientConnection.java:194) ~[undertow-core-2.3.13.Final.jar!/:2.3.13.Final]
        at io.undertow.client.http.HttpClientConnection$5.handleEvent(HttpClientConnection.java:177) ~[undertow-core-2.3.13.Final.jar!/:2.3.13.Final]
        at org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92) ~[xnio-api-3.8.8.Final.jar!/:3.8.8.Final]
        at org.xnio.StreamConnection.invokeCloseListener(StreamConnection.java:132) ~[xnio-api-3.8.8.Final.jar!/:3.8.8.Final]
        at org.xnio.Connection.close(Connection.java:142) ~[xnio-api-3.8.8.Final.jar!/:3.8.8.Final]
        at org.xnio.IoUtils.safeClose(IoUtils.java:152) ~[xnio-api-3.8.8.Final.jar!/:3.8.8.Final]
        at io.undertow.util.ConnectionUtils.doDrain(ConnectionUtils.java:90) ~[undertow-core-2.3.13.Final.jar!/:2.3.13.Final]
        at io.undertow.util.ConnectionUtils.cleanClose(ConnectionUtils.java:74) ~[undertow-core-2.3.13.Final.jar!/:2.3.13.Final]
        at io.undertow.client.http.HttpClientConnection.close(HttpClientConnection.java:491) ~[undertow-core-2.3.13.Final.jar!/:2.3.13.Final]
        at org.xnio.IoUtils.safeClose(IoUtils.java:152) ~[xnio-api-3.8.8.Final.jar!/:3.8.8.Final]
        at io.undertow.client.http.HttpClientConnection$ClientReadListener.handleEvent(HttpClientConnection.java:605) ~[undertow-core-2.3.13.Final.jar!/:2.3.13.Final]
        at io.undertow.client.http.HttpClientConnection$ClientReadListener.handleEvent(HttpClientConnection.java:535) ~[undertow-core-2.3.13.Final.jar!/:2.3.13.Final]
        at org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92) ~[xnio-api-3.8.8.Final.jar!/:3.8.8.Final]
        at org.xnio.conduits.ReadReadyHandler$ChannelListenerHandler.readReady(ReadReadyHandler.java:66) ~[xnio-api-3.8.8.Final.jar!/:3.8.8.Final]
        at org.xnio.nio.NioSocketConduit.handleReady(NioSocketConduit.java:89) ~[xnio-nio-3.8.8.Final.jar!/:3.8.8.Final]
        at org.xnio.nio.WorkerThread.run(WorkerThread.java:591) ~[xnio-nio-3.8.8.Final.jar!/:3.8.8.Final]

2024-10-25T15:05:50.745Z ERROR 1 --- [   XNIO-1 I/O-1] io.undertow.proxy                        : UT005028: Proxy request to /proxy_endpoint/63da50cb-eda5-4fd6-a2fa-7b3a53d854e0/ failed

java.io.IOException: UT001000: Connection closed
        at io.undertow.client.http.HttpClientConnection$ClientReadListener.handleEvent(HttpClientConnection.java:600) ~[undertow-core-2.3.13.Final.jar!/:2.3.13.Final]
        at io.undertow.client.http.HttpClientConnection$ClientReadListener.handleEvent(HttpClientConnection.java:535) ~[undertow-core-2.3.13.Final.jar!/:2.3.13.Final]
        at org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92) ~[xnio-api-3.8.8.Final.jar!/:3.8.8.Final]
        at org.xnio.conduits.ReadReadyHandler$ChannelListenerHandler.readReady(ReadReadyHandler.java:66) ~[xnio-api-3.8.8.Final.jar!/:3.8.8.Final]
        at org.xnio.nio.NioSocketConduit.handleReady(NioSocketConduit.java:89) ~[xnio-nio-3.8.8.Final.jar!/:3.8.8.Final]
        at org.xnio.nio.WorkerThread.run(WorkerThread.java:591) ~[xnio-nio-3.8.8.Final.jar!/:3.8.8.Final]

2024-10-25T15:05:50.803Z  INFO 1 --- [   XNIO-1 I/O-1] e.o.c.util.ProxyMappingManager           : [user=jack proxyId=63da50cb-eda5-4fd6-a2fa-7b3a53d854e0 specId=01_hello] Failed request: GET http://localhost:8080/proxy_endpoint/63da50cb-eda5-4fd6-a2fa-7b3a53d854e0/ was proxied to: http://2b650140c42a:3838/, status: 503
@LEDfan
Copy link
Member

LEDfan commented Oct 28, 2024

Hi, as far as I know HTTP headers may not contain all UTF-8 characters, but only ASCII characters, see https://stackoverflow.com/questions/47687379/what-characters-are-allowed-in-http-header-values/48138818#48138818 .
One way to work-around is to base64 encode the value (see https://shinyproxy.io/documentation/spel/#tips--tricks) :

  - id: 01_hello
    display-name: Hello Application
    description: Application which demonstrates the basics of a Shiny app
    container-cmd: ["R", "-e", "shinyproxy::run_01_hello()"]
    container-image: openanalytics/shinyproxy-demo
    container-network: sp-example-net
    http_headers:
        test_header: "#{T(java.util.Base64).getEncoder().encodeToString('ěšťůšěř Főřáťěš'.getBytes())}"

@LDSamson
Copy link
Author

LDSamson commented Nov 4, 2024

Thanks for providing this workaround, this indeed helps with this problem and I will apply it to our application in production.

In the long term, would it be possible to make shinyproxy a bit more robust for these cases and, for example, create informative error messages if shinyproxy is asked to send non-ascii characters as http headers? Or, send a warning that the string is an invalid http header and send an empty string instead? I think this would be helpful for many shinyproxy users if their names consist characters less commonly used in English. If this is difficult to achieve, a small warning in the documentation about this problem would also already be helpful.

In my use case, my application will display a user name but will fall back to the email address if the user name is not available.

@LEDfan
Copy link
Member

LEDfan commented Nov 12, 2024

Yes, I agree ShinyProxy could handle this better. I created and internal ticket and we will improve this in the next release.
In the meantime I added an example to the demo https://github.com/openanalytics/shinyproxy-shiny-demo-auth?tab=readme-ov-file#utf-8-characters and a note on the website: https://shinyproxy.io/documentation/configuration/#http-headers

@LEDfan LEDfan added this to the Next milestone Nov 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants