def parse(buf)
      return nil if buf.size < 9
      frame = read_common_header(buf)
      return nil if buf.size < 9 + frame[:length]

      fail ProtocolError, 'payload too large' if frame[:length] > DEFAULT_MAX_FRAME_SIZE

      buf.read(9)
      payload = buf.read(frame[:length])

      # Implementations MUST discard frames
      # that have unknown or unsupported types.
      # - http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-5.5
      return nil if frame[:type].nil?

      # Process padding
      padlen = 0
      if FRAME_TYPES_WITH_PADDING.include?(frame[:type])
        padded = frame[:flags].include?(:padded)
        if padded
          padlen = payload.read(1).unpack(UINT8).first
          frame[:padding] = padlen + 1
          fail ProtocolError, 'padding too long' if padlen > payload.bytesize
          payload.slice!(-padlen, padlen) if padlen > 0
          frame[:length] -= frame[:padding]
          frame[:flags].delete(:padded)
        end
      end

      case frame[:type]
      when :data
        frame[:payload] = payload.read(frame[:length])
      when :headers
        if frame[:flags].include? :priority
          e_sd = payload.read_uint32
          frame[:stream_dependency] = e_sd & RBIT
          frame[:exclusive] = (e_sd & EBIT) != 0
          frame[:weight] = payload.getbyte + 1
        end
        frame[:payload] = payload.read(frame[:length])
      when :priority
        e_sd = payload.read_uint32
        frame[:stream_dependency] = e_sd & RBIT
        frame[:exclusive] = (e_sd & EBIT) != 0
        frame[:weight] = payload.getbyte + 1
      when :rst_stream
        frame[:error] = unpack_error payload.read_uint32

      when :settings
        # NOTE: frame[:length] might not match the number of frame[:payload]
        # because unknown extensions are ignored.
        frame[:payload] = []
        unless (frame[:length] % 6).zero?
          fail ProtocolError, 'Invalid settings payload length'
        end

        if (frame[:stream]).nonzero?
          fail ProtocolError, "Invalid stream ID (#{frame[:stream]})"
        end

        (frame[:length] / 6).times do
          id  = payload.read(2).unpack(UINT16).first
          val = payload.read_uint32

          # Unsupported or unrecognized settings MUST be ignored.
          # Here we send it along.
          name, _ = DEFINED_SETTINGS.find { |_name, v| v == id }
          frame[:payload] << [name, val] if name
        end
      when :push_promise
        frame[:promise_stream] = payload.read_uint32 & RBIT
        frame[:payload] = payload.read(frame[:length])
      when :ping
        frame[:payload] = payload.read(frame[:length])
      when :goaway
        frame[:last_stream] = payload.read_uint32 & RBIT
        frame[:error] = unpack_error payload.read_uint32

        size = frame[:length] - 8 # for last_stream and error
        frame[:payload] = payload.read(size) if size > 0
      when :window_update
        frame[:increment] = payload.read_uint32 & RBIT
      when :continuation
        frame[:payload] = payload.read(frame[:length])
      when :altsvc
        frame[:max_age], frame[:port] = payload.read(6).unpack(UINT32 + UINT16)

        len = payload.getbyte
        frame[:proto] = payload.read(len) if len > 0

        len = payload.getbyte
        frame[:host] = payload.read(len) if len > 0

        frame[:origin] = payload.read(payload.size) if payload.size > 0
        # else # Unknown frame type is explicitly allowed
      end

      frame
    end
def parse(buf)
      return nil if buf.size < 9
      frame = read_common_header(buf)
      return nil if buf.size < 9 + frame[:length]

      fail ProtocolError, 'payload too large' if frame[:length] > DEFAULT_MAX_FRAME_SIZE

      buf.read(9)
      payload = buf.read(frame[:length])

      # Implementations MUST discard frames
      # that have unknown or unsupported types.
      # - http://tools.ietf.org/html/draft-ietf-httpbis-http2-16#section-5.5
      return nil if frame[:type].nil?

      # Process padding
      padlen = 0
      if FRAME_TYPES_WITH_PADDING.include?(frame[:type])
        padded = frame[:flags].include?(:padded)
        if padded
          padlen = payload.read(1).unpack(UINT8).first
          frame[:padding] = padlen + 1
          fail ProtocolError, 'padding too long' if padlen > payload.bytesize
          payload.slice!(-padlen, padlen) if padlen > 0
          frame[:length] -= frame[:padding]
          frame[:flags].delete(:padded)
        end
      end

      case frame[:type]
      when :data
        frame[:payload] = payload.read(frame[:length])
      when :headers
        if frame[:flags].include? :priority
          e_sd = payload.read_uint32
          frame[:stream_dependency] = e_sd & RBIT
          frame[:exclusive] = (e_sd & EBIT) != 0
          frame[:weight] = payload.getbyte + 1
        end
        frame[:payload] = payload.read(frame[:length])
      when :priority
        e_sd = payload.read_uint32
        frame[:stream_dependency] = e_sd & RBIT
        frame[:exclusive] = (e_sd & EBIT) != 0
        frame[:weight] = payload.getbyte + 1
      when :rst_stream
        frame[:error] = unpack_error payload.read_uint32

      when :settings
        # NOTE: frame[:length] might not match the number of frame[:payload]
        # because unknown extensions are ignored.
        frame[:payload] = []
        unless (frame[:length] % 6).zero?
          fail ProtocolError, 'Invalid settings payload length'
        end

        if (frame[:stream]).nonzero?
          fail ProtocolError, "Invalid stream ID (#{frame[:stream]})"
        end

        (frame[:length] / 6).times do
          id  = payload.read(2).unpack(UINT16).first
          val = payload.read_uint32

          # Unsupported or unrecognized settings MUST be ignored.
          # Here we send it along.
          name, _ = DEFINED_SETTINGS.find { |_name, v| v == id }
          frame[:payload] << [name, val] if name
        end
      when :push_promise
        frame[:promise_stream] = payload.read_uint32 & RBIT
        frame[:payload] = payload.read(frame[:length])
      when :ping
        frame[:payload] = payload.read(frame[:length])
      when :goaway
        frame[:last_stream] = payload.read_uint32 & RBIT
        frame[:error] = unpack_error payload.read_uint32

        size = frame[:length] - 8 # for last_stream and error
        frame[:payload] = payload.read(size) if size > 0
      when :window_update
        frame[:increment] = payload.read_uint32 & RBIT
      when :continuation
        frame[:payload] = payload.read(frame[:length])
      when :altsvc
        frame[:max_age], frame[:port] = payload.read(6).unpack(UINT32 + UINT16)

        len = payload.getbyte
        frame[:proto] = payload.read(len) if len > 0

        len = payload.getbyte
        frame[:host] = payload.read(len) if len > 0

        frame[:origin] = payload.read(payload.size) if payload.size > 0
        # else # Unknown frame type is explicitly allowed
      end

      frame
    end
Decodes complete HTTP/2 frame from provided buffer. If the buffer
 does not contain enough data, no further work is performed.

 @param buf [Buffer]