Jetty9 WebSocketとChromeのバグ
サンプル を参考に実装してみたけど、いくつかメッセージを送受信するとエラーがずらっと。
Oct 22 23:58:29 [qtp1685059636-58] WARN org.eclipse.jetty.websocket.core.extensions.compress.DeflateCompressionMethod$InflaterProcess: ... org.eclipse.jetty.websocket.core.api.BadPayloadException: java.util.zip.DataFormatException: invalid distance too far back Caused by: java.util.zip.DataFormatException: invalid distance too far back
接続してたクライアントは Chrome 安定版(M22)だったんだけど、これに関連する Issue が、最近更新されていて、内容が Java の deflate 実装では BFINAL 1 の方で圧縮データを作成してるけど、Chrome の実装では BFINAL 0 にしか対応していなかったというもの(WebSocket の draft では BFINAL 0, 1 の両方をサポートしてる)。M24 に Fix コードが取り込まれるようだけど、そもそも deflate-frame extension
は permessage-compress extension
に移行されるはずなので、WebkitDeflateFrameExtension
をオフにしても問題ないと判断して、このあたり を参考に拡張を登録解除して対処した。
import org.eclipse.jetty.server._ import org.eclipse.jetty.websocket.core.api._ import org.eclipse.jetty.websocket.server._ import org.slf4j._ class MyWebSocketHandler extends WebSocketListener { val logger = LoggerFactory.getLogger(classOf[MyWebSocketHandler]) def onWebSocketBinary(payload: Array[Byte], offset: Int, len: Int) { logger.info("WebSocket.onBinaryMessage: {}", len) } def onWebSocketClose(statusCode: Int, reason: String) { logger.info("onWebSocketClose: {}: {}", statusCode, reason) } def onWebSocketConnect(connection: WebSocketConnection) { logger.info("WebSocket.onOpen") } def onWebSocketException(error: WebSocketException) { error.printStackTrace } def onWebSocketText(message: String) { logger.info("WebSocket.onTextMessage: {}", message) } } object WebSocketServer { def main(args: Array[String]) { val server = new Server val connector = new ServerConnector(server) connector.setPort(9090) server.addConnector(connector) val handler = new WebSocketHandler() { override def configurePolicy(policy: WebSocketPolicy) { policy.setBufferSize(1024) policy.setIdleTimeout(30000) policy.setMaxTextMessageSize(1024) policy.setMaxBinaryMessageSize(1024) } override def configure(factory: WebSocketServerFactory) { factory.getExtensionRegistry.unregister("x-webkit-deflate-frame") factory.setCreator(new WebSocketCreator() { def createWebSocket(req: UpgradeRequest, resp: UpgradeResponse): Object = { new MyWebSocketHandler } }) } } server.setHandler(handler) server.start server.join } }
WebSocket Extension がまともに実装されてる WebSocket ライブラリはじめて見た。
permessage-compress
もバッチリ実装されてる。
それはそうと、この拡張問題は安定版の Chrome に混入しちゃってる問題なので、今後 WebSocket の拡張に対応したサーバー(恐らく普通に対応することになるはず)を書くときは、古いバージョンの Chrome で接続されることを考慮した場合、x-webkit-deflate-frame
のサポートに関して少し注意しないといけない。