protocol-http2 0.20.0 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
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