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
@@ -34,6 +34,8 @@ module Raptor
34
34
 
35
35
  INTERNAL_SERVER_ERROR_RESPONSE: ::String
36
36
 
37
+ CHUNKED_TERMINATOR: ::String
38
+
37
39
  CONNECTION_CLOSE: ::String
38
40
 
39
41
  CONNECTION_KEEPALIVE: ::String
@@ -42,14 +44,18 @@ module Raptor
42
44
 
43
45
  TRANSFER_ENCODING_CHUNKED: ::String
44
46
 
45
- CHUNKED_TERMINATOR: ::String
46
-
47
47
  HTTP_CONNECTION: ::String
48
48
 
49
49
  HTTP_EXPECT: ::String
50
50
 
51
51
  HTTP_TRANSFER_ENCODING: ::String
52
52
 
53
+ HTTP_X_FORWARDED_PROTO: ::String
54
+
55
+ HTTP_X_FORWARDED_SCHEME: ::String
56
+
57
+ HTTP_X_FORWARDED_SSL: ::String
58
+
53
59
  RACK_HEADER_PREFIX: ::String
54
60
 
55
61
  RACK_HIJACKED: ::String
@@ -78,6 +84,15 @@ module Raptor
78
84
  # @rbs (Hash[String, untyped] env) -> bool
79
85
  def self.request_smuggling?: (Hash[String, untyped] env) -> bool
80
86
 
87
+ # Returns any pipelined bytes following the request, or nil if none remain.
88
+ #
89
+ # @param buffer [String] the raw request bytes
90
+ # @param offset [Integer] the byte offset where the request ends
91
+ # @return [String, nil]
92
+ #
93
+ # @rbs (String buffer, Integer offset) -> String?
94
+ def self.pipelined_bytes: (String buffer, Integer offset) -> String?
95
+
81
96
  # Encodes one HTTP/1.1 response chunk.
82
97
  #
83
98
  # @param chunk [String] response body bytes
@@ -96,7 +111,8 @@ module Raptor
96
111
 
97
112
  # Advances an HTTP/1.x request parse from the state hash's buffered
98
113
  # bytes. A complete well-formed request returns with `:complete` set
99
- # plus populated `:env` and `:body`; malformed or oversized input flips
114
+ # plus populated `:env` and `:body`, and records any bytes after it in
115
+ # the parse data's `:pipelined`; malformed or oversized input flips
100
116
  # `:malformed` or `:too_large`; incomplete input returns the state
101
117
  # so the reactor can wait for more.
102
118
  #
@@ -110,8 +126,6 @@ module Raptor
110
126
 
111
127
  @app: ^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ]
112
128
 
113
- @server_port: Integer
114
-
115
129
  @server_port_string: String
116
130
 
117
131
  @write_timeout: Integer
@@ -128,7 +142,7 @@ module Raptor
128
142
 
129
143
  @clean_fiber_locals: bool
130
144
 
131
- @on_error: ^(Hash[String, untyped]?, Exception) -> void | nil
145
+ @on_error: (^(Hash[String, untyped]?, Exception) -> void)?
132
146
 
133
147
  @running: AtomicBoolean
134
148
 
@@ -150,39 +164,16 @@ module Raptor
150
164
  # @param on_error [#call, nil] callback invoked with (env, exception) when the Rack app raises
151
165
  # @return [void]
152
166
  #
153
- # @rbs (^(Hash[String, untyped]) -> [Integer, Hash[String, String | Array[String]], untyped] app, Integer server_port, ?connection_options: Hash[Symbol, untyped], ?http1_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
154
- def initialize: (^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ] app, Integer server_port, ?connection_options: Hash[Symbol, untyped], ?http1_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
167
+ # @rbs (^(Hash[String, untyped]) -> [Integer, Hash[String, String | Array[String]], untyped] app, Integer server_port, ?connection_options: Hash[Symbol, untyped], ?http1_options: Hash[Symbol, untyped], ?access_log_io: IO?, ?clean_thread_locals: bool, ?clean_fiber_locals: bool, ?on_error: (^(Hash[String, untyped]?, Exception) -> void)?) -> void
168
+ def initialize: (^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ] app, Integer server_port, ?connection_options: Hash[Symbol, untyped], ?http1_options: Hash[Symbol, untyped], ?access_log_io: IO?, ?clean_thread_locals: bool, ?clean_fiber_locals: bool, ?on_error: (^(Hash[String, untyped]?, Exception) -> void)?) -> void
155
169
 
156
- # Instance-level wrapper around {Http.parser_worker} that binds this
157
- # handler's env template and body-size limit into the worker proc.
170
+ # Returns a Ractor-safe proc that parses HTTP/1.x requests.
158
171
  #
159
172
  # @return [Proc]
160
173
  #
161
174
  # @rbs () -> ^(Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
162
175
  def parser_worker: () -> ^(Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
163
176
 
164
- # Instance-level wrapper around {Http.socket_write} that applies the
165
- # configured `write_timeout`.
166
- #
167
- # @param socket [TCPSocket] the socket to write to
168
- # @param string [String] the data to write
169
- # @return [void]
170
- # @raise [Http::WriteError] if the socket is not writable within the timeout or raises IOError
171
- #
172
- # @rbs (TCPSocket socket, String string) -> void
173
- def socket_write: (TCPSocket socket, String string) -> void
174
-
175
- # Instance-level wrapper around {Http.socket_writev} that applies the
176
- # configured `write_timeout`.
177
- #
178
- # @param socket [TCPSocket] the socket to write to
179
- # @param strings [Array<String>] the buffers to write in order
180
- # @return [void]
181
- # @raise [Http::WriteError] if the socket is not writable within the timeout or raises IOError
182
- #
183
- # @rbs (TCPSocket socket, Array[String] strings) -> void
184
- def socket_writev: (TCPSocket socket, Array[String] strings) -> void
185
-
186
177
  # Signals eager keep-alive loops to stop processing further requests on
187
178
  # their connections. In-flight requests complete normally.
188
179
  #
@@ -196,10 +187,10 @@ module Raptor
196
187
  # when complete. Falls back to the reactor when more data is needed.
197
188
  #
198
189
  # @param socket [TCPSocket] the freshly accepted client socket
199
- # @param id [Integer] unique client identifier
190
+ # @param id [Integer] unique connection identifier
200
191
  # @param reactor [Reactor] the reactor for fallback registration
201
192
  # @param thread_pool [AtomicThreadPool] thread pool for application processing
202
- # @param remote_addr [String] client IP address
193
+ # @param remote_addr [String] the client IP address
203
194
  # @param url_scheme [String] "http" or "https"
204
195
  # @return [void]
205
196
  #
@@ -217,46 +208,61 @@ module Raptor
217
208
  # @rbs (Hash[Symbol, untyped] parsed_request, Reactor reactor, AtomicThreadPool thread_pool) -> void
218
209
  def handle_parsed_request: (Hash[Symbol, untyped] parsed_request, Reactor reactor, AtomicThreadPool thread_pool) -> void
219
210
 
211
+ # Processes kept-alive requests on application threads, yielding to queued
212
+ # work and returning idle or incomplete connections to the reactor.
213
+ #
214
+ # @param socket [TCPSocket] the client socket
215
+ # @param id [Integer] unique connection identifier
216
+ # @param reactor [Reactor] the reactor for fallback registration
217
+ # @param thread_pool [AtomicThreadPool] thread pool for application processing
218
+ # @param request_count [Integer] number of requests handled on this connection
219
+ # @param remote_addr [String] the client IP address
220
+ # @param url_scheme [String] "http" or "https"
221
+ # @param resumed [Boolean] whether the reactor queued the connection once its next request became readable
222
+ # @param pipelined [String, nil] bytes the client sent after the previous request
223
+ # @return [void]
224
+ #
225
+ # @rbs (TCPSocket socket, Integer id, Reactor reactor, AtomicThreadPool thread_pool, Integer request_count, String remote_addr, String url_scheme, ?resumed: bool, ?pipelined: String?) -> void
226
+ def eager_keepalive: (TCPSocket socket, Integer id, Reactor reactor, AtomicThreadPool thread_pool, Integer request_count, String remote_addr, String url_scheme, ?resumed: bool, ?pipelined: String?) -> void
227
+
220
228
  private
221
229
 
222
230
  # Reads pending bytes off `socket` into the thread-local read buffer,
223
231
  # draining any additional SSL-buffered bytes so `pending` is empty on
224
- # return. Raises `IO::WaitReadable`, `EOFError`, or `IOError` like the
225
- # underlying `read_nonblock` does.
232
+ # return.
226
233
  #
227
234
  # @param socket [TCPSocket] the socket to read from
228
235
  # @return [String] the thread-local buffer, freshly populated
236
+ # @raise [IO::WaitReadable] if no bytes are ready to read
237
+ # @raise [EOFError, IOError, SystemCallError] if the connection is closed or fails
229
238
  #
230
239
  # @rbs (TCPSocket socket) -> String
231
240
  def read_into_thread_buffer: (TCPSocket socket) -> String
232
241
 
233
- # Runs a fresh HTTP/1.x parse against `buffer`, returning
234
- # `[env, parse_data, nread, parser]`. Raises `HttpParserError` on
235
- # malformed input.
242
+ # Runs a fresh HTTP/1.x parse against `buffer`.
236
243
  #
237
244
  # @param buffer [String] the raw request bytes
238
- # @return [Array(Hash, Hash, Integer, HttpParser)]
245
+ # @return [Array(Hash, Hash, Integer, HttpParser)] the env, parse data, bytes read, and parser
246
+ # @raise [HttpParserError] if the request is malformed
239
247
  #
240
248
  # @rbs (String buffer) -> [Hash[String, untyped], Hash[Symbol, untyped], Integer, HttpParser]
241
249
  def parse_next_request: (String buffer) -> [ Hash[String, untyped], Hash[Symbol, untyped], Integer, HttpParser ]
242
250
 
243
- # Resolves the request body for a finished parse. Returns the body
244
- # `String` (or `nil` when the request has no body), or one of
245
- # `:incomplete`, `:too_large`, `:malformed` when the caller must
246
- # fall back or reject.
251
+ # Validates request framing and extracts the body, preserving pipelined bytes.
247
252
  #
248
253
  # @param buffer [String] the raw request bytes
249
254
  # @param env [Hash] the Rack environment being built
255
+ # @param parse_data [Hash] metadata from the parsing pass
250
256
  # @param parser [HttpParser] the parser holding the finished parse state
251
257
  # @param nread [Integer] the byte offset where the body begins in `buffer`
252
- # @param decode_chunked [Boolean] whether to decode chunked bodies inline; when false chunked bodies signal `:incomplete`
253
- # @return [String, nil, Symbol]
258
+ # @return [String, nil, Symbol] body, nil when absent, or `:incomplete`,
259
+ # `:too_large`, or `:malformed`
254
260
  #
255
- # @rbs (String buffer, Hash[String, untyped] env, HttpParser parser, Integer nread, decode_chunked: bool) -> (String | Symbol)?
256
- def extract_body: (String buffer, Hash[String, untyped] env, HttpParser parser, Integer nread, decode_chunked: bool) -> (String | Symbol)?
261
+ # @rbs (String buffer, Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, HttpParser parser, Integer nread) -> (String | Symbol)?
262
+ def extract_body: (String buffer, Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, HttpParser parser, Integer nread) -> (String | Symbol)?
257
263
 
258
- # Returns true if the request expects a 100 Continue response per
259
- # RFC 7231 section 5.1.1.
264
+ # Returns true when the request expects a 100 Continue response per
265
+ # RFC 9110 section 10.1.1.
260
266
  #
261
267
  # @param env [Hash] the parsed Rack environment (possibly incomplete)
262
268
  # @return [Boolean]
@@ -279,32 +285,32 @@ module Raptor
279
285
  # if keep-alive, eagerly reading subsequent requests inline.
280
286
  #
281
287
  # @param socket [TCPSocket] the client socket
282
- # @param id [Integer] unique client identifier
288
+ # @param id [Integer] unique connection identifier
283
289
  # @param env [Hash] partial env hash from the HTTP parser
284
290
  # @param parse_data [Hash] metadata from the parsing pass
285
291
  # @param body [String, nil] decoded request body
286
292
  # @param reactor [Reactor] the reactor managing the client connection
287
293
  # @param thread_pool [AtomicThreadPool] thread pool for application processing
288
294
  # @param request_count [Integer] number of requests handled on this connection
289
- # @param remote_addr [String] client IP address
295
+ # @param remote_addr [String] the client IP address
290
296
  # @param url_scheme [String] "http" or "https"
291
297
  # @return [void]
292
298
  #
293
299
  # @rbs (TCPSocket socket, Integer id, Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, String? body, Reactor reactor, AtomicThreadPool thread_pool, Integer request_count, String remote_addr, String url_scheme) -> void
294
300
  def process_client: (TCPSocket socket, Integer id, Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, String? body, Reactor reactor, AtomicThreadPool thread_pool, Integer request_count, String remote_addr, String url_scheme) -> void
295
301
 
296
- # Processes a single request. Builds the Rack env, calls the app,
297
- # writes the response, and returns whether the connection stays open
298
- # for another request.
302
+ # Processes a single request, isolating fiber and thread locals as
303
+ # configured, and returns whether the connection stays open for another
304
+ # request.
299
305
  #
300
306
  # @param socket [TCPSocket] the client socket
301
- # @param id [Integer] unique client identifier
307
+ # @param id [Integer] unique connection identifier
302
308
  # @param env [Hash] partial env hash from the HTTP parser
303
309
  # @param parse_data [Hash] metadata from the parsing pass
304
310
  # @param body [String, nil] decoded request body
305
311
  # @param reactor [Reactor] the reactor managing the client connection
306
312
  # @param request_count [Integer] number of requests handled on this connection
307
- # @param remote_addr [String] client IP address
313
+ # @param remote_addr [String] the client IP address
308
314
  # @param url_scheme [String] "http" or "https"
309
315
  # @return [Boolean] true if the connection should be kept alive
310
316
  #
@@ -314,13 +320,13 @@ module Raptor
314
320
  # Calls the Rack app and writes its response for one request.
315
321
  #
316
322
  # @param socket [TCPSocket] the client socket
317
- # @param id [Integer] unique client identifier
323
+ # @param id [Integer] unique connection identifier
318
324
  # @param env [Hash] partial env hash from the HTTP parser
319
325
  # @param parse_data [Hash] metadata from the parsing pass
320
326
  # @param body [String, nil] decoded request body
321
327
  # @param reactor [Reactor] the reactor managing the client connection
322
328
  # @param request_count [Integer] number of requests handled on this connection
323
- # @param remote_addr [String] client IP address
329
+ # @param remote_addr [String] the client IP address
324
330
  # @param url_scheme [String] "http" or "https"
325
331
  # @return [Boolean] true if the connection should be kept alive
326
332
  #
@@ -334,50 +340,33 @@ module Raptor
334
340
  #
335
341
  # @param socket [TCPSocket] the client socket
336
342
  # @param rack_env [Hash, nil] the Rack environment, if it was built
337
- # @param status [Integer, nil] the status returned by the app, if any
343
+ # @param status [Object, nil] the status returned by the app, if any
338
344
  # @param headers [Hash, nil] the headers returned by the app, if any
339
345
  # @param error [Exception] the exception raised
340
346
  # @param response_started [Boolean] whether any response bytes have been written
341
347
  # @param hijacked [Boolean] whether the app took over the socket
342
348
  # @return [void]
343
349
  #
344
- # @rbs (TCPSocket socket, Hash[String, untyped]? rack_env, Integer? status, Hash[String, String | Array[String]]? headers, Exception error, response_started: bool, hijacked: bool) -> void
345
- def handle_app_error: (TCPSocket socket, Hash[String, untyped]? rack_env, Integer? status, Hash[String, String | Array[String]]? headers, Exception error, response_started: bool, hijacked: bool) -> void
346
-
347
- # Reads and processes subsequent requests inline on a kept-alive
348
- # connection. Returns the connection to the reactor when no data is ready
349
- # or a request is incomplete, and queues complete requests behind work
350
- # that is already waiting.
351
- #
352
- # @param socket [TCPSocket] the client socket
353
- # @param id [Integer] unique client identifier
354
- # @param reactor [Reactor] the reactor for fallback registration
355
- # @param thread_pool [AtomicThreadPool] thread pool for deprioritization
356
- # @param request_count [Integer] number of requests handled on this connection
357
- # @param remote_addr [String] client IP address
358
- # @param url_scheme [String] "http" or "https"
359
- # @return [void]
360
- #
361
- # @rbs (TCPSocket socket, Integer id, Reactor reactor, AtomicThreadPool thread_pool, Integer request_count, String remote_addr, String url_scheme) -> void
362
- def eager_keepalive: (TCPSocket socket, Integer id, Reactor reactor, AtomicThreadPool thread_pool, Integer request_count, String remote_addr, String url_scheme) -> void
350
+ # @rbs (TCPSocket socket, Hash[String, untyped]? rack_env, untyped status, Hash[String, String | Array[String]]? headers, Exception error, response_started: bool, hijacked: bool) -> void
351
+ def handle_app_error: (TCPSocket socket, Hash[String, untyped]? rack_env, untyped status, Hash[String, String | Array[String]]? headers, Exception error, response_started: bool, hijacked: bool) -> void
363
352
 
364
353
  # Re-registers a socket with the reactor for further processing when
365
354
  # an incomplete request is received on the fast path.
366
355
  #
367
356
  # @param socket [TCPSocket] the client socket
368
- # @param id [Integer] unique client identifier
357
+ # @param id [Integer] unique connection identifier
369
358
  # @param buffer [String] the partial request data already read
370
359
  # @param env [Hash] partial env hash from the HTTP parser
371
360
  # @param parse_data [Hash] metadata from the parsing pass
372
361
  # @param reactor [Reactor] the reactor to re-register with
373
362
  # @param request_count [Integer] number of requests handled on this connection
374
- # @param remote_addr [String] client IP address
363
+ # @param remote_addr [String] the client IP address
375
364
  # @param url_scheme [String] "http" or "https"
376
365
  # @param persisted [Boolean] whether the connection has already completed at least one request
377
366
  # @return [void]
378
367
  #
379
- # @rbs (TCPSocket socket, Integer id, String buffer, Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, Reactor reactor, Integer request_count, String remote_addr, String url_scheme, persisted: bool) -> void
380
- def fallback_to_reactor: (TCPSocket socket, Integer id, String buffer, Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, Reactor reactor, Integer request_count, String remote_addr, String url_scheme, persisted: bool) -> void
368
+ # @rbs (TCPSocket socket, Integer id, String buffer, Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, Reactor reactor, Integer request_count, String remote_addr, String url_scheme, ?persisted: bool) -> void
369
+ def fallback_to_reactor: (TCPSocket socket, Integer id, String buffer, Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, Reactor reactor, Integer request_count, String remote_addr, String url_scheme, ?persisted: bool) -> void
381
370
 
382
371
  # Writes a 413 response and closes the socket.
383
372
  #
@@ -401,7 +390,7 @@ module Raptor
401
390
  # @param parse_data [Hash] metadata from the parsing pass, including content_length
402
391
  # @param body [String, nil] decoded request body, or nil if no body
403
392
  # @param socket [TCPSocket] the client socket, used for hijack support
404
- # @param remote_addr [String] client IP address
393
+ # @param remote_addr [String] the client IP address
405
394
  # @param url_scheme [String] "http" or "https"
406
395
  # @return [Hash] fully populated Rack environment hash
407
396
  #
@@ -481,10 +470,10 @@ module Raptor
481
470
  # @raise [TypeError] if status is not an Integer
482
471
  # @raise [ArgumentError] if status is less than 100
483
472
  #
484
- # @rbs (Integer status) -> void
485
- def validate_status: (Integer status) -> void
473
+ # @rbs (untyped status) -> void
474
+ def validate_status: (untyped status) -> void
486
475
 
487
- # Returns a normalised copy of the response headers with lowercased
476
+ # Returns a normalized copy of the response headers with lowercased
488
477
  # keys and illegal/`rack.*`/`status` entries dropped.
489
478
  #
490
479
  # @param headers [Hash] raw headers from the Rack application
@@ -515,8 +504,8 @@ module Raptor
515
504
  # @rbs (String http_version, Integer status) -> String
516
505
  def build_status_line: (String http_version, Integer status) -> String
517
506
 
518
- # Writes the response headers, uncorks the socket, and hands the raw
519
- # socket to the hijack callback.
507
+ # Writes the response headers and hands the raw socket to the hijack
508
+ # callback.
520
509
  #
521
510
  # @param socket [TCPSocket] the client socket
522
511
  # @param response [String] the status line accumulated so far
@@ -550,6 +539,7 @@ module Raptor
550
539
  # @param body [Object] the response body
551
540
  # @param http_version [String] "HTTP/1.1" or "HTTP/1.0"
552
541
  # @return [void]
542
+ # @raise [TypeError] if the body responds to none of `each`, `to_ary`, or `to_path`
553
543
  #
554
544
  # @rbs (TCPSocket socket, String response, Hash[String, String | Array[String]] headers, untyped body, String http_version) -> void
555
545
  def write_full_response: (TCPSocket socket, String response, Hash[String, String | Array[String]] headers, untyped body, String http_version) -> void
@@ -622,8 +612,27 @@ module Raptor
622
612
  # @rbs (TCPSocket socket, String response, untyped body, bool use_chunked) -> void
623
613
  def write_enumerable_body: (TCPSocket socket, String response, untyped body, bool use_chunked) -> void
624
614
 
625
- # Instance-level wrapper around {Http.write_access_log} that routes to
626
- # the configured `@access_log_io`.
615
+ # Writes response bytes within the configured write timeout.
616
+ #
617
+ # @param socket [TCPSocket] the socket to write to
618
+ # @param string [String] the data to write
619
+ # @return [void]
620
+ # @raise [Http::WriteError] if the socket is not writable within the timeout or raises IOError
621
+ #
622
+ # @rbs (TCPSocket socket, String string) -> void
623
+ def socket_write: (TCPSocket socket, String string) -> void
624
+
625
+ # Writes response buffers in order within the configured write timeout.
626
+ #
627
+ # @param socket [TCPSocket] the socket to write to
628
+ # @param strings [Array<String>] the buffers to write in order
629
+ # @return [void]
630
+ # @raise [Http::WriteError] if the socket is not writable within the timeout or raises IOError
631
+ #
632
+ # @rbs (TCPSocket socket, Array[String] strings) -> void
633
+ def socket_writev: (TCPSocket socket, Array[String] strings) -> void
634
+
635
+ # Writes a completed request to the access log.
627
636
  #
628
637
  # @param env [Hash] the Rack environment
629
638
  # @param status [Integer] the response status code