From nobody Fri May 3 08:46:07 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488471094022966.7031067422014; Thu, 2 Mar 2017 08:11:34 -0800 (PST) Received: from localhost ([::1]:53127 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cjTKD-00064v-PS for importer@patchew.org; Thu, 02 Mar 2017 11:11:29 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49079) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cjTJQ-00063c-TM for qemu-devel@nongnu.org; Thu, 02 Mar 2017 11:10:42 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cjTJQ-0008Ra-3g for qemu-devel@nongnu.org; Thu, 02 Mar 2017 11:10:40 -0500 Received: from mx1.redhat.com ([209.132.183.28]:52650) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cjTJP-0008R8-U8 for qemu-devel@nongnu.org; Thu, 02 Mar 2017 11:10:40 -0500 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 2A5087FD47; Thu, 2 Mar 2017 16:10:40 +0000 (UTC) Received: from t460.redhat.com (ovpn-116-205.ams2.redhat.com [10.36.116.205]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v22GAaKP016904; Thu, 2 Mar 2017 11:10:38 -0500 From: "Daniel P. Berrange" To: qemu-devel@nongnu.org Date: Thu, 2 Mar 2017 16:10:31 +0000 Message-Id: <20170302161033.4787-2-berrange@redhat.com> In-Reply-To: <20170302161033.4787-1-berrange@redhat.com> References: <20170302161033.4787-1-berrange@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.27]); Thu, 02 Mar 2017 16:10:40 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v2 1/3] io: fix decoding when multiple websockets frames arrive at once X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The qio_channel_websock_read_wire() method will read upto 4096 bytes off the socket and then decode the websockets header and payload. The code was only decoding a single websockets frame, even if the buffered data contained multiple frames. This meant that decoding of subsequent frames was delayed until further input arrived on the socket. This backlog of delayed frames gets worse & worse over time. Symptom was that when connecting to the VNC server via the built-in websockets server, mouse/keyboard interaction would start out fine, but slowly get more & more delayed until it was unusable. Signed-off-by: Daniel P. Berrange --- io/channel-websock.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/io/channel-websock.c b/io/channel-websock.c index e47279a..a06a4a8 100644 --- a/io/channel-websock.c +++ b/io/channel-websock.c @@ -570,21 +570,24 @@ static ssize_t qio_channel_websock_read_wire(QIOChann= elWebsock *ioc, ioc->encinput.offset +=3D ret; } =20 - if (ioc->payload_remain =3D=3D 0) { - ret =3D qio_channel_websock_decode_header(ioc, errp); + while (ioc->encinput.offset !=3D 0) { + if (ioc->payload_remain =3D=3D 0) { + ret =3D qio_channel_websock_decode_header(ioc, errp); + if (ret < 0) { + return ret; + } + if (ret =3D=3D 0) { + ioc->io_eof =3D TRUE; + break; + } + } + + ret =3D qio_channel_websock_decode_payload(ioc, errp); if (ret < 0) { return ret; } - if (ret =3D=3D 0) { - return 0; - } } - - ret =3D qio_channel_websock_decode_payload(ioc, errp); - if (ret < 0) { - return ret; - } - return ret; + return 1; } =20 =20 @@ -642,9 +645,6 @@ static gboolean qio_channel_websock_flush(QIOChannel *i= oc, if (ret < 0) { goto cleanup; } - if (ret =3D=3D 0) { - wioc->io_eof =3D TRUE; - } } =20 cleanup: --=20 2.9.3 From nobody Fri May 3 08:46:07 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488471180193388.85921587865914; Thu, 2 Mar 2017 08:13:00 -0800 (PST) Received: from localhost ([::1]:53133 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cjTLf-0007RK-1C for importer@patchew.org; Thu, 02 Mar 2017 11:12:59 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49108) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cjTJT-000640-A2 for qemu-devel@nongnu.org; Thu, 02 Mar 2017 11:10:44 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cjTJS-0008Sw-FN for qemu-devel@nongnu.org; Thu, 02 Mar 2017 11:10:43 -0500 Received: from mx1.redhat.com ([209.132.183.28]:36064) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cjTJS-0008SH-9B for qemu-devel@nongnu.org; Thu, 02 Mar 2017 11:10:42 -0500 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6B5307FB76; Thu, 2 Mar 2017 16:10:42 +0000 (UTC) Received: from t460.redhat.com (ovpn-116-205.ams2.redhat.com [10.36.116.205]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v22GAaKQ016904; Thu, 2 Mar 2017 11:10:40 -0500 From: "Daniel P. Berrange" To: qemu-devel@nongnu.org Date: Thu, 2 Mar 2017 16:10:32 +0000 Message-Id: <20170302161033.4787-3-berrange@redhat.com> In-Reply-To: <20170302161033.4787-1-berrange@redhat.com> References: <20170302161033.4787-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Thu, 02 Mar 2017 16:10:42 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v2 2/3] tests: fix leaks in test-io-channel-command X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" From: Marc-Andr=C3=A9 Lureau No need for strdup, fix leaks when socat is missing. Spotted by ASAN. Signed-off-by: Marc-Andr=C3=A9 Lureau Signed-off-by: Daniel P. Berrange --- tests/test-io-channel-command.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/test-io-channel-command.c b/tests/test-io-channel-comman= d.c index 1d1f461..46ce1ff 100644 --- a/tests/test-io-channel-command.c +++ b/tests/test-io-channel-command.c @@ -29,8 +29,8 @@ static void test_io_channel_command_fifo(bool async) #define TEST_FIFO "tests/test-io-channel-command.fifo" QIOChannel *src, *dst; QIOChannelTest *test; - char *srcfifo =3D g_strdup_printf("PIPE:%s,wronly", TEST_FIFO); - char *dstfifo =3D g_strdup_printf("PIPE:%s,rdonly", TEST_FIFO); + const char *srcfifo =3D "PIPE:" TEST_FIFO ",wronly"; + const char *dstfifo =3D "PIPE:" TEST_FIFO ",rdonly"; const char *srcargv[] =3D { "/bin/socat", "-", srcfifo, NULL, }; @@ -59,8 +59,6 @@ static void test_io_channel_command_fifo(bool async) object_unref(OBJECT(src)); object_unref(OBJECT(dst)); =20 - g_free(srcfifo); - g_free(dstfifo); unlink(TEST_FIFO); } =20 --=20 2.9.3 From nobody Fri May 3 08:46:07 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488471177736160.30337519877673; Thu, 2 Mar 2017 08:12:57 -0800 (PST) Received: from localhost ([::1]:53132 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cjTLc-0007Od-5Q for importer@patchew.org; Thu, 02 Mar 2017 11:12:56 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49131) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cjTJV-00065w-Mf for qemu-devel@nongnu.org; Thu, 02 Mar 2017 11:10:47 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cjTJU-0008Tj-Be for qemu-devel@nongnu.org; Thu, 02 Mar 2017 11:10:45 -0500 Received: from mx1.redhat.com ([209.132.183.28]:53056) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cjTJU-0008TR-2u for qemu-devel@nongnu.org; Thu, 02 Mar 2017 11:10:44 -0500 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 3FFCEC054918; Thu, 2 Mar 2017 16:10:44 +0000 (UTC) Received: from t460.redhat.com (ovpn-116-205.ams2.redhat.com [10.36.116.205]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v22GAaKR016904; Thu, 2 Mar 2017 11:10:42 -0500 From: "Daniel P. Berrange" To: qemu-devel@nongnu.org Date: Thu, 2 Mar 2017 16:10:33 +0000 Message-Id: <20170302161033.4787-4-berrange@redhat.com> In-Reply-To: <20170302161033.4787-1-berrange@redhat.com> References: <20170302161033.4787-1-berrange@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Thu, 02 Mar 2017 16:10:44 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v2 3/3] io: fully parse & validate HTTP headers for websocket protocol handshake X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The current websockets protocol handshake code is very relaxed, just doing crude string searching across the HTTP header data. This causes it to both reject valid connections and fail to reject invalid connections. For example, according to the RFC 6455 it: - MUST reject any method other than "GET" - MUST reject any HTTP version less than "HTTP/1.1" - MUST reject Connection header without "Upgrade" listed - MUST reject Upgrade header which is not 'websocket' - MUST reject missing Host header - MUST treat HTTP header names as case insensitive To do all this validation correctly requires that we fully parse the HTTP headers, populating a data structure containing the header fields. After this change, we also reject any path other than '/' Signed-off-by: Daniel P. Berrange --- io/channel-websock.c | 236 ++++++++++++++++++++++++++++++++++++++++++-----= ---- 1 file changed, 194 insertions(+), 42 deletions(-) diff --git a/io/channel-websock.c b/io/channel-websock.c index a06a4a8..8fabade 100644 --- a/io/channel-websock.c +++ b/io/channel-websock.c @@ -33,11 +33,16 @@ #define QIO_CHANNEL_WEBSOCK_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" #define QIO_CHANNEL_WEBSOCK_GUID_LEN strlen(QIO_CHANNEL_WEBSOCK_GUID) =20 -#define QIO_CHANNEL_WEBSOCK_HEADER_PROTOCOL "Sec-WebSocket-Protocol" -#define QIO_CHANNEL_WEBSOCK_HEADER_VERSION "Sec-WebSocket-Version" -#define QIO_CHANNEL_WEBSOCK_HEADER_KEY "Sec-WebSocket-Key" +#define QIO_CHANNEL_WEBSOCK_HEADER_PROTOCOL "sec-websocket-protocol" +#define QIO_CHANNEL_WEBSOCK_HEADER_VERSION "sec-websocket-version" +#define QIO_CHANNEL_WEBSOCK_HEADER_KEY "sec-websocket-key" +#define QIO_CHANNEL_WEBSOCK_HEADER_UPGRADE "upgrade" +#define QIO_CHANNEL_WEBSOCK_HEADER_HOST "host" +#define QIO_CHANNEL_WEBSOCK_HEADER_CONNECTION "connection" =20 #define QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY "binary" +#define QIO_CHANNEL_WEBSOCK_CONNECTION_UPGRADE "Upgrade" +#define QIO_CHANNEL_WEBSOCK_UPGRADE_WEBSOCKET "websocket" =20 #define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RESPONSE \ "HTTP/1.1 101 Switching Protocols\r\n" \ @@ -49,6 +54,9 @@ #define QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM "\r\n" #define QIO_CHANNEL_WEBSOCK_HANDSHAKE_END "\r\n\r\n" #define QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION "13" +#define QIO_CHANNEL_WEBSOCK_HTTP_METHOD "GET" +#define QIO_CHANNEL_WEBSOCK_HTTP_PATH "/" +#define QIO_CHANNEL_WEBSOCK_HTTP_VERSION "HTTP/1.1" =20 /* The websockets packet header is variable length * depending on the size of the payload... */ @@ -99,6 +107,13 @@ struct QEMU_PACKED QIOChannelWebsockHeader { } u; }; =20 +typedef struct QIOChannelWebsockHTTPHeader QIOChannelWebsockHTTPHeader; + +struct QIOChannelWebsockHTTPHeader { + char *name; + char *value; +}; + enum { QIO_CHANNEL_WEBSOCK_OPCODE_CONTINUATION =3D 0x0, QIO_CHANNEL_WEBSOCK_OPCODE_TEXT_FRAME =3D 0x1, @@ -108,25 +123,130 @@ enum { QIO_CHANNEL_WEBSOCK_OPCODE_PONG =3D 0xA }; =20 -static char *qio_channel_websock_handshake_entry(const char *handshake, - size_t handshake_len, - const char *name) -{ - char *begin, *end, *ret =3D NULL; - char *line =3D g_strdup_printf("%s%s: ", - QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM, - name); - begin =3D g_strstr_len(handshake, handshake_len, line); - if (begin !=3D NULL) { - begin +=3D strlen(line); - end =3D g_strstr_len(begin, handshake_len - (begin - handshake), - QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM); - if (end !=3D NULL) { - ret =3D g_strndup(begin, end - begin); +static size_t +qio_channel_websock_extract_headers(char *buffer, + QIOChannelWebsockHTTPHeader *hdrs, + size_t nhdrsalloc, + Error **errp) +{ + char *nl, *sep, *tmp; + size_t nhdrs =3D 0; + + /* + * First parse the HTTP protocol greeting of format: + * + * $METHOD $PATH $VERSION + * + * e.g. + * + * GET / HTTP/1.1 + */ + + nl =3D strstr(buffer, QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM); + if (!nl) { + error_setg(errp, "Missing HTTP header delimiter"); + return 0; + } + *nl =3D '\0'; + + tmp =3D strchr(buffer, ' '); + if (!tmp) { + error_setg(errp, "Missing HTTP path delimiter"); + return 0; + } + *tmp =3D '\0'; + + if (!g_str_equal(buffer, QIO_CHANNEL_WEBSOCK_HTTP_METHOD)) { + error_setg(errp, "Unsupported HTTP method %s", buffer); + return 0; + } + + buffer =3D tmp + 1; + tmp =3D strchr(buffer, ' '); + if (!tmp) { + error_setg(errp, "Missing HTTP version delimiter"); + return 0; + } + *tmp =3D '\0'; + + if (!g_str_equal(buffer, QIO_CHANNEL_WEBSOCK_HTTP_PATH)) { + error_setg(errp, "Unexpected HTTP path %s", buffer); + return 0; + } + + buffer =3D tmp + 1; + + if (!g_str_equal(buffer, QIO_CHANNEL_WEBSOCK_HTTP_VERSION)) { + error_setg(errp, "Unsupported HTTP version %s", buffer); + return 0; + } + + buffer =3D nl + strlen(QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM); + + /* + * Now parse all the header fields of format + * + * $NAME: $VALUE + * + * e.g. + * + * Cache-control: no-cache + */ + do { + QIOChannelWebsockHTTPHeader *hdr; + + nl =3D strstr(buffer, QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM); + if (nl) { + *nl =3D '\0'; + } + + sep =3D strchr(buffer, ':'); + if (!sep) { + error_setg(errp, "Malformed HTTP header"); + return 0; + } + *sep =3D '\0'; + sep++; + while (*sep =3D=3D ' ') { + sep++; + } + + if (nhdrs >=3D nhdrsalloc) { + error_setg(errp, "Too many HTTP headers"); + return 0; + } + + hdr =3D &hdrs[nhdrs++]; + hdr->name =3D buffer; + hdr->value =3D sep; + + /* Canonicalize header name for easier identification later */ + for (tmp =3D hdr->name; *tmp; tmp++) { + *tmp =3D g_ascii_tolower(*tmp); + } + + if (nl) { + buffer =3D nl + strlen(QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM); + } + } while (nl !=3D NULL); + + return nhdrs; +} + +static const char * +qio_channel_websock_find_header(QIOChannelWebsockHTTPHeader *hdrs, + size_t nhdrs, + const char *name) +{ + size_t i; + + for (i =3D 0; i < nhdrs; i++) { + if (g_str_equal(hdrs[i].name, name)) { + return hdrs[i].value; } } - g_free(line); - return ret; + + return NULL; } =20 =20 @@ -166,58 +286,90 @@ static int qio_channel_websock_handshake_send_respons= e(QIOChannelWebsock *ioc, } =20 static int qio_channel_websock_handshake_process(QIOChannelWebsock *ioc, - const char *line, - size_t size, + char *buffer, Error **errp) { - int ret =3D -1; - char *protocols =3D qio_channel_websock_handshake_entry( - line, size, QIO_CHANNEL_WEBSOCK_HEADER_PROTOCOL); - char *version =3D qio_channel_websock_handshake_entry( - line, size, QIO_CHANNEL_WEBSOCK_HEADER_VERSION); - char *key =3D qio_channel_websock_handshake_entry( - line, size, QIO_CHANNEL_WEBSOCK_HEADER_KEY); + QIOChannelWebsockHTTPHeader hdrs[32]; + size_t nhdrs =3D G_N_ELEMENTS(hdrs); + const char *protocols =3D NULL, *version =3D NULL, *key =3D NULL, + *host =3D NULL, *connection =3D NULL, *upgrade =3D NULL; =20 + nhdrs =3D qio_channel_websock_extract_headers(buffer, hdrs, nhdrs, err= p); + if (!nhdrs) { + return -1; + } + + protocols =3D qio_channel_websock_find_header( + hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_PROTOCOL); if (!protocols) { error_setg(errp, "Missing websocket protocol header data"); - goto cleanup; + return -1; } =20 + version =3D qio_channel_websock_find_header( + hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_VERSION); if (!version) { error_setg(errp, "Missing websocket version header data"); - goto cleanup; + return -1; } =20 + key =3D qio_channel_websock_find_header( + hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_KEY); if (!key) { error_setg(errp, "Missing websocket key header data"); - goto cleanup; + return -1; + } + + host =3D qio_channel_websock_find_header( + hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_HOST); + if (!host) { + error_setg(errp, "Missing websocket host header data"); + return -1; + } + + connection =3D qio_channel_websock_find_header( + hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_CONNECTION); + if (!connection) { + error_setg(errp, "Missing websocket connection header data"); + return -1; + } + + upgrade =3D qio_channel_websock_find_header( + hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_UPGRADE); + if (!upgrade) { + error_setg(errp, "Missing websocket upgrade header data"); + return -1; } =20 if (!g_strrstr(protocols, QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY)) { error_setg(errp, "No '%s' protocol is supported by client '%s'", QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY, protocols); - goto cleanup; + return -1; } =20 if (!g_str_equal(version, QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION)) { error_setg(errp, "Version '%s' is not supported by client '%s'", QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION, version); - goto cleanup; + return -1; } =20 if (strlen(key) !=3D QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN) { error_setg(errp, "Key length '%zu' was not as expected '%d'", strlen(key), QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN); - goto cleanup; + return -1; } =20 - ret =3D qio_channel_websock_handshake_send_response(ioc, key, errp); + if (!g_strrstr(connection, QIO_CHANNEL_WEBSOCK_CONNECTION_UPGRADE)) { + error_setg(errp, "No connection upgrade requested '%s'", connectio= n); + return -1; + } =20 - cleanup: - g_free(protocols); - g_free(version); - g_free(key); - return ret; + if (!g_str_equal(upgrade, QIO_CHANNEL_WEBSOCK_UPGRADE_WEBSOCKET)) { + error_setg(errp, "Incorrect upgrade method '%s'", upgrade); + return -1; + } + + return qio_channel_websock_handshake_send_response(ioc, key, errp); } =20 static int qio_channel_websock_handshake_read(QIOChannelWebsock *ioc, @@ -248,10 +400,10 @@ static int qio_channel_websock_handshake_read(QIOChan= nelWebsock *ioc, return 0; } } + *handshake_end =3D '\0'; =20 if (qio_channel_websock_handshake_process(ioc, (char *)ioc->encinput.buffer, - ioc->encinput.offset, errp) < 0) { return -1; } --=20 2.9.3