protocol-http2 0.22.1 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,14 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2024, by Samuel Williams.
4
+ # Copyright, 2019-2025, by Samuel Williams.
5
5
  # Copyright, 2019, by Yuta Iwama.
6
6
 
7
7
  require_relative "window_update_frame"
8
8
 
9
9
  module Protocol
10
10
  module HTTP2
11
+ # Provides flow control functionality for HTTP/2 connections and streams.
12
+ # This module implements window-based flow control as defined in RFC 7540.
11
13
  module FlowControlled
14
+ # Get the available window size for sending data.
15
+ # @returns [Integer] The number of bytes that can be sent.
12
16
  def available_size
13
17
  @remote_window.available
14
18
  end
@@ -40,17 +44,22 @@ module Protocol
40
44
  end
41
45
  end
42
46
 
47
+ # Update the local window after receiving data.
48
+ # @parameter frame [Frame] The frame that was received.
43
49
  def update_local_window(frame)
44
50
  consume_local_window(frame)
45
51
  request_window_update
46
52
  end
47
53
 
54
+ # Consume local window space for a received frame.
55
+ # @parameter frame [Frame] The frame that consumed window space.
48
56
  def consume_local_window(frame)
49
57
  # For flow-control calculations, the 9-octet frame header is not counted.
50
58
  amount = frame.length
51
59
  @local_window.consume(amount)
52
60
  end
53
61
 
62
+ # Request a window update if the local window is limited.
54
63
  def request_window_update
55
64
  if @local_window.limited?
56
65
  self.send_window_update(@local_window.wanted)
@@ -67,6 +76,9 @@ module Protocol
67
76
  @local_window.expand(window_increment)
68
77
  end
69
78
 
79
+ # Process a received WINDOW_UPDATE frame.
80
+ # @parameter frame [WindowUpdateFrame] The window update frame to process.
81
+ # @raises [ProtocolError] If the window increment is invalid.
70
82
  def receive_window_update(frame)
71
83
  amount = frame.unpack
72
84
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2024, by Samuel Williams.
4
+ # Copyright, 2019-2025, by Samuel Williams.
5
5
  # Copyright, 2019, by Yuta Iwama.
6
6
 
7
7
  require_relative "error"
@@ -17,6 +17,9 @@ module Protocol
17
17
  MINIMUM_ALLOWED_FRAME_SIZE = 0x4000
18
18
  MAXIMUM_ALLOWED_FRAME_SIZE = 0xFFFFFF
19
19
 
20
+ # Represents the base class for all HTTP/2 frames.
21
+ # This class provides common functionality for frame parsing, serialization,
22
+ # and manipulation according to RFC 7540.
20
23
  class Frame
21
24
  include Comparable
22
25
 
@@ -43,14 +46,21 @@ module Protocol
43
46
  @payload = payload
44
47
  end
45
48
 
49
+ # Check if the frame has a valid type identifier.
50
+ # @returns [Boolean] True if the frame type is valid.
46
51
  def valid_type?
47
52
  @type == self.class::TYPE
48
53
  end
49
54
 
55
+ # Compare frames based on their essential properties.
56
+ # @parameter other [Frame] The frame to compare with.
57
+ # @returns [Integer] -1, 0, or 1 for comparison result.
50
58
  def <=> other
51
59
  to_ary <=> other.to_ary
52
60
  end
53
61
 
62
+ # Convert frame to array representation for comparison.
63
+ # @returns [Array] Frame properties as an array.
54
64
  def to_ary
55
65
  [@length, @type, @flags, @stream_id, @payload]
56
66
  end
@@ -73,10 +83,16 @@ module Protocol
73
83
  attr_accessor :stream_id
74
84
  attr_accessor :payload
75
85
 
86
+ # Unpack the frame payload data.
87
+ # @returns [String] The frame payload.
76
88
  def unpack
77
89
  @payload
78
90
  end
79
91
 
92
+ # Pack payload data into the frame.
93
+ # @parameter payload [String] The payload data to pack.
94
+ # @parameter maximum_size [Integer | Nil] Optional maximum payload size.
95
+ # @raises [ProtocolError] If payload exceeds maximum size.
80
96
  def pack(payload, maximum_size: nil)
81
97
  @payload = payload
82
98
  @length = payload.bytesize
@@ -86,14 +102,21 @@ module Protocol
86
102
  end
87
103
  end
88
104
 
105
+ # Set specific flags on the frame.
106
+ # @parameter mask [Integer] The flag bits to set.
89
107
  def set_flags(mask)
90
108
  @flags |= mask
91
109
  end
92
110
 
111
+ # Clear specific flags on the frame.
112
+ # @parameter mask [Integer] The flag bits to clear.
93
113
  def clear_flags(mask)
94
114
  @flags &= ~mask
95
115
  end
96
116
 
117
+ # Check if specific flags are set on the frame.
118
+ # @parameter mask [Integer] The flag bits to check.
119
+ # @returns [Boolean] True if any of the flags are set.
97
120
  def flag_set?(mask)
98
121
  @flags & mask != 0
99
122
  end
@@ -101,7 +124,7 @@ module Protocol
101
124
  # Check if frame is a connection frame: SETTINGS, PING, GOAWAY, and any
102
125
  # frame addressed to stream ID = 0.
103
126
  #
104
- # @return [Boolean]
127
+ # @return [Boolean] If this is a connection frame.
105
128
  def connection?
106
129
  @stream_id.zero?
107
130
  end
@@ -145,6 +168,9 @@ module Protocol
145
168
  return length, type, flags, stream_id
146
169
  end
147
170
 
171
+ # Read the frame header from a stream.
172
+ # @parameter stream [IO] The stream to read from.
173
+ # @raises [EOFError] If the header cannot be read completely.
148
174
  def read_header(stream)
149
175
  if buffer = stream.read(9) and buffer.bytesize == 9
150
176
  @length, @type, @flags, @stream_id = Frame.parse_header(buffer)
@@ -154,6 +180,9 @@ module Protocol
154
180
  end
155
181
  end
156
182
 
183
+ # Read the frame payload from a stream.
184
+ # @parameter stream [IO] The stream to read from.
185
+ # @raises [EOFError] If the payload cannot be read completely.
157
186
  def read_payload(stream)
158
187
  if payload = stream.read(@length) and payload.bytesize == @length
159
188
  @payload = payload
@@ -162,6 +191,11 @@ module Protocol
162
191
  end
163
192
  end
164
193
 
194
+ # Read the complete frame (header and payload) from a stream.
195
+ # @parameter stream [IO] The stream to read from.
196
+ # @parameter maximum_frame_size [Integer] The maximum allowed frame size.
197
+ # @raises [FrameSizeError] If the frame exceeds the maximum size.
198
+ # @returns [Frame] Self for method chaining.
165
199
  def read(stream, maximum_frame_size = MAXIMUM_ALLOWED_FRAME_SIZE)
166
200
  read_header(stream) unless @length
167
201
 
@@ -172,14 +206,21 @@ module Protocol
172
206
  read_payload(stream)
173
207
  end
174
208
 
209
+ # Write the frame header to a stream.
210
+ # @parameter stream [IO] The stream to write to.
175
211
  def write_header(stream)
176
212
  stream.write self.header
177
213
  end
178
214
 
215
+ # Write the frame payload to a stream.
216
+ # @parameter stream [IO] The stream to write to.
179
217
  def write_payload(stream)
180
218
  stream.write(@payload) if @payload
181
219
  end
182
220
 
221
+ # Write the complete frame (header and payload) to a stream.
222
+ # @parameter stream [IO] The stream to write to.
223
+ # @raises [ProtocolError] If frame validation fails.
183
224
  def write(stream)
184
225
  # Validate the payload size:
185
226
  if @payload.nil?
@@ -196,10 +237,14 @@ module Protocol
196
237
  self.write_payload(stream)
197
238
  end
198
239
 
240
+ # Apply the frame to a connection for processing.
241
+ # @parameter connection [Connection] The connection to apply the frame to.
199
242
  def apply(connection)
200
243
  connection.receive_frame(self)
201
244
  end
202
245
 
246
+ # Provide a readable representation of the frame for debugging.
247
+ # @returns [String] A formatted string representation of the frame.
203
248
  def inspect
204
249
  "\#<#{self.class} stream_id=#{@stream_id} flags=#{@flags} payload=#{self.unpack}>"
205
250
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2024, by Samuel Williams.
4
+ # Copyright, 2019-2025, by Samuel Williams.
5
5
 
6
6
  require_relative "error"
7
7
 
@@ -42,28 +42,40 @@ module Protocol
42
42
  # Default connection "fast-fail" preamble string as defined by the spec.
43
43
  CONNECTION_PREFACE = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n".freeze
44
44
 
45
+ # Handles frame serialization and deserialization for HTTP/2 connections.
46
+ # This class manages the reading and writing of HTTP/2 frames to/from a stream.
45
47
  class Framer
48
+ # Initialize a new framer with a stream and frame definitions.
49
+ # @parameter stream [IO] The underlying stream for frame I/O.
50
+ # @parameter frames [Array] Frame type definitions to use.
46
51
  def initialize(stream, frames = FRAMES)
47
52
  @stream = stream
48
53
  @frames = frames
49
54
  end
50
55
 
56
+ # Flush the underlying stream.
51
57
  def flush
52
58
  @stream.flush
53
59
  end
54
60
 
61
+ # Close the underlying stream.
55
62
  def close
56
63
  @stream.close
57
64
  end
58
65
 
66
+ # Check if the underlying stream is closed.
67
+ # @returns [Boolean] True if the stream is closed.
59
68
  def closed?
60
69
  @stream.closed?
61
70
  end
62
71
 
72
+ # Write the HTTP/2 connection preface to the stream.
63
73
  def write_connection_preface
64
74
  @stream.write(CONNECTION_PREFACE)
65
75
  end
66
76
 
77
+ # Read and validate the HTTP/2 connection preface from the stream.
78
+ # @raises [HandshakeError] If the preface is invalid.
67
79
  def read_connection_preface
68
80
  string = @stream.read(CONNECTION_PREFACE.bytesize)
69
81
 
@@ -105,6 +117,9 @@ module Protocol
105
117
  return frame
106
118
  end
107
119
 
120
+ # Read a frame header from the stream.
121
+ # @returns [Array] Parsed frame header components: length, type, flags, stream_id.
122
+ # @raises [EOFError] If the header cannot be read completely.
108
123
  def read_header
109
124
  if buffer = @stream.read(9)
110
125
  if buffer.bytesize == 9
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2024, by Samuel Williams.
4
+ # Copyright, 2019-2025, by Samuel Williams.
5
5
 
6
6
  require_relative "frame"
7
7
 
@@ -21,10 +21,14 @@ module Protocol
21
21
  TYPE = 0x7
22
22
  FORMAT = "NN"
23
23
 
24
+ # Check if this frame applies to the connection level.
25
+ # @returns [Boolean] Always returns true for GOAWAY frames.
24
26
  def connection?
25
27
  true
26
28
  end
27
29
 
30
+ # Unpack the GOAWAY frame payload.
31
+ # @returns [Array] Last stream ID, error code, and debug data.
28
32
  def unpack
29
33
  data = super
30
34
 
@@ -33,10 +37,16 @@ module Protocol
33
37
  return last_stream_id, error_code, data.slice(8, data.bytesize-8)
34
38
  end
35
39
 
40
+ # Pack GOAWAY frame data into payload.
41
+ # @parameter last_stream_id [Integer] The last processed stream ID.
42
+ # @parameter error_code [Integer] The error code for connection termination.
43
+ # @parameter data [String] Additional debug data.
36
44
  def pack(last_stream_id, error_code, data)
37
45
  super [last_stream_id, error_code].pack(FORMAT) + data
38
46
  end
39
47
 
48
+ # Apply this GOAWAY frame to a connection for processing.
49
+ # @parameter connection [Connection] The connection to apply the frame to.
40
50
  def apply(connection)
41
51
  connection.receive_goaway(self)
42
52
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2024, by Samuel Williams.
4
+ # Copyright, 2019-2025, by Samuel Williams.
5
5
 
6
6
  require_relative "frame"
7
7
  require_relative "padded"
@@ -28,14 +28,20 @@ module Protocol
28
28
 
29
29
  TYPE = 0x1
30
30
 
31
+ # Check if this frame contains priority information.
32
+ # @returns [Boolean] True if the PRIORITY flag is set.
31
33
  def priority?
32
34
  flag_set?(PRIORITY)
33
35
  end
34
36
 
37
+ # Check if this frame ends the stream.
38
+ # @returns [Boolean] True if the END_STREAM flag is set.
35
39
  def end_stream?
36
40
  flag_set?(END_STREAM)
37
41
  end
38
42
 
43
+ # Unpack the header block fragment from the frame.
44
+ # @returns [String] The unpacked header block data.
39
45
  def unpack
40
46
  data = super
41
47
 
@@ -47,6 +53,10 @@ module Protocol
47
53
  return data
48
54
  end
49
55
 
56
+ # Pack header block data into the frame.
57
+ # @parameter data [String] The header block data to pack.
58
+ # @parameter arguments [Array] Additional arguments.
59
+ # @parameter options [Hash] Options for packing.
50
60
  def pack(data, *arguments, **options)
51
61
  buffer = String.new.b
52
62
 
@@ -55,10 +65,14 @@ module Protocol
55
65
  super(buffer, *arguments, **options)
56
66
  end
57
67
 
68
+ # Apply this HEADERS frame to a connection for processing.
69
+ # @parameter connection [Connection] The connection to apply the frame to.
58
70
  def apply(connection)
59
71
  connection.receive_headers(self)
60
72
  end
61
73
 
74
+ # Get a string representation of the headers frame.
75
+ # @returns [String] Human-readable frame information.
62
76
  def inspect
63
77
  "\#<#{self.class} stream_id=#{@stream_id} flags=#{@flags} #{@length || 0}b>"
64
78
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2024, by Samuel Williams.
4
+ # Copyright, 2019-2025, by Samuel Williams.
5
5
 
6
6
  require_relative "frame"
7
7
 
@@ -18,11 +18,19 @@ module Protocol
18
18
  # | Padding (*) ...
19
19
  # +---------------------------------------------------------------+
20
20
  #
21
+ # Provides padding functionality for HTTP/2 frames.
22
+ # Padding can be used to obscure the actual size of frame payloads.
21
23
  module Padded
24
+ # Check if the frame has padding enabled.
25
+ # @returns [Boolean] True if the PADDED flag is set.
22
26
  def padded?
23
27
  flag_set?(PADDED)
24
28
  end
25
29
 
30
+ # Pack data with optional padding into the frame.
31
+ # @parameter data [String] The data to pack.
32
+ # @parameter padding_size [Integer | Nil] Number of padding bytes to add.
33
+ # @parameter maximum_size [Integer | Nil] Maximum frame size limit.
26
34
  def pack(data, padding_size: nil, maximum_size: nil)
27
35
  if padding_size
28
36
  set_flags(PADDED)
@@ -44,6 +52,9 @@ module Protocol
44
52
  end
45
53
  end
46
54
 
55
+ # Unpack frame data, removing padding if present.
56
+ # @returns [String] The unpacked data without padding.
57
+ # @raises [ProtocolError] If padding length is invalid.
47
58
  def unpack
48
59
  if padded?
49
60
  padding_size = @payload[0].ord
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2024, by Samuel Williams.
4
+ # Copyright, 2019-2025, by Samuel Williams.
5
5
 
6
6
  require_relative "frame"
7
7
 
@@ -9,15 +9,22 @@ module Protocol
9
9
  module HTTP2
10
10
  ACKNOWLEDGEMENT = 0x1
11
11
 
12
+ # Provides acknowledgement functionality for frames that support it.
13
+ # This module handles setting and checking acknowledgement flags on frames.
12
14
  module Acknowledgement
15
+ # Check if the frame is an acknowledgement.
16
+ # @returns [Boolean] True if the acknowledgement flag is set.
13
17
  def acknowledgement?
14
18
  flag_set?(ACKNOWLEDGEMENT)
15
19
  end
16
20
 
21
+ # Mark this frame as an acknowledgement.
17
22
  def acknowledgement!
18
23
  set_flags(ACKNOWLEDGEMENT)
19
24
  end
20
25
 
26
+ # Create an acknowledgement frame for this frame.
27
+ # @returns [Frame] A new frame marked as an acknowledgement.
21
28
  def acknowledge
22
29
  frame = self.class.new
23
30
 
@@ -41,14 +48,20 @@ module Protocol
41
48
 
42
49
  include Acknowledgement
43
50
 
51
+ # Check if this frame applies to the connection level.
52
+ # @returns [Boolean] Always returns true for PING frames.
44
53
  def connection?
45
54
  true
46
55
  end
47
56
 
57
+ # Apply this PING frame to a connection for processing.
58
+ # @parameter connection [Connection] The connection to apply the frame to.
48
59
  def apply(connection)
49
60
  connection.receive_ping(self)
50
61
  end
51
62
 
63
+ # Create an acknowledgement PING frame with the same payload.
64
+ # @returns [PingFrame] A new PING frame marked as an acknowledgement.
52
65
  def acknowledge
53
66
  frame = super
54
67
 
@@ -57,6 +70,9 @@ module Protocol
57
70
  return frame
58
71
  end
59
72
 
73
+ # Read and validate the PING frame payload.
74
+ # @parameter stream [IO] The stream to read from.
75
+ # @raises [ProtocolError] If validation fails.
60
76
  def read_payload(stream)
61
77
  super
62
78
 
@@ -21,6 +21,8 @@ module Protocol
21
21
  TYPE = 0x10
22
22
  FORMAT = "N".freeze
23
23
 
24
+ # Unpack the prioritized stream ID and priority field value.
25
+ # @returns [Array] An array containing the prioritized stream ID and priority field value.
24
26
  def unpack
25
27
  data = super
26
28
 
@@ -29,10 +31,16 @@ module Protocol
29
31
  return prioritized_stream_id, data.byteslice(4, data.bytesize - 4)
30
32
  end
31
33
 
34
+ # Pack the prioritized stream ID and priority field value into the frame.
35
+ # @parameter prioritized_stream_id [Integer] The stream ID to prioritize.
36
+ # @parameter data [String] The priority field value.
37
+ # @parameter options [Hash] Options for packing.
32
38
  def pack(prioritized_stream_id, data, **options)
33
39
  super([prioritized_stream_id].pack(FORMAT) + data, **options)
34
40
  end
35
41
 
42
+ # Apply this PRIORITY_UPDATE frame to a connection for processing.
43
+ # @parameter connection [Connection] The connection to apply the frame to.
36
44
  def apply(connection)
37
45
  connection.receive_priority_update(self)
38
46
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2024, by Samuel Williams.
4
+ # Copyright, 2019-2025, by Samuel Williams.
5
5
 
6
6
  require_relative "frame"
7
7
  require_relative "padded"
@@ -27,6 +27,8 @@ module Protocol
27
27
  TYPE = 0x5
28
28
  FORMAT = "N".freeze
29
29
 
30
+ # Unpack the promised stream ID and header block fragment.
31
+ # @returns [Array] An array containing the promised stream ID and header block data.
30
32
  def unpack
31
33
  data = super
32
34
 
@@ -35,10 +37,17 @@ module Protocol
35
37
  return stream_id, data.byteslice(4, data.bytesize - 4)
36
38
  end
37
39
 
40
+ # Pack the promised stream ID and header block data into the frame.
41
+ # @parameter stream_id [Integer] The promised stream ID.
42
+ # @parameter data [String] The header block data.
43
+ # @parameter arguments [Array] Additional arguments.
44
+ # @parameter options [Hash] Options for packing.
38
45
  def pack(stream_id, data, *arguments, **options)
39
46
  super([stream_id].pack(FORMAT) + data, *arguments, **options)
40
47
  end
41
48
 
49
+ # Apply this PUSH_PROMISE frame to a connection for processing.
50
+ # @parameter connection [Connection] The connection to apply the frame to.
42
51
  def apply(connection)
43
52
  connection.receive_push_promise(self)
44
53
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2024, by Samuel Williams.
4
+ # Copyright, 2019-2025, by Samuel Williams.
5
5
 
6
6
  require_relative "frame"
7
7
 
@@ -32,19 +32,28 @@ module Protocol
32
32
  TYPE = 0x3
33
33
  FORMAT = "N".freeze
34
34
 
35
+ # Unpack the error code from the frame payload.
36
+ # @returns [Integer] The error code.
35
37
  def unpack
36
38
  @payload.unpack1(FORMAT)
37
39
  end
38
40
 
41
+ # Pack an error code into the frame payload.
42
+ # @parameter error_code [Integer] The error code to pack.
39
43
  def pack(error_code = NO_ERROR)
40
44
  @payload = [error_code].pack(FORMAT)
41
45
  @length = @payload.bytesize
42
46
  end
43
47
 
48
+ # Apply this RST_STREAM frame to a connection for processing.
49
+ # @parameter connection [Connection] The connection to apply the frame to.
44
50
  def apply(connection)
45
51
  connection.receive_reset_stream(self)
46
52
  end
47
53
 
54
+ # Read and validate the RST_STREAM frame payload.
55
+ # @parameter stream [IO] The stream to read from.
56
+ # @raises [FrameSizeError] If the frame length is invalid.
48
57
  def read_payload(stream)
49
58
  super
50
59
 
@@ -1,29 +1,50 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2024, by Samuel Williams.
4
+ # Copyright, 2019-2025, by Samuel Williams.
5
5
 
6
6
  require_relative "connection"
7
7
 
8
8
  module Protocol
9
9
  module HTTP2
10
+ # Represents an HTTP/2 server connection.
11
+ # Manages server-side protocol semantics including stream ID allocation,
12
+ # connection preface handling, and settings negotiation.
10
13
  class Server < Connection
14
+ # Initialize a new HTTP/2 server connection.
15
+ # @parameter framer [Framer] The frame handler for reading/writing HTTP/2 frames.
11
16
  def initialize(framer)
12
17
  super(framer, 2)
13
18
  end
14
19
 
20
+ # Check if the given stream ID represents a locally-initiated stream.
21
+ # Server streams have even numbered IDs.
22
+ # @parameter id [Integer] The stream ID to check.
23
+ # @returns [Boolean] True if the stream ID is locally-initiated.
15
24
  def local_stream_id?(id)
16
25
  id.even?
17
26
  end
18
27
 
28
+ # Check if the given stream ID represents a remotely-initiated stream.
29
+ # Client streams have odd numbered IDs.
30
+ # @parameter id [Integer] The stream ID to check.
31
+ # @returns [Boolean] True if the stream ID is remotely-initiated.
19
32
  def remote_stream_id?(id)
20
33
  id.odd?
21
34
  end
22
35
 
36
+ # Check if the given stream ID is valid for remote initiation.
37
+ # Client-initiated streams must have odd numbered IDs.
38
+ # @parameter stream_id [Integer] The stream ID to validate.
39
+ # @returns [Boolean] True if the stream ID is valid for remote initiation.
23
40
  def valid_remote_stream_id?(stream_id)
24
41
  stream_id.odd?
25
42
  end
26
43
 
44
+ # Read the HTTP/2 connection preface from the client and send initial settings.
45
+ # This must be called once when the connection is first established.
46
+ # @parameter settings [Array] Optional settings to send during preface exchange.
47
+ # @raises [ProtocolError] If called when not in the new state or preface is invalid.
27
48
  def read_connection_preface(settings = [])
28
49
  if @state == :new
29
50
  @framer.read_connection_preface
@@ -40,10 +61,15 @@ module Protocol
40
61
  end
41
62
  end
42
63
 
64
+ # Servers cannot accept push promise streams from clients.
65
+ # @parameter stream_id [Integer] The stream ID (unused).
66
+ # @raises [ProtocolError] Always, as servers cannot accept push promises.
43
67
  def accept_push_promise_stream(stream_id, &block)
44
68
  raise ProtocolError, "Cannot accept push promises on server!"
45
69
  end
46
70
 
71
+ # Check if server push is enabled by the client.
72
+ # @returns [Boolean] True if push promises are enabled.
47
73
  def enable_push?
48
74
  @remote_settings.enable_push?
49
75
  end