class Protocol::HTTP2::Frame
Constants
- HEADER_FORMAT
- LENGTH_HISHIFT
Used for generating 24-bit frame length:
- LENGTH_LOMASK
- STREAM_ID_MASK
- VALID_LENGTH
The absolute maximum bounds for the length field:
- VALID_STREAM_ID
Stream
Identifier cannot be bigger than this: http2.github.stream/http2-spec/#rfc.section.4.1
Attributes
The generic frame header uses the following binary representation:
-----------------------------------------------
| Length (24) | ---------------
—————---------------
| Type (8) | Flags (8) | -
————----------------
——————————-+ |R| Stream
Identifier (31) | +=+=============================================================+ | Frame
Payload (0…) … ---------------------------------------------------------------
Public Class Methods
@param length [Integer] the length of the payload, or nil if the header has not been read yet.
# File lib/protocol/http2/frame.rb, line 50 def initialize(stream_id = 0, flags = 0, type = self.class::TYPE, length = nil, payload = nil) @length = length @type = type @flags = flags @stream_id = stream_id @payload = payload end
Decodes common 9-byte header.
@param buffer [String]
# File lib/protocol/http2/frame.rb, line 150 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
Public Instance Methods
# File lib/protocol/http2/frame.rb, line 62 def <=> other to_ary <=> other.to_ary end
# File lib/protocol/http2/frame.rb, line 204 def apply(connection) connection.receive_frame(self) end
# File lib/protocol/http2/frame.rb, line 105 def clear_flags(mask) @flags &= ~mask end
Check if frame is a connection frame: SETTINGS, PING, GOAWAY, and any frame addressed to stream ID = 0.
@return [Boolean]
# File lib/protocol/http2/frame.rb, line 117 def connection? @stream_id.zero? end
# File lib/protocol/http2/frame.rb, line 109 def flag_set?(mask) @flags & mask != 0 end
Generates common 9-byte frame header.
@return [String]
# File lib/protocol/http2/frame.rb, line 128 def header unless VALID_LENGTH.include? @length raise ProtocolError, "Invalid frame size: #{@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
# File lib/protocol/http2/frame.rb, line 208 def inspect "\#<#{self.class} stream_id=#{@stream_id} flags=#{@flags} #{self.unpack}>" end
# File lib/protocol/http2/frame.rb, line 92 def pack(payload, maximum_size: nil) @payload = payload @length = payload.bytesize if maximum_size and @length > maximum_size raise ProtocolError, "Frame length #{@length} bigger than maximum allowed: #{maximum_size}" end end
# File lib/protocol/http2/frame.rb, line 177 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
# File lib/protocol/http2/frame.rb, line 160 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
# File lib/protocol/http2/frame.rb, line 169 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
# File lib/protocol/http2/frame.rb, line 101 def set_flags(mask) @flags |= mask end
# File lib/protocol/http2/frame.rb, line 66 def to_ary [@length, @type, @flags, @stream_id, @payload] end
# File lib/protocol/http2/frame.rb, line 88 def unpack @payload end
# File lib/protocol/http2/frame.rb, line 58 def valid_type? @type == self.class::TYPE end
# File lib/protocol/http2/frame.rb, line 195 def write(stream) if @payload and @length != @payload.bytesize raise ProtocolError, "Invalid payload size: #{@length} != #{@payload.bytesize}" end self.write_header(stream) self.write_payload(stream) end
# File lib/protocol/http2/frame.rb, line 187 def write_header(stream) stream.write self.header end
# File lib/protocol/http2/frame.rb, line 191 def write_payload(stream) stream.write(@payload) if @payload end