def process_frame
if hixie_75? or hixie_76?
if @buffer.length >= 1
if @buffer[0].ord < 0x7f
if ending = @buffer.index("\xff")
frame = @buffer.slice! 0..ending
message = frame[1..-2]
EM.next_tick { receive_message message }
EM.next_tick { process_frame }
elsif @buffer.length > MAX_BUFFER_LENGTH
raise WebSocketProtocolError, "Maximum buffer length (#{MAX_BUFFER_LENGTH}) exceeded: #{@buffer.length}"
end
elsif @buffer[0] == "\xff"
if @buffer.length > 1
if @buffer[1] == "\x00"
@buffer.slice! 0..1
EM.next_tick { finish! }
else
raise WebSocketProtocolError, "Incorrect finish frame length: #{@buffer[1].inspect}"
end
end
else
raise WebSocketProtocolError, "Unknown frame type: #{@buffer[0].inspect}"
end
end
else
@frame_state ||= :opcode
if @frame_state == :opcode
return unless @buffer.length >= 2
bytes = @buffer.slice!(0...2).unpack("C*")
@opcode = bytes[0] & 0x0f
@fin = (bytes[0] & 0x80) != 0
@payload_length = bytes[1] & 0x7f
@masked = (bytes[1] & 0x80) != 0
return error! "Received unmasked data" unless @masked
if @payload_length == 126
@frame_state = :payload_2
elsif @payload_length == 127
@frame_state = :payload_8
else
@frame_state = :payload
end
elsif @frame_state == :payload_2
return unless @buffer.length >= 2
@payload_length = @buffer.slice!(0...2).unpack("n")[0]
@frame_state = :mask
elsif @frame_state == :payload_8
return unless @buffer.length >= 8
(high, low) = @buffer.slice!(0...8).unpack("NN")
@payload_length = high * (2 ** 32) + low
@frame_state = :mask
elsif @frame_state == :mask
return unless @buffer.length >= 4
bytes = @buffer[(offset)...(offset += 4)]
@mask_key = bytes.unpack("C*")
@frame_state = :payload
elsif @frame_state == :payload
return unless @buffer.length >= @payload_length
payload = @buffer.slice!(0...@payload_length)
payload = mask(payload, @mask_key)
if @opcode == OPCODE_TEXT
message = payload.force_encoding("UTF-8") if payload.respond_to? :force_encoding
EM.next_tick { receive_message payload }
elsif @opcode == OPCODE_CLOSE
EM.next_tick { finish! }
else
error! "Unsupported opcode: %d" % @opcode
end
@frame_state = nil
@opcode = @fin = @payload_length = @masked = nil
end
end
rescue
error! "Error while processing WebSocket frames"
end