in Sources/NIOWebSocket/WebSocketFrameDecoder.swift [107:184]
mutating func parseStep(_ buffer: inout ByteBuffer) -> ParseResult {
switch self.state {
case .idle:
// This is a new buffer. We want to find the first octet and save it off.
guard let firstByte = buffer.readInteger(as: UInt8.self) else {
return .insufficientData
}
self.state = .firstByteReceived(firstByte: firstByte)
return .continueParsing
case .firstByteReceived(let firstByte):
// Now we're looking for the length. We begin by finding the length byte to see if we
// need any more data.
guard let lengthByte = buffer.readInteger(as: UInt8.self) else {
return .insufficientData
}
let masked = (lengthByte & 0x80) != 0
switch (lengthByte & 0x7F, masked) {
case (126, _):
self.state = .waitingForLengthWord(firstByte: firstByte, masked: masked)
case (127, _):
self.state = .waitingForLengthQWord(firstByte: firstByte, masked: masked)
case (let len, true):
assert(len <= 125)
self.state = .waitingForMask(firstByte: firstByte, length: Int(len))
case (let len, false):
assert(len <= 125)
self.state = .waitingForData(firstByte: firstByte, length: Int(len), maskingKey: nil)
}
return .continueParsing
case .waitingForLengthWord(let firstByte, let masked):
// We've got a one-word length here.
guard let lengthWord = buffer.readInteger(as: UInt16.self) else {
return .insufficientData
}
if masked {
self.state = .waitingForMask(firstByte: firstByte, length: Int(lengthWord))
} else {
self.state = .waitingForData(firstByte: firstByte, length: Int(lengthWord), maskingKey: nil)
}
return .continueParsing
case .waitingForLengthQWord(let firstByte, let masked):
// We've got a qword of length here.
guard let lengthQWord = buffer.readInteger(as: UInt64.self) else {
return .insufficientData
}
if masked {
self.state = .waitingForMask(firstByte: firstByte, length: Int(lengthQWord))
} else {
self.state = .waitingForData(firstByte: firstByte, length: Int(lengthQWord), maskingKey: nil)
}
return .continueParsing
case .waitingForMask(let firstByte, let length):
// We're waiting for the masking key.
guard let maskingKey = buffer.readInteger(as: UInt32.self) else {
return .insufficientData
}
self.state = .waitingForData(firstByte: firstByte, length: length, maskingKey: WebSocketMaskingKey(networkRepresentation: maskingKey))
return .continueParsing
case .waitingForData(let firstByte, let length, let maskingKey):
guard let data = buffer.readSlice(length: length) else {
return .insufficientData
}
let frame = WebSocketFrame(firstByte: firstByte, maskKey: maskingKey, applicationData: data)
self.state = .idle
return .result(frame)
}
}