raptor 0.22.3 → 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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +30 -0
  3. data/Dockerfile +3 -1
  4. data/README.md +38 -31
  5. data/docs/raptor-vs-puma.md +44 -38
  6. data/docs/talk.md +1295 -0
  7. data/ext/raptor_bpf/reuseport_select.bpf.c +18 -9
  8. data/ext/raptor_http/extconf.rb +2 -0
  9. data/ext/raptor_http/raptor_http.c +91 -119
  10. data/ext/raptor_http2/raptor_http2.c +272 -223
  11. data/ext/raptor_native/raptor_native.c +38 -20
  12. data/lib/rackup/handler/raptor.rb +12 -11
  13. data/lib/raptor/binder.rb +12 -12
  14. data/lib/raptor/cli.rb +18 -18
  15. data/lib/raptor/cluster.rb +44 -44
  16. data/lib/raptor/control_server.rb +3 -2
  17. data/lib/raptor/detached_body.rb +6 -2
  18. data/lib/raptor/http.rb +7 -5
  19. data/lib/raptor/http1.rb +232 -207
  20. data/lib/raptor/http2.rb +312 -265
  21. data/lib/raptor/reactor.rb +138 -148
  22. data/lib/raptor/reuseport_bpf.rb +62 -38
  23. data/lib/raptor/server.rb +45 -34
  24. data/lib/raptor/stats.rb +15 -3
  25. data/lib/raptor/thread_locals.rb +4 -3
  26. data/lib/raptor/version.rb +1 -1
  27. data/sig/generated/rackup/handler/raptor.rbs +2 -1
  28. data/sig/generated/raptor/binder.rbs +9 -9
  29. data/sig/generated/raptor/cli.rbs +6 -6
  30. data/sig/generated/raptor/cluster.rbs +9 -9
  31. data/sig/generated/raptor/control_server.rbs +2 -1
  32. data/sig/generated/raptor/detached_body.rbs +5 -1
  33. data/sig/generated/raptor/http.rbs +3 -3
  34. data/sig/generated/raptor/http1.rbs +100 -91
  35. data/sig/generated/raptor/http2.rbs +200 -189
  36. data/sig/generated/raptor/reactor.rbs +107 -118
  37. data/sig/generated/raptor/reuseport_bpf.rbs +54 -17
  38. data/sig/generated/raptor/server.rbs +26 -26
  39. data/sig/generated/raptor/stats.rbs +3 -2
  40. data/sig/generated/raptor/thread_locals.rbs +4 -3
  41. metadata +2 -2
  42. data/docs/brisrails-talk.md +0 -2398
@@ -3,8 +3,49 @@
3
3
  module Raptor
4
4
  # Handles HTTP/2 request processing and Rack application integration.
5
5
  class Http2
6
+ EAGER_READ_BUFFER_SIZE: untyped
7
+
8
+ EAGER_MAX_ROUNDS: ::Integer
9
+
10
+ FLAG_END_STREAM: ::Integer
11
+
12
+ FLAG_ACK: ::Integer
13
+
14
+ FLAG_END_HEADERS: ::Integer
15
+
16
+ FLAG_PADDED: ::Integer
17
+
18
+ FLAG_PRIORITY: ::Integer
19
+
20
+ ERROR_NO_ERROR: ::Integer
21
+
22
+ ERROR_PROTOCOL_ERROR: ::Integer
23
+
24
+ ERROR_INTERNAL_ERROR: ::Integer
25
+
26
+ ERROR_FRAME_SIZE_ERROR: ::Integer
27
+
28
+ ERROR_REFUSED_STREAM: ::Integer
29
+
30
+ ERROR_COMPRESSION_ERROR: ::Integer
31
+
32
+ DEFAULT_WINDOW_SIZE: ::Integer
33
+
34
+ MAX_FRAME_SIZE: ::Integer
35
+
6
36
  RESPONSE_TRAILERS: ::String
7
37
 
38
+ SERVER_PROTOCOL: ::String
39
+
40
+ REQUEST_PSEUDO_HEADERS: untyped
41
+
42
+ REQUIRED_REQUEST_PSEUDO_HEADERS: untyped
43
+
44
+ class StreamClosedError < StandardError
45
+ # @rbs () -> String
46
+ def message: () -> String
47
+ end
48
+
8
49
  # Queues concurrent frame writes while the reactor remains the sole
9
50
  # owner of the connection socket.
10
51
  class Writer
@@ -34,12 +75,12 @@ module Raptor
34
75
  # Queues frames for the reactor to write. Before attachment, writes
35
76
  # directly so the writer remains usable during connection setup.
36
77
  #
37
- # @param socket [OpenSSL::SSL::SSLSocket] the connection socket
78
+ # @param socket [TCPSocket, OpenSSL::SSL::SSLSocket] the connection socket
38
79
  # @param frames [Array<String>, nil] frame bytes to write in order
39
80
  # @return [void]
40
81
  #
41
- # @rbs (OpenSSL::SSL::SSLSocket socket, Array[String]? frames) -> void
42
- def write_frames: (OpenSSL::SSL::SSLSocket socket, Array[String]? frames) -> void
82
+ # @rbs (TCPSocket | OpenSSL::SSL::SSLSocket socket, Array[String]? frames) -> void
83
+ def write_frames: (TCPSocket | OpenSSL::SSL::SSLSocket socket, Array[String]? frames) -> void
43
84
 
44
85
  # Attaches a response body that outlives its application thread.
45
86
  #
@@ -52,11 +93,6 @@ module Raptor
52
93
  def attach_body: (Integer stream_id, DetachedBody body, ^(Symbol) -> void finished) -> bool
53
94
  end
54
95
 
55
- class StreamClosedError < StandardError
56
- # @rbs () -> String
57
- def message: () -> String
58
- end
59
-
60
96
  # Coordinates outbound flow control and stream cancellation without
61
97
  # polling or mutexes.
62
98
  class FlowControl
@@ -79,11 +115,12 @@ module Raptor
79
115
 
80
116
  # Reserves outbound capacity on the given stream, waiting until at
81
117
  # least one byte is available on both the connection and stream
82
- # windows. Raises when the stream or connection closes.
118
+ # windows.
83
119
  #
84
120
  # @param stream_id [Integer] the HTTP/2 stream identifier
85
121
  # @param max_bytes [Integer] the largest size the caller would like to send
86
122
  # @return [Integer] the number of bytes the caller may now send
123
+ # @raise [StreamClosedError] if the stream or connection has closed
87
124
  #
88
125
  # @rbs (Integer stream_id, Integer max_bytes) -> Integer
89
126
  def acquire: (Integer stream_id, Integer max_bytes) -> Integer
@@ -93,6 +130,7 @@ module Raptor
93
130
  # @param stream_id [Integer] the HTTP/2 stream identifier
94
131
  # @param max_bytes [Integer] the largest size the caller would like to send
95
132
  # @return [Integer] available bytes, or 0 when flow control is exhausted
133
+ # @raise [StreamClosedError] if the stream or connection has closed
96
134
  #
97
135
  # @rbs (Integer stream_id, Integer max_bytes) -> Integer
98
136
  def try_acquire: (Integer stream_id, Integer max_bytes) -> Integer
@@ -115,7 +153,7 @@ module Raptor
115
153
  def add_stream_window: (Integer stream_id, Integer increment) -> void
116
154
 
117
155
  # Updates the peer's `SETTINGS_INITIAL_WINDOW_SIZE`. Shifts every
118
- # existing stream window by the delta as required by RFC 7540 section 6.9.2.
156
+ # existing stream window by the delta as required by RFC 9113 section 6.9.2.
119
157
  #
120
158
  # @param new_size [Integer] the peer's new initial window size
121
159
  # @return [void]
@@ -157,12 +195,10 @@ module Raptor
157
195
 
158
196
  private
159
197
 
160
- # Reserves up to `capped` bytes from the connection window,
161
- # returning the number of bytes granted (0 when the window is
162
- # exhausted).
198
+ # Reserves up to `capped` bytes from the connection window.
163
199
  #
164
200
  # @param capped [Integer] the largest reservation the caller will accept
165
- # @return [Integer]
201
+ # @return [Integer] bytes granted, or 0 when the window is exhausted
166
202
  #
167
203
  # @rbs (Integer capped) -> Integer
168
204
  def reserve_connection: (Integer capped) -> Integer
@@ -184,7 +220,7 @@ module Raptor
184
220
 
185
221
  @writer: Writer
186
222
 
187
- @socket: OpenSSL::SSL::SSLSocket
223
+ @socket: TCPSocket | OpenSSL::SSL::SSLSocket
188
224
 
189
225
  # Returns the number of response body bytes written to the stream.
190
226
  #
@@ -193,19 +229,19 @@ module Raptor
193
229
 
194
230
  # Creates a response stream for a Rack streaming body.
195
231
  #
196
- # @param socket [OpenSSL::SSL::SSLSocket] the connection socket
232
+ # @param socket [TCPSocket, OpenSSL::SSL::SSLSocket] the connection socket
197
233
  # @param writer [Writer] frame writer for the connection
198
- # @param flow_control [FlowControl] outbound flow controller
234
+ # @param flow_control [FlowControl] per-connection outbound flow controller
199
235
  # @param stream_id [Integer] the HTTP/2 stream identifier
200
236
  # @param trailers [Hash] trailing response headers populated by the Rack application
201
237
  # @return [void]
202
238
  #
203
- # @rbs (OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Hash[String, String | Array[String]] trailers) -> void
204
- def initialize: (OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Hash[String, String | Array[String]] trailers) -> void
239
+ # @rbs (TCPSocket | OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Hash[String, String | Array[String]] trailers) -> void
240
+ def initialize: (TCPSocket | OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Hash[String, String | Array[String]] trailers) -> void
205
241
 
206
- # Streaming responses are write-only.
242
+ # Rejects reads; streaming responses are write-only.
207
243
  #
208
- # @raise [IOError]
244
+ # @raise [IOError] always
209
245
  #
210
246
  # @rbs (*untyped) -> bot
211
247
  def read: (*untyped) -> bot
@@ -214,6 +250,9 @@ module Raptor
214
250
  #
215
251
  # @param chunk [String] response body bytes
216
252
  # @return [Integer] number of bytes written
253
+ # @raise [IOError] if the stream has already closed
254
+ # @raise [TypeError] if the chunk is not a String
255
+ # @raise [StreamClosedError] if the stream or connection has closed
217
256
  #
218
257
  # @rbs (String chunk) -> Integer
219
258
  def write: (String chunk) -> Integer
@@ -226,7 +265,8 @@ module Raptor
226
265
  # @rbs (String chunk) -> ResponseStream
227
266
  def <<: (String chunk) -> ResponseStream
228
267
 
229
- # Flushes the stream. Frame writes are already immediate.
268
+ # Flushes the stream. Frames are already handed to the writer as they
269
+ # are produced.
230
270
  #
231
271
  # @return [ResponseStream]
232
272
  #
@@ -236,13 +276,14 @@ module Raptor
236
276
  # Finishes the stream.
237
277
  #
238
278
  # @return [void]
279
+ # @raise [StreamClosedError] if the stream or connection has closed
239
280
  #
240
281
  # @rbs () -> void
241
282
  def close: () -> void
242
283
 
243
284
  # Closes the unsupported read side of the stream.
244
285
  #
245
- # @raise [IOError]
286
+ # @raise [IOError] always
246
287
  #
247
288
  # @rbs () -> bot
248
289
  def close_read: () -> bot
@@ -262,113 +303,6 @@ module Raptor
262
303
  def closed?: () -> bool
263
304
  end
264
305
 
265
- EAGER_READ_BUFFER_SIZE: untyped
266
-
267
- EAGER_MAX_ROUNDS: ::Integer
268
-
269
- FLAG_END_STREAM: ::Integer
270
-
271
- FLAG_END_HEADERS: ::Integer
272
-
273
- FLAG_ACK: ::Integer
274
-
275
- FLAG_PRIORITY: ::Integer
276
-
277
- ERROR_NO_ERROR: ::Integer
278
-
279
- ERROR_PROTOCOL_ERROR: ::Integer
280
-
281
- ERROR_INTERNAL_ERROR: ::Integer
282
-
283
- ERROR_REFUSED_STREAM: ::Integer
284
-
285
- DEFAULT_WINDOW_SIZE: ::Integer
286
-
287
- MAX_FRAME_SIZE: ::Integer
288
-
289
- SERVER_PROTOCOL: ::String
290
-
291
- REQUEST_PSEUDO_HEADERS: untyped
292
-
293
- REQUIRED_REQUEST_PSEUDO_HEADERS: untyped
294
-
295
- # Returns true when a decoded header block violates the HTTP/2 pseudo-header
296
- # rules from RFC 9113 section 8.3: an unknown pseudo-header, a duplicate
297
- # pseudo-header, a pseudo-header appearing after any regular header, or a
298
- # required pseudo-header (`:method`, `:scheme`, `:path`) missing on
299
- # non-`CONNECT` requests.
300
- #
301
- # @param headers [Array<Array(String, String)>] decoded header pairs
302
- # @return [Boolean]
303
- #
304
- # @rbs (Array[[String, String]] headers) -> bool
305
- def self.invalid_pseudo_headers?: (Array[[ String, String ]] headers) -> bool
306
-
307
- @running: AtomicBoolean
308
-
309
- @initial_settings_frame: String
310
-
311
- @on_error: ^(Hash[String, untyped]?, Exception) -> void | nil
312
-
313
- @clean_fiber_locals: bool
314
-
315
- @clean_thread_locals: bool
316
-
317
- @access_log_io: IO?
318
-
319
- @write_timeout: Integer
320
-
321
- @server_port: Integer
322
-
323
- @app: ^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ]
324
-
325
- # Returns the initial server SETTINGS frame to send on every new
326
- # HTTP/2 connection.
327
- #
328
- # @return [String]
329
- attr_reader initial_settings_frame: untyped
330
-
331
- # Creates a new Http2 handler.
332
- #
333
- # @param app [#call] the Rack application to dispatch requests to
334
- # @param server_port [Integer] port number used to populate SERVER_PORT in the Rack env
335
- # @param connection_options [Hash] per-connection settings shared across protocols
336
- # @option connection_options [Integer] :write_timeout per-write socket timeout in seconds
337
- # @param http2_options [Hash] HTTP/2-specific settings
338
- # @option http2_options [Integer] :max_concurrent_streams maximum HTTP/2 concurrent streams per connection
339
- # @param access_log_io [IO, nil] IO to write Common Log Format access entries to, or nil to disable
340
- # @param clean_thread_locals [Boolean] whether to clear application thread locals after each request
341
- # @param clean_fiber_locals [Boolean] whether to process each request in a fresh Fiber
342
- # @param on_error [#call, nil] callback invoked with (env, exception) when the Rack app raises
343
- # @return [void]
344
- #
345
- # @rbs (^(Hash[String, untyped]) -> [Integer, Hash[String, String | Array[String]], untyped] app, Integer server_port, ?connection_options: Hash[Symbol, untyped], ?http2_options: Hash[Symbol, untyped], ?access_log_io: IO?, ?clean_thread_locals: bool, ?clean_fiber_locals: bool, ?on_error: ^(Hash[String, untyped]?, Exception) -> void | nil) -> void
346
- def initialize: (^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ] app, Integer server_port, ?connection_options: Hash[Symbol, untyped], ?http2_options: Hash[Symbol, untyped], ?access_log_io: IO?, ?clean_thread_locals: bool, ?clean_fiber_locals: bool, ?on_error: ^(Hash[String, untyped]?, Exception) -> void | nil) -> void
347
-
348
- # Creates a per-connection {Writer} configured with the handler's write timeout.
349
- #
350
- # @return [Writer] a new per-connection frame writer
351
- #
352
- # @rbs () -> Writer
353
- def create_writer: () -> Writer
354
-
355
- # Stops new stream dispatch and asks clients to finish streams already
356
- # handed to the application.
357
- #
358
- # @param reactor [Reactor] the reactor managing HTTP/2 connections
359
- # @return [void]
360
- #
361
- # @rbs (Reactor reactor) -> void
362
- def shutdown: (Reactor reactor) -> void
363
-
364
- # Returns a Ractor-safe proc that parses HTTP/2 frames from the
365
- # state hash's buffered bytes.
366
- #
367
- # @return [Proc]
368
- #
369
- # @rbs () -> ^(Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
370
- def parser_worker: () -> ^(Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
371
-
372
306
  # Advances HTTP/2 frame parsing from the connection buffer, returning
373
307
  # updated connection state along with any outgoing protocol frames and
374
308
  # completed stream requests.
@@ -379,6 +313,23 @@ module Raptor
379
313
  # @rbs (Hash[Symbol, untyped] data) -> Hash[Symbol, untyped]
380
314
  def self.process_frames: (Hash[Symbol, untyped] data) -> Hash[Symbol, untyped]
381
315
 
316
+ # Returns a DATA or HEADERS payload without padding, or nil if padding
317
+ # is invalid.
318
+ #
319
+ # @param frame [Hash] the parsed frame
320
+ # @return [String, nil]
321
+ #
322
+ # @rbs (Hash[Symbol, untyped] frame) -> String?
323
+ def self.unpadded_payload: (Hash[Symbol, untyped] frame) -> String?
324
+
325
+ # Returns whether request pseudo-headers violate RFC 9113 section 8.3.
326
+ #
327
+ # @param headers [Array<Array(String, String)>] decoded header pairs
328
+ # @return [Boolean]
329
+ #
330
+ # @rbs (Array[[String, String]] headers) -> bool
331
+ def self.invalid_pseudo_headers?: (Array[[ String, String ]] headers) -> bool
332
+
382
333
  # Applies one complete request header block to its stream, resetting
383
334
  # malformed initial headers or trailers and completing valid trailers.
384
335
  #
@@ -386,7 +337,7 @@ module Raptor
386
337
  # @param completed_requests [Array<Hash>] accumulator of completed stream requests
387
338
  # @param outgoing_frames [Array<String>] accumulator of protocol response frames
388
339
  # @param parser [Http2Parser] frame parser and encoder
389
- # @param stream_id [Integer] the stream identifier
340
+ # @param stream_id [Integer] the HTTP/2 stream identifier
390
341
  # @param decoded_headers [Array<Array(String, String)>] decoded header pairs
391
342
  # @param end_stream [Boolean] whether the source frame had END_STREAM set
392
343
  # @param trailers [Boolean] whether this is a trailing header block
@@ -400,7 +351,7 @@ module Raptor
400
351
  #
401
352
  # @param streams [Hash] current open-stream map
402
353
  # @param completed_requests [Array<Hash>] accumulator of completed stream requests
403
- # @param stream_id [Integer] the stream identifier
354
+ # @param stream_id [Integer] the HTTP/2 stream identifier
404
355
  # @param decoded_headers [Array<Array(String, String)>] decoded header pairs
405
356
  # @param end_stream [Boolean] whether the source frame had END_STREAM set
406
357
  # @return [Array(Hash, Array<Hash>)] updated streams and completed_requests
@@ -430,42 +381,101 @@ module Raptor
430
381
  # @rbs (Hash[Symbol, untyped] data, String buffer, Array[untyped] hpack_table, Hash[Integer, Hash[Symbol, untyped]] streams, Array[String] outgoing_frames, Array[Hash[Symbol, untyped]] completed_requests, Array[Integer] cancelled_streams, Array[[Integer, Integer]] window_updates, Array[String] ping_acknowledgements, Integer? peer_initial_window_size, Integer connection_window, bool preface_received, Integer last_client_stream_id, Hash[Symbol, untyped]? pending_headers, bool close_connection) -> Hash[Symbol, untyped]
431
382
  def self.build_result: (Hash[Symbol, untyped] data, String buffer, Array[untyped] hpack_table, Hash[Integer, Hash[Symbol, untyped]] streams, Array[String] outgoing_frames, Array[Hash[Symbol, untyped]] completed_requests, Array[Integer] cancelled_streams, Array[[ Integer, Integer ]] window_updates, Array[String] ping_acknowledgements, Integer? peer_initial_window_size, Integer connection_window, bool preface_received, Integer last_client_stream_id, Hash[Symbol, untyped]? pending_headers, bool close_connection) -> Hash[Symbol, untyped]
432
383
 
384
+ @initial_settings_frame: String
385
+
386
+ @running: AtomicBoolean
387
+
388
+ @on_error: (^(Hash[String, untyped]?, Exception) -> void)?
389
+
390
+ @clean_fiber_locals: bool
391
+
392
+ @clean_thread_locals: bool
393
+
394
+ @access_log_io: IO?
395
+
396
+ @write_timeout: Integer
397
+
398
+ @server_port_string: String
399
+
400
+ @app: ^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ]
401
+
402
+ # Creates a new Http2 handler.
403
+ #
404
+ # @param app [#call] the Rack application to dispatch requests to
405
+ # @param server_port [Integer] port number used to populate SERVER_PORT in the Rack env
406
+ # @param connection_options [Hash] per-connection settings shared across protocols
407
+ # @option connection_options [Integer] :write_timeout per-write socket timeout in seconds
408
+ # @param http2_options [Hash] HTTP/2-specific settings
409
+ # @option http2_options [Integer] :max_concurrent_streams maximum HTTP/2 concurrent streams per connection
410
+ # @param access_log_io [IO, nil] IO to write Common Log Format access entries to, or nil to disable
411
+ # @param clean_thread_locals [Boolean] whether to clear application thread locals after each request
412
+ # @param clean_fiber_locals [Boolean] whether to process each request in a fresh Fiber
413
+ # @param on_error [#call, nil] callback invoked with (env, exception) when the Rack app raises
414
+ # @return [void]
415
+ #
416
+ # @rbs (^(Hash[String, untyped]) -> [Integer, Hash[String, String | Array[String]], untyped] app, Integer server_port, ?connection_options: Hash[Symbol, untyped], ?http2_options: Hash[Symbol, untyped], ?access_log_io: IO?, ?clean_thread_locals: bool, ?clean_fiber_locals: bool, ?on_error: (^(Hash[String, untyped]?, Exception) -> void)?) -> void
417
+ def initialize: (^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ] app, Integer server_port, ?connection_options: Hash[Symbol, untyped], ?http2_options: Hash[Symbol, untyped], ?access_log_io: IO?, ?clean_thread_locals: bool, ?clean_fiber_locals: bool, ?on_error: (^(Hash[String, untyped]?, Exception) -> void)?) -> void
418
+
419
+ # Returns a Ractor-safe proc that parses HTTP/2 frames from the
420
+ # state hash's buffered bytes.
421
+ #
422
+ # @return [Proc]
423
+ #
424
+ # @rbs () -> ^(Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
425
+ def parser_worker: () -> ^(Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
426
+
427
+ # Stops new stream dispatch and asks clients to finish streams already
428
+ # handed to the application.
429
+ #
430
+ # @param reactor [Reactor] the reactor managing HTTP/2 connections
431
+ # @return [void]
432
+ #
433
+ # @rbs (Reactor reactor) -> void
434
+ def shutdown: (Reactor reactor) -> void
435
+
433
436
  # Sends the server SETTINGS frame on a freshly negotiated HTTP/2
434
437
  # connection, then eagerly reads and parses the first client frame
435
438
  # batch, dispatching completed streams directly to the thread pool.
436
439
  # Falls back to the reactor when no initial data is ready.
437
440
  #
438
- # @param socket [OpenSSL::SSL::SSLSocket] the connection socket
439
- # @param id [Integer] unique client identifier
441
+ # @param socket [TCPSocket, OpenSSL::SSL::SSLSocket] the connection socket
442
+ # @param id [Integer] unique connection identifier
440
443
  # @param reactor [Reactor] the reactor managing the connection
441
444
  # @param thread_pool [AtomicThreadPool] thread pool for application processing
442
- # @param remote_addr [String] client IP address
443
- # @param url_scheme [String] "https"
445
+ # @param remote_addr [String] the client IP address
446
+ # @param url_scheme [String] "http" or "https"
444
447
  # @return [void]
445
448
  #
446
- # @rbs (OpenSSL::SSL::SSLSocket socket, Integer id, Reactor reactor, AtomicThreadPool thread_pool, String remote_addr, String url_scheme) -> void
447
- def eager_accept: (OpenSSL::SSL::SSLSocket socket, Integer id, Reactor reactor, AtomicThreadPool thread_pool, String remote_addr, String url_scheme) -> void
449
+ # @rbs (TCPSocket | OpenSSL::SSL::SSLSocket socket, Integer id, Reactor reactor, AtomicThreadPool thread_pool, String remote_addr, String url_scheme) -> void
450
+ def eager_accept: (TCPSocket | OpenSSL::SSL::SSLSocket socket, Integer id, Reactor reactor, AtomicThreadPool thread_pool, String remote_addr, String url_scheme) -> void
448
451
 
449
452
  # Handles a parsed HTTP/2 result. Writes outgoing frames, dispatches
450
453
  # completed stream requests to the thread pool, and eagerly consumes
451
454
  # further buffered frame batches before returning control to the
452
455
  # reactor.
453
456
  #
454
- # @param result [Hash] the parsed result produced by {process_frames}
457
+ # @param parsed_request [Hash] the parsed result produced by {.process_frames}
455
458
  # @param reactor [Reactor] the reactor managing the connection
456
- # @param thread_pool [AtomicThreadPool] thread pool for Rack app dispatch
459
+ # @param thread_pool [AtomicThreadPool] thread pool for application processing
457
460
  # @return [void]
458
461
  #
459
- # @rbs (Hash[Symbol, untyped] result, Reactor reactor, AtomicThreadPool thread_pool) -> void
460
- def handle_parsed_request: (Hash[Symbol, untyped] result, Reactor reactor, AtomicThreadPool thread_pool) -> void
462
+ # @rbs (Hash[Symbol, untyped] parsed_request, Reactor reactor, AtomicThreadPool thread_pool) -> void
463
+ def handle_parsed_request: (Hash[Symbol, untyped] parsed_request, Reactor reactor, AtomicThreadPool thread_pool) -> void
461
464
 
462
465
  private
463
466
 
467
+ # Creates a per-connection {Writer} configured with the handler's write timeout.
468
+ #
469
+ # @return [Writer] a new per-connection frame writer
470
+ #
471
+ # @rbs () -> Writer
472
+ def create_writer: () -> Writer
473
+
464
474
  # Applies inbound flow-control updates from a parsed result to the
465
- # connection's `FlowControl`.
475
+ # connection's {FlowControl}.
466
476
  #
467
- # @param flow_control [FlowControl] the per-connection flow controller
468
- # @param result [Hash] the parsed result from `process_frames`
477
+ # @param flow_control [FlowControl] per-connection outbound flow controller
478
+ # @param result [Hash] the parsed result from {.process_frames}
469
479
  # @return [void]
470
480
  #
471
481
  # @rbs (FlowControl flow_control, Hash[Symbol, untyped] result) -> void
@@ -474,17 +484,17 @@ module Raptor
474
484
  # Reads the next frame batch from `socket` if it has already arrived,
475
485
  # without waiting on the shared collector thread.
476
486
  #
477
- # @param socket [OpenSSL::SSL::SSLSocket] the connection socket
487
+ # @param socket [TCPSocket, OpenSSL::SSL::SSLSocket] the connection socket
478
488
  # @return [String, nil] the bytes read, or nil if nothing was available
479
489
  #
480
- # @rbs (OpenSSL::SSL::SSLSocket socket) -> String?
481
- def eager_read_next_batch: (OpenSSL::SSL::SSLSocket socket) -> String?
490
+ # @rbs (TCPSocket | OpenSSL::SSL::SSLSocket socket) -> String?
491
+ def eager_read_next_batch: (TCPSocket | OpenSSL::SSL::SSLSocket socket) -> String?
482
492
 
483
493
  # Dispatches a completed stream request to the Rack app and writes
484
494
  # the response back as HTTP/2 frames.
485
495
  #
486
- # @param socket [OpenSSL::SSL::SSLSocket] the connection socket
487
- # @param writer [Writer] lock-free frame writer for the connection
496
+ # @param socket [TCPSocket, OpenSSL::SSL::SSLSocket] the connection socket
497
+ # @param writer [Writer] frame writer for the connection
488
498
  # @param flow_control [FlowControl] per-connection outbound flow controller
489
499
  # @param stream_id [Integer] the HTTP/2 stream identifier
490
500
  # @param headers [Array<Array(String, String)>] request headers
@@ -492,13 +502,13 @@ module Raptor
492
502
  # @param remote_addr [String] the client IP address
493
503
  # @return [void]
494
504
  #
495
- # @rbs (OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Array[[String, String]] headers, String body, remote_addr: String) -> void
496
- def dispatch_stream_request: (OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Array[[ String, String ]] headers, String body, remote_addr: String) -> void
505
+ # @rbs (TCPSocket | OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Array[[String, String]] headers, String body, remote_addr: String) -> void
506
+ def dispatch_stream_request: (TCPSocket | OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Array[[ String, String ]] headers, String body, remote_addr: String) -> void
497
507
 
498
508
  # Calls the Rack app and writes its response for one stream.
499
509
  #
500
- # @param socket [OpenSSL::SSL::SSLSocket] the connection socket
501
- # @param writer [Writer] lock-free frame writer for the connection
510
+ # @param socket [TCPSocket, OpenSSL::SSL::SSLSocket] the connection socket
511
+ # @param writer [Writer] frame writer for the connection
502
512
  # @param flow_control [FlowControl] per-connection outbound flow controller
503
513
  # @param stream_id [Integer] the HTTP/2 stream identifier
504
514
  # @param headers [Array<Array(String, String)>] request headers
@@ -506,13 +516,13 @@ module Raptor
506
516
  # @param remote_addr [String] the client IP address
507
517
  # @return [void]
508
518
  #
509
- # @rbs (OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Array[[String, String]] headers, String body, remote_addr: String) -> void
510
- def perform_stream_request: (OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Array[[ String, String ]] headers, String body, remote_addr: String) -> void
519
+ # @rbs (TCPSocket | OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Array[[String, String]] headers, String body, remote_addr: String) -> void
520
+ def perform_stream_request: (TCPSocket | OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Array[[ String, String ]] headers, String body, remote_addr: String) -> void
511
521
 
512
522
  # Starts a detached HTTP/2 response after writing its response headers.
513
523
  #
514
- # @param socket [OpenSSL::SSL::SSLSocket] the connection socket
515
- # @param writer [Writer] lock-free frame writer for the connection
524
+ # @param socket [TCPSocket, OpenSSL::SSL::SSLSocket] the connection socket
525
+ # @param writer [Writer] frame writer for the connection
516
526
  # @param flow_control [FlowControl] per-connection outbound flow controller
517
527
  # @param stream_id [Integer] the HTTP/2 stream identifier
518
528
  # @param status [Integer] HTTP status code
@@ -522,14 +532,14 @@ module Raptor
522
532
  # @yield once the response headers are queued
523
533
  # @return [void]
524
534
  #
525
- # @rbs (OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Integer status, Hash[String, String | Array[String]] headers, DetachedBody body, ^(Symbol) -> void finished) { () -> void } -> void
526
- def write_http2_detached_response: (OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Integer status, Hash[String, String | Array[String]] headers, DetachedBody body, ^(Symbol) -> void finished) { () -> void } -> void
535
+ # @rbs (TCPSocket | OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Integer status, Hash[String, String | Array[String]] headers, DetachedBody body, ^(Symbol) -> void finished) { () -> void } -> void
536
+ def write_detached_response: (TCPSocket | OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Integer status, Hash[String, String | Array[String]] headers, DetachedBody body, ^(Symbol) -> void finished) { () -> void } -> void
527
537
 
528
538
  # Writes a Rack response as HTTP/2 frames to the socket, partitioning
529
539
  # DATA frames through `flow_control` to fit within the peer's windows.
530
540
  #
531
- # @param socket [OpenSSL::SSL::SSLSocket] the connection socket
532
- # @param writer [Writer] lock-free frame writer for the connection
541
+ # @param socket [TCPSocket, OpenSSL::SSL::SSLSocket] the connection socket
542
+ # @param writer [Writer] frame writer for the connection
533
543
  # @param flow_control [FlowControl] per-connection outbound flow controller
534
544
  # @param stream_id [Integer] the HTTP/2 stream identifier
535
545
  # @param status [Integer] HTTP status code
@@ -537,68 +547,58 @@ module Raptor
537
547
  # @param body [Object] response body responding to each
538
548
  # @param trailers [Hash] trailing response headers populated by the Rack application
539
549
  # @param request_method [String] request method used to suppress HEAD response bodies
550
+ # @yield once the response headers are queued
540
551
  # @return [String] the response body size in bytes
541
552
  #
542
- # @rbs (OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Integer status, Hash[String, String | Array[String]] headers, untyped body, trailers: Hash[String, String | Array[String]], request_method: String) ?{ () -> void } -> String
543
- def write_http2_response: (OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Integer status, Hash[String, String | Array[String]] headers, untyped body, trailers: Hash[String, String | Array[String]], request_method: String) ?{ () -> void } -> String
553
+ # @rbs (TCPSocket | OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Integer status, Hash[String, String | Array[String]] headers, untyped body, trailers: Hash[String, String | Array[String]], request_method: String) ?{ () -> void } -> String
554
+ def write_response: (TCPSocket | OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Integer status, Hash[String, String | Array[String]] headers, untyped body, trailers: Hash[String, String | Array[String]], request_method: String) ?{ () -> void } -> String
544
555
 
545
556
  # Sends an HTTP 103 Early Hints response.
546
557
  #
547
- # @param socket [OpenSSL::SSL::SSLSocket] the connection socket
558
+ # @param socket [TCPSocket, OpenSSL::SSL::SSLSocket] the connection socket
548
559
  # @param writer [Writer] frame writer for the connection
549
560
  # @param flow_control [FlowControl] per-connection outbound flow controller
550
561
  # @param stream_id [Integer] the HTTP/2 stream identifier
551
562
  # @param hints [Hash] response headers to send as early hints
552
563
  # @return [void]
553
564
  #
554
- # @rbs (OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Hash[String, String | Array[String]] hints) -> void
555
- def send_early_hints: (OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Hash[String, String | Array[String]] hints) -> void
565
+ # @rbs (TCPSocket | OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Hash[String, String | Array[String]] hints) -> void
566
+ def send_early_hints: (TCPSocket | OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Hash[String, String | Array[String]] hints) -> void
556
567
 
557
568
  # Resets one HTTP/2 stream with the given error code.
558
569
  #
559
- # @param socket [OpenSSL::SSL::SSLSocket] the connection socket
570
+ # @param socket [TCPSocket, OpenSSL::SSL::SSLSocket] the connection socket
560
571
  # @param writer [Writer] frame writer for the connection
561
572
  # @param stream_id [Integer] the HTTP/2 stream identifier
562
573
  # @param error_code [Integer] the HTTP/2 error code
563
574
  # @return [void]
564
575
  #
565
- # @rbs (OpenSSL::SSL::SSLSocket socket, Writer writer, Integer stream_id, Integer error_code) -> void
566
- def write_http2_reset_stream: (OpenSSL::SSL::SSLSocket socket, Writer writer, Integer stream_id, Integer error_code) -> void
576
+ # @rbs (TCPSocket | OpenSSL::SSL::SSLSocket socket, Writer writer, Integer stream_id, Integer error_code) -> void
577
+ def write_reset_stream: (TCPSocket | OpenSSL::SSL::SSLSocket socket, Writer writer, Integer stream_id, Integer error_code) -> void
567
578
 
568
579
  # Writes a 500 error response as HTTP/2 frames.
569
580
  #
570
- # @param socket [OpenSSL::SSL::SSLSocket] the connection socket
571
- # @param writer [Writer] lock-free frame writer for the connection
581
+ # @param socket [TCPSocket, OpenSSL::SSL::SSLSocket] the connection socket
582
+ # @param writer [Writer] frame writer for the connection
572
583
  # @param stream_id [Integer] the HTTP/2 stream identifier
573
584
  # @return [void]
574
585
  #
575
- # @rbs (OpenSSL::SSL::SSLSocket socket, Writer writer, Integer stream_id) -> void
576
- def write_http2_error_response: (OpenSSL::SSL::SSLSocket socket, Writer writer, Integer stream_id) -> void
577
-
578
- # Instance-level wrapper around {Http.write_access_log} that routes to
579
- # the configured `@access_log_io`.
580
- #
581
- # @param env [Hash] the Rack environment
582
- # @param status [Integer] the response status code
583
- # @param size [String] the response body size in bytes, or `-` if unknown
584
- # @param remote_addr [String] the client IP address
585
- # @return [void]
586
- #
587
- # @rbs (Hash[String, untyped] env, Integer status, String size, String remote_addr) -> void
588
- def write_access_log: (Hash[String, untyped] env, Integer status, String size, String remote_addr) -> void
586
+ # @rbs (TCPSocket | OpenSSL::SSL::SSLSocket socket, Writer writer, Integer stream_id) -> void
587
+ def write_error_response: (TCPSocket | OpenSSL::SSL::SSLSocket socket, Writer writer, Integer stream_id) -> void
589
588
 
590
589
  # Builds a Rack environment hash from HTTP/2 headers and body.
591
590
  #
592
591
  # @param headers [Array<Array(String, String)>] HTTP/2 header pairs
593
592
  # @param body [String] the request body
594
- # @param socket [OpenSSL::SSL::SSLSocket] the connection socket
593
+ # @param socket [TCPSocket, OpenSSL::SSL::SSLSocket] the connection socket
595
594
  # @param writer [Writer] frame writer for the connection
595
+ # @param flow_control [FlowControl] per-connection outbound flow controller
596
596
  # @param stream_id [Integer] the HTTP/2 stream identifier
597
597
  # @param remote_addr [String] the client IP address
598
598
  # @return [Hash] fully populated Rack environment hash
599
599
  #
600
- # @rbs (Array[[String, String]] headers, String body, OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, remote_addr: String) -> Hash[String, untyped]
601
- def build_rack_env: (Array[[ String, String ]] headers, String body, OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, remote_addr: String) -> Hash[String, untyped]
600
+ # @rbs (Array[[String, String]] headers, String body, TCPSocket | OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, remote_addr: String) -> Hash[String, untyped]
601
+ def build_rack_env: (Array[[ String, String ]] headers, String body, TCPSocket | OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, remote_addr: String) -> Hash[String, untyped]
602
602
 
603
603
  # Populates SERVER_NAME and SERVER_PORT from the HTTP_HOST header.
604
604
  #
@@ -607,5 +607,16 @@ module Raptor
607
607
  #
608
608
  # @rbs (Hash[String, untyped] env) -> void
609
609
  def populate_server_name_and_port: (Hash[String, untyped] env) -> void
610
+
611
+ # Writes a completed request to the access log.
612
+ #
613
+ # @param env [Hash] the Rack environment
614
+ # @param status [Integer] the response status code
615
+ # @param size [String] the response body size in bytes, or `-` if unknown
616
+ # @param remote_addr [String] the client IP address
617
+ # @return [void]
618
+ #
619
+ # @rbs (Hash[String, untyped] env, Integer status, String size, String remote_addr) -> void
620
+ def write_access_log: (Hash[String, untyped] env, Integer status, String size, String remote_addr) -> void
610
621
  end
611
622
  end