protocol-http2 0.20.0 → 0.21.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 80a795de54c7f452a70b82f310c4f0aa3bda4bd15f034f548114a41bfc8d1649
4
- data.tar.gz: 496e203587367c71ce4b0298ba96492d5ce4892842fdcbf57796031556ca3f1a
3
+ metadata.gz: 90e7e77b799044d635c41f870e4d852fb8b9c3e51e5e637e70400420fa318c4f
4
+ data.tar.gz: f2d9106c992e4503e36c5f3b4d57859744cd0281bcd8f261b7d902b7574e7cfd
5
5
  SHA512:
6
- metadata.gz: e4b587ae75dc73dbd99ff3bc20cafe6c55cb329ab275bac187572730de5d5365f2f8c521d88b32bffb80363736cf0cdc62d579d2495872f13982b4f1cd1fdfa0
7
- data.tar.gz: f2964d07b204b702ded73b1a3df961dad07c95989e78311732d4264184b59a6671f7bb81511e1d196c1dd9ccf18f81db1fd8064607c3156550191dc7cec8a5d2
6
+ metadata.gz: 2b181f107bb843771deeb1d546a58315643faea3abcfa8f5a37198e2bf301a25f33d58d140879e676ac3928f932ed9b4a64325613b62e6b9e1297cc31264ef17
7
+ data.tar.gz: 89ed0a08306f0e6a1835afc1867fac8c9f0c01c28aeb4828eec3f2611f90244ddbf2be01faaf15f775ed30457b044f7a8956bede2cb0f83de913d1945524eccf
checksums.yaml.gz.sig CHANGED
Binary file
@@ -28,6 +28,10 @@ module Protocol
28
28
  if @state == :new
29
29
  @framer.write_connection_preface
30
30
 
31
+ # We don't support RFC7540 priorities:
32
+ settings = settings.to_a
33
+ settings << [Settings::NO_RFC7540_PRIORITIES, 1]
34
+
31
35
  send_settings(settings)
32
36
 
33
37
  yield if block_given?
@@ -5,7 +5,6 @@
5
5
  # Copyright, 2023, by Marco Concetto Rudilosso.
6
6
 
7
7
  require_relative "framer"
8
- require_relative "dependency"
9
8
  require_relative "flow_controlled"
10
9
 
11
10
  require "protocol/hpack"
@@ -23,10 +22,6 @@ module Protocol
23
22
  # Hash(Integer, Stream)
24
23
  @streams = {}
25
24
 
26
- # Hash(Integer, Dependency)
27
- @dependency = Dependency.new(self, 0)
28
- @dependencies = {0 => @dependency}
29
-
30
25
  @framer = framer
31
26
 
32
27
  # The next stream id to use:
@@ -95,7 +90,6 @@ module Protocol
95
90
 
96
91
  def delete(id)
97
92
  @streams.delete(id)
98
- @dependencies[id]&.delete!
99
93
  end
100
94
 
101
95
  # Close the underlying framer and all streams.
@@ -402,22 +396,6 @@ module Protocol
402
396
  end
403
397
  end
404
398
 
405
- def send_priority(stream_id, priority)
406
- frame = PriorityFrame.new(stream_id)
407
- frame.pack(priority)
408
-
409
- write_frame(frame)
410
- end
411
-
412
- # Sets the priority for an incoming stream.
413
- def receive_priority(frame)
414
- if dependency = @dependencies[frame.stream_id]
415
- dependency.receive_priority(frame)
416
- elsif idle_stream_id?(frame.stream_id)
417
- Dependency.create(self, frame.stream_id, frame.unpack)
418
- end
419
- end
420
-
421
399
  def receive_push_promise(frame)
422
400
  raise ProtocolError, "Unable to receive push promise!"
423
401
  end
@@ -470,23 +448,17 @@ module Protocol
470
448
  end
471
449
  end
472
450
 
473
- # Traverse active streams in order of priority and allow them to consume the available flow-control window.
474
- # @param amount [Integer] the amount of data to write. Defaults to the current window capacity.
451
+ # Traverse active streams and allow them to consume the available flow-control window.
452
+ # @parameter amount [Integer] the amount of data to write. Defaults to the current window capacity.
475
453
  def consume_window(size = self.available_size)
476
454
  # Return if there is no window to consume:
477
455
  return unless size > 0
478
456
 
479
- # Console.info(self) do |buffer|
480
- # @dependencies.each do |id, dependency|
481
- # buffer.puts "- #{dependency}"
482
- # end
483
- #
484
- # buffer.puts
485
- #
486
- # @dependency.print_hierarchy(buffer)
487
- # end
488
-
489
- @dependency.consume_window(size)
457
+ @streams.each_value do |stream|
458
+ if stream.active?
459
+ stream.window_updated(size)
460
+ end
461
+ end
490
462
  end
491
463
 
492
464
  def receive_window_update(frame)
@@ -78,7 +78,7 @@ module Protocol
78
78
  end
79
79
 
80
80
  # The window has been expanded by the given amount.
81
- # @param size [Integer] the maximum amount of data to send.
81
+ # @parameter size [Integer] the maximum amount of data to send.
82
82
  # @return [Boolean] whether the window update was used or not.
83
83
  def window_updated(size)
84
84
  return false
@@ -34,7 +34,7 @@ module Protocol
34
34
  # The base class does not have any specific type index:
35
35
  TYPE = nil
36
36
 
37
- # @param length [Integer] the length of the payload, or nil if the header has not been read yet.
37
+ # @parameter length [Integer] the length of the payload, or nil if the header has not been read yet.
38
38
  def initialize(stream_id = 0, flags = 0, type = self.class::TYPE, length = nil, payload = nil)
39
39
  @stream_id = stream_id
40
40
  @flags = flags
@@ -134,7 +134,7 @@ module Protocol
134
134
 
135
135
  # Decodes common 9-byte header.
136
136
  #
137
- # @param buffer [String]
137
+ # @parameter buffer [String]
138
138
  def self.parse_header(buffer)
139
139
  length_hi, length_lo, type, flags, stream_id = buffer.unpack(HEADER_FORMAT)
140
140
  length = (length_hi << LENGTH_HISHIFT) | length_lo
@@ -7,7 +7,6 @@ require_relative "error"
7
7
 
8
8
  require_relative "data_frame"
9
9
  require_relative "headers_frame"
10
- require_relative "priority_frame"
11
10
  require_relative "reset_stream_frame"
12
11
  require_relative "settings_frame"
13
12
  require_relative "push_promise_frame"
@@ -22,7 +21,7 @@ module Protocol
22
21
  FRAMES = [
23
22
  DataFrame,
24
23
  HeadersFrame,
25
- PriorityFrame,
24
+ nil, # PriorityFrame is deprecated / removed.
26
25
  ResetStreamFrame,
27
26
  SettingsFrame,
28
27
  PushPromiseFrame,
@@ -6,7 +6,6 @@
6
6
  require_relative "frame"
7
7
  require_relative "padded"
8
8
  require_relative "continuation_frame"
9
- require_relative "priority_frame"
10
9
 
11
10
  module Protocol
12
11
  module HTTP2
@@ -41,23 +40,16 @@ module Protocol
41
40
  data = super
42
41
 
43
42
  if priority?
44
- priority = Priority.unpack(data)
43
+ # We no longer support priority frames, so strip the data:
45
44
  data = data.byteslice(5, data.bytesize - 5)
46
45
  end
47
46
 
48
- return priority, data
47
+ return data
49
48
  end
50
49
 
51
- def pack(priority, data, *arguments, **options)
50
+ def pack(data, *arguments, **options)
52
51
  buffer = String.new.b
53
52
 
54
- if priority
55
- buffer << priority.pack
56
- set_flags(PRIORITY)
57
- else
58
- clear_flags(PRIORITY)
59
- end
60
-
61
53
  buffer << data
62
54
 
63
55
  super(buffer, *arguments, **options)
@@ -28,6 +28,10 @@ module Protocol
28
28
  if @state == :new
29
29
  @framer.read_connection_preface
30
30
 
31
+ # We don't support RFC7540 priorities:
32
+ settings = settings.to_a
33
+ settings << [Settings::NO_RFC7540_PRIORITIES, 1]
34
+
31
35
  send_settings(settings)
32
36
 
33
37
  read_frame do |frame|
@@ -15,6 +15,7 @@ module Protocol
15
15
  MAXIMUM_FRAME_SIZE = 0x5
16
16
  MAXIMUM_HEADER_LIST_SIZE = 0x6
17
17
  ENABLE_CONNECT_PROTOCOL = 0x8
18
+ NO_RFC7540_PRIORITIES = 0x9
18
19
 
19
20
  ASSIGN = [
20
21
  nil,
@@ -4,7 +4,6 @@
4
4
  # Copyright, 2019-2024, by Samuel Williams.
5
5
 
6
6
  require_relative "connection"
7
- require_relative "dependency"
8
7
 
9
8
  module Protocol
10
9
  module HTTP2
@@ -77,8 +76,6 @@ module Protocol
77
76
 
78
77
  @local_window = Window.new(@connection.local_settings.initial_window_size)
79
78
  @remote_window = Window.new(@connection.remote_settings.initial_window_size)
80
-
81
- @dependency = Dependency.create(@connection, @id)
82
79
  end
83
80
 
84
81
  # The connection this stream belongs to.
@@ -90,27 +87,9 @@ module Protocol
90
87
  # Stream state, e.g. `idle`, `closed`.
91
88
  attr_accessor :state
92
89
 
93
- attr :dependency
94
-
95
90
  attr :local_window
96
91
  attr :remote_window
97
92
 
98
- def weight
99
- @dependency.weight
100
- end
101
-
102
- def priority
103
- @dependency.priority
104
- end
105
-
106
- def priority= priority
107
- @dependency.priority = priority
108
- end
109
-
110
- def parent=(stream)
111
- @dependency.parent = stream.dependency
112
- end
113
-
114
93
  def maximum_frame_size
115
94
  @connection.available_frame_size
116
95
  end
@@ -141,13 +120,13 @@ module Protocol
141
120
  @state == :idle or @state == :reserved_local or @state == :open or @state == :half_closed_remote
142
121
  end
143
122
 
144
- private def write_headers(priority, headers, flags = 0)
123
+ private def write_headers(headers, flags = 0)
145
124
  frame = HeadersFrame.new(@id, flags)
146
125
 
147
126
  @connection.write_frames do |framer|
148
127
  data = @connection.encode_headers(headers)
149
128
 
150
- frame.pack(priority, data, maximum_size: @connection.maximum_frame_size)
129
+ frame.pack(data, maximum_size: @connection.maximum_frame_size)
151
130
 
152
131
  framer.write_frame(frame)
153
132
  end
@@ -157,6 +136,10 @@ module Protocol
157
136
 
158
137
  # The HEADERS frame is used to open a stream, and additionally carries a header block fragment. HEADERS frames can be sent on a stream in the "idle", "reserved (local)", "open", or "half-closed (remote)" state.
159
138
  def send_headers(*arguments)
139
+ if arguments.first.nil?
140
+ arguments.shift # Remove nil priority.
141
+ end
142
+
160
143
  if @state == :idle
161
144
  frame = write_headers(*arguments)
162
145
 
@@ -236,7 +219,7 @@ module Protocol
236
219
  end
237
220
 
238
221
  # Transition the stream into the closed state.
239
- # @param error_code [Integer] the error code if the stream was closed due to a stream reset.
222
+ # @parameter error_code [Integer] the error code if the stream was closed due to a stream reset.
240
223
  def close!(error_code = nil)
241
224
  @state = :closed
242
225
  @connection.delete(@id)
@@ -265,11 +248,7 @@ module Protocol
265
248
 
266
249
  def process_headers(frame)
267
250
  # Receiving request headers:
268
- priority, data = frame.unpack
269
-
270
- if priority
271
- @dependency.process_priority(priority)
272
- end
251
+ data = frame.unpack
273
252
 
274
253
  @connection.decode_headers(data)
275
254
  end
@@ -401,7 +380,7 @@ module Protocol
401
380
  end
402
381
 
403
382
  # Server push is semantically equivalent to a server responding to a request; however, in this case, that request is also sent by the server, as a PUSH_PROMISE frame.
404
- # @param headers [Hash] contains a complete set of request header fields that the server attributes to the request.
383
+ # @parameter headers [Hash] contains a complete set of request header fields that the server attributes to the request.
405
384
  def send_push_promise(headers)
406
385
  if @state == :open or @state == :half_closed_remote
407
386
  promised_stream = self.create_push_promise_stream(headers)
@@ -427,7 +406,6 @@ module Protocol
427
406
  headers = @connection.decode_headers(data)
428
407
 
429
408
  stream = self.accept_push_promise_stream(promised_stream_id, headers)
430
- stream.parent = self
431
409
  stream.reserved_remote!
432
410
 
433
411
  return stream, headers
@@ -5,6 +5,6 @@
5
5
 
6
6
  module Protocol
7
7
  module HTTP2
8
- VERSION = "0.20.0"
8
+ VERSION = "0.21.0"
9
9
  end
10
10
  end
@@ -9,7 +9,7 @@ module Protocol
9
9
  # 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
10
  DEFAULT_CAPACITY = 0xFFFF
11
11
 
12
- # @param capacity [Integer] The initial window size, typically from the settings.
12
+ # @parameter capacity [Integer] The initial window size, typically from the settings.
13
13
  def initialize(capacity = DEFAULT_CAPACITY)
14
14
  # This is the main field required:
15
15
  @available = capacity
data/readme.md CHANGED
@@ -58,7 +58,7 @@ Async do
58
58
  ]
59
59
 
60
60
  puts "Sending request on stream id=#{stream.id} state=#{stream.state}..."
61
- stream.send_headers(nil, headers, Protocol::HTTP2::END_STREAM)
61
+ stream.send_headers(headers, Protocol::HTTP2::END_STREAM)
62
62
 
63
63
  puts "Waiting for response..."
64
64
  $count = 0
data/releases.md ADDED
@@ -0,0 +1,7 @@
1
+ # Releases
2
+
3
+ ## Unreleased
4
+
5
+ ### Remove Priority Frame and Dependency Tracking
6
+
7
+ HTTP/2 has deprecated the priority frame and stream dependency tracking. This feature has been effectively removed from the protocol. As a consequence, the internal implementation is greatly simplified. The `Protocol::HTTP2::Stream` class no longer tracks dependencies or priorities, and this includes `Stream#send_headers` which no longer takes `priority` as the first argument.
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.20.0
4
+ version: 0.21.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: 2024-11-09 00:00:00.000000000 Z
43
+ date: 2024-11-28 00:00:00.000000000 Z
44
44
  dependencies:
45
45
  - !ruby/object:Gem::Dependency
46
46
  name: protocol-hpack
@@ -81,7 +81,6 @@ files:
81
81
  - lib/protocol/http2/connection.rb
82
82
  - lib/protocol/http2/continuation_frame.rb
83
83
  - lib/protocol/http2/data_frame.rb
84
- - lib/protocol/http2/dependency.rb
85
84
  - lib/protocol/http2/error.rb
86
85
  - lib/protocol/http2/flow_controlled.rb
87
86
  - lib/protocol/http2/frame.rb
@@ -90,7 +89,6 @@ files:
90
89
  - lib/protocol/http2/headers_frame.rb
91
90
  - lib/protocol/http2/padded.rb
92
91
  - lib/protocol/http2/ping_frame.rb
93
- - lib/protocol/http2/priority_frame.rb
94
92
  - lib/protocol/http2/push_promise_frame.rb
95
93
  - lib/protocol/http2/reset_stream_frame.rb
96
94
  - lib/protocol/http2/server.rb
@@ -103,6 +101,7 @@ files:
103
101
  - lib/traces/provider/protocol/http2/framer.rb
104
102
  - license.md
105
103
  - readme.md
104
+ - releases.md
106
105
  homepage: https://github.com/socketry/protocol-http2
107
106
  licenses:
108
107
  - MIT
metadata.gz.sig CHANGED
Binary file
@@ -1,245 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2020-2023, by Samuel Williams.
5
-
6
- module Protocol
7
- module HTTP2
8
- DEFAULT_WEIGHT = 16
9
-
10
- class Dependency
11
- def self.create(connection, id, priority = nil)
12
- weight = DEFAULT_WEIGHT
13
- exclusive = false
14
-
15
- if priority
16
- if parent = connection.dependencies[priority.stream_dependency]
17
- exclusive = priority.exclusive
18
- end
19
-
20
- weight = priority.weight
21
- end
22
-
23
- if parent.nil?
24
- parent = connection.dependency
25
- end
26
-
27
- dependency = self.new(connection, id, weight)
28
-
29
- connection.dependencies[id] = dependency
30
-
31
- if exclusive
32
- parent.exclusive_child(dependency)
33
- else
34
- parent.add_child(dependency)
35
- end
36
-
37
- return dependency
38
- end
39
-
40
- def initialize(connection, id, weight = DEFAULT_WEIGHT)
41
- @connection = connection
42
- @id = id
43
-
44
- @parent = nil
45
- @children = nil
46
-
47
- @weight = weight
48
-
49
- # Cache of any associated stream:
50
- @stream = nil
51
-
52
- # Cache of children for window allocation:
53
- @total_weight = 0
54
- @ordered_children = nil
55
- end
56
-
57
- def <=> other
58
- @weight <=> other.weight
59
- end
60
-
61
- def == other
62
- @id == other.id
63
- end
64
-
65
- # The connection this stream belongs to.
66
- attr :connection
67
-
68
- # Stream ID (odd for client initiated streams, even otherwise).
69
- attr :id
70
-
71
- # The parent dependency.
72
- attr_accessor :parent
73
-
74
- # The dependent children.
75
- attr_accessor :children
76
-
77
- # The weight of the stream relative to other siblings.
78
- attr_accessor :weight
79
-
80
- def stream
81
- @stream ||= @connection.streams[@id]
82
- end
83
-
84
- def clear_cache!
85
- @ordered_children = nil
86
- end
87
-
88
- def delete!
89
- @connection.dependencies.delete(@id)
90
-
91
- @parent.remove_child(self)
92
-
93
- @children&.each do |id, child|
94
- parent.add_child(child)
95
- end
96
-
97
- @connection = nil
98
- @parent = nil
99
- @children = nil
100
- end
101
-
102
- def add_child(dependency)
103
- @children ||= {}
104
- @children[dependency.id] = dependency
105
-
106
- dependency.parent = self
107
-
108
- if @ordered_children
109
- # Binary search for insertion point:
110
- index = @ordered_children.bsearch_index do |child|
111
- child.weight >= dependency.weight
112
- end
113
-
114
- if index
115
- @ordered_children.insert(index, dependency)
116
- else
117
- @ordered_children.push(dependency)
118
- end
119
-
120
- @total_weight += dependency.weight
121
- end
122
- end
123
-
124
- def remove_child(dependency)
125
- @children&.delete(dependency.id)
126
-
127
- if @ordered_children
128
- # Don't do a linear search here, it can be slow. Instead, the child's parent will be set to `nil`, and we check this in {#consume_window} using `delete_if`.
129
- # @ordered_children.delete(dependency)
130
- @total_weight -= dependency.weight
131
- end
132
- end
133
-
134
- # An exclusive flag allows for the insertion of a new level of dependencies. The exclusive flag causes the stream to become the sole dependency of its parent stream, causing other dependencies to become dependent on the exclusive stream.
135
- # @param parent [Dependency] the dependency which will be inserted, taking control of all current children.
136
- def exclusive_child(parent)
137
- parent.children = @children
138
-
139
- @children&.each_value do |child|
140
- child.parent = parent
141
- end
142
-
143
- parent.clear_cache!
144
-
145
- @children = {parent.id => parent}
146
- self.clear_cache!
147
-
148
- parent.parent = self
149
- end
150
-
151
- def process_priority(priority)
152
- dependent_id = priority.stream_dependency
153
-
154
- if dependent_id == @id
155
- raise ProtocolError, "Stream priority for stream id #{@id} cannot depend on itself!"
156
- end
157
-
158
- @weight = priority.weight
159
-
160
- # We essentially ignore `dependent_id` if the dependency does not exist:
161
- if parent = @connection.dependencies[dependent_id]
162
- if priority.exclusive
163
- @parent.remove_child(self)
164
-
165
- parent.exclusive_child(self)
166
- elsif !@parent.equal?(parent)
167
- @parent.remove_child(self)
168
-
169
- parent.add_child(self)
170
- end
171
- end
172
- end
173
-
174
- # Change the priority of the stream both locally and remotely.
175
- def priority= priority
176
- send_priority(priority)
177
- process_priority(priority)
178
- end
179
-
180
- # The current local priority of the stream.
181
- def priority(exclusive = false)
182
- Priority.new(exclusive, @parent.id, @weight)
183
- end
184
-
185
- def send_priority(priority)
186
- @connection.send_priority(@id, priority)
187
- end
188
-
189
- def receive_priority(frame)
190
- self.process_priority(frame.unpack)
191
- end
192
-
193
- def total_weight
194
- self.ordered_children
195
-
196
- return @total_weight
197
- end
198
-
199
- def ordered_children
200
- unless @ordered_children
201
- if @children and !@children.empty?
202
- @ordered_children = @children.values.sort
203
- @total_weight = @ordered_children.sum(&:weight)
204
- end
205
- end
206
-
207
- return @ordered_children
208
- end
209
-
210
- # Traverse active streams in order of priority and allow them to consume the available flow-control window.
211
- # @param amount [Integer] the amount of data to write. Defaults to the current window capacity.
212
- def consume_window(size)
213
- # If there is an associated stream, give it priority:
214
- if stream = self.stream
215
- return if stream.window_updated(size)
216
- end
217
-
218
- # Otherwise, allow the dependent children to use up the available window:
219
- self.ordered_children&.delete_if do |child|
220
- if child.parent
221
- # Compute the proportional allocation:
222
- allocated = (child.weight * size) / @total_weight
223
-
224
- child.consume_window(allocated) if allocated > 0
225
-
226
- false
227
- else
228
- true
229
- end
230
- end
231
- end
232
-
233
- def inspect
234
- "\#<#{self.class} id=#{@id} parent id=#{@parent&.id} weight=#{@weight} #{@children&.size || 0} children>"
235
- end
236
-
237
- def print_hierarchy(output = $stderr, indent: 0)
238
- output.puts "#{"\t" * indent}#{self.inspect}"
239
- @children&.each_value do |child|
240
- child.print_hierarchy(output, indent: indent+1)
241
- end
242
- end
243
- end
244
- end
245
- end
@@ -1,82 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2019-2024, by Samuel Williams.
5
-
6
- require_relative "frame"
7
-
8
- module Protocol
9
- module HTTP2
10
- VALID_WEIGHT = (1..256)
11
-
12
- # Stream Dependency: A 31-bit stream identifier for the stream that
13
- # this stream depends on (see Section 5.3). This field is only
14
- # present if the PRIORITY flag is set.
15
- class Priority < Struct.new(:exclusive, :stream_dependency, :weight)
16
- FORMAT = "NC".freeze
17
- EXCLUSIVE = 1 << 31
18
-
19
- # All streams are initially assigned a non-exclusive dependency on stream 0x0. Pushed streams (Section 8.2) initially depend on their associated stream. In both cases, streams are assigned a default weight of 16.
20
- def self.default(stream_dependency = 0, weight = 16)
21
- self.new(false, stream_dependency, weight)
22
- end
23
-
24
- def self.unpack(data)
25
- stream_dependency, weight = data.unpack(FORMAT)
26
-
27
- # Weight: An unsigned 8-bit integer representing a priority weight for the stream (see Section 5.3). Add one to the value to obtain a weight between 1 and 256. This field is only present if the PRIORITY flag is set.
28
- return self.new(stream_dependency & EXCLUSIVE != 0, stream_dependency & ~EXCLUSIVE, weight + 1)
29
- end
30
-
31
- def pack
32
- if exclusive
33
- stream_dependency = self.stream_dependency | EXCLUSIVE
34
- else
35
- stream_dependency = self.stream_dependency
36
- end
37
-
38
- return [stream_dependency, self.weight - 1].pack(FORMAT)
39
- end
40
-
41
- def weight= value
42
- if VALID_WEIGHT.include?(value)
43
- super
44
- else
45
- raise ArgumentError, "Weight #{value} must be between 1-256!"
46
- end
47
- end
48
- end
49
-
50
- # The PRIORITY frame specifies the sender-advised priority of a stream. It can be sent in any stream state, including idle or closed streams.
51
- #
52
- # +-+-------------------------------------------------------------+
53
- # |E| Stream Dependency (31) |
54
- # +-+-------------+-----------------------------------------------+
55
- # | Weight (8) |
56
- # +-+-------------+
57
- #
58
- class PriorityFrame < Frame
59
- TYPE = 0x2
60
-
61
- def pack priority
62
- super priority.pack
63
- end
64
-
65
- def unpack
66
- Priority.unpack(super)
67
- end
68
-
69
- def apply(connection)
70
- connection.receive_priority(self)
71
- end
72
-
73
- def read_payload(stream)
74
- super
75
-
76
- if @length != 5
77
- raise FrameSizeError, "Invalid frame length"
78
- end
79
- end
80
- end
81
- end
82
- end