From eed84b6cd6f7eca3fc5bf2ed6e2c3c48a25f63c8 Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 13 Jul 2026 15:50:01 +0200 Subject: [PATCH 1/3] WebSocketClient: fix undefined read order in frame length Multiple read() calls in one expression have unspecified evaluation order in C++, so the length bytes could be combined wrong. Read each byte into its own variable before combining them. --- src/WebSocketClient.cpp | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/WebSocketClient.cpp b/src/WebSocketClient.cpp index ab41b0a..437748d 100644 --- a/src/WebSocketClient.cpp +++ b/src/WebSocketClient.cpp @@ -213,18 +213,30 @@ int WebSocketClient::parseMessage() } else if (length == 126) { - iRxSize = (HttpClient::read() << 8) | HttpClient::read(); + // read each byte in a well-defined order (the evaluation order of + // multiple read() calls in a single expression is unspecified) + uint8_t b1 = HttpClient::read(); + uint8_t b0 = HttpClient::read(); + iRxSize = ((uint64_t)b1 << 8) | b0; } else { - iRxSize = ((uint64_t)HttpClient::read() << 56) | - ((uint64_t)HttpClient::read() << 48) | - ((uint64_t)HttpClient::read() << 40) | - ((uint64_t)HttpClient::read() << 32) | - ((uint64_t)HttpClient::read() << 24) | - ((uint64_t)HttpClient::read() << 16) | - ((uint64_t)HttpClient::read() << 8) | - (uint64_t)HttpClient::read(); + uint8_t b7 = HttpClient::read(); + uint8_t b6 = HttpClient::read(); + uint8_t b5 = HttpClient::read(); + uint8_t b4 = HttpClient::read(); + uint8_t b3 = HttpClient::read(); + uint8_t b2 = HttpClient::read(); + uint8_t b1 = HttpClient::read(); + uint8_t b0 = HttpClient::read(); + iRxSize = ((uint64_t)b7 << 56) | + ((uint64_t)b6 << 48) | + ((uint64_t)b5 << 40) | + ((uint64_t)b4 << 32) | + ((uint64_t)b3 << 24) | + ((uint64_t)b2 << 16) | + ((uint64_t)b1 << 8) | + (uint64_t)b0; } // read in the mask, if present From 532b516b73857dadd972bb464f96590821b64acd Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 13 Jul 2026 15:50:15 +0200 Subject: [PATCH 2/3] WebSocketClient: simplify RX size branching Default iRxSize to the inline length and only override it for the 126/127 extended-length cases. No behavioural change. --- src/WebSocketClient.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/WebSocketClient.cpp b/src/WebSocketClient.cpp index 437748d..f7c1ddc 100644 --- a/src/WebSocketClient.cpp +++ b/src/WebSocketClient.cpp @@ -207,11 +207,8 @@ int WebSocketClient::parseMessage() length &= 0x7f; // read the RX size - if (length < 126) - { - iRxSize = length; - } - else if (length == 126) + iRxSize = length; + if (length == 126) { // read each byte in a well-defined order (the evaluation order of // multiple read() calls in a single expression is unspecified) @@ -219,7 +216,7 @@ int WebSocketClient::parseMessage() uint8_t b0 = HttpClient::read(); iRxSize = ((uint64_t)b1 << 8) | b0; } - else + else if (length == 127) { uint8_t b7 = HttpClient::read(); uint8_t b6 = HttpClient::read(); From d0a757775795fa0e84dd0c6d5bfede2d5ed634e7 Mon Sep 17 00:00:00 2001 From: pennam Date: Mon, 13 Jul 2026 15:50:30 +0200 Subject: [PATCH 3/3] WebSocketClient: check extended length/mask bytes are available Only 2 header bytes were guaranteed before reading the extended length and mask, so a partial header made read() return -1 and corrupt iRxSize. Bail out until all header bytes have arrived. --- src/WebSocketClient.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/WebSocketClient.cpp b/src/WebSocketClient.cpp index f7c1ddc..e97d4a9 100644 --- a/src/WebSocketClient.cpp +++ b/src/WebSocketClient.cpp @@ -206,6 +206,26 @@ int WebSocketClient::parseMessage() iRxMasked = (length & 0x80); length &= 0x7f; + // work out how many extended length and mask bytes follow the + // initial opcode + length bytes + int extendedLength = 0; + if (length == 126) + { + extendedLength = 2; + } + else if (length == 127) + { + extendedLength = 8; + } + int maskLength = iRxMasked ? (int)sizeof(iRxMaskKey) : 0; + + // make sure the remaining header bytes are available before reading + // them, otherwise the frame header is incomplete + if (HttpClient::available() < (extendedLength + maskLength)) + { + return 0; + } + // read the RX size iRxSize = length; if (length == 126)