class Protocol::HTTP2::Frame
and manipulation according to RFC 7540.
This class provides common functionality for frame parsing, serialization,
Represents the base class for all HTTP/2 frames.
def self.parse_header(buffer)
Decodes common 9-byte header.
def self.parse_header(buffer) length_hi, length_lo, type, flags, stream_id = buffer.unpack(HEADER_FORMAT) length = (length_hi << LENGTH_HISHIFT) | length_lo stream_id = stream_id & STREAM_ID_MASK # puts "parse_header: length=#{length} type=#{type} flags=#{flags} stream_id=#{stream_id}" return length, type, flags, stream_id end
def <=> other
@parameter other [Frame] The frame to compare with.
Compare frames based on their essential properties.
def <=> other to_ary <=> other.to_ary end
def apply(connection)
Apply the frame to a connection for processing.
def apply(connection) connection.receive_frame(self) end
def clear_flags(mask)
Clear specific flags on the frame.
def clear_flags(mask) @flags &= ~mask end
def connection?
-
(Boolean)- If this is a connection frame.
def connection? @stream_id.zero? end
def flag_set?(mask)
@parameter mask [Integer] The flag bits to check.
Check if specific flags are set on the frame.
def flag_set?(mask) @flags & mask != 0 end
def header
-
(String)-
def header unless VALID_LENGTH.include? @length raise ProtocolError, "Invalid frame length: #{@length.inspect}" end unless VALID_STREAM_ID.include? @stream_id raise ProtocolError, "Invalid stream identifier: #{@stream_id.inspect}" end [ # These are guaranteed correct due to the length check above. @length >> LENGTH_HISHIFT, @length & LENGTH_LOMASK, @type, @flags, @stream_id ].pack(HEADER_FORMAT) end
def initialize(stream_id = 0, flags = 0, type = self.class::TYPE, length = nil, payload = nil)
def initialize(stream_id = 0, flags = 0, type = self.class::TYPE, length = nil, payload = nil) @stream_id = stream_id @flags = flags @type = type @length = length @payload = payload end
def inspect
Provide a readable representation of the frame for debugging.
def inspect "\#<#{self.class} stream_id=#{@stream_id} flags=#{@flags} payload=#{self.unpack}>" end
def pack(payload, maximum_size: nil)
@parameter maximum_size [Integer | Nil] Optional maximum payload size.
@parameter payload [String] The payload data to pack.
Pack payload data into the frame.
def pack(payload, maximum_size: nil) @payload = payload @length = payload.bytesize if maximum_size and @length > maximum_size raise ProtocolError, "Frame length bigger than maximum allowed: #{@length} > #{maximum_size}" end end
def read(stream, maximum_frame_size = MAXIMUM_ALLOWED_FRAME_SIZE)
@raises [FrameSizeError] If the frame exceeds the maximum size.
@parameter maximum_frame_size [Integer] The maximum allowed frame size.
@parameter stream [IO] The stream to read from.
Read the complete frame (header and payload) from a stream.
def read(stream, maximum_frame_size = MAXIMUM_ALLOWED_FRAME_SIZE) read_header(stream) unless @length if @length > maximum_frame_size raise FrameSizeError, "#{self.class} (type=#{@type}) frame length #{@length} exceeds maximum frame size #{maximum_frame_size}!" end read_payload(stream) end
def read_header(stream)
@parameter stream [IO] The stream to read from.
Read the frame header from a stream.
def read_header(stream) if buffer = stream.read(9) and buffer.bytesize == 9 @length, @type, @flags, @stream_id = Frame.parse_header(buffer) # puts "read_header: #{@length} #{@type} #{@flags} #{@stream_id}" else raise EOFError, "Could not read frame header!" end end
def read_payload(stream)
@parameter stream [IO] The stream to read from.
Read the frame payload from a stream.
def read_payload(stream) if payload = stream.read(@length) and payload.bytesize == @length @payload = payload else raise EOFError, "Could not read frame payload!" end end
def set_flags(mask)
Set specific flags on the frame.
def set_flags(mask) @flags |= mask end
def to_ary
Convert frame to array representation for comparison.
def to_ary [@length, @type, @flags, @stream_id, @payload] end
def unpack
Unpack the frame payload data.
def unpack @payload end
def valid_type?
Check if the frame has a valid type identifier.
def valid_type? @type == self.class::TYPE end
def write(stream)
@parameter stream [IO] The stream to write to.
Write the complete frame (header and payload) to a stream.
def write(stream) # Validate the payload size: if @payload.nil? if @length != 0 raise ProtocolError, "Invalid frame length: #{@length} != 0" end else if @length != @payload.bytesize raise ProtocolError, "Invalid payload size: #{@length} != #{@payload.bytesize}" end end self.write_header(stream) self.write_payload(stream) end
def write_header(stream)
Write the frame header to a stream.
def write_header(stream) stream.write self.header end
def write_payload(stream)
Write the frame payload to a stream.
def write_payload(stream) stream.write(@payload) if @payload end