raptor 0.1.0 → 0.3.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 +4 -4
- data/CHANGELOG.md +16 -0
- data/README.md +21 -13
- data/lib/rackup/handler/raptor.rb +102 -0
- data/lib/raptor/binder.rb +1 -0
- data/lib/raptor/cli.rb +84 -1
- data/lib/raptor/cluster.rb +88 -23
- data/lib/raptor/http2.rb +99 -39
- data/lib/raptor/reactor.rb +12 -12
- data/lib/raptor/request.rb +197 -37
- data/lib/raptor/server.rb +22 -13
- data/lib/raptor/version.rb +1 -1
- data/lib/raptor.rb +3 -3
- data/sig/generated/rackup/handler/raptor.rbs +40 -0
- data/sig/generated/raptor/cli.rbs +37 -0
- data/sig/generated/raptor/cluster.rbs +32 -3
- data/sig/generated/raptor/http2.rbs +39 -11
- data/sig/generated/raptor/reactor.rbs +7 -5
- data/sig/generated/raptor/request.rbs +72 -8
- data/sig/generated/raptor/server.rbs +13 -7
- data/sig/generated/raptor.rbs +3 -3
- metadata +3 -1
data/lib/raptor/server.rb
CHANGED
|
@@ -15,16 +15,19 @@ module Raptor
|
|
|
15
15
|
#
|
|
16
16
|
# Supports TCP, Unix domain, and SSL listeners transparently. TCP_NODELAY is
|
|
17
17
|
# applied only to TCP sockets, and SSL handshakes are performed synchronously
|
|
18
|
-
# before
|
|
18
|
+
# before the connection is dispatched.
|
|
19
19
|
#
|
|
20
|
-
# For
|
|
21
|
-
#
|
|
22
|
-
#
|
|
20
|
+
# For HTTP/1.1 connections the first request is parsed inline on the server
|
|
21
|
+
# thread and dispatched directly to the thread pool, falling back to the
|
|
22
|
+
# reactor only when more data is needed. For HTTP/2 connections (negotiated
|
|
23
|
+
# via ALPN) the server sends initial SETTINGS and registers the connection
|
|
24
|
+
# with the reactor for frame processing through the ractor pool.
|
|
23
25
|
#
|
|
24
26
|
# @example
|
|
25
27
|
# binder = Binder.new(["tcp://0.0.0.0:3000"])
|
|
26
28
|
# reactor = Reactor.new(thread_pool, ractor_pool, client_options: {})
|
|
27
|
-
#
|
|
29
|
+
# request = Request.new(app, 3000)
|
|
30
|
+
# server = Server.new(binder, reactor, thread_pool, request)
|
|
28
31
|
# server.run
|
|
29
32
|
# # ... later
|
|
30
33
|
# server.shutdown
|
|
@@ -37,6 +40,7 @@ module Raptor
|
|
|
37
40
|
# @rbs @binder: Binder
|
|
38
41
|
# @rbs @reactor: Reactor
|
|
39
42
|
# @rbs @thread_pool: AtomicThreadPool
|
|
43
|
+
# @rbs @request: Request
|
|
40
44
|
# @rbs @running: AtomicBoolean
|
|
41
45
|
|
|
42
46
|
# Creates a new Server instance.
|
|
@@ -44,13 +48,15 @@ module Raptor
|
|
|
44
48
|
# @param binder [Binder] the binder managing listening sockets
|
|
45
49
|
# @param reactor [Reactor] the reactor for handling client connections
|
|
46
50
|
# @param thread_pool [AtomicThreadPool] thread pool for application processing
|
|
51
|
+
# @param request [Request] the HTTP/1.1 request handler
|
|
47
52
|
# @return [void]
|
|
48
53
|
#
|
|
49
|
-
# @rbs (Binder binder, Reactor reactor, AtomicThreadPool thread_pool) -> void
|
|
50
|
-
def initialize(binder, reactor, thread_pool)
|
|
54
|
+
# @rbs (Binder binder, Reactor reactor, AtomicThreadPool thread_pool, Request request) -> void
|
|
55
|
+
def initialize(binder, reactor, thread_pool, request)
|
|
51
56
|
@binder = binder
|
|
52
57
|
@reactor = reactor
|
|
53
58
|
@thread_pool = thread_pool
|
|
59
|
+
@request = request
|
|
54
60
|
@running = AtomicBoolean.new(true)
|
|
55
61
|
end
|
|
56
62
|
|
|
@@ -149,18 +155,21 @@ module Raptor
|
|
|
149
155
|
socket: ssl_socket,
|
|
150
156
|
remote_addr: remote_addr,
|
|
151
157
|
url_scheme: HTTPS_SCHEME,
|
|
152
|
-
protocol: :http2
|
|
158
|
+
protocol: :http2,
|
|
159
|
+
writer: Http2::Writer.new
|
|
153
160
|
)
|
|
154
161
|
|
|
155
162
|
return
|
|
156
163
|
end
|
|
157
164
|
end
|
|
158
165
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
166
|
+
@request.eager_accept(
|
|
167
|
+
client,
|
|
168
|
+
client.object_id,
|
|
169
|
+
reactor,
|
|
170
|
+
@thread_pool,
|
|
171
|
+
remote_addr,
|
|
172
|
+
url_scheme
|
|
164
173
|
)
|
|
165
174
|
end
|
|
166
175
|
end
|
data/lib/raptor/version.rb
CHANGED
data/lib/raptor.rb
CHANGED
|
@@ -5,9 +5,9 @@ require_relative "raptor/version"
|
|
|
5
5
|
|
|
6
6
|
# Main module for the Raptor web server.
|
|
7
7
|
#
|
|
8
|
-
# Raptor is a high-performance, multi-
|
|
9
|
-
#
|
|
10
|
-
# extensions for HTTP parsing and HPACK compression, and NIO for non-blocking I/O.
|
|
8
|
+
# Raptor is a high-performance, preloading, multi-process, multi-threaded Ruby 4+ web server
|
|
9
|
+
# implementing Rack 3+, leveraging Ractors for parallel HTTP/1.1 and HTTP/2 request processing,
|
|
10
|
+
# native C extensions for HTTP parsing and HPACK compression, and NIO for non-blocking I/O.
|
|
11
11
|
#
|
|
12
12
|
module Raptor
|
|
13
13
|
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Generated from lib/rackup/handler/raptor.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Rackup
|
|
4
|
+
module Handler
|
|
5
|
+
# Rack handler for booting Raptor through Rackup, `rails server`, or any
|
|
6
|
+
# other host that follows the Rack handler protocol.
|
|
7
|
+
module Raptor
|
|
8
|
+
DEFAULT_OPTIONS: untyped
|
|
9
|
+
|
|
10
|
+
# Boots a Raptor cluster serving the given Rack application.
|
|
11
|
+
#
|
|
12
|
+
# @param app [#call] the Rack application to serve
|
|
13
|
+
# @param options [Hash] handler options provided by Rackup or the host
|
|
14
|
+
# @yield [cluster] the cluster instance, before it starts running
|
|
15
|
+
# @return [void]
|
|
16
|
+
#
|
|
17
|
+
# @rbs (^(Hash[String, untyped]) -> [Integer, Hash[String, String | Array[String]], untyped] app, **untyped options) { (::Raptor::Cluster) -> void } -> void
|
|
18
|
+
def self.run: (^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ] app, **untyped options) { (::Raptor::Cluster) -> void } -> void
|
|
19
|
+
|
|
20
|
+
# Returns the handler-specific options surfaced by `rackup --help`.
|
|
21
|
+
#
|
|
22
|
+
# @return [Hash{String => String}] option spec to description mapping
|
|
23
|
+
#
|
|
24
|
+
# @rbs () -> Hash[String, String]
|
|
25
|
+
def self.valid_options: () -> Hash[String, String]
|
|
26
|
+
|
|
27
|
+
# Builds a Raptor cluster options hash from Rack handler options.
|
|
28
|
+
#
|
|
29
|
+
# Options not explicitly supplied by the user (per the `:user_supplied_options`
|
|
30
|
+
# key) are treated as host-provided defaults.
|
|
31
|
+
#
|
|
32
|
+
# @param app [#call] the Rack application to serve
|
|
33
|
+
# @param options [Hash] handler options provided by Rackup or the host
|
|
34
|
+
# @return [Hash{Symbol => untyped}] cluster configuration
|
|
35
|
+
#
|
|
36
|
+
# @rbs (^(Hash[String, untyped]) -> [Integer, Hash[String, String | Array[String]], untyped] app, Hash[Symbol, untyped] options) -> Hash[Symbol, untyped]
|
|
37
|
+
def self.build_cluster_options: (^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ] app, Hash[Symbol, untyped] options) -> Hash[Symbol, untyped]
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -20,6 +20,19 @@ module Raptor
|
|
|
20
20
|
|
|
21
21
|
DEFAULT_OPTIONS: untyped
|
|
22
22
|
|
|
23
|
+
# Loads a configuration file and returns the hash it evaluates to.
|
|
24
|
+
#
|
|
25
|
+
# The file is evaluated at the top level so constants like `Raptor::*` resolve
|
|
26
|
+
# the same as in a regular Ruby script. The final expression must be a Hash
|
|
27
|
+
# of cluster options (the same keys accepted by {Raptor::Cluster#initialize}).
|
|
28
|
+
#
|
|
29
|
+
# @param path [String] path to a Ruby file that evaluates to a Hash
|
|
30
|
+
# @return [Hash{Symbol => untyped}] cluster options
|
|
31
|
+
# @raise [ArgumentError] if the file does not evaluate to a Hash
|
|
32
|
+
#
|
|
33
|
+
# @rbs (String path) -> Hash[Symbol, untyped]
|
|
34
|
+
def self.load_config_file: (String path) -> Hash[Symbol, untyped]
|
|
35
|
+
|
|
23
36
|
@command: Symbol
|
|
24
37
|
|
|
25
38
|
@options: Hash[Symbol, untyped]
|
|
@@ -61,6 +74,30 @@ module Raptor
|
|
|
61
74
|
# @rbs () -> void
|
|
62
75
|
def run_stats: () -> void
|
|
63
76
|
|
|
77
|
+
# Scans argv for a `-c`/`--config` flag and returns the configured path.
|
|
78
|
+
#
|
|
79
|
+
# The pre-scan runs before the main OptionParser pass so the config file
|
|
80
|
+
# can be applied as a base layer that CLI args then override. All four
|
|
81
|
+
# OptionParser-accepted forms (`-c PATH`, `-cPATH`, `--config PATH`,
|
|
82
|
+
# `--config=PATH`) are recognized.
|
|
83
|
+
#
|
|
84
|
+
# @param argv [Array<String>] command-line arguments to scan
|
|
85
|
+
# @return [String, nil] the config path, or nil if no flag was supplied
|
|
86
|
+
#
|
|
87
|
+
# @rbs (Array[String] argv) -> String?
|
|
88
|
+
def extract_config_path: (Array[String] argv) -> String?
|
|
89
|
+
|
|
90
|
+
# Loads a config file and merges it into `@options` over the defaults.
|
|
91
|
+
#
|
|
92
|
+
# Top-level keys replace defaults; the nested `:client` hash is merged
|
|
93
|
+
# key-by-key so a config file does not need to restate every client option.
|
|
94
|
+
#
|
|
95
|
+
# @param path [String, nil] path to the config file, or nil to no-op
|
|
96
|
+
# @return [void]
|
|
97
|
+
#
|
|
98
|
+
# @rbs (String? path) -> void
|
|
99
|
+
def apply_config_file: (String? path) -> void
|
|
100
|
+
|
|
64
101
|
# Creates the OptionParser instance with all supported command-line options.
|
|
65
102
|
#
|
|
66
103
|
# @return [OptionParser] configured option parser
|
|
@@ -37,7 +37,9 @@ module Raptor
|
|
|
37
37
|
# @rbs (Hash[Symbol, untyped] options) -> void
|
|
38
38
|
def self.run: (Hash[Symbol, untyped] options) -> void
|
|
39
39
|
|
|
40
|
-
@
|
|
40
|
+
@phased_restarting: bool
|
|
41
|
+
|
|
42
|
+
@phased_restart_requested: bool
|
|
41
43
|
|
|
42
44
|
@stats: Stats
|
|
43
45
|
|
|
@@ -51,6 +53,12 @@ module Raptor
|
|
|
51
53
|
|
|
52
54
|
@binder: Binder
|
|
53
55
|
|
|
56
|
+
@pidfile: String?
|
|
57
|
+
|
|
58
|
+
@stats_file: String?
|
|
59
|
+
|
|
60
|
+
@on_error: ^(Hash[String, untyped]?, Exception) -> void | nil
|
|
61
|
+
|
|
54
62
|
@client_options: Hash[Symbol, Integer]
|
|
55
63
|
|
|
56
64
|
@worker_count: Integer
|
|
@@ -70,8 +78,12 @@ module Raptor
|
|
|
70
78
|
# @option options [Integer] :ractors number of ractors per worker process
|
|
71
79
|
# @option options [Integer] :workers number of worker processes
|
|
72
80
|
# @option options [Array<String>] :binds array of bind URIs
|
|
81
|
+
# @option options [#call] :app pre-built Rack application
|
|
73
82
|
# @option options [String] :rackup path to Rack configuration file
|
|
74
|
-
# @option options [Hash] :client client
|
|
83
|
+
# @option options [Hash] :client client configuration
|
|
84
|
+
# @option options [#call] :on_error callback invoked with (env, exception) when the Rack app raises
|
|
85
|
+
# @option options [String, nil] :stats_file path to write per-worker stats JSON, or nil to disable
|
|
86
|
+
# @option options [String, nil] :pidfile path to write the master PID to, or nil to disable
|
|
75
87
|
# @return [void]
|
|
76
88
|
#
|
|
77
89
|
# @rbs (Hash[Symbol, untyped] options) -> void
|
|
@@ -81,7 +93,8 @@ module Raptor
|
|
|
81
93
|
#
|
|
82
94
|
# Forks the configured number of worker processes and monitors them,
|
|
83
95
|
# automatically restarting any that exit unexpectedly. Handles graceful
|
|
84
|
-
# shutdown via INT or TERM signals,
|
|
96
|
+
# shutdown via INT or TERM signals, stats logging via USR1, and phased
|
|
97
|
+
# restart via USR2.
|
|
85
98
|
#
|
|
86
99
|
# Each worker process includes:
|
|
87
100
|
# - 1 server thread (continuously accepts connections with backpressure control)
|
|
@@ -114,6 +127,22 @@ module Raptor
|
|
|
114
127
|
# @rbs (Integer index) -> void
|
|
115
128
|
def spawn_worker: (Integer index) -> void
|
|
116
129
|
|
|
130
|
+
# Reaps any worker processes that have exited, respawning each one
|
|
131
|
+
# unless the cluster is shutting down.
|
|
132
|
+
#
|
|
133
|
+
# @return [Symbol] :no_children when there are no remaining children, otherwise :reaped
|
|
134
|
+
#
|
|
135
|
+
# @rbs () -> Symbol
|
|
136
|
+
def reap_workers: () -> Symbol
|
|
137
|
+
|
|
138
|
+
# Replaces each worker process one at a time, waiting for the new
|
|
139
|
+
# worker to boot before moving on to the next. Triggered by SIGUSR2.
|
|
140
|
+
#
|
|
141
|
+
# @return [void]
|
|
142
|
+
#
|
|
143
|
+
# @rbs () -> void
|
|
144
|
+
def perform_phased_restart: () -> void
|
|
145
|
+
|
|
117
146
|
# Runs the full server stack inside a worker process.
|
|
118
147
|
#
|
|
119
148
|
# Sets up and coordinates the reactor, server, ractor pool, thread pool,
|
|
@@ -8,6 +8,31 @@ module Raptor
|
|
|
8
8
|
# It integrates with the same reactor, ractor pool, and thread pool
|
|
9
9
|
# pipeline used by HTTP/1.1 connections.
|
|
10
10
|
class Http2
|
|
11
|
+
# Lock-free per-connection frame writer.
|
|
12
|
+
#
|
|
13
|
+
# Serializes concurrent socket writes from multiple stream workers
|
|
14
|
+
# without blocking any of them.
|
|
15
|
+
class Writer
|
|
16
|
+
IDLE: ::Symbol
|
|
17
|
+
|
|
18
|
+
@state: Atom
|
|
19
|
+
|
|
20
|
+
# Creates a new Writer.
|
|
21
|
+
#
|
|
22
|
+
# @rbs () -> void
|
|
23
|
+
def initialize: () -> void
|
|
24
|
+
|
|
25
|
+
# Writes frames to the socket, coordinating with concurrent writers
|
|
26
|
+
# so that exactly one thread is actively writing at any time.
|
|
27
|
+
#
|
|
28
|
+
# @param socket [OpenSSL::SSL::SSLSocket] the connection socket
|
|
29
|
+
# @param frames [Array<String>] frame bytes to write in order
|
|
30
|
+
# @return [void]
|
|
31
|
+
#
|
|
32
|
+
# @rbs (OpenSSL::SSL::SSLSocket socket, Array[String] frames) -> void
|
|
33
|
+
def write_frames: (OpenSSL::SSL::SSLSocket socket, Array[String] frames) -> void
|
|
34
|
+
end
|
|
35
|
+
|
|
11
36
|
FLAG_END_STREAM: ::Integer
|
|
12
37
|
|
|
13
38
|
FLAG_END_HEADERS: ::Integer
|
|
@@ -22,6 +47,8 @@ module Raptor
|
|
|
22
47
|
|
|
23
48
|
HOP_BY_HOP_HEADERS: untyped
|
|
24
49
|
|
|
50
|
+
@on_error: ^(Hash[String, untyped]?, Exception) -> void | nil
|
|
51
|
+
|
|
25
52
|
@server_port: Integer
|
|
26
53
|
|
|
27
54
|
@app: ^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ]
|
|
@@ -30,10 +57,11 @@ module Raptor
|
|
|
30
57
|
#
|
|
31
58
|
# @param app [#call] the Rack application to dispatch requests to
|
|
32
59
|
# @param server_port [Integer] port number used to populate SERVER_PORT in the Rack env
|
|
60
|
+
# @param on_error [#call, nil] callback invoked with (env, exception) when the Rack app raises
|
|
33
61
|
# @return [void]
|
|
34
62
|
#
|
|
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
|
|
63
|
+
# @rbs (^(Hash[String, untyped]) -> [Integer, Hash[String, String | Array[String]], untyped] app, Integer server_port, ?on_error: ^(Hash[String, untyped]?, Exception) -> void | nil) -> void
|
|
64
|
+
def initialize: (^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ] app, Integer server_port, ?on_error: ^(Hash[String, untyped]?, Exception) -> void | nil) -> void
|
|
37
65
|
|
|
38
66
|
# Builds the initial server SETTINGS frame to send on connection establishment.
|
|
39
67
|
#
|
|
@@ -88,38 +116,38 @@ module Raptor
|
|
|
88
116
|
# the response back as HTTP/2 frames.
|
|
89
117
|
#
|
|
90
118
|
# @param socket [OpenSSL::SSL::SSLSocket] the connection socket
|
|
91
|
-
# @param
|
|
119
|
+
# @param writer [Writer] lock-free frame writer for the connection
|
|
92
120
|
# @param stream_id [Integer] the HTTP/2 stream identifier
|
|
93
121
|
# @param headers [Array<Array(String, String)>] request headers
|
|
94
122
|
# @param body [String] request body
|
|
95
123
|
# @param remote_addr [String] the client IP address
|
|
96
124
|
# @return [void]
|
|
97
125
|
#
|
|
98
|
-
# @rbs (OpenSSL::SSL::SSLSocket socket,
|
|
99
|
-
def dispatch_stream_request: (OpenSSL::SSL::SSLSocket socket,
|
|
126
|
+
# @rbs (OpenSSL::SSL::SSLSocket socket, Writer writer, Integer stream_id, Array[[String, String]] headers, String body, remote_addr: String) -> void
|
|
127
|
+
def dispatch_stream_request: (OpenSSL::SSL::SSLSocket socket, Writer writer, Integer stream_id, Array[[ String, String ]] headers, String body, remote_addr: String) -> void
|
|
100
128
|
|
|
101
129
|
# Writes a Rack response as HTTP/2 frames to the socket.
|
|
102
130
|
#
|
|
103
131
|
# @param socket [OpenSSL::SSL::SSLSocket] the connection socket
|
|
104
|
-
# @param
|
|
132
|
+
# @param writer [Writer] lock-free frame writer for the connection
|
|
105
133
|
# @param stream_id [Integer] the HTTP/2 stream identifier
|
|
106
134
|
# @param status [Integer] HTTP status code
|
|
107
135
|
# @param headers [Hash] response headers from the Rack application
|
|
108
136
|
# @param body [Object] response body responding to each
|
|
109
137
|
# @return [void]
|
|
110
138
|
#
|
|
111
|
-
# @rbs (OpenSSL::SSL::SSLSocket socket,
|
|
112
|
-
def write_http2_response: (OpenSSL::SSL::SSLSocket socket,
|
|
139
|
+
# @rbs (OpenSSL::SSL::SSLSocket socket, Writer writer, Integer stream_id, Integer status, Hash[String, String | Array[String]] headers, untyped body) -> void
|
|
140
|
+
def write_http2_response: (OpenSSL::SSL::SSLSocket socket, Writer writer, Integer stream_id, Integer status, Hash[String, String | Array[String]] headers, untyped body) -> void
|
|
113
141
|
|
|
114
142
|
# Writes a 500 error response as HTTP/2 frames.
|
|
115
143
|
#
|
|
116
144
|
# @param socket [OpenSSL::SSL::SSLSocket] the connection socket
|
|
117
|
-
# @param
|
|
145
|
+
# @param writer [Writer] lock-free frame writer for the connection
|
|
118
146
|
# @param stream_id [Integer] the HTTP/2 stream identifier
|
|
119
147
|
# @return [void]
|
|
120
148
|
#
|
|
121
|
-
# @rbs (OpenSSL::SSL::SSLSocket socket,
|
|
122
|
-
def write_http2_error_response: (OpenSSL::SSL::SSLSocket socket,
|
|
149
|
+
# @rbs (OpenSSL::SSL::SSLSocket socket, Writer writer, Integer stream_id) -> void
|
|
150
|
+
def write_http2_error_response: (OpenSSL::SSL::SSLSocket socket, Writer writer, Integer stream_id) -> void
|
|
123
151
|
|
|
124
152
|
# Builds a Rack environment hash from HTTP/2 headers and body.
|
|
125
153
|
#
|
|
@@ -55,7 +55,7 @@ module Raptor
|
|
|
55
55
|
|
|
56
56
|
TIMEOUT_RESPONSE: ::String
|
|
57
57
|
|
|
58
|
-
@
|
|
58
|
+
@id_to_writer: Hash[Integer, untyped]
|
|
59
59
|
|
|
60
60
|
@id_to_timeout: Hash[Integer, TimeoutClient]
|
|
61
61
|
|
|
@@ -159,13 +159,15 @@ module Raptor
|
|
|
159
159
|
# @rbs (Integer id) -> TCPSocket?
|
|
160
160
|
def socket_for: (Integer id) -> TCPSocket?
|
|
161
161
|
|
|
162
|
-
# Returns the
|
|
162
|
+
# Returns the writer object associated with a given connection, if one
|
|
163
|
+
# was supplied when the connection was added. Used by protocol handlers
|
|
164
|
+
# that need to coordinate concurrent socket writes.
|
|
163
165
|
#
|
|
164
166
|
# @param id [Integer] unique client identifier
|
|
165
|
-
# @return [
|
|
167
|
+
# @return [Object, nil] the writer, if found
|
|
166
168
|
#
|
|
167
|
-
# @rbs (Integer id) ->
|
|
168
|
-
def
|
|
169
|
+
# @rbs (Integer id) -> untyped?
|
|
170
|
+
def writer_for: (Integer id) -> untyped?
|
|
169
171
|
|
|
170
172
|
# Updates connection state for an HTTP/2 connection after frame processing.
|
|
171
173
|
#
|
|
@@ -13,7 +13,7 @@ module Raptor
|
|
|
13
13
|
|
|
14
14
|
FILE_CHUNK_SIZE: untyped
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
READ_BUFFER_SIZE: untyped
|
|
17
17
|
|
|
18
18
|
WRITE_TIMEOUT: ::Integer
|
|
19
19
|
|
|
@@ -33,7 +33,9 @@ module Raptor
|
|
|
33
33
|
|
|
34
34
|
STATUS_WITH_NO_ENTITY_BODY: untyped
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
INTERNAL_SERVER_ERROR_RESPONSE: ::String
|
|
37
|
+
|
|
38
|
+
CONTENT_TOO_LARGE_RESPONSE: ::String
|
|
37
39
|
|
|
38
40
|
CONNECTION_CLOSE: ::String
|
|
39
41
|
|
|
@@ -63,6 +65,25 @@ module Raptor
|
|
|
63
65
|
def message: () -> String
|
|
64
66
|
end
|
|
65
67
|
|
|
68
|
+
# Decodes a chunked transfer-encoded body buffer.
|
|
69
|
+
#
|
|
70
|
+
# Returns the decoded bytes and a state symbol: `:complete` when the
|
|
71
|
+
# terminating zero-length chunk was found, `:too_large` when the decoded
|
|
72
|
+
# size would exceed `max_size`, or `:incomplete` otherwise.
|
|
73
|
+
#
|
|
74
|
+
# @param buffer [String] the raw body buffer to decode
|
|
75
|
+
# @param max_size [Integer, nil] maximum decoded body size, or nil for unlimited
|
|
76
|
+
# @return [Array(String, Symbol)] decoded body and completion state
|
|
77
|
+
#
|
|
78
|
+
# @rbs (String buffer, ?Integer? max_size) -> [String, Symbol]
|
|
79
|
+
def self.decode_chunked: (String buffer, ?Integer? max_size) -> [ String, Symbol ]
|
|
80
|
+
|
|
81
|
+
@on_error: ^(Hash[String, untyped]?, Exception) -> void | nil
|
|
82
|
+
|
|
83
|
+
@body_spool_threshold: Integer?
|
|
84
|
+
|
|
85
|
+
@max_body_size: Integer?
|
|
86
|
+
|
|
66
87
|
@server_port: Integer
|
|
67
88
|
|
|
68
89
|
@app: ^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ]
|
|
@@ -71,10 +92,29 @@ module Raptor
|
|
|
71
92
|
#
|
|
72
93
|
# @param app [#call] the Rack application to dispatch complete requests to
|
|
73
94
|
# @param server_port [Integer] port number used to populate SERVER_PORT in the Rack env
|
|
95
|
+
# @param client_options [Hash] client limits configuration
|
|
96
|
+
# @option client_options [Integer, nil] :max_body_size maximum request body size in bytes
|
|
97
|
+
# @option client_options [Integer, nil] :body_spool_threshold spool bodies larger than this to a tempfile
|
|
98
|
+
# @param on_error [#call, nil] callback invoked with (env, exception) when the Rack app raises
|
|
99
|
+
# @return [void]
|
|
100
|
+
#
|
|
101
|
+
# @rbs (^(Hash[String, untyped]) -> [Integer, Hash[String, String | Array[String]], untyped] app, Integer server_port, ?client_options: Hash[Symbol, untyped], ?on_error: ^(Hash[String, untyped]?, Exception) -> void | nil) -> void
|
|
102
|
+
def initialize: (^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ] app, Integer server_port, ?client_options: Hash[Symbol, untyped], ?on_error: ^(Hash[String, untyped]?, Exception) -> void | nil) -> void
|
|
103
|
+
|
|
104
|
+
# Eagerly reads and parses the first request on a freshly accepted
|
|
105
|
+
# connection on the server thread, dispatching directly to the thread pool
|
|
106
|
+
# when complete. Falls back to the reactor when more data is needed.
|
|
107
|
+
#
|
|
108
|
+
# @param socket [TCPSocket] the freshly accepted client socket
|
|
109
|
+
# @param id [Integer] unique client identifier
|
|
110
|
+
# @param reactor [Reactor] the reactor for fallback registration
|
|
111
|
+
# @param thread_pool [AtomicThreadPool] thread pool for application processing
|
|
112
|
+
# @param remote_addr [String] client IP address
|
|
113
|
+
# @param url_scheme [String] "http" or "https"
|
|
74
114
|
# @return [void]
|
|
75
115
|
#
|
|
76
|
-
# @rbs (
|
|
77
|
-
def
|
|
116
|
+
# @rbs (TCPSocket socket, Integer id, Reactor reactor, AtomicThreadPool thread_pool, String remote_addr, String url_scheme) -> void
|
|
117
|
+
def eager_accept: (TCPSocket socket, Integer id, Reactor reactor, AtomicThreadPool thread_pool, String remote_addr, String url_scheme) -> void
|
|
78
118
|
|
|
79
119
|
# Returns a Proc for HTTP parsing work in Ractor context.
|
|
80
120
|
#
|
|
@@ -154,8 +194,12 @@ module Raptor
|
|
|
154
194
|
# @rbs (TCPSocket socket, Integer id, Reactor reactor, AtomicThreadPool thread_pool, Integer request_count, String remote_addr, String url_scheme) -> void
|
|
155
195
|
def eager_keepalive: (TCPSocket socket, Integer id, Reactor reactor, AtomicThreadPool thread_pool, Integer request_count, String remote_addr, String url_scheme) -> void
|
|
156
196
|
|
|
157
|
-
# Re-registers a socket with the reactor for further processing
|
|
158
|
-
#
|
|
197
|
+
# Re-registers a socket with the reactor for further processing when
|
|
198
|
+
# an incomplete request is received during eager accept or eager keep-alive.
|
|
199
|
+
#
|
|
200
|
+
# The persisted flag selects between persistent_data_timeout (for
|
|
201
|
+
# kept-alive connections awaiting the next request) and chunk_data_timeout
|
|
202
|
+
# (for fresh connections awaiting the rest of the first request).
|
|
159
203
|
#
|
|
160
204
|
# @param socket [TCPSocket] the client socket
|
|
161
205
|
# @param id [Integer] unique client identifier
|
|
@@ -166,10 +210,20 @@ module Raptor
|
|
|
166
210
|
# @param request_count [Integer] number of requests handled on this connection
|
|
167
211
|
# @param remote_addr [String] client IP address
|
|
168
212
|
# @param url_scheme [String] "http" or "https"
|
|
213
|
+
# @param persisted [Boolean] whether the connection has already completed at least one request
|
|
214
|
+
# @return [void]
|
|
215
|
+
#
|
|
216
|
+
# @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
|
|
217
|
+
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
|
|
218
|
+
|
|
219
|
+
# Writes a 413 response and closes the socket. Used when a request body
|
|
220
|
+
# exceeds the configured maximum size.
|
|
221
|
+
#
|
|
222
|
+
# @param socket [TCPSocket] the client socket
|
|
169
223
|
# @return [void]
|
|
170
224
|
#
|
|
171
|
-
# @rbs (TCPSocket socket
|
|
172
|
-
def
|
|
225
|
+
# @rbs (TCPSocket socket) -> void
|
|
226
|
+
def reject_oversized: (TCPSocket socket) -> void
|
|
173
227
|
|
|
174
228
|
# Builds a Rack environment hash from parsed HTTP request data.
|
|
175
229
|
#
|
|
@@ -187,6 +241,16 @@ module Raptor
|
|
|
187
241
|
# @rbs (Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, String? body, TCPSocket socket, ?remote_addr: String, ?url_scheme: String) -> Hash[String, untyped]
|
|
188
242
|
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
243
|
|
|
244
|
+
# Builds the `rack.input` IO object for the request body. Returns an
|
|
245
|
+
# in-memory StringIO for bodies up to the spool threshold, or a Tempfile
|
|
246
|
+
# for larger bodies to bound per-worker memory.
|
|
247
|
+
#
|
|
248
|
+
# @param body [String, nil] decoded request body
|
|
249
|
+
# @return [IO] an IO-like object positioned at the start of the body
|
|
250
|
+
#
|
|
251
|
+
# @rbs (String? body) -> IO
|
|
252
|
+
def build_rack_input: (String? body) -> IO
|
|
253
|
+
|
|
190
254
|
# Determines whether the connection should be kept alive after the response.
|
|
191
255
|
#
|
|
192
256
|
# Returns false if the request limit has been reached. For HTTP/1.1, keep-alive
|
|
@@ -10,16 +10,19 @@ module Raptor
|
|
|
10
10
|
#
|
|
11
11
|
# Supports TCP, Unix domain, and SSL listeners transparently. TCP_NODELAY is
|
|
12
12
|
# applied only to TCP sockets, and SSL handshakes are performed synchronously
|
|
13
|
-
# before
|
|
13
|
+
# before the connection is dispatched.
|
|
14
14
|
#
|
|
15
|
-
# For
|
|
16
|
-
#
|
|
17
|
-
#
|
|
15
|
+
# For HTTP/1.1 connections the first request is parsed inline on the server
|
|
16
|
+
# thread and dispatched directly to the thread pool, falling back to the
|
|
17
|
+
# reactor only when more data is needed. For HTTP/2 connections (negotiated
|
|
18
|
+
# via ALPN) the server sends initial SETTINGS and registers the connection
|
|
19
|
+
# with the reactor for frame processing through the ractor pool.
|
|
18
20
|
#
|
|
19
21
|
# @example
|
|
20
22
|
# binder = Binder.new(["tcp://0.0.0.0:3000"])
|
|
21
23
|
# reactor = Reactor.new(thread_pool, ractor_pool, client_options: {})
|
|
22
|
-
#
|
|
24
|
+
# request = Request.new(app, 3000)
|
|
25
|
+
# server = Server.new(binder, reactor, thread_pool, request)
|
|
23
26
|
# server.run
|
|
24
27
|
# # ... later
|
|
25
28
|
# server.shutdown
|
|
@@ -36,6 +39,8 @@ module Raptor
|
|
|
36
39
|
|
|
37
40
|
@thread_pool: AtomicThreadPool
|
|
38
41
|
|
|
42
|
+
@request: Request
|
|
43
|
+
|
|
39
44
|
@running: AtomicBoolean
|
|
40
45
|
|
|
41
46
|
# Creates a new Server instance.
|
|
@@ -43,10 +48,11 @@ module Raptor
|
|
|
43
48
|
# @param binder [Binder] the binder managing listening sockets
|
|
44
49
|
# @param reactor [Reactor] the reactor for handling client connections
|
|
45
50
|
# @param thread_pool [AtomicThreadPool] thread pool for application processing
|
|
51
|
+
# @param request [Request] the HTTP/1.1 request handler
|
|
46
52
|
# @return [void]
|
|
47
53
|
#
|
|
48
|
-
# @rbs (Binder binder, Reactor reactor, AtomicThreadPool thread_pool) -> void
|
|
49
|
-
def initialize: (Binder binder, Reactor reactor, AtomicThreadPool thread_pool) -> void
|
|
54
|
+
# @rbs (Binder binder, Reactor reactor, AtomicThreadPool thread_pool, Request request) -> void
|
|
55
|
+
def initialize: (Binder binder, Reactor reactor, AtomicThreadPool thread_pool, Request request) -> void
|
|
50
56
|
|
|
51
57
|
# Starts the server's main accept loop in a new thread.
|
|
52
58
|
#
|
data/sig/generated/raptor.rbs
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
# Main module for the Raptor web server.
|
|
4
4
|
#
|
|
5
|
-
# Raptor is a high-performance, multi-
|
|
6
|
-
#
|
|
7
|
-
# extensions for HTTP parsing and HPACK compression, and NIO for non-blocking I/O.
|
|
5
|
+
# Raptor is a high-performance, preloading, multi-process, multi-threaded Ruby 4+ web server
|
|
6
|
+
# implementing Rack 3+, leveraging Ractors for parallel HTTP/1.1 and HTTP/2 request processing,
|
|
7
|
+
# native C extensions for HTTP parsing and HPACK compression, and NIO for non-blocking I/O.
|
|
8
8
|
module Raptor
|
|
9
9
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: raptor
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Joshua Young
|
|
@@ -114,6 +114,7 @@ files:
|
|
|
114
114
|
- ext/raptor_http2/extconf.rb
|
|
115
115
|
- ext/raptor_http2/huffman_table.h
|
|
116
116
|
- ext/raptor_http2/raptor_http2.c
|
|
117
|
+
- lib/rackup/handler/raptor.rb
|
|
117
118
|
- lib/raptor.rb
|
|
118
119
|
- lib/raptor/binder.rb
|
|
119
120
|
- lib/raptor/cli.rb
|
|
@@ -124,6 +125,7 @@ files:
|
|
|
124
125
|
- lib/raptor/server.rb
|
|
125
126
|
- lib/raptor/stats.rb
|
|
126
127
|
- lib/raptor/version.rb
|
|
128
|
+
- sig/generated/rackup/handler/raptor.rbs
|
|
127
129
|
- sig/generated/raptor.rbs
|
|
128
130
|
- sig/generated/raptor/binder.rbs
|
|
129
131
|
- sig/generated/raptor/cli.rbs
|