protocol-http2 0.5.2 → 0.6.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: 868932fdb503f3fb6cc3fed243af7019b56e24bb1ac56a42e69132e0dad1af41
4
- data.tar.gz: fb965bc65c34b0ad14f10985c0f21676e1b9a9ceab1052d7482635d5542f461b
3
+ metadata.gz: b5f71a68091b631d1c6a776ae1730539cf753ee6ec24d27dc3b1d739dd971426
4
+ data.tar.gz: ea202fecbfe30bfbe0b9facf5d507f09344a2a959822be6f22d2d082cf273477
5
5
  SHA512:
6
- metadata.gz: d3f8197a22080d609c376e48fd4019aa751b9cf2b845c7d5c9d5f3917e349a09a3ea14d256cac36e815d7126ad72c95a268f754884db200eed006e2f6400d450
7
- data.tar.gz: a9cf712bc5eee80c7d77f3628e7df163b3c253a5910358534d52910f13064b5c197ca815eb248483be429544f2cff0af0ce8a540172143eb44bea2f53223a6f3
6
+ metadata.gz: 9d1a0a6e6a8461e985fcb9dc83e64c622743cb3d05e52d3b72f1b8a0f48d8190ac01417070807ada1d4ee0434dd7daa775d054ca89d54ba2010d6c153d9fad91
7
+ data.tar.gz: a17e3d970e3a2539361f518aff2ccc5ec40ca77f9b639a0b6bd69aabab1d0ade8a2e1f7049c08f5a001acfa9eb2fca4c5f2e785475d09e0c21c8088cec050d97
@@ -31,7 +31,6 @@ module Protocol
31
31
  def initialize(framer, local_stream_id)
32
32
  @state = :new
33
33
  @streams = {}
34
- @closed = 0
35
34
 
36
35
  @framer = framer
37
36
  @local_stream_id = local_stream_id
@@ -76,28 +75,22 @@ module Protocol
76
75
  # Our window for sending data. When we send data, it reduces this window.
77
76
  attr :remote_window
78
77
 
78
+ # The highest stream_id that has been successfully accepted by this connection.
79
+ attr :remote_stream_id
80
+
79
81
  def closed?
80
82
  @state == :closed
81
83
  end
82
84
 
83
- def stream_closed(stream)
84
- @closed += 1
85
- end
86
-
87
- def active_stream_count
88
- @streams.size - @closed
85
+ def active_streams
86
+ @streams.each_value.select(&:active?)
89
87
  end
90
88
 
91
- def connection_error!(error, message)
92
- return if @framer.closed?
93
-
94
- send_goaway(error, message)
95
-
96
- self.close
97
- end
98
-
99
- def close
89
+ # Close the underlying framer and all streams.
90
+ def close(error = nil)
100
91
  @framer.close
92
+
93
+ @streams.each_value{|stream| stream.close(error)}
101
94
  end
102
95
 
103
96
  def encode_headers(headers, buffer = String.new.b)
@@ -121,31 +114,45 @@ module Protocol
121
114
 
122
115
  attr :streams
123
116
 
117
+ # 6.8. GOAWAY
118
+ # There is an inherent race condition between an endpoint starting new streams and the remote sending a GOAWAY frame. To deal with this case, the GOAWAY contains the stream identifier of the last peer-initiated stream that was or might be processed on the sending endpoint in this connection. For instance, if the server sends a GOAWAY frame, the identified stream is the highest-numbered stream initiated by the client.
119
+ # Once sent, the sender will ignore frames sent on streams initiated by the receiver if the stream has an identifier higher than the included last stream identifier. Receivers of a GOAWAY frame MUST NOT open additional streams on the connection, although a new connection can be established for new streams.
120
+ def ignore_frame?(frame)
121
+ if self.closed?
122
+ puts "ignore_frame? #{frame.stream_id} -> #{valid_remote_stream_id?(frame.stream_id)} > #{@remote_stream_id}"
123
+ if valid_remote_stream_id?(frame.stream_id)
124
+ return frame.stream_id > @remote_stream_id
125
+ end
126
+ end
127
+ end
128
+
129
+ # Reads one frame from the network and processes. Processing the frame updates the state of the connection and related streams. If the frame triggers an error, e.g. a protocol error, the connection will typically emit a goaway frame and re-raise the exception. You should continue processing frames until the underlying connection is closed.
124
130
  def read_frame
125
131
  frame = @framer.read_frame(@local_settings.maximum_frame_size)
126
- # puts "#{self.class} #{@state} read_frame: class=#{frame.class} flags=#{frame.flags} length=#{frame.length}"
132
+ # puts "#{self.class} #{@state} read_frame: class=#{frame.class} stream_id=#{frame.stream_id} flags=#{frame.flags} length=#{frame.length} (remote_stream_id=#{@remote_stream_id})"
127
133
  # puts "Windows: local_window=#{@local_window.inspect}; remote_window=#{@remote_window.inspect}"
128
134
 
129
- yield frame if block_given?
135
+ return if ignore_frame?(frame)
130
136
 
137
+ yield frame if block_given?
131
138
  frame.apply(self)
132
139
 
133
140
  return frame
134
- rescue GoawayError
135
- # This is not a connection error. We are done.
136
- self.close
141
+ rescue GoawayError => error
142
+ # Go directly to jail. Do not pass go, do not collect $200.
143
+ self.close(error)
137
144
 
138
145
  raise
139
146
  rescue ProtocolError => error
140
- connection_error!(error.code || PROTOCOL_ERROR, error.message)
147
+ send_goaway(error.code || PROTOCOL_ERROR, error.message)
141
148
 
142
149
  raise
143
150
  rescue HPACK::CompressionError => error
144
- connection_error!(COMPRESSION_ERROR, error.message)
151
+ send_goaway(COMPRESSION_ERROR, error.message)
145
152
 
146
153
  raise
147
154
  rescue
148
- connection_error!(PROTOCOL_ERROR, $!.message)
155
+ send_goaway(PROTOCOL_ERROR, $!.message)
149
156
 
150
157
  raise
151
158
  end
@@ -159,21 +166,31 @@ module Protocol
159
166
  write_frame(frame)
160
167
  end
161
168
 
169
+ # Transition the connection into the closed state.
170
+ def close!
171
+ @state = :closed
172
+
173
+ return self
174
+ end
175
+
176
+ # Tell the remote end that the connection is being shut down. If the `error_code` is 0, this is a graceful shutdown. The other end of the connection should not make any new streams, but existing streams may be completed.
162
177
  def send_goaway(error_code = 0, message = "")
163
178
  frame = GoawayFrame.new
164
179
  frame.pack @remote_stream_id, error_code, message
165
180
 
166
181
  write_frame(frame)
167
182
 
168
- @state = :closed
183
+ self.close!
169
184
  end
170
185
 
171
186
  def receive_goaway(frame)
172
- @state = :closed
187
+ # We capture the last stream that was processed.
188
+ @remote_stream_id, error_code, message = frame.unpack
173
189
 
174
- last_stream_id, error_code, message = frame.unpack
190
+ self.close!
175
191
 
176
192
  if error_code != 0
193
+ # Shut down immediately.
177
194
  raise GoawayError.new(message, error_code)
178
195
  end
179
196
  end
@@ -336,7 +353,7 @@ module Protocol
336
353
  if stream = @streams[frame.stream_id]
337
354
  stream.receive_headers(frame)
338
355
  else
339
- if self.active_stream_count < self.maximum_concurrent_streams
356
+ if self.active_streams.count < self.maximum_concurrent_streams
340
357
  stream = accept_stream(frame.stream_id)
341
358
  stream.receive_headers(frame)
342
359
  else
@@ -90,6 +90,10 @@ module Protocol
90
90
  @connection.streams[@id] = self
91
91
  end
92
92
 
93
+ # The stream is being closed because the connection is being closed.
94
+ def close(error = nil)
95
+ end
96
+
93
97
  # Stream ID (odd for client initiated streams, even otherwise).
94
98
  attr :id
95
99
 
@@ -118,6 +122,10 @@ module Protocol
118
122
  @connection.write_frame(frame)
119
123
  end
120
124
 
125
+ def active?
126
+ @state != :closed && @state != :idle
127
+ end
128
+
121
129
  def closed?
122
130
  @state == :closed
123
131
  end
@@ -217,11 +225,11 @@ module Protocol
217
225
  end
218
226
  end
219
227
 
220
- # This is not the same as a `close` method. If you are looking for that, use `send_stream_reset`.
228
+ # Transition the stream into the closed state.
221
229
  def close!
222
230
  @state = :closed
223
231
 
224
- @connection.stream_closed(self)
232
+ self.close
225
233
  end
226
234
 
227
235
  def send_reset_stream(error_code = 0)
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Protocol
22
22
  module HTTP2
23
- VERSION = "0.5.2"
23
+ VERSION = "0.6.0"
24
24
  end
25
25
  end
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.5.2
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams