raptor 0.20.2 → 0.22.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 +19 -0
- data/README.md +41 -64
- data/docs/raptor-vs-puma.md +22 -20
- data/ext/raptor_http2/raptor_http2.c +12 -0
- data/lib/raptor/binder.rb +39 -13
- data/lib/raptor/cli.rb +10 -0
- data/lib/raptor/cluster.rb +6 -3
- data/lib/raptor/detached_body.rb +293 -0
- data/lib/raptor/http.rb +18 -0
- data/lib/raptor/http1.rb +87 -35
- data/lib/raptor/http2.rb +501 -112
- data/lib/raptor/reactor.rb +992 -50
- data/lib/raptor/server.rb +12 -0
- data/lib/raptor/version.rb +1 -1
- data/lib/raptor.rb +1 -0
- data/sig/generated/raptor/binder.rbs +26 -13
- data/sig/generated/raptor/detached_body.rbs +127 -0
- data/sig/generated/raptor/http.rbs +12 -0
- data/sig/generated/raptor/http1.rbs +22 -16
- data/sig/generated/raptor/http2.rbs +240 -25
- data/sig/generated/raptor/reactor.rbs +388 -19
- metadata +4 -2
data/lib/raptor/server.rb
CHANGED
|
@@ -182,6 +182,18 @@ module Raptor
|
|
|
182
182
|
return true
|
|
183
183
|
end
|
|
184
184
|
|
|
185
|
+
if listener.is_a?(Binder::H2cListener)
|
|
186
|
+
@http2.eager_accept(
|
|
187
|
+
tcp_client,
|
|
188
|
+
tcp_client.object_id,
|
|
189
|
+
@reactor,
|
|
190
|
+
@thread_pool,
|
|
191
|
+
remote_addr,
|
|
192
|
+
HTTP_SCHEME
|
|
193
|
+
)
|
|
194
|
+
return true
|
|
195
|
+
end
|
|
196
|
+
|
|
185
197
|
@http1.eager_accept(
|
|
186
198
|
tcp_client,
|
|
187
199
|
tcp_client.object_id,
|
data/lib/raptor/version.rb
CHANGED
data/lib/raptor.rb
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Generated from lib/raptor/binder.rb with RBS::Inline
|
|
2
2
|
|
|
3
3
|
module Raptor
|
|
4
|
-
# Binds
|
|
5
|
-
# holds them for the server. Reconstructs listeners from inherited
|
|
6
|
-
# descriptors when provided (systemd socket activation, hot restart).
|
|
4
|
+
# Binds TCP, Unix, SSL, and cleartext HTTP/2 URIs to listening sockets
|
|
5
|
+
# and holds them for the server. Reconstructs listeners from inherited
|
|
6
|
+
# file descriptors when provided (systemd socket activation, hot restart).
|
|
7
7
|
class Binder
|
|
8
8
|
SOCKET_BACKLOG: ::Integer
|
|
9
9
|
|
|
@@ -27,9 +27,21 @@ module Raptor
|
|
|
27
27
|
def members: () -> [ :tcp_server, :ssl_context ]
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
# Marks a TCPServer as accepting cleartext HTTP/2 connections.
|
|
31
|
+
class H2cListener < Data
|
|
32
|
+
attr_reader tcp_server(): untyped
|
|
33
|
+
|
|
34
|
+
def self.new: (untyped tcp_server) -> instance
|
|
35
|
+
| (tcp_server: untyped) -> instance
|
|
36
|
+
|
|
37
|
+
def self.members: () -> [ :tcp_server ]
|
|
38
|
+
|
|
39
|
+
def members: () -> [ :tcp_server ]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
@uri_listeners: Hash[String, Array[TCPServer | UNIXServer | SslListener | H2cListener]]
|
|
31
43
|
|
|
32
|
-
@listeners: Array[TCPServer | UNIXServer | SslListener]
|
|
44
|
+
@listeners: Array[TCPServer | UNIXServer | SslListener | H2cListener]
|
|
33
45
|
|
|
34
46
|
@inherited_fds: Hash[String, Array[Integer]]
|
|
35
47
|
|
|
@@ -49,7 +61,7 @@ module Raptor
|
|
|
49
61
|
|
|
50
62
|
# Returns the array of listening sockets.
|
|
51
63
|
#
|
|
52
|
-
# @return [Array<TCPServer, UNIXServer, SslListener>]
|
|
64
|
+
# @return [Array<TCPServer, UNIXServer, SslListener, H2cListener>]
|
|
53
65
|
attr_reader listeners: untyped
|
|
54
66
|
|
|
55
67
|
# Creates a new Binder and binds each URI. `localhost` expands to both
|
|
@@ -66,7 +78,8 @@ module Raptor
|
|
|
66
78
|
def initialize: (Array[String] bind_uris, ?socket_backlog: Integer, ?inherited_fds: Hash[String, Array[Integer]]) -> void
|
|
67
79
|
|
|
68
80
|
# Returns the bound addresses as strings: TCP as `host:port`, Unix as
|
|
69
|
-
# the socket path, SSL as `ssl://host:port
|
|
81
|
+
# the socket path, SSL as `ssl://host:port`, and cleartext HTTP/2 as
|
|
82
|
+
# `h2c://host:port`.
|
|
70
83
|
#
|
|
71
84
|
# @return [Array<String>]
|
|
72
85
|
#
|
|
@@ -124,22 +137,22 @@ module Raptor
|
|
|
124
137
|
# Creates fresh listeners for the given URI.
|
|
125
138
|
#
|
|
126
139
|
# @param uri [URI] the parsed bind URI
|
|
127
|
-
# @return [Array<TCPServer, UNIXServer, SslListener>]
|
|
140
|
+
# @return [Array<TCPServer, UNIXServer, SslListener, H2cListener>]
|
|
128
141
|
# @raise [UnknownBindSchemeError] if the URI scheme is not supported
|
|
129
142
|
#
|
|
130
|
-
# @rbs (URI::Generic uri) -> Array[TCPServer | UNIXServer | SslListener]
|
|
131
|
-
def create_listeners: (URI::Generic uri) -> Array[TCPServer | UNIXServer | SslListener]
|
|
143
|
+
# @rbs (URI::Generic uri) -> Array[TCPServer | UNIXServer | SslListener | H2cListener]
|
|
144
|
+
def create_listeners: (URI::Generic uri) -> Array[TCPServer | UNIXServer | SslListener | H2cListener]
|
|
132
145
|
|
|
133
146
|
# Reconstructs listeners for the given URI from inherited file
|
|
134
147
|
# descriptors.
|
|
135
148
|
#
|
|
136
149
|
# @param uri [URI] the parsed bind URI the FDs were bound to
|
|
137
150
|
# @param filenos [Array<Integer>] file descriptors to wrap
|
|
138
|
-
# @return [Array<TCPServer, UNIXServer, SslListener>]
|
|
151
|
+
# @return [Array<TCPServer, UNIXServer, SslListener, H2cListener>]
|
|
139
152
|
# @raise [UnknownBindSchemeError] if the URI scheme is not supported
|
|
140
153
|
#
|
|
141
|
-
# @rbs (URI::Generic uri, Array[Integer] filenos) -> Array[TCPServer | UNIXServer | SslListener]
|
|
142
|
-
def restore_listeners: (URI::Generic uri, Array[Integer] filenos) -> Array[TCPServer | UNIXServer | SslListener]
|
|
154
|
+
# @rbs (URI::Generic uri, Array[Integer] filenos) -> Array[TCPServer | UNIXServer | SslListener | H2cListener]
|
|
155
|
+
def restore_listeners: (URI::Generic uri, Array[Integer] filenos) -> Array[TCPServer | UNIXServer | SslListener | H2cListener]
|
|
143
156
|
|
|
144
157
|
# Creates TCP server sockets for the given host and port.
|
|
145
158
|
#
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Generated from lib/raptor/detached_body.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Raptor
|
|
4
|
+
# A bounded response body that may be written after its application thread
|
|
5
|
+
# has returned.
|
|
6
|
+
class DetachedBody
|
|
7
|
+
DEFAULT_MAX_BUFFER_SIZE: untyped
|
|
8
|
+
|
|
9
|
+
# Tracks buffered bytes shared by a group of detached bodies.
|
|
10
|
+
class Budget
|
|
11
|
+
@max_size: Integer
|
|
12
|
+
|
|
13
|
+
@size: Atom
|
|
14
|
+
|
|
15
|
+
# @rbs (Integer max_size) -> void
|
|
16
|
+
def initialize: (Integer max_size) -> void
|
|
17
|
+
|
|
18
|
+
# @rbs (Integer bytes) -> bool
|
|
19
|
+
def reserve: (Integer bytes) -> bool
|
|
20
|
+
|
|
21
|
+
# @rbs (Integer bytes) -> void
|
|
22
|
+
def release: (Integer bytes) -> void
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
@on_close: (^(Symbol) -> void)?
|
|
26
|
+
|
|
27
|
+
@on_open: (^(DetachedBody) -> void)?
|
|
28
|
+
|
|
29
|
+
@finished: ^(Symbol) -> void
|
|
30
|
+
|
|
31
|
+
@dispatch: ^(Proc) -> void
|
|
32
|
+
|
|
33
|
+
@wake: ^() -> void
|
|
34
|
+
|
|
35
|
+
@budgets: Array[Budget]
|
|
36
|
+
|
|
37
|
+
@state: Atom
|
|
38
|
+
|
|
39
|
+
@max_buffer_size: Integer
|
|
40
|
+
|
|
41
|
+
# Creates a detached body with a bounded byte buffer.
|
|
42
|
+
#
|
|
43
|
+
# @param max_buffer_size [Integer] maximum body bytes waiting to be written
|
|
44
|
+
# @return [void]
|
|
45
|
+
#
|
|
46
|
+
# @rbs (?max_buffer_size: Integer) -> void
|
|
47
|
+
def initialize: (?max_buffer_size: Integer) -> void
|
|
48
|
+
|
|
49
|
+
# Registers a callback for when the server accepts the response stream.
|
|
50
|
+
#
|
|
51
|
+
# @yieldparam stream [DetachedBody] the opened response stream
|
|
52
|
+
# @return [DetachedBody]
|
|
53
|
+
#
|
|
54
|
+
# @rbs () { (DetachedBody stream) -> void } -> DetachedBody
|
|
55
|
+
def on_open: () { (DetachedBody stream) -> void } -> DetachedBody
|
|
56
|
+
|
|
57
|
+
# Registers a callback for when the response stream closes.
|
|
58
|
+
#
|
|
59
|
+
# @yieldparam reason [Symbol] why the stream closed
|
|
60
|
+
# @return [DetachedBody]
|
|
61
|
+
#
|
|
62
|
+
# @rbs () { (Symbol reason) -> void } -> DetachedBody
|
|
63
|
+
def on_close: () { (Symbol reason) -> void } -> DetachedBody
|
|
64
|
+
|
|
65
|
+
# Adds body bytes without waiting for socket or flow-control capacity.
|
|
66
|
+
#
|
|
67
|
+
# @param chunk [String] response body bytes
|
|
68
|
+
# @return [Symbol] `:accepted`, `:full`, or `:closed`
|
|
69
|
+
#
|
|
70
|
+
# @rbs (String chunk) -> Symbol
|
|
71
|
+
def try_write: (String chunk) -> Symbol
|
|
72
|
+
|
|
73
|
+
# Finishes the body after all accepted bytes have been written.
|
|
74
|
+
#
|
|
75
|
+
# @param trailers [Hash] trailing response headers
|
|
76
|
+
# @return [void]
|
|
77
|
+
#
|
|
78
|
+
# @rbs (?trailers: Hash[String, String | Array[String]]) -> void
|
|
79
|
+
def close: (?trailers: Hash[String, String | Array[String]]) -> void
|
|
80
|
+
|
|
81
|
+
# Returns whether the stream has closed.
|
|
82
|
+
#
|
|
83
|
+
# @return [Boolean]
|
|
84
|
+
#
|
|
85
|
+
# @rbs () -> bool
|
|
86
|
+
def closed?: () -> bool
|
|
87
|
+
|
|
88
|
+
# Connects the body to its reactor-owned response stream.
|
|
89
|
+
#
|
|
90
|
+
# @rbs (Array[Budget] budgets, ^() -> void wake, ^(Proc) -> void dispatch, ^(Symbol) -> void finished) -> bool
|
|
91
|
+
def attach: (Array[Budget] budgets, ^() -> void wake, ^(Proc) -> void dispatch, ^(Symbol) -> void finished) -> bool
|
|
92
|
+
|
|
93
|
+
# Notifies the application that its response stream is ready.
|
|
94
|
+
#
|
|
95
|
+
# @rbs () -> void
|
|
96
|
+
def open: () -> void
|
|
97
|
+
|
|
98
|
+
# Returns the size of the next buffered chunk, 0 when closing, or nil
|
|
99
|
+
# while waiting for more data.
|
|
100
|
+
#
|
|
101
|
+
# @rbs () -> Integer?
|
|
102
|
+
def next_size: () -> Integer?
|
|
103
|
+
|
|
104
|
+
# Removes up to `max_bytes` from the next buffered chunk.
|
|
105
|
+
#
|
|
106
|
+
# @rbs (Integer max_bytes) -> String?
|
|
107
|
+
def shift: (Integer max_bytes) -> String?
|
|
108
|
+
|
|
109
|
+
# Returns the response trailers supplied when the body closed.
|
|
110
|
+
#
|
|
111
|
+
# @rbs () -> Hash[String, String | Array[String]]
|
|
112
|
+
def trailers: () -> Hash[String, String | Array[String]]
|
|
113
|
+
|
|
114
|
+
# Closes the stream and invokes its callback exactly once.
|
|
115
|
+
#
|
|
116
|
+
# @rbs (Symbol reason) -> void
|
|
117
|
+
def finish: (Symbol reason) -> void
|
|
118
|
+
|
|
119
|
+
private
|
|
120
|
+
|
|
121
|
+
# @rbs (Integer bytes) -> bool
|
|
122
|
+
def reserve: (Integer bytes) -> bool
|
|
123
|
+
|
|
124
|
+
# @rbs (Integer bytes) -> void
|
|
125
|
+
def release: (Integer bytes) -> void
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -61,6 +61,18 @@ module Raptor
|
|
|
61
61
|
# @rbs (Hash[String, untyped] env_template, Integer? max_body_size) -> ^(Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
62
62
|
def self.parser_worker: (Hash[String, untyped] env_template, Integer? max_body_size) -> ^(Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
63
63
|
|
|
64
|
+
# Calls every `rack.response_finished` callback in reverse
|
|
65
|
+
# registration order, rescuing any that raise.
|
|
66
|
+
#
|
|
67
|
+
# @param env [Hash, nil] the Rack environment
|
|
68
|
+
# @param status [Integer, nil] the response status code
|
|
69
|
+
# @param headers [Hash, nil] the response headers
|
|
70
|
+
# @param error [Exception, nil] any error raised during processing, or nil on success
|
|
71
|
+
# @return [void]
|
|
72
|
+
#
|
|
73
|
+
# @rbs (Hash[String, untyped]? env, Integer? status, Hash[String, String | Array[String]]? headers, Exception? error) -> void
|
|
74
|
+
def self.call_response_finished: (Hash[String, untyped]? env, Integer? status, Hash[String, String | Array[String]]? headers, Exception? error) -> void
|
|
75
|
+
|
|
64
76
|
# Writes a Common Log Format entry to `io`. Write failures are silently
|
|
65
77
|
# ignored.
|
|
66
78
|
#
|
|
@@ -78,6 +78,16 @@ module Raptor
|
|
|
78
78
|
# @rbs (Hash[String, untyped] env) -> bool
|
|
79
79
|
def self.request_smuggling?: (Hash[String, untyped] env) -> bool
|
|
80
80
|
|
|
81
|
+
# Encodes one HTTP/1.1 response chunk.
|
|
82
|
+
#
|
|
83
|
+
# @rbs (String chunk) -> String
|
|
84
|
+
def self.encode_chunk: (String chunk) -> String
|
|
85
|
+
|
|
86
|
+
# Encodes the final HTTP/1.1 response chunk and its trailers.
|
|
87
|
+
#
|
|
88
|
+
# @rbs (Hash[String, String | Array[String]] trailers) -> String
|
|
89
|
+
def self.encode_trailers: (Hash[String, String | Array[String]] trailers) -> String
|
|
90
|
+
|
|
81
91
|
# Advances an HTTP/1.x request parse from the state hash's buffered
|
|
82
92
|
# bytes. A complete well-formed request returns with `:complete` set
|
|
83
93
|
# plus populated `:env` and `:body`; malformed or oversized input flips
|
|
@@ -282,21 +292,23 @@ module Raptor
|
|
|
282
292
|
# for another request.
|
|
283
293
|
#
|
|
284
294
|
# @param socket [TCPSocket] the client socket
|
|
295
|
+
# @param id [Integer] unique client identifier
|
|
285
296
|
# @param env [Hash] partial env hash from the HTTP parser
|
|
286
297
|
# @param parse_data [Hash] metadata from the parsing pass
|
|
287
298
|
# @param body [String, nil] decoded request body
|
|
299
|
+
# @param reactor [Reactor] the reactor managing the client connection
|
|
288
300
|
# @param request_count [Integer] number of requests handled on this connection
|
|
289
301
|
# @param remote_addr [String] client IP address
|
|
290
302
|
# @param url_scheme [String] "http" or "https"
|
|
291
303
|
# @return [Boolean] true if the connection should be kept alive
|
|
292
304
|
#
|
|
293
|
-
# @rbs (TCPSocket socket, Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, String? body, Integer request_count, String remote_addr, String url_scheme) -> bool
|
|
294
|
-
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
|
|
305
|
+
# @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
|
|
306
|
+
def process_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
|
|
295
307
|
|
|
296
308
|
# Calls the Rack app and writes its response for one request.
|
|
297
309
|
#
|
|
298
|
-
# @rbs (TCPSocket socket, Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, String? body, Integer request_count, String remote_addr, String url_scheme) -> bool
|
|
299
|
-
def perform_request: (TCPSocket socket, Hash[String, untyped] env, Hash[Symbol, untyped] parse_data, String? body, Integer request_count, String remote_addr, String url_scheme) -> bool
|
|
310
|
+
# @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
|
+
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
|
|
300
312
|
|
|
301
313
|
# Handles an exception raised while processing a request. Fires the
|
|
302
314
|
# `rack.response_finished` callbacks with the error, writes a 500
|
|
@@ -419,6 +431,12 @@ module Raptor
|
|
|
419
431
|
# @rbs (TCPSocket socket, Hash[String, String | Array[String]] hints) -> void
|
|
420
432
|
def send_early_hints: (TCPSocket socket, Hash[String, String | Array[String]] hints) -> void
|
|
421
433
|
|
|
434
|
+
# Starts a detached response, chunked on HTTP/1.1 and ended by closing
|
|
435
|
+
# the connection on HTTP/1.0.
|
|
436
|
+
#
|
|
437
|
+
# @rbs (TCPSocket socket, Integer status, Hash[String, String | Array[String]] headers, chunked: bool, keep_alive: bool) -> void
|
|
438
|
+
def write_detached_response: (TCPSocket socket, Integer status, Hash[String, String | Array[String]] headers, chunked: bool, keep_alive: bool) -> void
|
|
439
|
+
|
|
422
440
|
# Writes a complete HTTP response to the socket.
|
|
423
441
|
#
|
|
424
442
|
# @param socket [TCPSocket] the client socket to write to
|
|
@@ -580,18 +598,6 @@ module Raptor
|
|
|
580
598
|
# @rbs (TCPSocket socket, String response, untyped body, bool use_chunked) -> void
|
|
581
599
|
def write_enumerable_body: (TCPSocket socket, String response, untyped body, bool use_chunked) -> void
|
|
582
600
|
|
|
583
|
-
# Calls every `rack.response_finished` callback in reverse
|
|
584
|
-
# registration order, rescuing any that raise.
|
|
585
|
-
#
|
|
586
|
-
# @param env [Hash, nil] the Rack environment
|
|
587
|
-
# @param status [Integer, nil] the response status code
|
|
588
|
-
# @param headers [Hash, nil] the response headers
|
|
589
|
-
# @param error [Exception, nil] any error raised during processing, or nil on success
|
|
590
|
-
# @return [void]
|
|
591
|
-
#
|
|
592
|
-
# @rbs (Hash[String, untyped] env, Integer? status, Hash[String, String | Array[String]]? headers, Exception? error) -> void
|
|
593
|
-
def call_response_finished: (Hash[String, untyped] env, Integer? status, Hash[String, String | Array[String]]? headers, Exception? error) -> void
|
|
594
|
-
|
|
595
601
|
# Instance-level wrapper around {Http.write_access_log} that routes to
|
|
596
602
|
# the configured `@access_log_io`.
|
|
597
603
|
#
|