ktorio / ktor

Framework for quickly creating connected applications in Kotlin with minimal effort
https://ktor.io
Apache License 2.0
12.81k stars 1.04k forks source link

Can't connect to Ktor WebSocket when running as WAR in Tomcat #1917

Open wulf0r opened 4 years ago

wulf0r commented 4 years ago

KTOR 1.3.1 Server with WebSockets, Auth, Locations, Jackson, Servlet

In my application I defined a websocket route per the Websockets DSL:

    webSocket("$appPath$ANWESENHEIT_WEBSOCKET_PATH") {
    ...
    }

When I connect to it via ws://... or wss://... in standalone mode (KTOR from main) it works perfectly. When I deploy my app as WAR in Tomcat 9.0.8 and let KTOR run via Servlet and try to connect to the same websocket either securely or unsecure it gives a 501 HTTP Status with no further information.

I turned on the tracing and found that the route works as expected:

Trace for [einteilung, anwesenheit_websocket]
/einteilung, segment:1 -> SUCCESS @ 
/einteilung/anwesenheit_websocket/(method:GET)/(header:Connection = 
Upgrade)/(header:Upgrade = websocket))

the response I get is

> HTTP/1.1 501
> Set-Cookie: EINTEILUNG_USER_SESSION_ID=1b064e9791cb6ab7; Path=/; HttpOnly; $x-enc=URI_ENCODING
> Upgrade: websocket
> Connection: Upgrade
> Sec-WebSocket-Accept: nSWkl5USR60+FmPXuYa/zsZXdxo=
> Content-Type: text/html;charset=utf-8
> Content-Language: en
> Content-Length: 1080
> Date: Tue, 02 Jun 2020 14:59:30 GMT
> Connection: close

I also tried to connect to a WebSocket that has no route defined and as expected I got a 404 error

wulf0r commented 4 years ago

Having looked more into this I now think that forwarding websocket from Tomcat to Ktor is simply not implemented.

In order to run Ktor in a servlet container the Servlet io.ktor.server.servlet.ServletApplicationEngine which is a io.ktor.server.servlet.KtorServlet creates the ApplicationEngine and forwards the normal HTTP Requests to it. However, Websocket in Servlet Containers works over a different API javax.websocket.* and require a declared ServerEndpoint that receives and processes the websocket message. As far as I can tell neither the Ktor Servlet nor the Ktor WebSockets feature provides a shim here and this is why this use case fails with 501 Not Implemented.

oleg-larshin commented 4 years ago

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.