Class: WebSocket::Frame::Handler::Handler03

### Home Classes Methods

### In Files

- lib/websocket/frame/handler/handler03.rb

### Parent

WebSocket::Frame::Handler::Base

### Methods

- #decode_frame
- #encode_frame
- #masking?
- #supported_frames

### Class/Module Index

Quicksearch

- WebSocket
- WebSocket::Error
- WebSocket::Error::Frame
- WebSocket::Error::Frame::ControlFramePayloadTooLong
- WebSocket::Error::Frame::DataFrameInsteadContinuation
- WebSocket::Error::Frame::FragmentedControlFrame
- WebSocket::Error::Frame::Invalid
- WebSocket::Error::Frame::InvalidPayloadEncoding
- WebSocket::Error::Frame::MaskTooShort
- WebSocket::Error::Frame::ReservedBitUsed
- WebSocket::Error::Frame::TooLong
- WebSocket::Error::Frame::UnexpectedContinuationFrame
- WebSocket::Error::Frame::UnknownCloseCode
- WebSocket::Error::Frame::UnknownFrameType
- WebSocket::Error::Frame::UnknownOpcode
- WebSocket::Error::Frame::UnknownVersion
- WebSocket::Error::Handshake
- WebSocket::Error::Handshake::GetRequestRequired
- WebSocket::Error::Handshake::InvalidAuthentication
- WebSocket::Error::Handshake::InvalidHeader
- WebSocket::Error::Handshake::InvalidStatusCode
- WebSocket::Error::Handshake::NoHostProvided
- WebSocket::Error::Handshake::UnknownVersion
- WebSocket::ExceptionHandler
- WebSocket::ExceptionHandler::ClassMethods
- WebSocket::Frame
- WebSocket::Frame::Base
- WebSocket::Frame::Data
- WebSocket::Frame::Handler
- WebSocket::Frame::Handler::Base
- WebSocket::Frame::Handler::Handler03
- WebSocket::Frame::Handler::Handler04
- WebSocket::Frame::Handler::Handler05
- WebSocket::Frame::Handler::Handler07
- WebSocket::Frame::Handler::Handler75
- WebSocket::Frame::Incoming
- WebSocket::Frame::Incoming::Client
- WebSocket::Frame::Incoming::Server
- WebSocket::Frame::Outgoing
- WebSocket::Frame::Outgoing::Client
- WebSocket::Frame::Outgoing::Server
- WebSocket::Handshake
- WebSocket::Handshake::Base
- WebSocket::Handshake::Client
- WebSocket::Handshake::Handler
- WebSocket::Handshake::Handler::Base
- WebSocket::Handshake::Handler::Client
- WebSocket::Handshake::Handler::Client01
- WebSocket::Handshake::Handler::Client04
- WebSocket::Handshake::Handler::Client11
- WebSocket::Handshake::Handler::Client75
- WebSocket::Handshake::Handler::Client76
- WebSocket::Handshake::Handler::Server
- WebSocket::Handshake::Handler::Server04
- WebSocket::Handshake::Handler::Server75
- WebSocket::Handshake::Handler::Server76
- WebSocket::Handshake::Server

No matching classes.

# WebSocket::Frame::Handler::Handler03

### Constants

FRAME_TYPES

  Hash of frame names and it's opcodes

FRAME_TYPES_INVERSE

  Hash of frame opcodes and it's names

### Public Instance Methods

decode_frame() click to toggle source

@see WebSocket::Frame::Handler::Base#decode_frame

    # File lib/websocket/frame/handler/handler03.rb, line 60
    def decode_frame
      while @frame.data.size > 1
        pointer = 0

        more = ((@frame.data.getbyte(pointer) & 0b10000000) == 0b10000000) ^ fin

        raise(WebSocket::Error::Frame::ReservedBitUsed) if @frame.data.getbyte(pointer) & 0b01110000 != 0b00000000

        opcode = @frame.data.getbyte(pointer) & 0b00001111
        frame_type = opcode_to_type(opcode)
        pointer += 1

        raise(WebSocket::Error::Frame::FragmentedControlFrame) if more && control_frame?(frame_type)
        raise(WebSocket::Error::Frame::DataFrameInsteadContinuation) if data_frame?(frame_type) && !@application_data_buffer.nil?

        mask = @frame.incoming_masking? && (@frame.data.getbyte(pointer) & 0b10000000) == 0b10000000
        length = @frame.data.getbyte(pointer) & 0b01111111

        raise(WebSocket::Error::Frame::ControlFramePayloadTooLong) if length > 125 && control_frame?(frame_type)

        pointer += 1

        payload_length = case length
        when 127 # Length defined by 8 bytes
          # Check buffer size
          return if @frame.data.getbyte(pointer + 8 - 1) == nil # Buffer incomplete

          # Only using the last 4 bytes for now, till I work out how to
          # unpack 8 bytes. I'm sure 4GB frames will do for now :)
          l = @frame.data.getbytes(pointer + 4, 4).unpack('N').first
          pointer += 8
          l
        when 126 # Length defined by 2 bytes
          # Check buffer size
          return if @frame.data.getbyte(pointer + 2 - 1) == nil # Buffer incomplete

          l = @frame.data.getbytes(pointer, 2).unpack('n').first
          pointer += 2
          l
        else
          length
        end

        # Compute the expected frame length
        frame_length = pointer + payload_length
        frame_length += 4 if mask

        raise(WebSocket::Error::Frame::TooLong) if frame_length > WebSocket.max_frame_size

        # Check buffer size
        return if @frame.data.getbyte(frame_length - 1) == nil # Buffer incomplete

        # Remove frame header
        @frame.data.slice!(0...pointer)
        pointer = 0

        # Read application data (unmasked if required)
        @frame.data.set_mask if mask
        pointer += 4 if mask
        application_data = @frame.data.getbytes(pointer, payload_length)
        application_data.force_encoding('UTF-8')
        pointer += payload_length
        @frame.data.unset_mask if mask

        # Throw away data up to pointer
        @frame.data.slice!(0...pointer)

        raise(WebSocket::Error::Frame::UnexpectedContinuationFrame) if frame_type == :continuation && !@frame_type

        if more
          @application_data_buffer ||= ''
          @application_data_buffer << application_data
          @frame_type ||= frame_type
        else
          # Message is complete
          if frame_type == :continuation
            @application_data_buffer << application_data
            # Test valid UTF-8 encoding
            raise(WebSocket::Error::Frame::InvalidPayloadEncoding) if @frame_type == :text && !@application_data_buffer.valid_encoding?
            message = @frame.class.new(version: @frame.version, type: @frame_type, data: @application_data_buffer, decoded: true)
            @application_data_buffer = nil
            @frame_type = nil
            return message
          else
            raise(WebSocket::Error::Frame::InvalidPayloadEncoding) if frame_type == :text && !application_data.valid_encoding?
            return @frame.class.new(version: @frame.version, type: frame_type, data: application_data, decoded: true)
          end
        end
      end
      return nil
    end

encode_frame() click to toggle source

@see WebSocket::Frame::Handler::Base#encode_frame

    # File lib/websocket/frame/handler/handler03.rb, line 26
    def encode_frame
      frame = ''

      opcode = type_to_opcode(@frame.type)
      byte1 = opcode | (fin ? 0b10000000 : 0b00000000) # since more, rsv1-3 are 0 and 0x80 for Draft 4
      frame << byte1

      mask = @frame.outgoing_masking? ? 0b10000000 : 0b00000000

      length = @frame.data.size
      if length <= 125
        byte2 = length # since rsv4 is 0
        frame << (byte2 | mask)
      elsif length < 65_536 # write 2 byte length
        frame << (126 | mask)
        frame << [length].pack('n')
      else # write 8 byte length
        frame << (127 | mask)
        frame << [length >> 32, length & 0xFFFFFFFF].pack('NN')
      end

      if @frame.outgoing_masking?
        masking_key = [rand(256).chr, rand(256).chr, rand(256).chr, rand(256).chr].join
        tmp_data = Data.new([masking_key, @frame.data.to_s].join)
        tmp_data.set_mask
        frame << masking_key + tmp_data.getbytes(4, tmp_data.size)
      else
        frame << @frame.data
      end

      frame
    end

masking?() click to toggle source

Allow turning on or off masking

    # File lib/websocket/frame/handler/handler03.rb, line 153
    def masking?; false; end

supported_frames() click to toggle source

@see WebSocket::Frame::Base#supported_frames

    # File lib/websocket/frame/handler/handler03.rb, line 21
    def supported_frames
      [:text, :binary, :close, :ping, :pong]
    end

[Validate]

Generated with the Darkfish Rdoc Generator 2.