raptor 0.7.0 → 0.8.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.
@@ -17,10 +17,15 @@ module Raptor
17
17
 
18
18
  @state: Atom
19
19
 
20
+ @write_timeout: Integer
21
+
20
22
  # Creates a new Writer.
21
23
  #
22
- # @rbs () -> void
23
- def initialize: () -> void
24
+ # @param write_timeout [Integer] per-write socket timeout passed through to {Http.socket_write}
25
+ # @return [void]
26
+ #
27
+ # @rbs (write_timeout: Integer) -> void
28
+ def initialize: (write_timeout: Integer) -> void
24
29
 
25
30
  # Writes frames to the socket, coordinating with concurrent writers
26
31
  # so that exactly one thread is actively writing at any time.
@@ -36,7 +41,7 @@ module Raptor
36
41
  # Per-connection outbound flow-control accounting.
37
42
  #
38
43
  # Tracks the peer's connection-level and per-stream receive windows so
39
- # outbound DATA frames respect RFC 7540 §5.2. Threads dispatching stream
44
+ # outbound DATA frames respect RFC 7540 section 5.2. Threads dispatching stream
40
45
  # responses call `acquire` to reserve send capacity; threads applying
41
46
  # inbound WINDOW_UPDATE or SETTINGS frames call the mutating methods to
42
47
  # replenish it. The connection window and per-stream windows live in
@@ -93,7 +98,7 @@ module Raptor
93
98
  def add_stream_window: (Integer stream_id, Integer increment) -> void
94
99
 
95
100
  # Updates the peer's `SETTINGS_INITIAL_WINDOW_SIZE`. Shifts every
96
- # existing stream window by the delta as required by RFC 7540 §6.9.2.
101
+ # existing stream window by the delta as required by RFC 7540 section 6.9.2.
97
102
  #
98
103
  # @param new_size [Integer] the peer's new initial window size
99
104
  # @return [void]
@@ -140,28 +145,44 @@ module Raptor
140
145
 
141
146
  HOP_BY_HOP_HEADERS: untyped
142
147
 
148
+ @initial_settings_frame: String
149
+
143
150
  @on_error: ^(Hash[String, untyped]?, Exception) -> void | nil
144
151
 
152
+ @access_log_io: IO?
153
+
154
+ @write_timeout: Integer
155
+
145
156
  @server_port: Integer
146
157
 
147
158
  @app: ^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ]
148
159
 
160
+ # The initial server SETTINGS frame sent on every new HTTP/2 connection.
161
+ #
162
+ # @return [String] the encoded SETTINGS frame
163
+ attr_reader initial_settings_frame: untyped
164
+
149
165
  # Creates a new Http2 handler.
150
166
  #
151
167
  # @param app [#call] the Rack application to dispatch requests to
152
168
  # @param server_port [Integer] port number used to populate SERVER_PORT in the Rack env
169
+ # @param connection_options [Hash] per-connection settings shared across protocols
170
+ # @option connection_options [Integer] :write_timeout per-write socket timeout in seconds
171
+ # @param http2_options [Hash] HTTP/2-specific settings
172
+ # @option http2_options [Integer] :max_concurrent_streams maximum HTTP/2 concurrent streams per connection
173
+ # @param access_log_io [IO, nil] IO to write Common Log Format access entries to, or nil to disable
153
174
  # @param on_error [#call, nil] callback invoked with (env, exception) when the Rack app raises
154
175
  # @return [void]
155
176
  #
156
- # @rbs (^(Hash[String, untyped]) -> [Integer, Hash[String, String | Array[String]], untyped] app, Integer server_port, ?on_error: ^(Hash[String, untyped]?, Exception) -> void | nil) -> void
157
- 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
177
+ # @rbs (^(Hash[String, untyped]) -> [Integer, Hash[String, String | Array[String]], untyped] app, Integer server_port, ?connection_options: Hash[Symbol, untyped], ?http2_options: Hash[Symbol, untyped], ?access_log_io: IO?, ?on_error: ^(Hash[String, untyped]?, Exception) -> void | nil) -> void
178
+ def initialize: (^(Hash[String, untyped]) -> [ Integer, Hash[String, String | Array[String]], untyped ] app, Integer server_port, ?connection_options: Hash[Symbol, untyped], ?http2_options: Hash[Symbol, untyped], ?access_log_io: IO?, ?on_error: ^(Hash[String, untyped]?, Exception) -> void | nil) -> void
158
179
 
159
- # Builds the initial server SETTINGS frame to send on connection establishment.
180
+ # Creates a per-connection {Writer} configured with the handler's write timeout.
160
181
  #
161
- # @return [String] the encoded SETTINGS frame
182
+ # @return [Writer] a new per-connection frame writer
162
183
  #
163
- # @rbs () -> String
164
- def self.build_server_settings_frame: () -> String
184
+ # @rbs () -> Writer
185
+ def create_writer: () -> Writer
165
186
 
166
187
  # Processes HTTP/2 frames from the connection buffer.
167
188
  #
@@ -271,10 +292,10 @@ module Raptor
271
292
  # @param status [Integer] HTTP status code
272
293
  # @param headers [Hash] response headers from the Rack application
273
294
  # @param body [Object] response body responding to each
274
- # @return [void]
295
+ # @return [String] the response body size in bytes
275
296
  #
276
- # @rbs (OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Integer status, Hash[String, String | Array[String]] headers, untyped body) -> void
277
- def write_http2_response: (OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Integer status, Hash[String, String | Array[String]] headers, untyped body) -> void
297
+ # @rbs (OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Integer status, Hash[String, String | Array[String]] headers, untyped body) -> String
298
+ def write_http2_response: (OpenSSL::SSL::SSLSocket socket, Writer writer, FlowControl flow_control, Integer stream_id, Integer status, Hash[String, String | Array[String]] headers, untyped body) -> String
278
299
 
279
300
  # Writes a 500 error response as HTTP/2 frames.
280
301
  #
@@ -286,6 +307,18 @@ module Raptor
286
307
  # @rbs (OpenSSL::SSL::SSLSocket socket, Writer writer, Integer stream_id) -> void
287
308
  def write_http2_error_response: (OpenSSL::SSL::SSLSocket socket, Writer writer, Integer stream_id) -> void
288
309
 
310
+ # Instance-level wrapper around {Http.write_access_log} that routes to
311
+ # the configured `@access_log_io`.
312
+ #
313
+ # @param env [Hash] the Rack environment
314
+ # @param status [Integer] the response status code
315
+ # @param size [String] the response body size in bytes, or `-` if unknown
316
+ # @param remote_addr [String] the client IP address
317
+ # @return [void]
318
+ #
319
+ # @rbs (Hash[String, untyped] env, Integer status, String size, String remote_addr) -> void
320
+ def write_access_log: (Hash[String, untyped] env, Integer status, String size, String remote_addr) -> void
321
+
289
322
  # Builds a Rack environment hash from HTTP/2 headers and body.
290
323
  #
291
324
  # Translates HTTP/2 pseudo-headers into Rack-compatible environment keys
@@ -10,10 +10,12 @@ module Raptor
10
10
  # the server uses for backpressure control to prevent overload.
11
11
  #
12
12
  # @example
13
- # reactor = Reactor.new(ractor_pool, thread_pool, client_options: {
14
- # first_data_timeout: 30,
15
- # chunk_data_timeout: 10
16
- # })
13
+ # reactor = Reactor.new(
14
+ # ractor_pool,
15
+ # thread_pool,
16
+ # connection_options: { first_data_timeout: 30, chunk_data_timeout: 10 },
17
+ # http1_options: { persistent_data_timeout: 65 }
18
+ # )
17
19
  # reactor.run
18
20
  # reactor.add(id: client.object_id, socket: client)
19
21
  # # ... later
@@ -71,7 +73,11 @@ module Raptor
71
73
 
72
74
  @selector: NIO::Selector
73
75
 
74
- @client_options: Hash[Symbol, Integer]
76
+ @persistent_data_timeout: Integer
77
+
78
+ @chunk_data_timeout: Integer
79
+
80
+ @first_data_timeout: Integer
75
81
 
76
82
  @ractor_pool: untyped
77
83
 
@@ -81,14 +87,15 @@ module Raptor
81
87
  #
82
88
  # @param ractor_pool [RactorPool] ractor pool for HTTP parsing
83
89
  # @param thread_pool [AtomicThreadPool] thread pool for application processing
84
- # @param client_options [Hash] timeout configuration options
85
- # @option client_options [Integer] :first_data_timeout timeout for initial data
86
- # @option client_options [Integer] :chunk_data_timeout timeout for subsequent chunks
87
- # @option client_options [Integer] :persistent_data_timeout timeout for keep-alive connections
90
+ # @param connection_options [Hash] per-connection timeout configuration
91
+ # @option connection_options [Integer] :first_data_timeout timeout for initial data
92
+ # @option connection_options [Integer] :chunk_data_timeout timeout for subsequent chunks
93
+ # @param http1_options [Hash] HTTP/1.1-specific configuration
94
+ # @option http1_options [Integer] :persistent_data_timeout timeout for keep-alive idle connections
88
95
  # @return [void]
89
96
  #
90
- # @rbs (untyped ractor_pool, untyped thread_pool, client_options: Hash[Symbol, Integer]) -> void
91
- def initialize: (untyped ractor_pool, untyped thread_pool, client_options: Hash[Symbol, Integer]) -> void
97
+ # @rbs (untyped ractor_pool, untyped thread_pool, connection_options: Hash[Symbol, untyped], http1_options: Hash[Symbol, untyped]) -> void
98
+ def initialize: (untyped ractor_pool, untyped thread_pool, connection_options: Hash[Symbol, untyped], http1_options: Hash[Symbol, untyped]) -> void
92
99
 
93
100
  # Starts the reactor's main event loop in a new thread.
94
101
  #
@@ -14,9 +14,10 @@ module Raptor
14
14
  #
15
15
  # @example
16
16
  # binder = Binder.new(["tcp://0.0.0.0:3000"])
17
- # reactor = Reactor.new(ractor_pool, thread_pool, client_options: {})
18
- # request = Request.new(app, 3000)
19
- # server = Server.new(binder, reactor, thread_pool, request, client_options: { first_data_timeout: 30 })
17
+ # reactor = Reactor.new(ractor_pool, thread_pool, connection_options: {}, http1_options: {})
18
+ # http1 = Http1.new(app, 3000)
19
+ # http2 = Http2.new(app, 3000)
20
+ # server = Server.new(binder, reactor, thread_pool, http1, http2, connection_options: { first_data_timeout: 30 })
20
21
  # server.run
21
22
  # # ... later
22
23
  # server.shutdown
@@ -35,9 +36,13 @@ module Raptor
35
36
 
36
37
  @running: AtomicBoolean
37
38
 
38
- @client_options: Hash[Symbol, untyped]
39
+ @drain_accept_queue: bool
39
40
 
40
- @request: Request
41
+ @first_data_timeout: Integer
42
+
43
+ @http2: Http2
44
+
45
+ @http1: Http1
41
46
 
42
47
  @thread_pool: AtomicThreadPool
43
48
 
@@ -50,12 +55,14 @@ module Raptor
50
55
  # @param binder [Binder] the binder managing listening sockets
51
56
  # @param reactor [Reactor] the reactor for handling client connections
52
57
  # @param thread_pool [AtomicThreadPool] thread pool for application processing
53
- # @param request [Request] the HTTP/1.1 request handler
54
- # @param client_options [Hash] client timeout configuration, used to bound TLS handshakes
58
+ # @param http1 [Http1] the HTTP/1.1 handler
59
+ # @param http2 [Http2] the HTTP/2 handler (provides the initial SETTINGS frame)
60
+ # @param connection_options [Hash] per-connection timeout configuration, used to bound TLS handshakes
61
+ # @param drain_accept_queue [Boolean] whether to drain the kernel accept queue on shutdown
55
62
  # @return [void]
56
63
  #
57
- # @rbs (Binder binder, Reactor reactor, AtomicThreadPool thread_pool, Request request, client_options: Hash[Symbol, untyped]) -> void
58
- def initialize: (Binder binder, Reactor reactor, AtomicThreadPool thread_pool, Request request, client_options: Hash[Symbol, untyped]) -> void
64
+ # @rbs (Binder binder, Reactor reactor, AtomicThreadPool thread_pool, Http1 http1, Http2 http2, connection_options: Hash[Symbol, untyped], ?drain_accept_queue: bool) -> void
65
+ def initialize: (Binder binder, Reactor reactor, AtomicThreadPool thread_pool, Http1 http1, Http2 http2, connection_options: Hash[Symbol, untyped], ?drain_accept_queue: bool) -> void
59
66
 
60
67
  # Starts the server's main accept loop in a new thread.
61
68
  #
@@ -71,8 +78,9 @@ module Raptor
71
78
 
72
79
  # Gracefully shuts down the server.
73
80
  #
74
- # Stops accepting new connections and closes all listening sockets.
75
- # The server thread will exit after handling any in-flight accept operations.
81
+ # Stops accepting new connections and closes all listening sockets. When
82
+ # `drain_accept_queue` is enabled, dispatches every connection already in
83
+ # the kernel accept queue before closing the listeners.
76
84
  #
77
85
  # @return [void]
78
86
  #
@@ -81,6 +89,14 @@ module Raptor
81
89
 
82
90
  private
83
91
 
92
+ # Dispatches every connection already in the kernel accept queue for each
93
+ # listener until all are drained.
94
+ #
95
+ # @return [void]
96
+ #
97
+ # @rbs () -> void
98
+ def drain_accept_queue: () -> void
99
+
84
100
  # Accepts a connection from the given listener and dispatches it.
85
101
  #
86
102
  # For SSL listeners the TLS handshake is offloaded to the thread pool so
@@ -90,11 +106,10 @@ module Raptor
90
106
  # follow the HTTP/1.1 path.
91
107
  #
92
108
  # @param listener [TCPServer, UNIXServer, Binder::SslListener] the ready listener
93
- # @param reactor [Reactor] the reactor to dispatch connections to
94
- # @return [void]
109
+ # @return [Boolean] true if a connection was accepted, false if the listener had nothing to dispatch
95
110
  #
96
- # @rbs (TCPServer | UNIXServer | Binder::SslListener listener, Reactor reactor) -> void
97
- def accept_connection: (TCPServer | UNIXServer | Binder::SslListener listener, Reactor reactor) -> void
111
+ # @rbs (TCPServer | UNIXServer | Binder::SslListener listener) -> bool
112
+ def accept_connection: (TCPServer | UNIXServer | Binder::SslListener listener) -> bool
98
113
 
99
114
  # Performs the TLS handshake for an accepted SSL connection and dispatches
100
115
  # it through the HTTP/2 or HTTP/1.1 path. The handshake is bounded by
@@ -103,11 +118,10 @@ module Raptor
103
118
  # @param listener [Binder::SslListener] the SSL listener that accepted the connection
104
119
  # @param tcp_client [TCPSocket] the accepted TCP socket
105
120
  # @param remote_addr [String] the client's IP address
106
- # @param reactor [Reactor] the reactor to dispatch the connection to
107
121
  # @return [void]
108
122
  #
109
- # @rbs (Binder::SslListener listener, TCPSocket tcp_client, String remote_addr, Reactor reactor) -> void
110
- def dispatch_ssl_connection: (Binder::SslListener listener, TCPSocket tcp_client, String remote_addr, Reactor reactor) -> void
123
+ # @rbs (Binder::SslListener listener, TCPSocket tcp_client, String remote_addr) -> void
124
+ def dispatch_ssl_connection: (Binder::SslListener listener, TCPSocket tcp_client, String remote_addr) -> void
111
125
 
112
126
  # Drives a non-blocking SSL handshake to completion, bounded by the
113
127
  # configured first-data timeout. Returns true on success, false on
@@ -0,0 +1,42 @@
1
+ # Generated from lib/raptor/systemd.rb with RBS::Inline
2
+
3
+ module Raptor
4
+ # Integration with systemd's service notification protocol and
5
+ # socket-activation file descriptors.
6
+ module Systemd
7
+ LISTEN_FDS_START: ::Integer
8
+
9
+ LISTEN_FDNAMES_ENV: ::String
10
+
11
+ LISTEN_FDS_ENV: ::String
12
+
13
+ LISTEN_PID_ENV: ::String
14
+
15
+ NOTIFY_SOCKET_ENV: ::String
16
+
17
+ # Sends `message` to the systemd notification socket, returning true on
18
+ # success and false when the socket is unset or the send fails.
19
+ #
20
+ # @param message [String] notify protocol payload, e.g. "READY=1"
21
+ # @return [Boolean]
22
+ #
23
+ # @rbs (String message) -> bool
24
+ def self.notify: (String message) -> bool
25
+
26
+ # Returns the file descriptors passed in via socket activation, or an
27
+ # empty array when systemd has not exported any.
28
+ #
29
+ # @return [Array<Integer>]
30
+ #
31
+ # @rbs () -> Array[Integer]
32
+ def self.listen_fds: () -> Array[Integer]
33
+
34
+ # Clears the socket-activation environment variables so children don't
35
+ # act on stale values.
36
+ #
37
+ # @return [void]
38
+ #
39
+ # @rbs () -> void
40
+ def self.clear_listen_env: () -> void
41
+ end
42
+ 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.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Young
@@ -121,24 +121,28 @@ files:
121
121
  - lib/raptor/binder.rb
122
122
  - lib/raptor/cli.rb
123
123
  - lib/raptor/cluster.rb
124
+ - lib/raptor/http.rb
125
+ - lib/raptor/http1.rb
124
126
  - lib/raptor/http2.rb
125
127
  - lib/raptor/log.rb
126
128
  - lib/raptor/reactor.rb
127
- - lib/raptor/request.rb
128
129
  - lib/raptor/server.rb
129
130
  - lib/raptor/stats.rb
131
+ - lib/raptor/systemd.rb
130
132
  - lib/raptor/version.rb
131
133
  - sig/generated/rackup/handler/raptor.rbs
132
134
  - sig/generated/raptor.rbs
133
135
  - sig/generated/raptor/binder.rbs
134
136
  - sig/generated/raptor/cli.rbs
135
137
  - sig/generated/raptor/cluster.rbs
138
+ - sig/generated/raptor/http.rbs
139
+ - sig/generated/raptor/http1.rbs
136
140
  - sig/generated/raptor/http2.rbs
137
141
  - sig/generated/raptor/log.rbs
138
142
  - sig/generated/raptor/reactor.rbs
139
- - sig/generated/raptor/request.rbs
140
143
  - sig/generated/raptor/server.rbs
141
144
  - sig/generated/raptor/stats.rbs
145
+ - sig/generated/raptor/systemd.rbs
142
146
  - sig/generated/raptor/version.rbs
143
147
  homepage: https://github.com/joshuay03/raptor
144
148
  licenses: