Uploaded image for project: 'Undertow'
  1. Undertow
  2. UNDERTOW-1139

A not-accepted websocket extension kills the connection

XMLWordPrintable

    • Hide

      Create a websocket handler with the PerMessageDeflateHandshake handler extension added. This adds support for the "permessage-deflate" extension.

      Hit this server with a websocket client that does request an extension, but not "permessage-deflate". For example, iOS 10 safari will request "x-webkit-deflate-frame".

      The connection will fail due to a null pointer exception with a stacktrace like this:

      UT005071: Undertow request failed HttpServerExchange{ GET /websocket-endpoint request {X-Real-IP=[REDACTED], Cache-Control=[no-cache], Sec-WebSocket-Version=[13], Sec-WebSocket-Key=[REDACTED], Upgrade=[websocket], Origin=[https://my.example.org], Pragma=[no-cache], X-Scheme=[https], User-Agent=[Mozilla/5.0 (iPad; CPU OS 10_3_2 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) CriOS/59.0.3071.102 Mobile/14F89 Safari/602.1], Sec-WebSocket-Extensions=[x-webkit-deflate-frame], Connection=[upgrade], Cookie=[REDACTED], Host=[my.example.org]} response {Connection=[Upgrade], Access-Control-Allow-Origin=[https://my.example.org], Access-Control-Allow-Headers=[content-type], Server=[undertow], Access-Control-Allow-Credentials=[true], Origin=[https://my.example.org], Access-Control-Max-Age=[1728000], Access-Control-Allow-Methods=[DELETE, GET, PATCH, POST, PUT]}}
         java.lang.NullPointerException: null
            at io.undertow.websockets.WebSocketExtension.toExtensionHeader(WebSocketExtension.java:130)
            at io.undertow.websockets.core.protocol.Handshake.selectExtensions(Handshake.java:178)
            at io.undertow.websockets.core.protocol.version13.Hybi13Handshake.handshakeInternal(Hybi13Handshake.java:59)
            at io.undertow.websockets.core.protocol.Handshake.handshake(Handshake.java:102)
            at io.undertow.websockets.WebSocketProtocolHandshakeHandler.handleRequest(WebSocketProtocolHandshakeHandler.java:202)
            at org.projectodd.wunderboss.web.undertow.async.websocket.UndertowWebsocket$2.handleRequest(UndertowWebsocket.java:105)
            at io.undertow.server.session.SessionAttachmentHandler.handleRequest(SessionAttachmentHandler.java:68)
            at io.undertow.server.Connectors.executeRootHandler(Connectors.java:202)
            at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:802)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
            at java.lang.Thread.run(Thread.java:745)
      
      Show
      Create a websocket handler with the PerMessageDeflateHandshake handler extension added. This adds support for the "permessage-deflate" extension. Hit this server with a websocket client that does request an extension, but not "permessage-deflate". For example, iOS 10 safari will request "x-webkit-deflate-frame". The connection will fail due to a null pointer exception with a stacktrace like this: UT005071: Undertow request failed HttpServerExchange{ GET /websocket-endpoint request {X-Real-IP=[REDACTED], Cache-Control=[no-cache], Sec-WebSocket-Version=[13], Sec-WebSocket-Key=[REDACTED], Upgrade=[websocket], Origin=[https://my.example.org], Pragma=[no-cache], X-Scheme=[https], User-Agent=[Mozilla/5.0 (iPad; CPU OS 10_3_2 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) CriOS/59.0.3071.102 Mobile/14F89 Safari/602.1], Sec-WebSocket-Extensions=[x-webkit-deflate-frame], Connection=[upgrade], Cookie=[REDACTED], Host=[my.example.org]} response {Connection=[Upgrade], Access-Control-Allow-Origin=[https://my.example.org], Access-Control-Allow-Headers=[content-type], Server=[undertow], Access-Control-Allow-Credentials=[true], Origin=[https://my.example.org], Access-Control-Max-Age=[1728000], Access-Control-Allow-Methods=[DELETE, GET, PATCH, POST, PUT]}} java.lang.NullPointerException: null at io.undertow.websockets.WebSocketExtension.toExtensionHeader(WebSocketExtension.java:130) at io.undertow.websockets.core.protocol.Handshake.selectExtensions(Handshake.java:178) at io.undertow.websockets.core.protocol.version13.Hybi13Handshake.handshakeInternal(Hybi13Handshake.java:59) at io.undertow.websockets.core.protocol.Handshake.handshake(Handshake.java:102) at io.undertow.websockets.WebSocketProtocolHandshakeHandler.handleRequest(WebSocketProtocolHandshakeHandler.java:202) at org.projectodd.wunderboss.web.undertow.async.websocket.UndertowWebsocket$2.handleRequest(UndertowWebsocket.java:105) at io.undertow.server.session.SessionAttachmentHandler.handleRequest(SessionAttachmentHandler.java:68) at io.undertow.server.Connectors.executeRootHandler(Connectors.java:202) at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:802) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745)
    • Compatibility/Configuration

      If a websocket ExtensionHandshake is available but fails negotiation against the client-supplied extensions, the websocket connection will die with a null pointer exception.

      The problem is that the Handshake class does not check the result of ExtensionHandshake.accept(WebSocketExtension ext) for null (meaning the extension should not be used) before adding this extension to the list of selected and configured extensions on the connection. The null blows up later.

      More concretely, line 202 in master currently reads:

                      WebSocketExtension negotiated = extHandshake.accept(ext);
                      if (ext != null && !extHandshake.isIncompatible(configured)) {
                          selected.add(negotiated);
                          configured.add(extHandshake);
                      }
      

      It should read:

                      WebSocketExtension negotiated = extHandshake.accept(ext);
                      if (negotiated != null && !extHandshake.isIncompatible(configured)) {
                          selected.add(negotiated);
                          configured.add(extHandshake);
                      }
      

      Note the null check was on ext (which is probably incorrect: Handshake.accept() will check it for null already and this item is from server configuration--its unlikely to have nulls in it). The null check should be on negotiated.

              sdouglas1@redhat.com Stuart Douglas (Inactive)
              favila_jira Francis Avila (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

                Created:
                Updated:
                Resolved: