From ff1300e626949fa9850b0f91dc5e8c2cb45b6a88 Mon Sep 17 00:00:00 2001 From: Brandon Carpenter Date: Tue, 12 Sep 2017 08:21:49 -0700 Subject: [PATCH] io: Add support for fragmented websocket binary frames Allows fragmented binary frames by saving the previous opcode. Handles the case where an intermediary (i.e., web proxy) fragments frames originally sent unfragmented by the client. Signed-off-by: Brandon Carpenter Signed-off-by: Daniel P. Berrange --- include/io/channel-websock.h | 1 + io/channel-websock.c | 26 ++++++++++++++++++-------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/include/io/channel-websock.h b/include/io/channel-websock.h index 3c9ff84727..7c896557c5 100644 --- a/include/io/channel-websock.h +++ b/include/io/channel-websock.h @@ -65,6 +65,7 @@ struct QIOChannelWebsock { guint io_tag; Error *io_err; gboolean io_eof; + uint8_t opcode; }; /** diff --git a/io/channel-websock.c b/io/channel-websock.c index 4e5afb2e95..909d6367f0 100644 --- a/io/channel-websock.c +++ b/io/channel-websock.c @@ -636,28 +636,38 @@ static int qio_channel_websock_decode_header(QIOChannelWebsock *ioc, has_mask = header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK; payload_len = header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_PAYLOAD_LEN; + /* Save or restore opcode. */ + if (opcode) { + ioc->opcode = opcode; + } else { + opcode = ioc->opcode; + } + if (opcode == QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE) { /* disconnect */ return 0; } /* Websocket frame sanity check: - * * Websocket fragmentation is not supported. - * * All websockets frames sent by a client have to be masked. + * * Fragmentation is only supported for binary frames. + * * All frames sent by a client MUST be masked. * * Only binary encoding is supported. */ if (!fin) { - error_setg(errp, "websocket fragmentation is not supported"); - return -1; + if (opcode != QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { + error_setg(errp, "only binary websocket frames may be fragmented"); + return -1; + } + } else { + if (opcode != QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { + error_setg(errp, "only binary websocket frames are supported"); + return -1; + } } if (!has_mask) { error_setg(errp, "client websocket frames must be masked"); return -1; } - if (opcode != QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { - error_setg(errp, "only binary websocket frames are supported"); - return -1; - } if (payload_len < QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_16_BIT) { ioc->payload_remain = payload_len;