raptor 0.1.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.
@@ -0,0 +1,145 @@
1
+ # Generated from lib/raptor/http2.rb with RBS::Inline
2
+
3
+ module Raptor
4
+ # Handles HTTP/2 request processing and Rack application integration.
5
+ #
6
+ # Http2 manages the HTTP/2 protocol lifecycle including frame processing,
7
+ # HPACK header compression, stream management, and response writing.
8
+ # It integrates with the same reactor, ractor pool, and thread pool
9
+ # pipeline used by HTTP/1.1 connections.
10
+ class Http2
11
+ FLAG_END_STREAM: ::Integer
12
+
13
+ FLAG_END_HEADERS: ::Integer
14
+
15
+ FLAG_ACK: ::Integer
16
+
17
+ FLAG_PRIORITY: ::Integer
18
+
19
+ SERVER_PROTOCOL: ::String
20
+
21
+ RACK_HEADER_PREFIX: ::String
22
+
23
+ HOP_BY_HOP_HEADERS: untyped
24
+
25
+ @server_port: Integer
26
+
27
+ @app: ^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ]
28
+
29
+ # Creates a new Http2 handler.
30
+ #
31
+ # @param app [#call] the Rack application to dispatch requests to
32
+ # @param server_port [Integer] port number used to populate SERVER_PORT in the Rack env
33
+ # @return [void]
34
+ #
35
+ # @rbs (^(Hash[String, untyped]) -> [Integer, Hash[String, String | Array[String]], untyped] app, Integer server_port) -> void
36
+ def initialize: (^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ] app, Integer server_port) -> void
37
+
38
+ # Builds the initial server SETTINGS frame to send on connection establishment.
39
+ #
40
+ # @return [String] the encoded SETTINGS frame
41
+ #
42
+ # @rbs () -> String
43
+ def self.build_server_settings_frame: () -> String
44
+
45
+ # Processes HTTP/2 frames from the connection buffer.
46
+ #
47
+ # Parses frames, handles HPACK decoding, tracks stream state, and returns
48
+ # updated connection state along with any outgoing protocol frames and
49
+ # completed stream requests. Ractor-safe.
50
+ #
51
+ # @param data [Hash] the connection state including buffer and HPACK table
52
+ # @return [Hash] updated state with outgoing_frames and completed_requests
53
+ #
54
+ # @rbs (Hash[Symbol, untyped] data) -> Hash[Symbol, untyped]
55
+ def self.process_frames: (Hash[Symbol, untyped] data) -> Hash[Symbol, untyped]
56
+
57
+ # Builds a frozen result hash from the current processing state.
58
+ #
59
+ # @param data [Hash] original connection state
60
+ # @param buffer [String] remaining unparsed data
61
+ # @param hpack_table [Array] updated HPACK dynamic table
62
+ # @param streams [Hash] updated stream states
63
+ # @param outgoing_frames [Array<String>] frames to write to the socket
64
+ # @param completed_requests [Array<Hash>] fully received stream requests
65
+ # @param connection_window [Integer] current connection flow control window
66
+ # @param preface_received [Boolean] whether the connection preface has been received
67
+ # @return [Hash] frozen result hash
68
+ #
69
+ # @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, Integer connection_window, bool preface_received) -> Hash[Symbol, untyped]
70
+ 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, Integer connection_window, bool preface_received) -> Hash[Symbol, untyped]
71
+
72
+ # Handles a parsed HTTP/2 request from the ractor pool.
73
+ #
74
+ # Writes outgoing protocol frames to the socket, updates reactor state,
75
+ # and dispatches completed stream requests to the thread pool.
76
+ #
77
+ # @param result [Hash] the parsed result from the ractor pool
78
+ # @param reactor [Reactor] the reactor managing the connection
79
+ # @param thread_pool [AtomicThreadPool] thread pool for Rack app dispatch
80
+ # @return [void]
81
+ #
82
+ # @rbs (Hash[Symbol, untyped] result, Reactor reactor, AtomicThreadPool thread_pool) -> void
83
+ def handle_parsed_request: (Hash[Symbol, untyped] result, Reactor reactor, AtomicThreadPool thread_pool) -> void
84
+
85
+ private
86
+
87
+ # Dispatches a completed stream request to the Rack app and writes
88
+ # the response back as HTTP/2 frames.
89
+ #
90
+ # @param socket [OpenSSL::SSL::SSLSocket] the connection socket
91
+ # @param mutex [Mutex] mutex for serializing writes to the connection socket
92
+ # @param stream_id [Integer] the HTTP/2 stream identifier
93
+ # @param headers [Array<Array(String, String)>] request headers
94
+ # @param body [String] request body
95
+ # @param remote_addr [String] the client IP address
96
+ # @return [void]
97
+ #
98
+ # @rbs (OpenSSL::SSL::SSLSocket socket, Mutex mutex, Integer stream_id, Array[[String, String]] headers, String body, remote_addr: String) -> void
99
+ def dispatch_stream_request: (OpenSSL::SSL::SSLSocket socket, Mutex mutex, Integer stream_id, Array[[ String, String ]] headers, String body, remote_addr: String) -> void
100
+
101
+ # Writes a Rack response as HTTP/2 frames to the socket.
102
+ #
103
+ # @param socket [OpenSSL::SSL::SSLSocket] the connection socket
104
+ # @param mutex [Mutex] mutex for serializing writes to the connection socket
105
+ # @param stream_id [Integer] the HTTP/2 stream identifier
106
+ # @param status [Integer] HTTP status code
107
+ # @param headers [Hash] response headers from the Rack application
108
+ # @param body [Object] response body responding to each
109
+ # @return [void]
110
+ #
111
+ # @rbs (OpenSSL::SSL::SSLSocket socket, Mutex mutex, Integer stream_id, Integer status, Hash[String, String | Array[String]] headers, untyped body) -> void
112
+ def write_http2_response: (OpenSSL::SSL::SSLSocket socket, Mutex mutex, Integer stream_id, Integer status, Hash[String, String | Array[String]] headers, untyped body) -> void
113
+
114
+ # Writes a 500 error response as HTTP/2 frames.
115
+ #
116
+ # @param socket [OpenSSL::SSL::SSLSocket] the connection socket
117
+ # @param mutex [Mutex] mutex for serializing writes to the connection socket
118
+ # @param stream_id [Integer] the HTTP/2 stream identifier
119
+ # @return [void]
120
+ #
121
+ # @rbs (OpenSSL::SSL::SSLSocket socket, Mutex mutex, Integer stream_id) -> void
122
+ def write_http2_error_response: (OpenSSL::SSL::SSLSocket socket, Mutex mutex, Integer stream_id) -> void
123
+
124
+ # Builds a Rack environment hash from HTTP/2 headers and body.
125
+ #
126
+ # Translates HTTP/2 pseudo-headers into Rack-compatible environment keys
127
+ # and populates all required Rack env entries.
128
+ #
129
+ # @param headers [Array<Array(String, String)>] HTTP/2 header pairs
130
+ # @param body [String] the request body
131
+ # @param remote_addr [String] the client IP address
132
+ # @return [Hash] fully populated Rack environment hash
133
+ #
134
+ # @rbs (Array[[String, String]] headers, String body, remote_addr: String) -> Hash[String, untyped]
135
+ def build_rack_env: (Array[[ String, String ]] headers, String body, remote_addr: String) -> Hash[String, untyped]
136
+
137
+ # Populates SERVER_NAME and SERVER_PORT from the HTTP_HOST header.
138
+ #
139
+ # @param env [Hash] the Rack environment to populate
140
+ # @return [void]
141
+ #
142
+ # @rbs (Hash[String, untyped] env) -> void
143
+ def populate_server_name_and_port: (Hash[String, untyped] env) -> void
144
+ end
145
+ end
@@ -0,0 +1,251 @@
1
+ # Generated from lib/raptor/reactor.rb with RBS::Inline
2
+
3
+ module Raptor
4
+ # High-performance I/O reactor for managing client connections and timeouts.
5
+ #
6
+ # Reactor uses NIO selectors for efficient I/O multiplexing and implements
7
+ # client timeouts using a red-black tree for O(log n) timeout management.
8
+ # It coordinates between thread pools for blocking operations and ractor
9
+ # pools for CPU-intensive HTTP parsing, and provides backlog metrics
10
+ # that the server uses for backpressure control to prevent overload.
11
+ #
12
+ # @example
13
+ # reactor = Reactor.new(thread_pool, ractor_pool, client_options: {
14
+ # first_data_timeout: 30,
15
+ # chunk_data_timeout: 10
16
+ # })
17
+ # reactor.run
18
+ # reactor.add(id: client.object_id, socket: client)
19
+ # # ... later
20
+ # reactor.shutdown
21
+ class Reactor
22
+ # Red-black tree node representing a client connection with timeout tracking.
23
+ #
24
+ # TimeoutClient extends RedBlackTree::Node to enable efficient timeout
25
+ # management using the tree's ordering properties.
26
+ class TimeoutClient < RedBlackTree::Node
27
+ # @rbs attr_accessor timeout_at: Float
28
+ attr_accessor timeout_at: untyped
29
+
30
+ # Returns the client data stored in this timeout node.
31
+ #
32
+ # @return [Hash] the client connection state data
33
+ #
34
+ # @rbs () -> Hash[Symbol, untyped]
35
+ def client_data: () -> Hash[Symbol, untyped]
36
+
37
+ # Calculates remaining timeout duration from the current time.
38
+ #
39
+ # @param now [Float] current monotonic timestamp
40
+ # @return [Float] remaining timeout in seconds, minimum 0
41
+ #
42
+ # @rbs (Float now) -> Float
43
+ def timeout: (Float now) -> Float
44
+
45
+ # Compares timeout nodes by their timeout_at values for tree ordering.
46
+ #
47
+ # @param other [TimeoutClient] another timeout client to compare
48
+ # @return [Integer] -1, 0, or 1 for ordering
49
+ #
50
+ # @rbs (TimeoutClient other) -> Integer
51
+ def <=>: (TimeoutClient other) -> Integer
52
+ end
53
+
54
+ CHUNK_SIZE: untyped
55
+
56
+ TIMEOUT_RESPONSE: ::String
57
+
58
+ @id_to_mutex: Hash[Integer, Mutex]
59
+
60
+ @id_to_timeout: Hash[Integer, TimeoutClient]
61
+
62
+ @socket_to_state: Hash[TCPSocket, Hash[Symbol, untyped]]
63
+
64
+ @id_to_socket: Hash[Integer, TCPSocket]
65
+
66
+ @timeouts: RedBlackTree[TimeoutClient]
67
+
68
+ @queue: Queue[TCPSocket]
69
+
70
+ @selector: NIO::Selector
71
+
72
+ @client_options: Hash[Symbol, Integer]
73
+
74
+ @ractor_pool: untyped
75
+
76
+ @thread_pool: untyped
77
+
78
+ # Creates a new Reactor instance.
79
+ #
80
+ # @param thread_pool [AtomicThreadPool] thread pool for application processing
81
+ # @param ractor_pool [RactorPool] ractor pool for HTTP parsing
82
+ # @param client_options [Hash] timeout configuration options
83
+ # @option client_options [Integer] :first_data_timeout timeout for initial data
84
+ # @option client_options [Integer] :chunk_data_timeout timeout for subsequent chunks
85
+ # @option client_options [Integer] :persistent_data_timeout timeout for keep-alive connections
86
+ # @return [void]
87
+ #
88
+ # @rbs (untyped thread_pool, untyped ractor_pool, client_options: Hash[Symbol, Integer]) -> void
89
+ def initialize: (untyped thread_pool, untyped ractor_pool, client_options: Hash[Symbol, Integer]) -> void
90
+
91
+ # Starts the reactor's main event loop in a new thread.
92
+ #
93
+ # The event loop handles I/O events, processes timeouts, manages
94
+ # the registration queue, and controls server connection acceptance.
95
+ # It continues until the queue is closed and emptied.
96
+ #
97
+ # @return [Thread] the thread running the reactor event loop
98
+ #
99
+ # @rbs () -> Thread
100
+ def run: () -> Thread
101
+
102
+ # Adds a new client connection to the reactor.
103
+ #
104
+ # @param state [Hash] client connection state including socket and ID
105
+ # @option state [TCPSocket] :socket the client socket
106
+ # @option state [Integer] :id unique identifier for the client
107
+ # @return [void]
108
+ #
109
+ # @rbs (Hash[Symbol, untyped] state) -> void
110
+ def add: (Hash[Symbol, untyped] state) -> void
111
+
112
+ # Updates the state of an existing client connection.
113
+ #
114
+ # Called when an incomplete HTTP request needs to be
115
+ # re-registered with the reactor for further processing.
116
+ #
117
+ # @param state [Hash] updated client connection state
118
+ # @option state [Integer] :id client identifier
119
+ # @return [void]
120
+ #
121
+ # @rbs (Hash[Symbol, untyped] state) -> void
122
+ def update_state: (Hash[Symbol, untyped] state) -> void
123
+
124
+ # Removes a client connection from the reactor.
125
+ #
126
+ # Called when an HTTP request is complete and ready for application
127
+ # processing. Triggers server accept re-enabling if system capacity allows.
128
+ #
129
+ # @param id [Integer] unique client identifier
130
+ # @return [TCPSocket, nil] the removed socket, if found
131
+ #
132
+ # @rbs (Integer id) -> TCPSocket?
133
+ def remove: (Integer id) -> TCPSocket?
134
+
135
+ # Re-registers a kept-alive connection for the next request cycle.
136
+ #
137
+ # Called after successfully writing a response when keep-alive is active.
138
+ # Resets the connection state and re-queues the socket in the selector
139
+ # using the persistent data timeout.
140
+ #
141
+ # @param socket [TCPSocket] the kept-alive client socket
142
+ # @param id [Integer] the unique client identifier
143
+ # @param request_count [Integer] number of requests handled on this connection
144
+ # @param remote_addr [String] the client's remote IP address
145
+ # @param url_scheme [String] "http" or "https"
146
+ # @return [void]
147
+ #
148
+ # @rbs (TCPSocket socket, Integer id, Integer request_count, remote_addr: String, url_scheme: String) -> void
149
+ def persist: (TCPSocket socket, Integer id, Integer request_count, remote_addr: String, url_scheme: String) -> void
150
+
151
+ # Returns the socket for a given client identifier without removing it.
152
+ #
153
+ # Used by HTTP/2 connections where the socket remains registered across
154
+ # multiple stream requests.
155
+ #
156
+ # @param id [Integer] unique client identifier
157
+ # @return [TCPSocket, nil] the socket, if found
158
+ #
159
+ # @rbs (Integer id) -> TCPSocket?
160
+ def socket_for: (Integer id) -> TCPSocket?
161
+
162
+ # Returns the mutex for a given HTTP/2 connection.
163
+ #
164
+ # @param id [Integer] unique client identifier
165
+ # @return [Mutex, nil] the mutex, if found
166
+ #
167
+ # @rbs (Integer id) -> Mutex?
168
+ def mutex_for: (Integer id) -> Mutex?
169
+
170
+ # Updates connection state for an HTTP/2 connection after frame processing.
171
+ #
172
+ # Re-registers the socket with the selector for further reads and stores
173
+ # the updated HPACK table and stream states.
174
+ #
175
+ # @param state [Hash] updated connection state from the ractor pool
176
+ # @return [void]
177
+ #
178
+ # @rbs (Hash[Symbol, untyped] state) -> void
179
+ def update_http2_state: (Hash[Symbol, untyped] state) -> void
180
+
181
+ # Initiates reactor shutdown.
182
+ #
183
+ # Closes the registration queue and wakes up the selector to begin
184
+ # graceful shutdown process.
185
+ #
186
+ # @return [void]
187
+ #
188
+ # @rbs () -> void
189
+ def shutdown: () -> void
190
+
191
+ # Returns the number of complete requests either being processed
192
+ # or awaiting processing.
193
+ #
194
+ # @return [Integer] number of complete requests
195
+ #
196
+ # @rbs () -> Integer
197
+ def backlog: () -> Integer
198
+
199
+ private
200
+
201
+ # Registers a socket with the NIO selector and sets up timeout tracking.
202
+ #
203
+ # @param socket [TCPSocket] the socket to register
204
+ # @return [void]
205
+ #
206
+ # @rbs (TCPSocket socket) -> void
207
+ def register: (TCPSocket socket) -> void
208
+
209
+ # Handles socket wakeup by deregistering and queuing for processing.
210
+ #
211
+ # @param socket [TCPSocket] the socket that became ready
212
+ # @return [void]
213
+ #
214
+ # @rbs (TCPSocket socket) -> void
215
+ def wakeup!: (TCPSocket socket) -> void
216
+
217
+ # Reads data from a socket and either queues it for parsing,
218
+ # or for selector registration.
219
+ #
220
+ # @param socket [TCPSocket] the socket to read from and queue
221
+ # @param state [Hash] current connection state
222
+ # @return [Hash, nil] updated state, if successful
223
+ #
224
+ # @rbs (TCPSocket socket, Hash[Symbol, untyped] state) -> Hash[Symbol, untyped]?
225
+ def read_and_queue_for_parse: (TCPSocket socket, Hash[Symbol, untyped] state) -> Hash[Symbol, untyped]?
226
+
227
+ # Cleans up a client connection by removing it from tracking and closing the socket.
228
+ #
229
+ # @param socket [TCPSocket] the socket to clean up
230
+ # @return [void]
231
+ #
232
+ # @rbs (TCPSocket socket) -> void
233
+ def cleanup: (TCPSocket socket) -> void
234
+
235
+ # Checks if a request is complete i.e., processable.
236
+ #
237
+ # @param state [Hash] connection state
238
+ # @return [Boolean] true if the request is complete
239
+ #
240
+ # @rbs (Hash[Symbol, untyped] state) -> bool
241
+ def complete?: (Hash[Symbol, untyped] state) -> bool
242
+
243
+ # Checks if any data has been received for this connection.
244
+ #
245
+ # @param state [Hash] connection state
246
+ # @return [Boolean] true if first data has been received
247
+ #
248
+ # @rbs (Hash[Symbol, untyped] state) -> bool
249
+ def first_data_received?: (Hash[Symbol, untyped] state) -> bool
250
+ end
251
+ end