raptor 0.22.0 → 0.22.2

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.
@@ -6,12 +6,15 @@ require "openssl"
6
6
  require "red-black-tree"
7
7
  require "timeout"
8
8
 
9
- require "atomic-ruby/atomic_queue"
10
9
  require "atomic-ruby/atom"
10
+ require "atomic-ruby/atomic_boolean"
11
11
  require "atomic-ruby/atomic_condition_variable"
12
- require "atomic-ruby/atomic_count_down_latch"
12
+ require "atomic-ruby/atomic_queue"
13
13
 
14
14
  require_relative "detached_body"
15
+ require_relative "http1"
16
+ require_relative "http2"
17
+ require_relative "log"
15
18
 
16
19
  module Raptor
17
20
  # Multiplexes client connections, manages connection deadlines, feeds
@@ -82,6 +85,10 @@ module Raptor
82
85
  # @rbs attr_reader output: Array[String]
83
86
  attr_reader :output
84
87
 
88
+ # Creates empty connection I/O state for reactor-owned writes.
89
+ #
90
+ # @return [void]
91
+ #
85
92
  # @rbs () -> void
86
93
  def initialize
87
94
  @output = []
@@ -93,6 +100,10 @@ module Raptor
93
100
  @timeout = nil
94
101
  end
95
102
 
103
+ # Returns whether the connection has no output waiting to be written.
104
+ #
105
+ # @return [Boolean]
106
+ #
96
107
  # @rbs () -> bool
97
108
  def empty?
98
109
  output.empty?
@@ -117,6 +128,12 @@ module Raptor
117
128
  # @rbs attr_reader state: Hash[Symbol, untyped]
118
129
  attr_reader :state
119
130
 
131
+ # Creates I/O state for an HTTP/1.x detached response.
132
+ #
133
+ # @param body [DetachedBody] the response body
134
+ # @param state [Hash] connection state restored after the response finishes
135
+ # @return [void]
136
+ #
120
137
  # @rbs (DetachedBody body, Hash[Symbol, untyped] state) -> void
121
138
  def initialize(body, state)
122
139
  super()
@@ -128,6 +145,10 @@ module Raptor
128
145
  @finishing = false
129
146
  end
130
147
 
148
+ # Returns whether the connection has no output or detached body remaining.
149
+ #
150
+ # @return [Boolean]
151
+ #
131
152
  # @rbs () -> bool
132
153
  def empty?
133
154
  super && !body
@@ -149,6 +170,10 @@ module Raptor
149
170
  # @rbs attr_reader budget: DetachedBody::Budget
150
171
  attr_reader :budget
151
172
 
173
+ # Creates empty I/O state for an HTTP/2 connection and its detached streams.
174
+ #
175
+ # @return [void]
176
+ #
152
177
  # @rbs () -> void
153
178
  def initialize
154
179
  super
@@ -158,6 +183,10 @@ module Raptor
158
183
  @budget = DetachedBody::Budget.new(DETACHED_CONNECTION_BUFFER_SIZE)
159
184
  end
160
185
 
186
+ # Returns whether the connection has no output or detached streams remaining.
187
+ #
188
+ # @return [Boolean]
189
+ #
161
190
  # @rbs () -> bool
162
191
  def empty?
163
192
  super && detached.empty?
@@ -166,8 +195,7 @@ module Raptor
166
195
 
167
196
  CHUNK_SIZE = 64 * 1024
168
197
  DETACHED_CONNECTION_BUFFER_SIZE = 1024 * 1024
169
- DETACHED_MAX_CHUNKS = 8
170
- DETACHED_MAX_FRAMES = 8
198
+ DETACHED_WRITE_BATCH = 8
171
199
  DETACHED_WORKER_BUFFER_SIZE = 16 * 1024 * 1024
172
200
  TIMEOUT_RESPONSE = "HTTP/1.1 408 Request Timeout\r\nContent-Length: 0\r\nConnection: close\r\n\r\n"
173
201
 
@@ -183,6 +211,7 @@ module Raptor
183
211
  # @rbs @selector: NIO::Selector
184
212
  # @rbs @queue: Queue[TCPSocket]
185
213
  # @rbs @io_queue: AtomicQueue
214
+ # @rbs @io_applied: AtomicConditionVariable
186
215
  # @rbs @timeouts: RedBlackTree[TimeoutClient]
187
216
  # @rbs @id_to_socket: Hash[Integer, TCPSocket]
188
217
  # @rbs @socket_to_state: Hash[TCPSocket, Hash[Symbol, untyped]]
@@ -206,6 +235,7 @@ module Raptor
206
235
  # @param connection_options [Hash] per-connection timeout configuration
207
236
  # @option connection_options [Integer] :first_data_timeout timeout for initial data
208
237
  # @option connection_options [Integer] :chunk_data_timeout timeout for subsequent chunks
238
+ # @option connection_options [Integer] :write_timeout timeout for non-blocking writes
209
239
  # @param http1_options [Hash] HTTP/1.1-specific configuration
210
240
  # @option http1_options [Integer] :persistent_data_timeout timeout for keep-alive idle connections
211
241
  # @param http2_options [Hash] HTTP/2-specific configuration
@@ -228,6 +258,7 @@ module Raptor
228
258
  @selector = NIO::Selector.new
229
259
  @queue = Queue.new
230
260
  @io_queue = AtomicQueue.new
261
+ @io_applied = AtomicConditionVariable.new
231
262
  @timeouts = RedBlackTree.new
232
263
 
233
264
  @id_to_socket = {}
@@ -409,12 +440,19 @@ module Raptor
409
440
 
410
441
  # Attaches a detached response body to an HTTP/1.x connection.
411
442
  #
443
+ # @param socket [TCPSocket] the client socket
444
+ # @param id [Integer] unique client identifier
445
+ # @param body [DetachedBody] the response body
446
+ # @param state [Hash] connection state restored once the response finishes
447
+ # @param finished [Proc] called with the close reason
448
+ # @return [Boolean] whether the body was attached
449
+ #
412
450
  # @rbs (TCPSocket socket, Integer id, DetachedBody body, Hash[Symbol, untyped] state, ^(Symbol) -> void finished) -> bool
413
451
  def attach_http1_body(socket, id, body, state, finished)
414
- attached = AtomicCountDownLatch.new(1)
452
+ attached = AtomicBoolean.new(false)
415
453
  @io_queue << [:attach_http1, id, socket, body, attached, finished, state]
416
454
  @selector.wakeup rescue nil
417
- attached.wait
455
+ @io_applied.wait { attached.true? }
418
456
  return false if body.closed?
419
457
 
420
458
  body.open
@@ -484,12 +522,18 @@ module Raptor
484
522
 
485
523
  # Attaches a detached response body to an HTTP/2 stream.
486
524
  #
525
+ # @param id [Integer] unique connection identifier
526
+ # @param stream_id [Integer] HTTP/2 stream identifier
527
+ # @param body [DetachedBody] the response body
528
+ # @param finished [Proc] called with the close reason
529
+ # @return [Boolean] whether the body was attached
530
+ #
487
531
  # @rbs (Integer id, Integer stream_id, DetachedBody body, ^(Symbol) -> void finished) -> bool
488
532
  def attach_http2_body(id, stream_id, body, finished)
489
- attached = AtomicCountDownLatch.new(1)
533
+ attached = AtomicBoolean.new(false)
490
534
  @io_queue << [:attach_http2, id, stream_id, body, attached, finished]
491
535
  @selector.wakeup rescue nil
492
- attached.wait
536
+ @io_applied.wait { attached.true? }
493
537
  return false if body.closed?
494
538
 
495
539
  body.open
@@ -501,6 +545,9 @@ module Raptor
501
545
 
502
546
  # Reconsiders detached streams after an outbound window update.
503
547
  #
548
+ # @param id [Integer] unique connection identifier
549
+ # @return [void]
550
+ #
504
551
  # @rbs (Integer id) -> void
505
552
  def resume_http2_bodies(id)
506
553
  return if @detached_count.value.zero?
@@ -511,6 +558,10 @@ module Raptor
511
558
 
512
559
  # Cancels a detached response stream.
513
560
  #
561
+ # @param id [Integer] unique connection identifier
562
+ # @param stream_id [Integer] HTTP/2 stream identifier
563
+ # @return [void]
564
+ #
514
565
  # @rbs (Integer id, Integer stream_id) -> void
515
566
  def cancel_http2_body(id, stream_id)
516
567
  return if @detached_count.value.zero?
@@ -522,12 +573,15 @@ module Raptor
522
573
  # Waits for detached responses to finish, then cancels any that outlive
523
574
  # the worker drain period.
524
575
  #
576
+ # @param timeout [Numeric] seconds to wait before cancelling open bodies
577
+ # @return [void]
578
+ #
525
579
  # @rbs (Numeric timeout) -> void
526
580
  def drain_detached_bodies(timeout)
527
- barrier = AtomicCountDownLatch.new(1)
581
+ barrier = AtomicBoolean.new(false)
528
582
  @io_queue << [:barrier, nil, barrier]
529
583
  @selector.wakeup rescue nil
530
- barrier.wait
584
+ @io_applied.wait { barrier.true? }
531
585
 
532
586
  Timeout.timeout(timeout) do
533
587
  @detached_drained.wait { @detached_count.value.zero? }
@@ -560,7 +614,7 @@ module Raptor
560
614
  @id_to_io[id] = Http2IO.new
561
615
  writer.attach(self, id)
562
616
  if @http2_keepalive_interval.positive?
563
- @id_to_http2_keepalive[id] = {frame: ping_frame, payload: ping_payload}
617
+ @id_to_http2_keepalive[id] = { frame: ping_frame, payload: ping_payload }
564
618
  end
565
619
  end
566
620
 
@@ -696,14 +750,16 @@ module Raptor
696
750
  begin
697
751
  attach_http2_detached_body(id, value, body, finished)
698
752
  ensure
699
- attached.count_down
753
+ attached.make_true
754
+ @io_applied.broadcast
700
755
  end
701
756
  connections[id] = true
702
757
  when :attach_http1
703
758
  begin
704
759
  attach_http1_detached_body(value, id, body, state, finished)
705
760
  ensure
706
- attached.count_down
761
+ attached.make_true
762
+ @io_applied.broadcast
707
763
  end
708
764
  when :ready_http1
709
765
  flush_http1_detached_body(id)
@@ -720,7 +776,8 @@ module Raptor
720
776
  when :cancel_all
721
777
  cancel_detached_bodies
722
778
  when :barrier
723
- value.count_down
779
+ value.make_true
780
+ @io_applied.broadcast
724
781
  end
725
782
  end
726
783
 
@@ -733,6 +790,13 @@ module Raptor
733
790
 
734
791
  # Adds a detached body to an HTTP/1.x connection.
735
792
  #
793
+ # @param socket [TCPSocket] the client socket
794
+ # @param id [Integer] unique client identifier
795
+ # @param body [DetachedBody] the response body
796
+ # @param state [Hash] connection state restored once the response finishes
797
+ # @param finished [Proc] called with the close reason
798
+ # @return [void]
799
+ #
736
800
  # @rbs (TCPSocket socket, Integer id, DetachedBody body, Hash[Symbol, untyped] state, ^(Symbol) -> void finished) -> void
737
801
  def attach_http1_detached_body(socket, id, body, state, finished)
738
802
  io = Http1IO.new(body, state)
@@ -747,7 +811,7 @@ module Raptor
747
811
  end
748
812
 
749
813
  @id_to_socket[id] = socket
750
- @socket_to_state[socket] = {id: id, protocol: :http1, detached: true}
814
+ @socket_to_state[socket] = { id: id, protocol: :http1, detached: true }
751
815
  @id_to_io[id] = io
752
816
  @detached_count.swap { |count| count + 1 }
753
817
  update_monitor(id, io)
@@ -755,12 +819,15 @@ module Raptor
755
819
 
756
820
  # Writes buffered HTTP/1.x body chunks without blocking.
757
821
  #
822
+ # @param id [Integer] unique client identifier
823
+ # @return [void]
824
+ #
758
825
  # @rbs (Integer id) -> void
759
826
  def flush_http1_detached_body(id)
760
827
  io = @id_to_io[id]
761
828
  return unless io.is_a?(Http1IO) && !io.wait && io.output.empty?
762
829
 
763
- DETACHED_MAX_CHUNKS.times do
830
+ DETACHED_WRITE_BATCH.times do
764
831
  size = io.body&.next_size
765
832
  break unless size
766
833
 
@@ -785,6 +852,10 @@ module Raptor
785
852
 
786
853
  # Finishes an HTTP/1.x detached response and either reuses or closes its connection.
787
854
  #
855
+ # @param id [Integer] unique client identifier
856
+ # @param io [Http1IO] connection I/O state
857
+ # @return [void]
858
+ #
788
859
  # @rbs (Integer id, Http1IO io) -> void
789
860
  def finish_http1_detached_body(id, io)
790
861
  socket = @id_to_socket[id]
@@ -804,7 +875,7 @@ module Raptor
804
875
  request_count: io.state[:request_count],
805
876
  remote_addr: io.state[:remote_addr],
806
877
  url_scheme: io.state[:url_scheme],
807
- persisted: true,
878
+ persisted: true
808
879
  }
809
880
  unless io.input.empty?
810
881
  state[:buffer] = io.input
@@ -823,6 +894,10 @@ module Raptor
823
894
 
824
895
  # Cancels an HTTP/1.x detached response and closes its connection.
825
896
  #
897
+ # @param id [Integer] unique client identifier
898
+ # @param reason [Symbol] why the response closed
899
+ # @return [void]
900
+ #
826
901
  # @rbs (Integer id, Symbol reason) -> void
827
902
  def remove_http1_detached_body(id, reason)
828
903
  io = @id_to_io[id]
@@ -837,6 +912,12 @@ module Raptor
837
912
 
838
913
  # Adds a detached body to an HTTP/2 stream.
839
914
  #
915
+ # @param id [Integer] unique connection identifier
916
+ # @param stream_id [Integer] HTTP/2 stream identifier
917
+ # @param body [DetachedBody] the response body
918
+ # @param finished [Proc] called with the close reason
919
+ # @return [void]
920
+ #
840
921
  # @rbs (Integer id, Integer stream_id, DetachedBody body, ^(Symbol) -> void finished) -> void
841
922
  def attach_http2_detached_body(id, stream_id, body, finished)
842
923
  io = @id_to_io[id]
@@ -859,6 +940,10 @@ module Raptor
859
940
 
860
941
  # Marks an HTTP/2 detached stream eligible for fair scheduling.
861
942
  #
943
+ # @param id [Integer] unique connection identifier
944
+ # @param stream_id [Integer] HTTP/2 stream identifier
945
+ # @return [void]
946
+ #
862
947
  # @rbs (Integer id, Integer stream_id) -> void
863
948
  def mark_http2_detached_body_ready(id, stream_id)
864
949
  io = @id_to_io[id]
@@ -870,6 +955,9 @@ module Raptor
870
955
 
871
956
  # Marks every HTTP/2 detached stream eligible after flow-control capacity changes.
872
957
  #
958
+ # @param id [Integer] unique connection identifier
959
+ # @return [void]
960
+ #
873
961
  # @rbs (Integer id) -> void
874
962
  def resume_http2_detached_bodies(id)
875
963
  io = @id_to_io[id]
@@ -880,6 +968,9 @@ module Raptor
880
968
 
881
969
  # Writes HTTP/2 detached streams in round-robin order without waiting for flow control.
882
970
  #
971
+ # @param id [Integer] unique connection identifier
972
+ # @return [void]
973
+ #
883
974
  # @rbs (Integer id) -> void
884
975
  def flush_http2_detached_bodies(id)
885
976
  io = @id_to_io[id]
@@ -887,7 +978,7 @@ module Raptor
887
978
  socket = @id_to_socket[id]
888
979
  return unless io && flow_control && socket
889
980
 
890
- DETACHED_MAX_FRAMES.times do
981
+ DETACHED_WRITE_BATCH.times do
891
982
  break if io.wait || !io.output.empty?
892
983
 
893
984
  stream_id = io.ready.shift
@@ -925,6 +1016,11 @@ module Raptor
925
1016
 
926
1017
  # Finishes an HTTP/2 detached stream with DATA or trailing HEADERS.
927
1018
  #
1019
+ # @param id [Integer] unique connection identifier
1020
+ # @param stream_id [Integer] HTTP/2 stream identifier
1021
+ # @param body [DetachedBody] the response body
1022
+ # @return [void]
1023
+ #
928
1024
  # @rbs (Integer id, Integer stream_id, DetachedBody body) -> void
929
1025
  def finish_http2_detached_body(id, stream_id, body)
930
1026
  parser = Http2Parser.new
@@ -942,6 +1038,11 @@ module Raptor
942
1038
 
943
1039
  # Removes an HTTP/2 detached stream and schedules its close callback.
944
1040
  #
1041
+ # @param id [Integer] unique connection identifier
1042
+ # @param stream_id [Integer] HTTP/2 stream identifier
1043
+ # @param reason [Symbol] why the stream closed
1044
+ # @return [void]
1045
+ #
945
1046
  # @rbs (Integer id, Integer stream_id, Symbol reason) -> void
946
1047
  def remove_http2_detached_body(id, stream_id, reason)
947
1048
  io = @id_to_io[id]
@@ -955,6 +1056,8 @@ module Raptor
955
1056
 
956
1057
  # Cancels every detached response during worker shutdown.
957
1058
  #
1059
+ # @return [void]
1060
+ #
958
1061
  # @rbs () -> void
959
1062
  def cancel_detached_bodies
960
1063
  @id_to_io.to_a.each do |id, io|
@@ -970,6 +1073,8 @@ module Raptor
970
1073
 
971
1074
  # Records one detached stream finishing.
972
1075
  #
1076
+ # @return [void]
1077
+ #
973
1078
  # @rbs () -> void
974
1079
  def detached_body_removed
975
1080
  remaining = nil
@@ -1127,7 +1232,7 @@ module Raptor
1127
1232
  # @rbs (Integer id, ConnectionIO io) -> void
1128
1233
  def track_write_timeout(id, io)
1129
1234
  clear_write_timeout(io)
1130
- client = TimeoutClient.new({id: id, write: true})
1235
+ client = TimeoutClient.new({ id: id, write: true })
1131
1236
  client.timeout_at = Process.clock_gettime(Process::CLOCK_MONOTONIC) + @write_timeout
1132
1237
  @timeouts << client
1133
1238
  io.timeout = client
@@ -1281,6 +1386,10 @@ module Raptor
1281
1386
 
1282
1387
  # Handles readiness for an HTTP/1.x detached response.
1283
1388
  #
1389
+ # @param monitor [NIO::Monitor] ready selector monitor
1390
+ # @param id [Integer] unique client identifier
1391
+ # @return [void]
1392
+ #
1284
1393
  # @rbs (NIO::Monitor monitor, Integer id) -> void
1285
1394
  def handle_http1_detached_monitor(monitor, id)
1286
1395
  socket = monitor.value
@@ -9,12 +9,14 @@ module Raptor
9
9
  PRESERVED_KEYS = [
10
10
  :raptor_http_parser,
11
11
  :raptor_read_buffer,
12
- :raptor_response_buffer,
12
+ :raptor_response_buffer
13
13
  ].freeze
14
14
 
15
15
  # Returns a reusable value stored on the current thread.
16
16
  #
17
- # @return [Object]
17
+ # @param key [Symbol] thread-variable key used to cache the value
18
+ # @yieldreturn [Object] value to store when the key is unset
19
+ # @return [Object] the existing or newly stored value
18
20
  #
19
21
  # @rbs (Symbol key) { () -> untyped } -> untyped
20
22
  def self.fetch(key)
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Raptor
5
- VERSION = "0.22.0"
5
+ VERSION = "0.22.2"
6
6
  end
@@ -3,20 +3,18 @@
3
3
  module Raptor
4
4
  # Serves cluster statistics over a Unix socket.
5
5
  class ControlServer
6
+ SHUTDOWN: ::Symbol
7
+
6
8
  @path: String
7
9
 
8
10
  @stats: ^() -> Hash[Symbol, untyped]
9
11
 
10
12
  @server: UNIXServer?
11
13
 
12
- @client: UNIXSocket?
14
+ @client: Atom
13
15
 
14
16
  @thread: Thread?
15
17
 
16
- @running: bool
17
-
18
- @mutex: Mutex
19
-
20
18
  # Creates a control server for `url` without binding it.
21
19
  #
22
20
  # @param url [String] `unix://` URL to listen on
@@ -50,12 +48,26 @@ module Raptor
50
48
 
51
49
  private
52
50
 
51
+ # Removes a stale socket while refusing to replace an active server.
52
+ #
53
+ # @return [void]
54
+ # @raise [RuntimeError] if another server is listening on the socket
55
+ #
53
56
  # @rbs () -> void
54
57
  def remove_stale_socket: () -> void
55
58
 
59
+ # Accepts and handles control requests until shutdown begins.
60
+ #
61
+ # @return [void]
62
+ #
56
63
  # @rbs () -> void
57
64
  def serve: () -> void
58
65
 
66
+ # Writes the response for one control-socket request.
67
+ #
68
+ # @param client [UNIXSocket] connected control client
69
+ # @return [void]
70
+ #
59
71
  # @rbs (UNIXSocket client) -> void
60
72
  def handle: (UNIXSocket client) -> void
61
73
  end
@@ -12,12 +12,27 @@ module Raptor
12
12
 
13
13
  @size: Atom
14
14
 
15
+ # Creates a shared budget with the given byte limit.
16
+ #
17
+ # @param max_size [Integer] maximum bytes that may be reserved
18
+ # @return [void]
19
+ #
15
20
  # @rbs (Integer max_size) -> void
16
21
  def initialize: (Integer max_size) -> void
17
22
 
23
+ # Reserves bytes when they fit within the shared limit.
24
+ #
25
+ # @param bytes [Integer] number of bytes to reserve
26
+ # @return [Boolean] whether the bytes were reserved
27
+ #
18
28
  # @rbs (Integer bytes) -> bool
19
29
  def reserve: (Integer bytes) -> bool
20
30
 
31
+ # Releases bytes previously charged to the shared limit.
32
+ #
33
+ # @param bytes [Integer] number of bytes to release
34
+ # @return [void]
35
+ #
21
36
  # @rbs (Integer bytes) -> void
22
37
  def release: (Integer bytes) -> void
23
38
  end
@@ -46,7 +61,8 @@ module Raptor
46
61
  # @rbs (?max_buffer_size: Integer) -> void
47
62
  def initialize: (?max_buffer_size: Integer) -> void
48
63
 
49
- # Registers a callback for when the server accepts the response stream.
64
+ # Registers a callback that runs on the request thread once the server
65
+ # accepts the response stream.
50
66
  #
51
67
  # @yieldparam stream [DetachedBody] the opened response stream
52
68
  # @return [DetachedBody]
@@ -87,40 +103,68 @@ module Raptor
87
103
 
88
104
  # Connects the body to its reactor-owned response stream.
89
105
  #
106
+ # @param budgets [Array<Budget>] buffer budgets shared with other bodies
107
+ # @param wake [Proc] called when buffered data or a close is ready to write
108
+ # @param dispatch [Proc] schedules application callbacks off the reactor thread
109
+ # @param finished [Proc] called with the close reason after `on_close`
110
+ # @return [Boolean] false when the bytes already buffered exceed a budget
111
+ #
90
112
  # @rbs (Array[Budget] budgets, ^() -> void wake, ^(Proc) -> void dispatch, ^(Symbol) -> void finished) -> bool
91
113
  def attach: (Array[Budget] budgets, ^() -> void wake, ^(Proc) -> void dispatch, ^(Symbol) -> void finished) -> bool
92
114
 
93
115
  # Notifies the application that its response stream is ready.
94
116
  #
117
+ # @return [void]
118
+ #
95
119
  # @rbs () -> void
96
120
  def open: () -> void
97
121
 
98
122
  # Returns the size of the next buffered chunk, 0 when closing, or nil
99
123
  # while waiting for more data.
100
124
  #
125
+ # @return [Integer, nil]
126
+ #
101
127
  # @rbs () -> Integer?
102
128
  def next_size: () -> Integer?
103
129
 
104
130
  # Removes up to `max_bytes` from the next buffered chunk.
105
131
  #
132
+ # @param max_bytes [Integer] the largest chunk to return
133
+ # @return [String, nil] the removed bytes, or nil when nothing is buffered
134
+ #
106
135
  # @rbs (Integer max_bytes) -> String?
107
136
  def shift: (Integer max_bytes) -> String?
108
137
 
109
138
  # Returns the response trailers supplied when the body closed.
110
139
  #
140
+ # @return [Hash] trailing response headers
141
+ #
111
142
  # @rbs () -> Hash[String, String | Array[String]]
112
143
  def trailers: () -> Hash[String, String | Array[String]]
113
144
 
114
145
  # Closes the stream and invokes its callback exactly once.
115
146
  #
147
+ # @param reason [Symbol] why the stream closed
148
+ # @return [void]
149
+ #
116
150
  # @rbs (Symbol reason) -> void
117
151
  def finish: (Symbol reason) -> void
118
152
 
119
153
  private
120
154
 
155
+ # Reserves bytes from every budget attached to this body.
156
+ #
157
+ # @param bytes [Integer] number of bytes to reserve
158
+ # @return [Boolean] whether every budget accepted the reservation
159
+ #
121
160
  # @rbs (Integer bytes) -> bool
122
161
  def reserve: (Integer bytes) -> bool
123
162
 
163
+ # Releases bytes from every budget attached to this body.
164
+ #
165
+ # @param bytes [Integer] number of bytes to release
166
+ # @return [void]
167
+ #
124
168
  # @rbs (Integer bytes) -> void
125
169
  def release: (Integer bytes) -> void
126
170
  end
@@ -26,6 +26,14 @@ module Raptor
26
26
  def message: () -> String
27
27
  end
28
28
 
29
+ # Returns whether an HTTP status forbids an entity body.
30
+ #
31
+ # @param status [Integer] the response status code
32
+ # @return [Boolean]
33
+ #
34
+ # @rbs (Integer status) -> bool
35
+ def self.no_entity_body_status?: (Integer status) -> bool
36
+
29
37
  # Writes `string` in full, retrying on partial writes. Bounded by
30
38
  # `timeout` so a slow client can't pin the writing thread.
31
39
  #
@@ -80,11 +80,17 @@ module Raptor
80
80
 
81
81
  # Encodes one HTTP/1.1 response chunk.
82
82
  #
83
+ # @param chunk [String] response body bytes
84
+ # @return [String] the encoded chunk
85
+ #
83
86
  # @rbs (String chunk) -> String
84
87
  def self.encode_chunk: (String chunk) -> String
85
88
 
86
89
  # Encodes the final HTTP/1.1 response chunk and its trailers.
87
90
  #
91
+ # @param trailers [Hash] trailing response headers
92
+ # @return [String] the final chunk followed by the trailer section
93
+ #
88
94
  # @rbs (Hash[String, String | Array[String]] trailers) -> String
89
95
  def self.encode_trailers: (Hash[String, String | Array[String]] trailers) -> String
90
96
 
@@ -307,6 +313,17 @@ module Raptor
307
313
 
308
314
  # Calls the Rack app and writes its response for one request.
309
315
  #
316
+ # @param socket [TCPSocket] the client socket
317
+ # @param id [Integer] unique client identifier
318
+ # @param env [Hash] partial env hash from the HTTP parser
319
+ # @param parse_data [Hash] metadata from the parsing pass
320
+ # @param body [String, nil] decoded request body
321
+ # @param reactor [Reactor] the reactor managing the client connection
322
+ # @param request_count [Integer] number of requests handled on this connection
323
+ # @param remote_addr [String] client IP address
324
+ # @param url_scheme [String] "http" or "https"
325
+ # @return [Boolean] true if the connection should be kept alive
326
+ #
310
327
  # @rbs (TCPSocket socket, Integer id, Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, String? body, Reactor reactor, Integer request_count, String remote_addr, String url_scheme) -> bool
311
328
  def perform_request: (TCPSocket socket, Integer id, Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, String? body, Reactor reactor, Integer request_count, String remote_addr, String url_scheme) -> bool
312
329
 
@@ -434,6 +451,13 @@ module Raptor
434
451
  # Starts a detached response, chunked on HTTP/1.1 and ended by closing
435
452
  # the connection on HTTP/1.0.
436
453
  #
454
+ # @param socket [TCPSocket] the client socket to write to
455
+ # @param status [Integer] HTTP status code
456
+ # @param headers [Hash] response headers from the Rack application
457
+ # @param chunked [Boolean] whether to use chunked transfer encoding
458
+ # @param keep_alive [Boolean] whether to send a keep-alive connection header
459
+ # @return [void]
460
+ #
437
461
  # @rbs (TCPSocket socket, Integer status, Hash[String, String | Array[String]] headers, chunked: bool, keep_alive: bool) -> void
438
462
  def write_detached_response: (TCPSocket socket, Integer status, Hash[String, String | Array[String]] headers, chunked: bool, keep_alive: bool) -> void
439
463