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,12 +1,13 @@
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 "ping_frame"
7
7
 
8
8
  module Protocol
9
9
  module HTTP2
10
+ # HTTP/2 connection settings container and management.
10
11
  class Settings
11
12
  HEADER_TABLE_SIZE = 0x1
12
13
  ENABLE_PUSH = 0x2
@@ -30,6 +31,7 @@ module Protocol
30
31
  :no_rfc7540_priorities=,
31
32
  ]
32
33
 
34
+ # Initialize settings with default values from HTTP/2 specification.
33
35
  def initialize
34
36
  # These limits are taken from the RFC:
35
37
  # https://tools.ietf.org/html/rfc7540#section-6.5.2
@@ -49,6 +51,9 @@ module Protocol
49
51
  # This setting can be used to disable server push. An endpoint MUST NOT send a PUSH_PROMISE frame if it receives this parameter set to a value of 0.
50
52
  attr :enable_push
51
53
 
54
+ # Set the server push enable flag.
55
+ # @parameter value [Integer] Must be 0 (disabled) or 1 (enabled).
56
+ # @raises [ProtocolError] If the value is invalid.
52
57
  def enable_push= value
53
58
  if value == 0 or value == 1
54
59
  @enable_push = value
@@ -57,6 +62,8 @@ module Protocol
57
62
  end
58
63
  end
59
64
 
65
+ # Check if server push is enabled.
66
+ # @returns [Boolean] True if server push is enabled.
60
67
  def enable_push?
61
68
  @enable_push == 1
62
69
  end
@@ -67,6 +74,9 @@ module Protocol
67
74
  # Indicates the sender's initial window size (in octets) for stream-level flow control.
68
75
  attr :initial_window_size
69
76
 
77
+ # Set the initial window size for stream-level flow control.
78
+ # @parameter value [Integer] The window size in octets.
79
+ # @raises [ProtocolError] If the value exceeds the maximum allowed.
70
80
  def initial_window_size= value
71
81
  if value <= MAXIMUM_ALLOWED_WINDOW_SIZE
72
82
  @initial_window_size = value
@@ -78,6 +88,9 @@ module Protocol
78
88
  # Indicates the size of the largest frame payload that the sender is willing to receive, in octets.
79
89
  attr :maximum_frame_size
80
90
 
91
+ # Set the maximum frame size the sender is willing to receive.
92
+ # @parameter value [Integer] The maximum frame size in octets.
93
+ # @raises [ProtocolError] If the value is outside the allowed range.
81
94
  def maximum_frame_size= value
82
95
  if value > MAXIMUM_ALLOWED_FRAME_SIZE
83
96
  raise ProtocolError, "Invalid value for maximum_frame_size: #{value} > #{MAXIMUM_ALLOWED_FRAME_SIZE}"
@@ -93,6 +106,9 @@ module Protocol
93
106
 
94
107
  attr :enable_connect_protocol
95
108
 
109
+ # Set the CONNECT protocol enable flag.
110
+ # @parameter value [Integer] Must be 0 (disabled) or 1 (enabled).
111
+ # @raises [ProtocolError] If the value is invalid.
96
112
  def enable_connect_protocol= value
97
113
  if value == 0 or value == 1
98
114
  @enable_connect_protocol = value
@@ -101,12 +117,17 @@ module Protocol
101
117
  end
102
118
  end
103
119
 
120
+ # Check if CONNECT protocol is enabled.
121
+ # @returns [Boolean] True if CONNECT protocol is enabled.
104
122
  def enable_connect_protocol?
105
123
  @enable_connect_protocol == 1
106
124
  end
107
125
 
108
126
  attr :no_rfc7540_priorities
109
127
 
128
+ # Set the RFC 7540 priorities disable flag.
129
+ # @parameter value [Integer] Must be 0 (enabled) or 1 (disabled).
130
+ # @raises [ProtocolError] If the value is invalid.
110
131
  def no_rfc7540_priorities= value
111
132
  if value == 0 or value == 1
112
133
  @no_rfc7540_priorities = value
@@ -115,10 +136,14 @@ module Protocol
115
136
  end
116
137
  end
117
138
 
139
+ # Check if RFC 7540 priorities are disabled.
140
+ # @returns [Boolean] True if RFC 7540 priorities are disabled.
118
141
  def no_rfc7540_priorities?
119
142
  @no_rfc7540_priorities == 1
120
143
  end
121
144
 
145
+ # Update settings with a hash of changes.
146
+ # @parameter changes [Hash] Hash of setting keys and values to update.
122
147
  def update(changes)
123
148
  changes.each do |key, value|
124
149
  if name = ASSIGN[key]
@@ -128,7 +153,10 @@ module Protocol
128
153
  end
129
154
  end
130
155
 
156
+ # Manages pending settings changes that haven't been acknowledged yet.
131
157
  class PendingSettings
158
+ # Initialize with current settings.
159
+ # @parameter current [Settings] The current settings object.
132
160
  def initialize(current = Settings.new)
133
161
  @current = current
134
162
  @pending = current.dup
@@ -139,11 +167,14 @@ module Protocol
139
167
  attr :current
140
168
  attr :pending
141
169
 
170
+ # Append changes to the pending queue.
171
+ # @parameter changes [Hash] Hash of setting changes to queue.
142
172
  def append(changes)
143
173
  @queue << changes
144
174
  @pending.update(changes)
145
175
  end
146
176
 
177
+ # Acknowledge the next set of pending changes.
147
178
  def acknowledge
148
179
  if changes = @queue.shift
149
180
  @current.update(changes)
@@ -154,30 +185,44 @@ module Protocol
154
185
  end
155
186
  end
156
187
 
188
+ # Get the current header table size setting.
189
+ # @returns [Integer] The header table size in octets.
157
190
  def header_table_size
158
191
  @current.header_table_size
159
192
  end
160
193
 
194
+ # Get the current enable push setting.
195
+ # @returns [Integer] 1 if push is enabled, 0 if disabled.
161
196
  def enable_push
162
197
  @current.enable_push
163
198
  end
164
199
 
200
+ # Get the current maximum concurrent streams setting.
201
+ # @returns [Integer] The maximum number of concurrent streams.
165
202
  def maximum_concurrent_streams
166
203
  @current.maximum_concurrent_streams
167
204
  end
168
205
 
206
+ # Get the current initial window size setting.
207
+ # @returns [Integer] The initial window size in octets.
169
208
  def initial_window_size
170
209
  @current.initial_window_size
171
210
  end
172
211
 
212
+ # Get the current maximum frame size setting.
213
+ # @returns [Integer] The maximum frame size in octets.
173
214
  def maximum_frame_size
174
215
  @current.maximum_frame_size
175
216
  end
176
217
 
218
+ # Get the current maximum header list size setting.
219
+ # @returns [Integer] The maximum header list size in octets.
177
220
  def maximum_header_list_size
178
221
  @current.maximum_header_list_size
179
222
  end
180
223
 
224
+ # Get the current CONNECT protocol enable setting.
225
+ # @returns [Integer] 1 if CONNECT protocol is enabled, 0 if disabled.
181
226
  def enable_connect_protocol
182
227
  @current.enable_connect_protocol
183
228
  end
@@ -197,10 +242,14 @@ module Protocol
197
242
 
198
243
  include Acknowledgement
199
244
 
245
+ # Check if this frame applies to the connection level.
246
+ # @returns [Boolean] Always returns true for SETTINGS frames.
200
247
  def connection?
201
248
  true
202
249
  end
203
250
 
251
+ # Unpack settings parameters from the frame payload.
252
+ # @returns [Array] Array of [key, value] pairs representing settings.
204
253
  def unpack
205
254
  if buffer = super
206
255
  # TODO String#each_slice, or #each_unpack would be nice.
@@ -210,14 +259,22 @@ module Protocol
210
259
  end
211
260
  end
212
261
 
262
+ # Pack settings parameters into the frame payload.
263
+ # @parameter settings [Array] Array of [key, value] pairs to pack.
213
264
  def pack(settings = [])
214
265
  super(settings.map{|s| s.pack(FORMAT)}.join)
215
266
  end
216
267
 
268
+ # Apply this SETTINGS frame to a connection for processing.
269
+ # @parameter connection [Connection] The connection to apply the frame to.
217
270
  def apply(connection)
218
271
  connection.receive_settings(self)
219
272
  end
220
273
 
274
+ # Read and validate the SETTINGS frame payload.
275
+ # @parameter stream [IO] The stream to read from.
276
+ # @raises [ProtocolError] If the frame is invalid.
277
+ # @raises [FrameSizeError] If the frame length is invalid.
221
278
  def read_payload(stream)
222
279
  super
223
280
 
@@ -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 "connection"
7
7
 
@@ -60,6 +60,10 @@ module Protocol
60
60
  class Stream
61
61
  include FlowControlled
62
62
 
63
+ # Create a new stream and add it to the connection.
64
+ # @parameter connection [Connection] The connection this stream belongs to.
65
+ # @parameter id [Integer] The stream identifier.
66
+ # @returns [Stream] The newly created stream.
63
67
  def self.create(connection, id)
64
68
  stream = self.new(connection, id)
65
69
 
@@ -68,6 +72,10 @@ module Protocol
68
72
  return stream
69
73
  end
70
74
 
75
+ # Initialize a new stream.
76
+ # @parameter connection [Connection] The connection this stream belongs to.
77
+ # @parameter id [Integer] The stream identifier.
78
+ # @parameter state [Symbol] The initial stream state.
71
79
  def initialize(connection, id, state = :idle)
72
80
  @connection = connection
73
81
  @id = id
@@ -95,18 +103,26 @@ module Protocol
95
103
  # @attribute [Protocol::HTTP::Header::Priority | Nil] the priority of the stream.
96
104
  attr_accessor :priority
97
105
 
106
+ # Get the maximum frame size for this stream.
107
+ # @returns [Integer] The maximum frame size from connection settings.
98
108
  def maximum_frame_size
99
109
  @connection.available_frame_size
100
110
  end
101
111
 
112
+ # Write a frame to the connection for this stream.
113
+ # @parameter frame [Frame] The frame to write.
102
114
  def write_frame(frame)
103
115
  @connection.write_frame(frame)
104
116
  end
105
117
 
118
+ # Check if the stream is active (not idle or closed).
119
+ # @returns [Boolean] True if the stream is active.
106
120
  def active?
107
121
  @state != :closed && @state != :idle
108
122
  end
109
123
 
124
+ # Check if the stream is closed.
125
+ # @returns [Boolean] True if the stream is in closed state.
110
126
  def closed?
111
127
  @state == :closed
112
128
  end
@@ -170,6 +186,8 @@ module Protocol
170
186
  end
171
187
  end
172
188
 
189
+ # Consume from the remote window for both stream and connection.
190
+ # @parameter frame [Frame] The frame that consumes window space.
173
191
  def consume_remote_window(frame)
174
192
  super
175
193
 
@@ -187,6 +205,9 @@ module Protocol
187
205
  return frame
188
206
  end
189
207
 
208
+ # Send data over this stream.
209
+ # @parameter arguments [Array] Arguments passed to write_data.
210
+ # @parameter options [Hash] Options passed to write_data.
190
211
  def send_data(*arguments, **options)
191
212
  if @state == :open
192
213
  frame = write_data(*arguments, **options)
@@ -205,6 +226,9 @@ module Protocol
205
226
  end
206
227
  end
207
228
 
229
+ # Open the stream by transitioning from idle to open state.
230
+ # @returns [Stream] Returns self for chaining.
231
+ # @raises [ProtocolError] If the stream cannot be opened from current state.
208
232
  def open!
209
233
  if @state == :idle
210
234
  @state = :open
@@ -234,6 +258,8 @@ module Protocol
234
258
  return self
235
259
  end
236
260
 
261
+ # Send a RST_STREAM frame to reset this stream.
262
+ # @parameter error_code [Integer] The error code to send.
237
263
  def send_reset_stream(error_code = 0)
238
264
  if @state != :idle and @state != :closed
239
265
  frame = ResetStreamFrame.new(@id)
@@ -247,6 +273,9 @@ module Protocol
247
273
  end
248
274
  end
249
275
 
276
+ # Process headers frame and decode the header block.
277
+ # @parameter frame [HeadersFrame] The headers frame to process.
278
+ # @returns [Array] The decoded headers.
250
279
  def process_headers(frame)
251
280
  # Receiving request headers:
252
281
  data = frame.unpack
@@ -258,6 +287,8 @@ module Protocol
258
287
  # Console.warn(self) {"Received headers in state: #{@state}!"}
259
288
  end
260
289
 
290
+ # Receive and process a headers frame on this stream.
291
+ # @parameter frame [HeadersFrame] The headers frame to receive.
261
292
  def receive_headers(frame)
262
293
  if @state == :idle
263
294
  if frame.end_stream?
@@ -295,6 +326,8 @@ module Protocol
295
326
  frame.unpack
296
327
  end
297
328
 
329
+ # Ignore data frame when in an invalid state.
330
+ # @parameter frame [DataFrame] The data frame to ignore.
298
331
  def ignore_data(frame)
299
332
  # Console.warn(self) {"Received headers in state: #{@state}!"}
300
333
  end
@@ -325,6 +358,10 @@ module Protocol
325
358
  end
326
359
  end
327
360
 
361
+ # Receive and process a RST_STREAM frame on this stream.
362
+ # @parameter frame [ResetStreamFrame] The reset stream frame to receive.
363
+ # @returns [Integer] The error code from the reset frame.
364
+ # @raises [ProtocolError] If reset is received on an idle stream.
328
365
  def receive_reset_stream(frame)
329
366
  if @state == :idle
330
367
  # If a RST_STREAM frame identifying an idle stream is received, the recipient MUST treat this as a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
@@ -355,6 +392,9 @@ module Protocol
355
392
  return frame
356
393
  end
357
394
 
395
+ # Transition stream to reserved local state.
396
+ # @returns [Stream] Returns self for chaining.
397
+ # @raises [ProtocolError] If the stream cannot be reserved from current state.
358
398
  def reserved_local!
359
399
  if @state == :idle
360
400
  @state = :reserved_local
@@ -365,6 +405,9 @@ module Protocol
365
405
  return self
366
406
  end
367
407
 
408
+ # Transition stream to reserved remote state.
409
+ # @returns [Stream] Returns self for chaining.
410
+ # @raises [ProtocolError] If the stream cannot be reserved from current state.
368
411
  def reserved_remote!
369
412
  if @state == :idle
370
413
  @state = :reserved_remote
@@ -402,6 +445,8 @@ module Protocol
402
445
  @connection.accept_push_promise_stream(stream_id)
403
446
  end
404
447
 
448
+ # Receive and process a PUSH_PROMISE frame on this stream.
449
+ # @parameter frame [PushPromiseFrame] The push promise frame to receive.
405
450
  def receive_push_promise(frame)
406
451
  promised_stream_id, data = frame.unpack
407
452
  headers = @connection.decode_headers(data)
@@ -412,6 +457,8 @@ module Protocol
412
457
  return stream, headers
413
458
  end
414
459
 
460
+ # Get a string representation of the stream.
461
+ # @returns [String] Human-readable stream information.
415
462
  def inspect
416
463
  "\#<#{self.class} id=#{@id} state=#{@state}>"
417
464
  end
@@ -1,10 +1,12 @@
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
+ # @namespace
6
7
  module Protocol
8
+ # @namespace
7
9
  module HTTP2
8
- VERSION = "0.22.1"
10
+ VERSION = "0.23.0"
9
11
  end
10
12
  end
@@ -1,14 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2024, by Samuel Williams.
4
+ # Copyright, 2024-2025, by Samuel Williams.
5
5
 
6
6
  module Protocol
7
7
  module HTTP2
8
+ # Flow control window for managing HTTP/2 data flow.
8
9
  class Window
9
10
  # When an HTTP/2 connection is first established, new streams are created with an initial flow-control window size of 65,535 octets. The connection flow-control window is also 65,535 octets.
10
11
  DEFAULT_CAPACITY = 0xFFFF
11
12
 
13
+ # Initialize a new flow control window.
12
14
  # @parameter capacity [Integer] The initial window size, typically from the settings.
13
15
  def initialize(capacity = DEFAULT_CAPACITY)
14
16
  # This is the main field required:
@@ -40,6 +42,8 @@ module Protocol
40
42
  @capacity = value
41
43
  end
42
44
 
45
+ # Consume a specific amount from the available window.
46
+ # @parameter amount [Integer] The amount to consume from the window.
43
47
  def consume(amount)
44
48
  @available -= amount
45
49
  @used += amount
@@ -47,10 +51,15 @@ module Protocol
47
51
 
48
52
  attr :available
49
53
 
54
+ # Check if there is available window capacity.
55
+ # @returns [Boolean] True if there is available capacity.
50
56
  def available?
51
57
  @available > 0
52
58
  end
53
59
 
60
+ # Expand the window by a specific amount.
61
+ # @parameter amount [Integer] The amount to expand the window by.
62
+ # @raises [FlowControlError] If expansion would cause overflow.
54
63
  def expand(amount)
55
64
  available = @available + amount
56
65
 
@@ -63,14 +72,20 @@ module Protocol
63
72
  @used -= amount
64
73
  end
65
74
 
75
+ # Get the amount of window that should be reclaimed.
76
+ # @returns [Integer] The amount of used window space.
66
77
  def wanted
67
78
  @used
68
79
  end
69
80
 
81
+ # Check if the window is limited and needs updating.
82
+ # @returns [Boolean] True if available capacity is less than half of total capacity.
70
83
  def limited?
71
84
  @available < (@capacity / 2)
72
85
  end
73
86
 
87
+ # Get a string representation of the window.
88
+ # @returns [String] Human-readable window information.
74
89
  def inspect
75
90
  "\#<#{self.class} available=#{@available} used=#{@used} capacity=#{@capacity}#{limited? ? " limited" : nil}>"
76
91
  end
@@ -80,6 +95,9 @@ module Protocol
80
95
 
81
96
  # This is a window which efficiently maintains a desired capacity.
82
97
  class LocalWindow < Window
98
+ # Initialize a local window with optional desired capacity.
99
+ # @parameter capacity [Integer] The initial window capacity.
100
+ # @parameter desired [Integer] The desired window capacity.
83
101
  def initialize(capacity = DEFAULT_CAPACITY, desired: nil)
84
102
  super(capacity)
85
103
 
@@ -91,6 +109,8 @@ module Protocol
91
109
  # The desired capacity of the window.
92
110
  attr_accessor :desired
93
111
 
112
+ # Get the amount of window that should be reclaimed, considering desired capacity.
113
+ # @returns [Integer] The amount needed to reach desired capacity or used space.
94
114
  def wanted
95
115
  if @desired
96
116
  # We must send an update which allows at least @desired bytes to be sent.
@@ -100,6 +120,8 @@ module Protocol
100
120
  end
101
121
  end
102
122
 
123
+ # Check if the window is limited, considering desired capacity.
124
+ # @returns [Boolean] True if window needs updating based on desired capacity.
103
125
  def limited?
104
126
  if @desired
105
127
  # Do not send window updates until we are less than half the desired capacity:
@@ -109,6 +131,8 @@ module Protocol
109
131
  end
110
132
  end
111
133
 
134
+ # Get a string representation of the local window.
135
+ # @returns [String] Human-readable local window information.
112
136
  def inspect
113
137
  "\#<#{self.class} available=#{@available} used=#{@used} capacity=#{@capacity} desired=#{@desired} #{limited? ? "limited" : nil}>"
114
138
  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 "window"
@@ -18,14 +18,21 @@ module Protocol
18
18
  TYPE = 0x8
19
19
  FORMAT = "N"
20
20
 
21
+ # Pack a window size increment into the frame.
22
+ # @parameter window_size_increment [Integer] The window size increment value.
21
23
  def pack(window_size_increment)
22
24
  super [window_size_increment].pack(FORMAT)
23
25
  end
24
26
 
27
+ # Unpack the window size increment from the frame payload.
28
+ # @returns [Integer] The window size increment value.
25
29
  def unpack
26
30
  super.unpack1(FORMAT)
27
31
  end
28
32
 
33
+ # Read and validate the WINDOW_UPDATE frame payload.
34
+ # @parameter stream [IO] The stream to read from.
35
+ # @raises [FrameSizeError] If the frame length is invalid.
29
36
  def read_payload(stream)
30
37
  super
31
38
 
@@ -34,6 +41,8 @@ module Protocol
34
41
  end
35
42
  end
36
43
 
44
+ # Apply this WINDOW_UPDATE frame to a connection for processing.
45
+ # @parameter connection [Connection] The connection to apply the frame to.
37
46
  def apply(connection)
38
47
  connection.receive_window_update(self)
39
48
  end
data/readme.md CHANGED
@@ -10,6 +10,18 @@ Please see the [project documentation](https://socketry.github.io/protocol-http2
10
10
 
11
11
  - [Getting Started](https://socketry.github.io/protocol-http2/guides/getting-started/index) - This guide explains how to use the `protocol-http2` gem to implement a basic HTTP/2 client.
12
12
 
13
+ ## Releases
14
+
15
+ Please see the [project releases](https://socketry.github.io/protocol-http2/releases/index) for all releases.
16
+
17
+ ### v0.23.0
18
+
19
+ - Introduce a limit to the number of CONTINUATION frames that can be read to prevent resource exhaustion. The default limit is 8 continuation frames, which means a total of 9 frames (1 initial + 8 continuation). This limit can be adjusted by passing a different value to the `limit` parameter in the `Continued.read` method. Setting the limit to 0 will only read the initial frame without any continuation frames. In order to change the default, you can redefine the `LIMIT` constant in the `Protocol::HTTP2::Continued` module, OR you can pass a different frame class to the framer.
20
+
21
+ ### v0.22.0
22
+
23
+ - [Added Priority Update Frame and Stream Priority](https://socketry.github.io/protocol-http2/releases/index#added-priority-update-frame-and-stream-priority)
24
+
13
25
  ## See Also
14
26
 
15
27
  - [Async::HTTP](https://github.com/socketry/async-http) - A high-level HTTP client and server implementation.
data/releases.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Releases
2
2
 
3
+ ## v0.23.0
4
+
5
+ - Introduce a limit to the number of CONTINUATION frames that can be read to prevent resource exhaustion. The default limit is 8 continuation frames, which means a total of 9 frames (1 initial + 8 continuation). This limit can be adjusted by passing a different value to the `limit` parameter in the `Continued.read` method. Setting the limit to 0 will only read the initial frame without any continuation frames. In order to change the default, you can redefine the `LIMIT` constant in the `Protocol::HTTP2::Continued` module, OR you can pass a different frame class to the framer.
6
+
3
7
  ## v0.22.0
4
8
 
5
9
  ### Added Priority Update Frame and Stream Priority
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: protocol-http2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.22.1
4
+ version: 0.23.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -40,7 +40,7 @@ cert_chain:
40
40
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
41
41
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
42
42
  -----END CERTIFICATE-----
43
- date: 2025-02-01 00:00:00.000000000 Z
43
+ date: 1980-01-02 00:00:00.000000000 Z
44
44
  dependencies:
45
45
  - !ruby/object:Gem::Dependency
46
46
  name: protocol-hpack
@@ -74,6 +74,8 @@ executables: []
74
74
  extensions: []
75
75
  extra_rdoc_files: []
76
76
  files:
77
+ - context/getting-started.md
78
+ - context/index.yaml
77
79
  - lib/protocol/http2.rb
78
80
  - lib/protocol/http2/client.rb
79
81
  - lib/protocol/http2/connection.rb
@@ -114,14 +116,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
114
116
  requirements:
115
117
  - - ">="
116
118
  - !ruby/object:Gem::Version
117
- version: '3.1'
119
+ version: '3.2'
118
120
  required_rubygems_version: !ruby/object:Gem::Requirement
119
121
  requirements:
120
122
  - - ">="
121
123
  - !ruby/object:Gem::Version
122
124
  version: '0'
123
125
  requirements: []
124
- rubygems_version: 3.6.2
126
+ rubygems_version: 3.6.9
125
127
  specification_version: 4
126
128
  summary: A low level implementation of the HTTP/2 protocol.
127
129
  test_files: []
metadata.gz.sig CHANGED
Binary file