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.
- checksums.yaml +7 -0
- data/.buildkite/pipeline.yml +36 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +21 -0
- data/README.md +86 -0
- data/Rakefile +28 -0
- data/exe/raptor +8 -0
- data/ext/raptor_http/extconf.rb +7 -0
- data/ext/raptor_http/raptor_http.c +1248 -0
- data/ext/raptor_http2/extconf.rb +7 -0
- data/ext/raptor_http2/huffman_table.h +4888 -0
- data/ext/raptor_http2/raptor_http2.c +772 -0
- data/lib/raptor/binder.rb +249 -0
- data/lib/raptor/cli.rb +171 -0
- data/lib/raptor/cluster.rb +357 -0
- data/lib/raptor/http2.rb +416 -0
- data/lib/raptor/reactor.rb +411 -0
- data/lib/raptor/request.rb +992 -0
- data/lib/raptor/server.rb +167 -0
- data/lib/raptor/stats.rb +94 -0
- data/lib/raptor/version.rb +6 -0
- data/lib/raptor.rb +13 -0
- data/sig/generated/raptor/binder.rbs +162 -0
- data/sig/generated/raptor/cli.rbs +71 -0
- data/sig/generated/raptor/cluster.rbs +171 -0
- data/sig/generated/raptor/http2.rbs +145 -0
- data/sig/generated/raptor/reactor.rbs +251 -0
- data/sig/generated/raptor/request.rbs +477 -0
- data/sig/generated/raptor/server.rbs +88 -0
- data/sig/generated/raptor/stats.rbs +78 -0
- data/sig/generated/raptor/version.rbs +5 -0
- data/sig/generated/raptor.rbs +9 -0
- metadata +160 -0
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
# Generated from lib/raptor/request.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Raptor
|
|
4
|
+
# Handles HTTP request processing and Rack application integration.
|
|
5
|
+
#
|
|
6
|
+
# Request manages the HTTP parsing pipeline using Ractors and coordinates
|
|
7
|
+
# with the reactor for connection state management. It bridges between the
|
|
8
|
+
# low-level HTTP parsing and high-level Rack application interface, handling
|
|
9
|
+
# both incomplete requests (that need more data) and complete requests
|
|
10
|
+
# (ready for application processing).
|
|
11
|
+
class Request
|
|
12
|
+
BODY_BUFFER_THRESHOLD: untyped
|
|
13
|
+
|
|
14
|
+
FILE_CHUNK_SIZE: untyped
|
|
15
|
+
|
|
16
|
+
KEEPALIVE_BUFFER_SIZE: untyped
|
|
17
|
+
|
|
18
|
+
WRITE_TIMEOUT: ::Integer
|
|
19
|
+
|
|
20
|
+
KEEPALIVE_READ_TIMEOUT: ::Float
|
|
21
|
+
|
|
22
|
+
MAX_KEEPALIVE_REQUESTS: ::Integer
|
|
23
|
+
|
|
24
|
+
HTTP_SCHEME: ::String
|
|
25
|
+
|
|
26
|
+
HTTP_10: ::String
|
|
27
|
+
|
|
28
|
+
HTTP_11: ::String
|
|
29
|
+
|
|
30
|
+
STATUS_LINE_CACHE_10: untyped
|
|
31
|
+
|
|
32
|
+
STATUS_LINE_CACHE_11: untyped
|
|
33
|
+
|
|
34
|
+
STATUS_WITH_NO_ENTITY_BODY: untyped
|
|
35
|
+
|
|
36
|
+
ERROR_RESPONSE_500: ::String
|
|
37
|
+
|
|
38
|
+
CONNECTION_CLOSE: ::String
|
|
39
|
+
|
|
40
|
+
CONNECTION_KEEPALIVE: ::String
|
|
41
|
+
|
|
42
|
+
TRANSFER_ENCODING_CHUNKED: ::String
|
|
43
|
+
|
|
44
|
+
HTTP_CONNECTION: ::String
|
|
45
|
+
|
|
46
|
+
HTTP_TRANSFER_ENCODING: ::String
|
|
47
|
+
|
|
48
|
+
RACK_HEADER_PREFIX: ::String
|
|
49
|
+
|
|
50
|
+
RACK_HIJACKED: ::String
|
|
51
|
+
|
|
52
|
+
RACK_HIJACK_IO: ::String
|
|
53
|
+
|
|
54
|
+
ILLEGAL_HEADER_KEY_REGEX: ::Regexp
|
|
55
|
+
|
|
56
|
+
ILLEGAL_HEADER_VALUE_REGEX: ::Regexp
|
|
57
|
+
|
|
58
|
+
class Error < StandardError
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
class WriteError < Error
|
|
62
|
+
# @rbs () -> String
|
|
63
|
+
def message: () -> String
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
@server_port: Integer
|
|
67
|
+
|
|
68
|
+
@app: ^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ]
|
|
69
|
+
|
|
70
|
+
# Creates a new Request handler.
|
|
71
|
+
#
|
|
72
|
+
# @param app [#call] the Rack application to dispatch complete requests to
|
|
73
|
+
# @param server_port [Integer] port number used to populate SERVER_PORT in the Rack env
|
|
74
|
+
# @return [void]
|
|
75
|
+
#
|
|
76
|
+
# @rbs (^(Hash[String, untyped]) -> [Integer, Hash[String, String | Array[String]], untyped] app, Integer server_port) -> void
|
|
77
|
+
def initialize: (^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ] app, Integer server_port) -> void
|
|
78
|
+
|
|
79
|
+
# Returns a Proc for HTTP parsing work in Ractor context.
|
|
80
|
+
#
|
|
81
|
+
# The returned Proc processes raw socket data through the appropriate
|
|
82
|
+
# HTTP parser and returns either a complete request state (ready for
|
|
83
|
+
# app processing) or incomplete request state (needs more data).
|
|
84
|
+
#
|
|
85
|
+
# @return [Proc] a Ractor-safe proc that accepts a state hash and returns an updated state hash
|
|
86
|
+
#
|
|
87
|
+
# @rbs () -> ^(Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
88
|
+
def http_parser_worker: () -> ^(Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
89
|
+
|
|
90
|
+
# Handles a parsed HTTP request by either continuing parsing or dispatching to the Rack app.
|
|
91
|
+
#
|
|
92
|
+
# For incomplete requests, updates reactor state and re-registers for more I/O.
|
|
93
|
+
# For complete requests, removes from reactor, builds Rack env, and dispatches to thread pool.
|
|
94
|
+
#
|
|
95
|
+
# @param parsed_request [Hash] the parsed request state from the ractor pool
|
|
96
|
+
# @param reactor [Reactor] the reactor managing the client connection
|
|
97
|
+
# @param thread_pool [AtomicThreadPool] thread pool for application processing
|
|
98
|
+
# @return [void]
|
|
99
|
+
#
|
|
100
|
+
# @rbs (Hash[Symbol, untyped] parsed_request, Reactor reactor, AtomicThreadPool thread_pool) -> void
|
|
101
|
+
def handle_parsed_request: (Hash[Symbol, untyped] parsed_request, Reactor reactor, AtomicThreadPool thread_pool) -> void
|
|
102
|
+
|
|
103
|
+
private
|
|
104
|
+
|
|
105
|
+
# Processes a client connection by handling the current request and,
|
|
106
|
+
# if keep-alive, eagerly reading subsequent requests inline.
|
|
107
|
+
#
|
|
108
|
+
# @param socket [TCPSocket] the client socket
|
|
109
|
+
# @param id [Integer] unique client identifier
|
|
110
|
+
# @param env [Hash] partial env hash from the HTTP parser
|
|
111
|
+
# @param parse_data [Hash] metadata from the parsing pass
|
|
112
|
+
# @param body [String, nil] decoded request body
|
|
113
|
+
# @param reactor [Reactor] the reactor managing the client connection
|
|
114
|
+
# @param thread_pool [AtomicThreadPool] thread pool for application processing
|
|
115
|
+
# @param request_count [Integer] number of requests handled on this connection
|
|
116
|
+
# @param remote_addr [String] client IP address
|
|
117
|
+
# @param url_scheme [String] "http" or "https"
|
|
118
|
+
# @return [void]
|
|
119
|
+
#
|
|
120
|
+
# @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
|
|
121
|
+
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
|
|
122
|
+
|
|
123
|
+
# Builds the Rack env, calls the application, and writes the response.
|
|
124
|
+
# Returns true if the connection should be kept alive for further
|
|
125
|
+
# requests, false otherwise (including hijack and error cases).
|
|
126
|
+
#
|
|
127
|
+
# @param socket [TCPSocket] the client socket
|
|
128
|
+
# @param env [Hash] partial env hash from the HTTP parser
|
|
129
|
+
# @param parse_data [Hash] metadata from the parsing pass
|
|
130
|
+
# @param body [String, nil] decoded request body
|
|
131
|
+
# @param request_count [Integer] number of requests handled on this connection
|
|
132
|
+
# @param remote_addr [String] client IP address
|
|
133
|
+
# @param url_scheme [String] "http" or "https"
|
|
134
|
+
# @return [Boolean] true if the connection should be kept alive
|
|
135
|
+
#
|
|
136
|
+
# @rbs (TCPSocket socket, Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, String? body, Integer request_count, String remote_addr, String url_scheme) -> bool
|
|
137
|
+
def process_request: (TCPSocket socket, Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, String? body, Integer request_count, String remote_addr, String url_scheme) -> bool
|
|
138
|
+
|
|
139
|
+
# Attempts to read and process subsequent requests inline on a
|
|
140
|
+
# kept-alive connection. Blocks briefly for the next request to avoid
|
|
141
|
+
# a full reactor round-trip. Falls back to the reactor when no data
|
|
142
|
+
# arrives within the timeout, when the thread pool has queued work
|
|
143
|
+
# (deprioritization), or when the request is incomplete.
|
|
144
|
+
#
|
|
145
|
+
# @param socket [TCPSocket] the client socket
|
|
146
|
+
# @param id [Integer] unique client identifier
|
|
147
|
+
# @param reactor [Reactor] the reactor for fallback registration
|
|
148
|
+
# @param thread_pool [AtomicThreadPool] thread pool for deprioritization
|
|
149
|
+
# @param request_count [Integer] number of requests handled on this connection
|
|
150
|
+
# @param remote_addr [String] client IP address
|
|
151
|
+
# @param url_scheme [String] "http" or "https"
|
|
152
|
+
# @return [void]
|
|
153
|
+
#
|
|
154
|
+
# @rbs (TCPSocket socket, Integer id, Reactor reactor, AtomicThreadPool thread_pool, Integer request_count, String remote_addr, String url_scheme) -> void
|
|
155
|
+
def eager_keepalive: (TCPSocket socket, Integer id, Reactor reactor, AtomicThreadPool thread_pool, Integer request_count, String remote_addr, String url_scheme) -> void
|
|
156
|
+
|
|
157
|
+
# Re-registers a socket with the reactor for further processing
|
|
158
|
+
# when an incomplete request is received during eager keep-alive.
|
|
159
|
+
#
|
|
160
|
+
# @param socket [TCPSocket] the client socket
|
|
161
|
+
# @param id [Integer] unique client identifier
|
|
162
|
+
# @param buffer [String] the partial request data already read
|
|
163
|
+
# @param env [Hash] partial env hash from the HTTP parser
|
|
164
|
+
# @param parse_data [Hash] metadata from the parsing pass
|
|
165
|
+
# @param reactor [Reactor] the reactor to re-register with
|
|
166
|
+
# @param request_count [Integer] number of requests handled on this connection
|
|
167
|
+
# @param remote_addr [String] client IP address
|
|
168
|
+
# @param url_scheme [String] "http" or "https"
|
|
169
|
+
# @return [void]
|
|
170
|
+
#
|
|
171
|
+
# @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) -> void
|
|
172
|
+
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) -> void
|
|
173
|
+
|
|
174
|
+
# Builds a Rack environment hash from parsed HTTP request data.
|
|
175
|
+
#
|
|
176
|
+
# Populates all required Rack env keys including rack.* keys, REMOTE_ADDR,
|
|
177
|
+
# SERVER_NAME, SERVER_PORT, and hijack support.
|
|
178
|
+
#
|
|
179
|
+
# @param env [Hash] partial env hash from the HTTP parser
|
|
180
|
+
# @param parse_data [Hash] metadata from the parsing pass, including content_length
|
|
181
|
+
# @param body [String, nil] decoded request body, or nil if no body
|
|
182
|
+
# @param socket [TCPSocket] the client socket, used for hijack support
|
|
183
|
+
# @param remote_addr [String] client IP address
|
|
184
|
+
# @param url_scheme [String] "http" or "https"
|
|
185
|
+
# @return [Hash] fully populated Rack environment hash
|
|
186
|
+
#
|
|
187
|
+
# @rbs (Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, String? body, TCPSocket socket, ?remote_addr: String, ?url_scheme: String) -> Hash[String, untyped]
|
|
188
|
+
def build_rack_env: (Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, String? body, TCPSocket socket, ?remote_addr: String, ?url_scheme: String) -> Hash[String, untyped]
|
|
189
|
+
|
|
190
|
+
# Determines whether the connection should be kept alive after the response.
|
|
191
|
+
#
|
|
192
|
+
# Returns false if the request limit has been reached. For HTTP/1.1, keep-alive
|
|
193
|
+
# is the default unless the client sent Connection: close. For HTTP/1.0,
|
|
194
|
+
# keep-alive must be explicitly requested.
|
|
195
|
+
#
|
|
196
|
+
# @param env [Hash] the Rack environment
|
|
197
|
+
# @param request_count [Integer] number of requests handled on this connection
|
|
198
|
+
# @return [Boolean] true if the connection should be kept alive
|
|
199
|
+
#
|
|
200
|
+
# @rbs (Hash[String, untyped] env, Integer request_count) -> bool
|
|
201
|
+
def keep_alive?: (Hash[String, untyped] env, Integer request_count) -> bool
|
|
202
|
+
|
|
203
|
+
# Sends an HTTP 103 Early Hints response to the client.
|
|
204
|
+
#
|
|
205
|
+
# Skips any hints with illegal header keys or values. No-ops if hints is empty.
|
|
206
|
+
#
|
|
207
|
+
# @param socket [TCPSocket] the client socket to write to
|
|
208
|
+
# @param hints [Hash] header name to value (or array of values) pairs
|
|
209
|
+
# @return [void]
|
|
210
|
+
#
|
|
211
|
+
# @rbs (TCPSocket socket, Hash[String, String | Array[String]] hints) -> void
|
|
212
|
+
def send_early_hints: (TCPSocket socket, Hash[String, String | Array[String]] hints) -> void
|
|
213
|
+
|
|
214
|
+
# Writes a complete HTTP response to the socket.
|
|
215
|
+
#
|
|
216
|
+
# Handles header normalization, validation, connection management, TCP corking,
|
|
217
|
+
# and dispatches to the appropriate body write strategy.
|
|
218
|
+
#
|
|
219
|
+
# @param socket [TCPSocket] the client socket to write to
|
|
220
|
+
# @param env [Hash] the Rack environment
|
|
221
|
+
# @param status [Integer] HTTP status code
|
|
222
|
+
# @param headers [Hash] response headers from the Rack application
|
|
223
|
+
# @param body [Object] response body (array, enumerable, file, or callable)
|
|
224
|
+
# @param keep_alive [Boolean] whether to send a keep-alive connection header
|
|
225
|
+
# @return [void]
|
|
226
|
+
#
|
|
227
|
+
# @rbs (TCPSocket socket, Hash[String, untyped] env, Integer status, Hash[String, String | Array[String]] headers, untyped body, ?keep_alive: bool) -> void
|
|
228
|
+
def write_response: (TCPSocket socket, Hash[String, untyped] env, Integer status, Hash[String, String | Array[String]] headers, untyped body, ?keep_alive: bool) -> void
|
|
229
|
+
|
|
230
|
+
# Validates that the status code is a valid integer.
|
|
231
|
+
#
|
|
232
|
+
# @param status [Object] the status value to validate
|
|
233
|
+
# @return [void]
|
|
234
|
+
# @raise [TypeError] if status is not an Integer
|
|
235
|
+
# @raise [ArgumentError] if status is less than 100
|
|
236
|
+
#
|
|
237
|
+
# @rbs (Integer status) -> void
|
|
238
|
+
def validate_status: (Integer status) -> void
|
|
239
|
+
|
|
240
|
+
# Normalizes response headers by downcasing keys and filtering invalid entries.
|
|
241
|
+
#
|
|
242
|
+
# Removes headers with illegal keys, rack.* prefixed headers, and "status" headers.
|
|
243
|
+
# Raises if headers is not a Hash or contains non-String keys.
|
|
244
|
+
#
|
|
245
|
+
# @param headers [Hash] raw headers from the Rack application
|
|
246
|
+
# @return [Hash] normalized headers with lowercased string keys
|
|
247
|
+
# @raise [TypeError] if headers is not a Hash or a key is not a String
|
|
248
|
+
#
|
|
249
|
+
# @rbs (Hash[String, String | Array[String]] headers) -> Hash[String, String | Array[String]]
|
|
250
|
+
def normalize_headers: (Hash[String, String | Array[String]] headers) -> Hash[String, String | Array[String]]
|
|
251
|
+
|
|
252
|
+
# Validates that headers are appropriate for the given status code.
|
|
253
|
+
#
|
|
254
|
+
# Raises if content-type or content-length are present for status codes
|
|
255
|
+
# that must not have an entity body (204, 304, 1xx).
|
|
256
|
+
#
|
|
257
|
+
# @param headers [Hash] normalized response headers
|
|
258
|
+
# @param status [Integer] HTTP status code
|
|
259
|
+
# @return [void]
|
|
260
|
+
# @raise [ArgumentError] if a forbidden header is present for the status
|
|
261
|
+
#
|
|
262
|
+
# @rbs (Hash[String, String | Array[String]] headers, Integer status) -> void
|
|
263
|
+
def validate_headers: (Hash[String, String | Array[String]] headers, Integer status) -> void
|
|
264
|
+
|
|
265
|
+
# Builds the HTTP status line string.
|
|
266
|
+
#
|
|
267
|
+
# @param http_version [String] "HTTP/1.1" or "HTTP/1.0"
|
|
268
|
+
# @param status [Integer] HTTP status code
|
|
269
|
+
# @return [String] the status line including trailing CRLF
|
|
270
|
+
#
|
|
271
|
+
# @rbs (String http_version, Integer status) -> String
|
|
272
|
+
def build_status_line: (String http_version, Integer status) -> String
|
|
273
|
+
|
|
274
|
+
# Writes response headers and delegates body writing to the hijack callback.
|
|
275
|
+
#
|
|
276
|
+
# Uncorks the socket before calling the hijack so the app has full control
|
|
277
|
+
# of the raw connection.
|
|
278
|
+
#
|
|
279
|
+
# @param socket [TCPSocket] the client socket
|
|
280
|
+
# @param response [String] the status line accumulated so far
|
|
281
|
+
# @param headers [Hash] normalized response headers
|
|
282
|
+
# @param response_hijack [Proc] callable that receives the socket and writes the body
|
|
283
|
+
# @return [void]
|
|
284
|
+
#
|
|
285
|
+
# @rbs (TCPSocket socket, String response, Hash[String, String | Array[String]] headers, ^(TCPSocket) -> void response_hijack) -> void
|
|
286
|
+
def write_hijacked_response: (TCPSocket socket, String response, Hash[String, String | Array[String]] headers, ^(TCPSocket) -> void response_hijack) -> void
|
|
287
|
+
|
|
288
|
+
# Writes a response with no entity body.
|
|
289
|
+
#
|
|
290
|
+
# Used for HEAD requests and status codes that must not carry a body
|
|
291
|
+
# (204, 304, 1xx). Adds a zero content-length for non-no-body statuses
|
|
292
|
+
# that did not supply one.
|
|
293
|
+
#
|
|
294
|
+
# @param socket [TCPSocket] the client socket
|
|
295
|
+
# @param response [String] the status line accumulated so far
|
|
296
|
+
# @param headers [Hash] normalized response headers
|
|
297
|
+
# @param status [Integer] HTTP status code
|
|
298
|
+
# @return [void]
|
|
299
|
+
#
|
|
300
|
+
# @rbs (TCPSocket socket, String response, Hash[String, String | Array[String]] headers, Integer status) -> void
|
|
301
|
+
def write_no_body_response: (TCPSocket socket, String response, Hash[String, String | Array[String]] headers, Integer status) -> void
|
|
302
|
+
|
|
303
|
+
# Writes a complete response with a body.
|
|
304
|
+
#
|
|
305
|
+
# Selects the appropriate write strategy based on body type: callable (streaming),
|
|
306
|
+
# file (zero-copy), array, or generic enumerable. Automatically determines
|
|
307
|
+
# content-length where possible, falling back to chunked transfer encoding
|
|
308
|
+
# for HTTP/1.1 when the length cannot be determined upfront.
|
|
309
|
+
#
|
|
310
|
+
# @param socket [TCPSocket] the client socket
|
|
311
|
+
# @param response [String] the status line accumulated so far
|
|
312
|
+
# @param headers [Hash] normalized response headers
|
|
313
|
+
# @param body [Object] the response body
|
|
314
|
+
# @param http_version [String] "HTTP/1.1" or "HTTP/1.0"
|
|
315
|
+
# @return [void]
|
|
316
|
+
#
|
|
317
|
+
# @rbs (TCPSocket socket, String response, Hash[String, String | Array[String]] headers, untyped body, String http_version) -> void
|
|
318
|
+
def write_full_response: (TCPSocket socket, String response, Hash[String, String | Array[String]] headers, untyped body, String http_version) -> void
|
|
319
|
+
|
|
320
|
+
# Calculates content length from an array or file body without consuming it.
|
|
321
|
+
#
|
|
322
|
+
# Returns nil for enumerable bodies whose length cannot be determined upfront.
|
|
323
|
+
#
|
|
324
|
+
# @param body [Object] the response body
|
|
325
|
+
# @return [Integer, nil] the byte length, or nil if it cannot be determined
|
|
326
|
+
#
|
|
327
|
+
# @rbs (untyped body) -> Integer?
|
|
328
|
+
def calculate_content_length: (untyped body) -> Integer?
|
|
329
|
+
|
|
330
|
+
# Writes a file body to the socket.
|
|
331
|
+
#
|
|
332
|
+
# Uses zero-copy IO.copy_stream for large files, direct buffering for small ones,
|
|
333
|
+
# and chunked encoding when required.
|
|
334
|
+
#
|
|
335
|
+
# @param socket [TCPSocket] the client socket
|
|
336
|
+
# @param response [String] headers already serialized, to be written before the body
|
|
337
|
+
# @param path [String] filesystem path of the file to send
|
|
338
|
+
# @param content_length [Integer, nil] pre-calculated file size
|
|
339
|
+
# @param use_chunked [Boolean] whether to use chunked transfer encoding
|
|
340
|
+
# @return [void]
|
|
341
|
+
#
|
|
342
|
+
# @rbs (TCPSocket socket, String response, String path, Integer? content_length, bool use_chunked) -> void
|
|
343
|
+
def write_file_body: (TCPSocket socket, String response, String path, Integer? content_length, bool use_chunked) -> void
|
|
344
|
+
|
|
345
|
+
# Writes an array body to the socket.
|
|
346
|
+
#
|
|
347
|
+
# Dispatches to the single-chunk or multi-chunk path based on array length.
|
|
348
|
+
#
|
|
349
|
+
# @param socket [TCPSocket] the client socket
|
|
350
|
+
# @param response [String] headers already serialized, to be written before the body
|
|
351
|
+
# @param body_array [Array<String>] the response body chunks
|
|
352
|
+
# @param use_chunked [Boolean] whether to use chunked transfer encoding
|
|
353
|
+
# @return [void]
|
|
354
|
+
#
|
|
355
|
+
# @rbs (TCPSocket socket, String response, Array[String] body_array, bool use_chunked) -> void
|
|
356
|
+
def write_array_body: (TCPSocket socket, String response, Array[String] body_array, bool use_chunked) -> void
|
|
357
|
+
|
|
358
|
+
# Writes a single-element array body, optionally buffering it with the headers.
|
|
359
|
+
#
|
|
360
|
+
# Small bodies are concatenated with the headers into one write to reduce
|
|
361
|
+
# system call overhead.
|
|
362
|
+
#
|
|
363
|
+
# @param socket [TCPSocket] the client socket
|
|
364
|
+
# @param response [String] headers already serialized, to be written before the body
|
|
365
|
+
# @param chunk [String] the single body chunk
|
|
366
|
+
# @param use_chunked [Boolean] whether to use chunked transfer encoding
|
|
367
|
+
# @return [void]
|
|
368
|
+
# @raise [TypeError] if the chunk is not a String
|
|
369
|
+
#
|
|
370
|
+
# @rbs (TCPSocket socket, String response, String chunk, bool use_chunked) -> void
|
|
371
|
+
def write_single_chunk: (TCPSocket socket, String response, String chunk, bool use_chunked) -> void
|
|
372
|
+
|
|
373
|
+
# Writes a multi-element array body to the socket.
|
|
374
|
+
#
|
|
375
|
+
# @param socket [TCPSocket] the client socket
|
|
376
|
+
# @param response [String] headers already serialized, to be written before the body
|
|
377
|
+
# @param body_array [Array<String>] the response body chunks
|
|
378
|
+
# @param use_chunked [Boolean] whether to use chunked transfer encoding
|
|
379
|
+
# @return [void]
|
|
380
|
+
# @raise [TypeError] if any chunk is not a String
|
|
381
|
+
#
|
|
382
|
+
# @rbs (TCPSocket socket, String response, Array[String] body_array, bool use_chunked) -> void
|
|
383
|
+
def write_multiple_chunks: (TCPSocket socket, String response, Array[String] body_array, bool use_chunked) -> void
|
|
384
|
+
|
|
385
|
+
# Writes a generic enumerable body to the socket.
|
|
386
|
+
#
|
|
387
|
+
# @param socket [TCPSocket] the client socket
|
|
388
|
+
# @param response [String] headers already serialized, to be written before the body
|
|
389
|
+
# @param body [Object] any object responding to each
|
|
390
|
+
# @param use_chunked [Boolean] whether to use chunked transfer encoding
|
|
391
|
+
# @return [void]
|
|
392
|
+
# @raise [TypeError] if any yielded chunk is not a String
|
|
393
|
+
#
|
|
394
|
+
# @rbs (TCPSocket socket, String response, untyped body, bool use_chunked) -> void
|
|
395
|
+
def write_enumerable_body: (TCPSocket socket, String response, untyped body, bool use_chunked) -> void
|
|
396
|
+
|
|
397
|
+
# Returns true if the header key contains characters illegal in HTTP headers.
|
|
398
|
+
#
|
|
399
|
+
# @param key [String] the header key to check
|
|
400
|
+
# @return [Boolean] true if the key is illegal
|
|
401
|
+
#
|
|
402
|
+
# @rbs (String key) -> bool
|
|
403
|
+
def illegal_header_key?: (String key) -> bool
|
|
404
|
+
|
|
405
|
+
# Returns true if the header value contains characters illegal in HTTP headers.
|
|
406
|
+
#
|
|
407
|
+
# @param value [String] the header value to check
|
|
408
|
+
# @return [Boolean] true if the value is illegal
|
|
409
|
+
#
|
|
410
|
+
# @rbs (String value) -> bool
|
|
411
|
+
def illegal_header_value?: (String value) -> bool
|
|
412
|
+
|
|
413
|
+
# Formats a headers hash into an HTTP header string.
|
|
414
|
+
#
|
|
415
|
+
# Skips entries with illegal keys or values. Array values are written
|
|
416
|
+
# as separate header lines.
|
|
417
|
+
#
|
|
418
|
+
# @param headers [Hash] normalized response headers
|
|
419
|
+
# @return [String] formatted header lines, each ending with CRLF
|
|
420
|
+
#
|
|
421
|
+
# @rbs (Hash[String, String | Array[String]] headers) -> String
|
|
422
|
+
def format_headers: (Hash[String, String | Array[String]] headers) -> String
|
|
423
|
+
|
|
424
|
+
# Calls all rack.response_finished callbacks registered in the environment.
|
|
425
|
+
#
|
|
426
|
+
# Callbacks are called in reverse registration order. Individual callback
|
|
427
|
+
# failures are rescued so all callbacks are always attempted.
|
|
428
|
+
#
|
|
429
|
+
# @param env [Hash, nil] the Rack environment
|
|
430
|
+
# @param status [Integer, nil] the response status code
|
|
431
|
+
# @param headers [Hash, nil] the response headers
|
|
432
|
+
# @param error [Exception, nil] any error raised during processing, or nil on success
|
|
433
|
+
# @return [void]
|
|
434
|
+
#
|
|
435
|
+
# @rbs (Hash[String, untyped] env, Integer? status, Hash[String, String | Array[String]]? headers, Exception? error) -> void
|
|
436
|
+
def call_response_finished: (Hash[String, untyped] env, Integer? status, Hash[String, String | Array[String]]? headers, Exception? error) -> void
|
|
437
|
+
|
|
438
|
+
# Writes a string to the socket, retrying on partial writes and flow control blocks.
|
|
439
|
+
#
|
|
440
|
+
# Uses write_nonblock with a 5-second writable timeout to avoid blocking the
|
|
441
|
+
# thread indefinitely on slow clients.
|
|
442
|
+
#
|
|
443
|
+
# @param socket [TCPSocket] the socket to write to
|
|
444
|
+
# @param string [String] the data to write
|
|
445
|
+
# @return [void]
|
|
446
|
+
# @raise [WriteError] if the socket is not writable within the timeout or raises IOError
|
|
447
|
+
#
|
|
448
|
+
# @rbs (TCPSocket socket, String string) -> void
|
|
449
|
+
def socket_write: (TCPSocket socket, String string) -> void
|
|
450
|
+
|
|
451
|
+
# Enables TCP_CORK on the socket to batch outgoing packets into fewer segments.
|
|
452
|
+
#
|
|
453
|
+
# Only applies to TCP sockets. No-op on non-TCP sockets.
|
|
454
|
+
# Available on Linux only; this method is not defined on other platforms.
|
|
455
|
+
#
|
|
456
|
+
# @param socket [TCPSocket] the socket to cork
|
|
457
|
+
# @return [void]
|
|
458
|
+
#
|
|
459
|
+
# @rbs (TCPSocket socket) -> void
|
|
460
|
+
def cork_socket: (TCPSocket socket) -> void
|
|
461
|
+
|
|
462
|
+
# Disables TCP_CORK on the socket, flushing any buffered packets.
|
|
463
|
+
#
|
|
464
|
+
# Only applies to TCP sockets. No-op on non-TCP sockets.
|
|
465
|
+
# Available on Linux only; this method is not defined on other platforms.
|
|
466
|
+
#
|
|
467
|
+
# @param socket [TCPSocket] the socket to uncork
|
|
468
|
+
# @return [void]
|
|
469
|
+
#
|
|
470
|
+
# @rbs (TCPSocket socket) -> void
|
|
471
|
+
def uncork_socket: (TCPSocket socket) -> void
|
|
472
|
+
|
|
473
|
+
def cork_socket: (untyped socket) -> untyped
|
|
474
|
+
|
|
475
|
+
def uncork_socket: (untyped socket) -> untyped
|
|
476
|
+
end
|
|
477
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Generated from lib/raptor/server.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Raptor
|
|
4
|
+
# High-performance HTTP server that accepts connections and dispatches them.
|
|
5
|
+
#
|
|
6
|
+
# Server manages the main accept loop, handling incoming client connections from
|
|
7
|
+
# bound sockets. It uses IO.select for efficient polling and implements automatic
|
|
8
|
+
# load balancing by checking reactor backlog before accepting connections,
|
|
9
|
+
# providing natural backpressure based on system capacity.
|
|
10
|
+
#
|
|
11
|
+
# Supports TCP, Unix domain, and SSL listeners transparently. TCP_NODELAY is
|
|
12
|
+
# applied only to TCP sockets, and SSL handshakes are performed synchronously
|
|
13
|
+
# before handing the connection to the reactor.
|
|
14
|
+
#
|
|
15
|
+
# For SSL connections, ALPN negotiation determines the protocol. HTTP/2
|
|
16
|
+
# connections are added to the reactor with initial SETTINGS and processed
|
|
17
|
+
# through the same ractor pool pipeline as HTTP/1.1 connections.
|
|
18
|
+
#
|
|
19
|
+
# @example
|
|
20
|
+
# binder = Binder.new(["tcp://0.0.0.0:3000"])
|
|
21
|
+
# reactor = Reactor.new(thread_pool, ractor_pool, client_options: {})
|
|
22
|
+
# server = Server.new(binder, reactor, thread_pool)
|
|
23
|
+
# server.run
|
|
24
|
+
# # ... later
|
|
25
|
+
# server.shutdown
|
|
26
|
+
class Server
|
|
27
|
+
HTTP_SCHEME: ::String
|
|
28
|
+
|
|
29
|
+
HTTPS_SCHEME: ::String
|
|
30
|
+
|
|
31
|
+
H2_PROTOCOL: ::String
|
|
32
|
+
|
|
33
|
+
@binder: Binder
|
|
34
|
+
|
|
35
|
+
@reactor: Reactor
|
|
36
|
+
|
|
37
|
+
@thread_pool: AtomicThreadPool
|
|
38
|
+
|
|
39
|
+
@running: AtomicBoolean
|
|
40
|
+
|
|
41
|
+
# Creates a new Server instance.
|
|
42
|
+
#
|
|
43
|
+
# @param binder [Binder] the binder managing listening sockets
|
|
44
|
+
# @param reactor [Reactor] the reactor for handling client connections
|
|
45
|
+
# @param thread_pool [AtomicThreadPool] thread pool for application processing
|
|
46
|
+
# @return [void]
|
|
47
|
+
#
|
|
48
|
+
# @rbs (Binder binder, Reactor reactor, AtomicThreadPool thread_pool) -> void
|
|
49
|
+
def initialize: (Binder binder, Reactor reactor, AtomicThreadPool thread_pool) -> void
|
|
50
|
+
|
|
51
|
+
# Starts the server's main accept loop in a new thread.
|
|
52
|
+
#
|
|
53
|
+
# The accept loop polls listening sockets for ready connections and accepts
|
|
54
|
+
# them when system capacity allows. It checks reactor backlog before accepting
|
|
55
|
+
# to prevent overload. This provides natural load balancing across multiple
|
|
56
|
+
# worker processes through backpressure control.
|
|
57
|
+
#
|
|
58
|
+
# @return [Thread] the thread running the accept loop
|
|
59
|
+
#
|
|
60
|
+
# @rbs () -> Thread
|
|
61
|
+
def run: () -> Thread
|
|
62
|
+
|
|
63
|
+
# Gracefully shuts down the server.
|
|
64
|
+
#
|
|
65
|
+
# Stops accepting new connections and closes all listening sockets.
|
|
66
|
+
# The server thread will exit after handling any in-flight accept operations.
|
|
67
|
+
#
|
|
68
|
+
# @return [void]
|
|
69
|
+
#
|
|
70
|
+
# @rbs () -> void
|
|
71
|
+
def shutdown: () -> void
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
# Accepts a connection from the given listener and dispatches it.
|
|
76
|
+
#
|
|
77
|
+
# For SSL connections with h2 negotiated via ALPN, the server sends
|
|
78
|
+
# initial SETTINGS and adds the connection to the reactor as an HTTP/2
|
|
79
|
+
# connection. All other connections follow the HTTP/1.1 path.
|
|
80
|
+
#
|
|
81
|
+
# @param listener [TCPServer, UNIXServer, Binder::SslListener] the ready listener
|
|
82
|
+
# @param reactor [Reactor] the reactor to dispatch connections to
|
|
83
|
+
# @return [void]
|
|
84
|
+
#
|
|
85
|
+
# @rbs (TCPServer | UNIXServer | Binder::SslListener listener, Reactor reactor) -> void
|
|
86
|
+
def accept_connection: (TCPServer | UNIXServer | Binder::SslListener listener, Reactor reactor) -> void
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Generated from lib/raptor/stats.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Raptor
|
|
4
|
+
# Shared memory store for per-worker process statistics.
|
|
5
|
+
#
|
|
6
|
+
# Stats uses an anonymous mmap (MAP_ANON | MAP_SHARED) created before
|
|
7
|
+
# forking so that worker processes can write their stats and the master
|
|
8
|
+
# process can read them without any pipes or signals. Each worker is
|
|
9
|
+
# assigned a fixed-size slot in the shared region.
|
|
10
|
+
#
|
|
11
|
+
# Binary layout per slot (native byte order):
|
|
12
|
+
# pid uint32 4 bytes
|
|
13
|
+
# requests uint64 8 bytes
|
|
14
|
+
# backlog uint32 4 bytes
|
|
15
|
+
# started_at float64 8 bytes
|
|
16
|
+
# last_checkin float64 8 bytes
|
|
17
|
+
# booted uint8 1 byte
|
|
18
|
+
# 33 bytes total
|
|
19
|
+
class Stats
|
|
20
|
+
SLOT_FORMAT: ::String
|
|
21
|
+
|
|
22
|
+
SLOT_SIZE: untyped
|
|
23
|
+
|
|
24
|
+
@num_workers: Integer
|
|
25
|
+
|
|
26
|
+
@mmap: untyped
|
|
27
|
+
|
|
28
|
+
# Creates a new Stats instance backed by anonymous shared memory.
|
|
29
|
+
#
|
|
30
|
+
# Allocates a MAP_ANON | MAP_SHARED mmap region large enough for
|
|
31
|
+
# num_workers slots. Must be called before forking so that all
|
|
32
|
+
# worker processes share the same backing memory.
|
|
33
|
+
#
|
|
34
|
+
# @param num_workers [Integer] number of worker slots to allocate
|
|
35
|
+
# @return [void]
|
|
36
|
+
#
|
|
37
|
+
# @rbs (Integer num_workers) -> void
|
|
38
|
+
def initialize: (Integer num_workers) -> void
|
|
39
|
+
|
|
40
|
+
# Writes stats for a worker slot into shared memory.
|
|
41
|
+
#
|
|
42
|
+
# @param index [Integer] slot index to write into
|
|
43
|
+
# @param pid [Integer] worker process ID
|
|
44
|
+
# @param requests [Integer] total requests handled by this worker
|
|
45
|
+
# @param backlog [Integer] current queue depth
|
|
46
|
+
# @param started_at [Float] process start time as a Unix timestamp
|
|
47
|
+
# @param last_checkin [Float] time of last stats write as a Unix timestamp
|
|
48
|
+
# @param booted [Boolean] whether the worker has finished starting
|
|
49
|
+
# @return [void]
|
|
50
|
+
#
|
|
51
|
+
# @rbs (Integer index, pid: Integer, requests: Integer, backlog: Integer, started_at: Float, last_checkin: Float, booted: bool) -> void
|
|
52
|
+
def write: (Integer index, pid: Integer, requests: Integer, backlog: Integer, started_at: Float, last_checkin: Float, booted: bool) -> void
|
|
53
|
+
|
|
54
|
+
# Returns stats for all worker slots.
|
|
55
|
+
#
|
|
56
|
+
# @return [Array<Hash>] per-worker stat hashes with :pid, :requests, :backlog, :started_at, :last_checkin, and :booted
|
|
57
|
+
#
|
|
58
|
+
# @rbs () -> Array[Hash[Symbol, untyped]]
|
|
59
|
+
def all: () -> Array[Hash[Symbol, untyped]]
|
|
60
|
+
|
|
61
|
+
# Releases the shared memory mapping.
|
|
62
|
+
#
|
|
63
|
+
# @return [void]
|
|
64
|
+
#
|
|
65
|
+
# @rbs () -> void
|
|
66
|
+
def unmap: () -> void
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
# Reads stats for a worker slot from shared memory.
|
|
71
|
+
#
|
|
72
|
+
# @param index [Integer] slot index to read from
|
|
73
|
+
# @return [Hash] stat hash with :pid, :requests, :backlog, :started_at, :last_checkin, and :booted
|
|
74
|
+
#
|
|
75
|
+
# @rbs (Integer index) -> Hash[Symbol, untyped]
|
|
76
|
+
def read: (Integer index) -> Hash[Symbol, untyped]
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Generated from lib/raptor.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
# Main module for the Raptor web server.
|
|
4
|
+
#
|
|
5
|
+
# Raptor is a high-performance, multi-threaded, multi-process Ruby web server that
|
|
6
|
+
# leverages Ractors for parallel HTTP/1.1 and HTTP/2 request processing, native C
|
|
7
|
+
# extensions for HTTP parsing and HPACK compression, and NIO for non-blocking I/O.
|
|
8
|
+
module Raptor
|
|
9
|
+
end
|