1212
1313module Protocol
1414 module HTTP2
15+ # This is the core connection class that handles HTTP/2 protocol semantics including
16+ # stream management, settings negotiation, and frame processing.
1517 class Connection
1618 include FlowControlled
1719
20+ # Initialize a new HTTP/2 connection.
21+ # @parameter framer [Framer] The frame handler for reading/writing HTTP/2 frames.
22+ # @parameter local_stream_id [Integer] The starting stream ID for locally-initiated streams.
1823 def initialize ( framer , local_stream_id )
1924 super ( )
2025
@@ -41,10 +46,15 @@ def initialize(framer, local_stream_id)
4146 @remote_window = Window . new
4247 end
4348
49+ # The connection stream ID (always 0 for connection-level operations).
50+ # @returns [Integer] Always returns 0 for the connection itself.
4451 def id
4552 0
4653 end
4754
55+ # Access streams by ID, with 0 returning the connection itself.
56+ # @parameter id [Integer] The stream ID to look up.
57+ # @returns [Connection | Stream | Nil] The connection (if id=0), stream, or nil.
4858 def [] id
4959 if id . zero?
5060 self
@@ -89,6 +99,9 @@ def closed?
8999 @state == :closed || @framer . nil?
90100 end
91101
102+ # Remove a stream from the active streams collection.
103+ # @parameter id [Integer] The stream ID to remove.
104+ # @returns [Stream | Nil] The removed stream, or nil if not found.
92105 def delete ( id )
93106 @streams . delete ( id )
94107 end
@@ -106,10 +119,17 @@ def close(error = nil)
106119 end
107120 end
108121
122+ # Encode headers using HPACK compression.
123+ # @parameter headers [Array] The headers to encode.
124+ # @parameter buffer [String] Optional buffer for encoding output.
125+ # @returns [String] The encoded header block.
109126 def encode_headers ( headers , buffer = String . new . b )
110127 HPACK ::Compressor . new ( buffer , @encoder , table_size_limit : @remote_settings . header_table_size ) . encode ( headers )
111128 end
112129
130+ # Decode headers using HPACK decompression.
131+ # @parameter data [String] The encoded header block data.
132+ # @returns [Array] The decoded headers.
113133 def decode_headers ( data )
114134 HPACK ::Decompressor . new ( data , @decoder , table_size_limit : @local_settings . header_table_size ) . decode
115135 end
@@ -141,6 +161,9 @@ def ignore_frame?(frame)
141161 end
142162 end
143163
164+ # Execute a block within a synchronized context.
165+ # This method provides a synchronization primitive for thread safety.
166+ # @yields The block to execute within the synchronized context.
144167 def synchronize
145168 yield
146169 end
@@ -171,6 +194,8 @@ def read_frame
171194 raise
172195 end
173196
197+ # Send updated settings to the remote peer.
198+ # @parameter changes [Hash] The settings changes to send.
174199 def send_settings ( changes )
175200 @local_settings . append ( changes )
176201
@@ -197,6 +222,9 @@ def send_goaway(error_code = 0, message = "")
197222 self . close!
198223 end
199224
225+ # Process a GOAWAY frame from the remote peer.
226+ # @parameter frame [GoawayFrame] The GOAWAY frame to process.
227+ # @raises [GoawayError] If the frame indicates a connection error.
200228 def receive_goaway ( frame )
201229 # We capture the last stream that was processed.
202230 @remote_stream_id , error_code , message = frame . unpack
@@ -209,6 +237,8 @@ def receive_goaway(frame)
209237 end
210238 end
211239
240+ # Write a single frame to the connection.
241+ # @parameter frame [Frame] The frame to write.
212242 def write_frame ( frame )
213243 synchronize do
214244 @framer . write_frame ( frame )
@@ -217,6 +247,10 @@ def write_frame(frame)
217247 @framer . flush
218248 end
219249
250+ # Write multiple frames within a synchronized block.
251+ # @yields {|framer| ...} The framer for writing multiple frames.
252+ # @parameter framer [Framer] The framer instance.
253+ # @raises [EOFError] If the connection is closed.
220254 def write_frames
221255 if @framer
222256 synchronize do
@@ -229,6 +263,8 @@ def write_frames
229263 end
230264 end
231265
266+ # Update local settings and adjust stream window capacities.
267+ # @parameter changes [Hash] The settings changes to apply locally.
232268 def update_local_settings ( changes )
233269 capacity = @local_settings . initial_window_size
234270
@@ -239,6 +275,8 @@ def update_local_settings(changes)
239275 @local_window . desired = capacity
240276 end
241277
278+ # Update remote settings and adjust stream window capacities.
279+ # @parameter changes [Hash] The settings changes to apply to remote peer.
242280 def update_remote_settings ( changes )
243281 capacity = @remote_settings . initial_window_size
244282
@@ -273,12 +311,17 @@ def process_settings(frame)
273311 end
274312 end
275313
314+ # Transition the connection to the open state.
315+ # @returns [Connection] Self for method chaining.
276316 def open!
277317 @state = :open
278318
279319 return self
280320 end
281321
322+ # Receive and process a SETTINGS frame from the remote peer.
323+ # @parameter frame [SettingsFrame] The settings frame to process.
324+ # @raises [ProtocolError] If the connection is in an invalid state.
282325 def receive_settings ( frame )
283326 if @state == :new
284327 # We transition to :open when we receive acknowledgement of first settings frame:
@@ -290,6 +333,8 @@ def receive_settings(frame)
290333 end
291334 end
292335
336+ # Send a PING frame to the remote peer.
337+ # @parameter data [String] The 8-byte ping payload data.
293338 def send_ping ( data )
294339 if @state != :closed
295340 frame = PingFrame . new
@@ -301,6 +346,9 @@ def send_ping(data)
301346 end
302347 end
303348
349+ # Process a PING frame from the remote peer.
350+ # @parameter frame [PingFrame] The ping frame to process.
351+ # @raises [ProtocolError] If ping is received in invalid state.
304352 def receive_ping ( frame )
305353 if @state != :closed
306354 # This is handled in `read_payload`:
@@ -318,6 +366,9 @@ def receive_ping(frame)
318366 end
319367 end
320368
369+ # Process a DATA frame from the remote peer.
370+ # @parameter frame [DataFrame] The data frame to process.
371+ # @raises [ProtocolError] If data is received for invalid stream.
321372 def receive_data ( frame )
322373 update_local_window ( frame )
323374
@@ -330,6 +381,10 @@ def receive_data(frame)
330381 end
331382 end
332383
384+ # Check if the given stream ID is valid for remote initiation.
385+ # This method should be overridden by client/server implementations.
386+ # @parameter stream_id [Integer] The stream ID to validate.
387+ # @returns [Boolean] True if the stream ID is valid for remote initiation.
333388 def valid_remote_stream_id? ( stream_id )
334389 false
335390 end
@@ -366,6 +421,10 @@ def create_stream(id = next_stream_id, &block)
366421 end
367422 end
368423
424+ # Create a push promise stream.
425+ # This method should be overridden by client/server implementations.
426+ # @yields {|stream| ...} Optional block to configure the created stream.
427+ # @returns [Stream] The created push promise stream.
369428 def create_push_promise_stream ( &block )
370429 create_stream ( &block )
371430 end
@@ -397,10 +456,16 @@ def receive_headers(frame)
397456 end
398457 end
399458
459+ # Receive and process a PUSH_PROMISE frame.
460+ # @parameter frame [PushPromiseFrame] The push promise frame.
461+ # @raises [ProtocolError] Always raises as push promises are not supported.
400462 def receive_push_promise ( frame )
401463 raise ProtocolError , "Unable to receive push promise!"
402464 end
403465
466+ # Receive and process a PRIORITY_UPDATE frame.
467+ # @parameter frame [PriorityUpdateFrame] The priority update frame.
468+ # @raises [ProtocolError] If the stream ID is invalid.
404469 def receive_priority_update ( frame )
405470 if frame . stream_id != 0
406471 raise ProtocolError , "Invalid stream id: #{ frame . stream_id } "
@@ -414,14 +479,25 @@ def receive_priority_update(frame)
414479 end
415480 end
416481
482+ # Check if the given stream ID represents a client-initiated stream.
483+ # Client streams always have odd numbered IDs.
484+ # @parameter id [Integer] The stream ID to check.
485+ # @returns [Boolean] True if the stream ID is client-initiated.
417486 def client_stream_id? ( id )
418487 id . odd?
419488 end
420489
490+ # Check if the given stream ID represents a server-initiated stream.
491+ # Server streams always have even numbered IDs.
492+ # @parameter id [Integer] The stream ID to check.
493+ # @returns [Boolean] True if the stream ID is server-initiated.
421494 def server_stream_id? ( id )
422495 id . even?
423496 end
424497
498+ # Check if the given stream ID represents an idle stream.
499+ # @parameter id [Integer] The stream ID to check.
500+ # @returns [Boolean] True if the stream ID is idle (not yet used).
425501 def idle_stream_id? ( id )
426502 if id . even?
427503 # Server-initiated streams are even.
@@ -450,6 +526,9 @@ def closed_stream_id?(id)
450526 end
451527 end
452528
529+ # Receive and process a RST_STREAM frame.
530+ # @parameter frame [ResetStreamFrame] The reset stream frame.
531+ # @raises [ProtocolError] If the frame is invalid for connection context.
453532 def receive_reset_stream ( frame )
454533 if frame . connection?
455534 raise ProtocolError , "Cannot reset connection!"
@@ -475,6 +554,8 @@ def consume_window(size = self.available_size)
475554 end
476555 end
477556
557+ # Receive and process a WINDOW_UPDATE frame.
558+ # @parameter frame [WindowUpdateFrame] The window update frame.
478559 def receive_window_update ( frame )
479560 if frame . connection?
480561 super
@@ -494,10 +575,15 @@ def receive_window_update(frame)
494575 end
495576 end
496577
578+ # Receive and process a CONTINUATION frame.
579+ # @parameter frame [ContinuationFrame] The continuation frame.
580+ # @raises [ProtocolError] Always raises as unexpected continuation frames are not supported.
497581 def receive_continuation ( frame )
498582 raise ProtocolError , "Received unexpected continuation: #{ frame . class } "
499583 end
500584
585+ # Receive and process a generic frame (default handler).
586+ # @parameter frame [Frame] The frame to receive.
501587 def receive_frame ( frame )
502588 # ignore.
503589 end
0 commit comments