Module: Quicsilver::Protocol::ControlStreamParser
- Included in:
- Client, Transport::Connection
- Defined in:
- lib/quicsilver/protocol/control_stream_parser.rb
Overview
Shared control stream parsing for both server Connection and Client.
RFC 9114 §7.2.4: Both endpoints MUST send and process SETTINGS. RFC 9114 §7.2.6: Both endpoints MUST validate incoming GOAWAY.
Includer must provide:
@settings_received — boolean, initially false
@peer_goaway_id — nil initially
Includer may override:
on_settings_received(settings_hash) — called after SETTINGS parsed
on_goaway_received(stream_id) — called after GOAWAY parsed
handle_control_frame(type, payload) — called for non-SETTINGS/GOAWAY frames
Constant Summary collapse
- HTTP2_SETTINGS =
RFC 9114 §7.2.4.1 / §11.2.2: HTTP/2 setting identifiers forbidden in HTTP/3 0x00 = SETTINGS_HEADER_TABLE_SIZE (reserved), 0x02-0x05 = various HTTP/2 settings Note: 0x08 (SETTINGS_ENABLE_CONNECT_PROTOCOL) is valid in HTTP/3 per RFC 9220
[0x00, 0x02, 0x03, 0x04, 0x05].freeze
Instance Method Summary collapse
- #parse_control_frames(data) ⇒ Object
-
#parse_peer_goaway(payload) ⇒ Object
RFC 9114 §7.2.6: Validate incoming GOAWAY frame.
- #parse_peer_settings(payload) ⇒ Object
Instance Method Details
#parse_control_frames(data) ⇒ Object
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/quicsilver/protocol/control_stream_parser.rb', line 24 def parse_control_frames(data) first_frame = !@settings_received Protocol::FrameReader.each(data) do |type, payload| if first_frame && type != Protocol::FRAME_SETTINGS raise Protocol::FrameError.new("First frame on control stream must be SETTINGS", error_code: Protocol::H3_MISSING_SETTINGS) end first_frame = false case type when Protocol::FRAME_SETTINGS raise Protocol::FrameError, "Duplicate SETTINGS frame on control stream" if @settings_received parse_peer_settings(payload) @settings_received = true when Protocol::FRAME_GOAWAY parse_peer_goaway(payload) else handle_control_frame(type, payload) end end end |
#parse_peer_goaway(payload) ⇒ Object
RFC 9114 §7.2.6: Validate incoming GOAWAY frame. Stream ID must be a client-initiated bidirectional stream ID (divisible by 4) and must not increase from a previous GOAWAY.
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/quicsilver/protocol/control_stream_parser.rb', line 75 def parse_peer_goaway(payload) stream_id, _ = Protocol.decode_varint(payload.bytes, 0) unless stream_id % 4 == 0 raise Protocol::FrameError.new( "GOAWAY stream ID #{stream_id} is not a client-initiated bidirectional stream ID", error_code: Protocol::H3_ID_ERROR) end if @peer_goaway_id && stream_id > @peer_goaway_id raise Protocol::FrameError.new( "GOAWAY stream ID #{stream_id} exceeds previous #{@peer_goaway_id}", error_code: Protocol::H3_ID_ERROR) end @peer_goaway_id = stream_id end |
#parse_peer_settings(payload) ⇒ Object
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/quicsilver/protocol/control_stream_parser.rb', line 47 def parse_peer_settings(payload) offset = 0 seen = Set.new settings = {} while offset < payload.bytesize id, id_len = Protocol.decode_varint(payload.bytes, offset) value, value_len = Protocol.decode_varint(payload.bytes, offset + id_len) break if id_len == 0 || value_len == 0 if HTTP2_SETTINGS.include?(id) raise Protocol::FrameError.new("HTTP/2 setting identifier 0x#{id.to_s(16)} not allowed in HTTP/3", error_code: Protocol::H3_SETTINGS_ERROR) end raise Protocol::FrameError, "Duplicate setting identifier 0x#{id.to_s(16)}" if seen.include?(id) seen.add(id) settings[id] = value offset += id_len + value_len end on_settings_received(settings) end |