@@ -518,9 +518,12 @@ void AsyncWebSocketClient::_onData(void *pbuf, size_t plen) {
518518 _pinfo.masked = ((fdata[1 ] & 0x80 ) != 0 ) ? 1 : 0 ;
519519 _pinfo.len = fdata[1 ] & 0x7F ;
520520
521- // async_ws_log_d("WS[%" PRIu32 "]: _onData: %" PRIu32, _clientId, plen);
522- // async_ws_log_d("WS[%" PRIu32 "]: _status = %" PRIu32, _clientId, _status);
523- // async_ws_log_d("WS[%" PRIu32 "]: _pinfo: index: %" PRIu64 ", final: %" PRIu8 ", opcode: %" PRIu8 ", masked: %" PRIu8 ", len: %" PRIu64, _clientId, _pinfo.index, _pinfo.final, _pinfo.opcode, _pinfo.masked, _pinfo.len);
521+ // async_ws_log_w("WS[%" PRIu32 "]: _onData: %" PRIu32, _clientId, plen);
522+ // async_ws_log_w("WS[%" PRIu32 "]: _status = %" PRIu32, _clientId, _status);
523+ // async_ws_log_w(
524+ // "WS[%" PRIu32 "]: _pinfo: index: %" PRIu64 ", final: %" PRIu8 ", opcode: %" PRIu8 ", masked: %" PRIu8 ", len: %" PRIu64, _clientId, _pinfo.index,
525+ // _pinfo.final, _pinfo.opcode, _pinfo.masked, _pinfo.len
526+ // );
524527
525528 data += 2 ;
526529 plen -= 2 ;
@@ -538,24 +541,48 @@ void AsyncWebSocketClient::_onData(void *pbuf, size_t plen) {
538541 }
539542 }
540543
541- if (_pinfo.masked > 0 && _pinfo.masked < 5 ) {
542- // Handle fragmented mask data - Safari may split the 4-byte mask across multiple packets
543- while (_pinfo.masked < 5 ) {
544- if (plen == 0 ) {
545- // wait for more data
544+ if (_pinfo.masked ) {
545+ // Read mask bytes (may be fragmented across packets in Safari)
546+ size_t mask_offset = 0 ;
547+
548+ // If we're resuming from a previous fragmented read, check _pinfo.index
549+ if (_pstate == 1 && _pinfo.index < 4 ) {
550+ mask_offset = _pinfo.index ;
551+ }
552+
553+ // Read as many mask bytes as available
554+ while (mask_offset < 4 && plen > 0 ) {
555+ _pinfo.mask [mask_offset++] = *data++;
556+ plen--;
557+ }
558+
559+ // Check if we have all 4 mask bytes
560+ if (mask_offset < 4 ) {
561+ // Incomplete mask
562+ if (_pinfo.opcode == WS_DISCONNECT && plen == 0 ) {
563+ // Safari close frame edge case: masked bit set but no mask data
564+ // async_ws_log_w("WS[%" PRIu32 "]: close frame with incomplete mask, treating as unmasked", _clientId);
565+ _pinfo.masked = 0 ;
566+ _pinfo.index = 0 ;
567+ } else {
568+ // Wait for more data
569+ // async_ws_log_w("WS[%" PRIu32 "]: waiting for more mask data: read=%zu/4", _clientId, mask_offset);
570+ _pinfo.index = mask_offset; // Save progress
546571 _pstate = 1 ;
547572 return ;
548573 }
549- _pinfo. mask [_pinfo. masked - 1 ] = data[ 0 ];
550- data += 1 ;
551- plen -= 1 ;
552- _pinfo.masked ++;
574+ } else {
575+ // All mask bytes received
576+ // async_ws_log_w("WS[%" PRIu32 "]: mask complete", _clientId) ;
577+ _pinfo.index = 0 ; // Reset index for payload processing
553578 }
554579 }
555580
556581 const size_t datalen = std::min ((size_t )(_pinfo.len - _pinfo.index ), plen);
557582 const auto datalast = data[datalen];
558583
584+ // async_ws_log_w("WS[%" PRIu32 "]: _processing data: datalen=%" PRIu32 ", plen=%" PRIu32, _clientId, datalen, plen);
585+
559586 if (_pinfo.masked ) {
560587 for (size_t i = 0 ; i < datalen; i++) {
561588 data[i] ^= _pinfo.mask [(_pinfo.index + i) % 4 ];
@@ -614,7 +641,7 @@ void AsyncWebSocketClient::_onData(void *pbuf, size_t plen) {
614641 }
615642 }
616643 } else {
617- // os_printf ("frame error: len: %u, index: %llu, total: %llu\n", datalen, _pinfo.index, _pinfo.len);
644+ // async_ws_log_w ("frame error: len: %u, index: %llu, total: %llu\n", datalen, _pinfo.index, _pinfo.len);
618645 // what should we do?
619646 break ;
620647 }
0 commit comments