# File lib/skinny.rb, line 238
    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 }

              # There might be more frames to process
              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