in lib/src/copy/web_socket_impl.dart [123:229]
void add(List<int> bytes) {
final buffer = bytes is Uint8List ? bytes : Uint8List.fromList(bytes);
var index = 0;
final lastIndex = buffer.length;
if (_state == CLOSED) {
throw WebSocketChannelException('Data on closed connection');
}
if (_state == FAILURE) {
throw WebSocketChannelException('Data on failed connection');
}
while ((index < lastIndex) && _state != CLOSED && _state != FAILURE) {
final byte = buffer[index];
if (_state <= LEN_REST) {
if (_state == START) {
_fin = (byte & FIN) != 0;
if ((byte & (RSV2 | RSV3)) != 0) {
// The RSV2, RSV3 bits must both be zero.
throw WebSocketChannelException('Protocol error');
}
_opcode = byte & OPCODE;
if (_opcode <= _WebSocketOpcode.BINARY) {
if (_opcode == _WebSocketOpcode.CONTINUATION) {
if (_currentMessageType == _WebSocketMessageType.NONE) {
throw WebSocketChannelException('Protocol error');
}
} else {
assert(_opcode == _WebSocketOpcode.TEXT ||
_opcode == _WebSocketOpcode.BINARY);
if (_currentMessageType != _WebSocketMessageType.NONE) {
throw WebSocketChannelException('Protocol error');
}
_currentMessageType = _opcode;
}
} else if (_opcode >= _WebSocketOpcode.CLOSE &&
_opcode <= _WebSocketOpcode.PONG) {
// Control frames cannot be fragmented.
if (!_fin) throw WebSocketChannelException('Protocol error');
} else {
throw WebSocketChannelException('Protocol error');
}
_state = LEN_FIRST;
} else if (_state == LEN_FIRST) {
_masked = (byte & 0x80) != 0;
_len = byte & 0x7F;
if (_isControlFrame() && _len > 125) {
throw WebSocketChannelException('Protocol error');
}
if (_len == 126) {
_len = 0;
_remainingLenBytes = 2;
_state = LEN_REST;
} else if (_len == 127) {
_len = 0;
_remainingLenBytes = 8;
_state = LEN_REST;
} else {
assert(_len < 126);
_lengthDone();
}
} else {
assert(_state == LEN_REST);
_len = _len << 8 | byte;
_remainingLenBytes--;
if (_remainingLenBytes == 0) {
_lengthDone();
}
}
} else {
if (_state == MASK) {
_maskingBytes[4 - _remainingMaskingKeyBytes--] = byte;
if (_remainingMaskingKeyBytes == 0) {
_maskDone();
}
} else {
assert(_state == PAYLOAD);
// The payload is not handled one byte at a time but in blocks.
final payloadLength = min(lastIndex - index, _remainingPayloadBytes);
_remainingPayloadBytes -= payloadLength;
// Unmask payload if masked.
if (_masked) {
_unmask(index, payloadLength, buffer);
}
// Control frame and data frame share _payloads.
_payload.add(Uint8List.view(buffer.buffer, index, payloadLength));
index += payloadLength;
if (_isControlFrame()) {
if (_remainingPayloadBytes == 0) _controlFrameEnd();
} else {
if (_currentMessageType != _WebSocketMessageType.TEXT &&
_currentMessageType != _WebSocketMessageType.BINARY) {
throw WebSocketChannelException('Protocol error');
}
if (_remainingPayloadBytes == 0) _messageFrameEnd();
}
// Hack - as we always do index++ below.
index--;
}
}
// Move to the next byte.
index++;
}
}