puma 5.6.7 → 6.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +327 -16
  3. data/README.md +79 -29
  4. data/bin/puma-wild +1 -1
  5. data/docs/compile_options.md +34 -0
  6. data/docs/fork_worker.md +1 -3
  7. data/docs/kubernetes.md +12 -0
  8. data/docs/nginx.md +1 -1
  9. data/docs/restart.md +1 -0
  10. data/docs/systemd.md +3 -6
  11. data/docs/testing_benchmarks_local_files.md +150 -0
  12. data/docs/testing_test_rackup_ci_files.md +36 -0
  13. data/ext/puma_http11/extconf.rb +16 -9
  14. data/ext/puma_http11/http11_parser.c +1 -1
  15. data/ext/puma_http11/http11_parser.h +1 -1
  16. data/ext/puma_http11/http11_parser.java.rl +2 -2
  17. data/ext/puma_http11/http11_parser.rl +2 -2
  18. data/ext/puma_http11/http11_parser_common.rl +2 -2
  19. data/ext/puma_http11/mini_ssl.c +127 -19
  20. data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
  21. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +1 -1
  22. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +157 -53
  23. data/ext/puma_http11/puma_http11.c +17 -9
  24. data/lib/puma/app/status.rb +4 -4
  25. data/lib/puma/binder.rb +50 -53
  26. data/lib/puma/cli.rb +16 -18
  27. data/lib/puma/client.rb +86 -19
  28. data/lib/puma/cluster/worker.rb +18 -11
  29. data/lib/puma/cluster/worker_handle.rb +4 -1
  30. data/lib/puma/cluster.rb +102 -40
  31. data/lib/puma/commonlogger.rb +21 -14
  32. data/lib/puma/configuration.rb +77 -59
  33. data/lib/puma/const.rb +129 -92
  34. data/lib/puma/control_cli.rb +15 -11
  35. data/lib/puma/detect.rb +7 -4
  36. data/lib/puma/dsl.rb +250 -56
  37. data/lib/puma/error_logger.rb +18 -9
  38. data/lib/puma/events.rb +6 -126
  39. data/lib/puma/io_buffer.rb +39 -4
  40. data/lib/puma/jruby_restart.rb +2 -1
  41. data/lib/puma/launcher/bundle_pruner.rb +104 -0
  42. data/lib/puma/launcher.rb +102 -175
  43. data/lib/puma/log_writer.rb +147 -0
  44. data/lib/puma/minissl/context_builder.rb +26 -12
  45. data/lib/puma/minissl.rb +104 -11
  46. data/lib/puma/null_io.rb +16 -2
  47. data/lib/puma/plugin/systemd.rb +90 -0
  48. data/lib/puma/plugin/tmp_restart.rb +1 -1
  49. data/lib/puma/rack/builder.rb +6 -6
  50. data/lib/puma/rack/urlmap.rb +1 -1
  51. data/lib/puma/rack_default.rb +19 -4
  52. data/lib/puma/reactor.rb +19 -10
  53. data/lib/puma/request.rb +365 -170
  54. data/lib/puma/runner.rb +56 -20
  55. data/lib/puma/sd_notify.rb +149 -0
  56. data/lib/puma/server.rb +137 -89
  57. data/lib/puma/single.rb +13 -11
  58. data/lib/puma/state_file.rb +3 -6
  59. data/lib/puma/thread_pool.rb +57 -19
  60. data/lib/puma/util.rb +0 -11
  61. data/lib/puma.rb +9 -10
  62. data/lib/rack/handler/puma.rb +113 -86
  63. data/tools/Dockerfile +2 -2
  64. metadata +11 -7
  65. data/lib/puma/queue_close.rb +0 -26
  66. data/lib/puma/systemd.rb +0 -46
  67. data/lib/rack/version_restriction.rb +0 -15
data/lib/puma/const.rb CHANGED
@@ -5,7 +5,6 @@ module Puma
5
5
  class UnsupportedOption < RuntimeError
6
6
  end
7
7
 
8
-
9
8
  # Every standard HTTP code mapped to the appropriate message. These are
10
9
  # used so frequently that they are placed directly in Puma for easy
11
10
  # access rather than Puma::Const itself.
@@ -19,6 +18,7 @@ module Puma
19
18
  100 => 'Continue',
20
19
  101 => 'Switching Protocols',
21
20
  102 => 'Processing',
21
+ 103 => 'Early Hints',
22
22
  200 => 'OK',
23
23
  201 => 'Created',
24
24
  202 => 'Accepted',
@@ -50,16 +50,16 @@ module Puma
50
50
  410 => 'Gone',
51
51
  411 => 'Length Required',
52
52
  412 => 'Precondition Failed',
53
- 413 => 'Payload Too Large',
53
+ 413 => 'Content Too Large',
54
54
  414 => 'URI Too Long',
55
55
  415 => 'Unsupported Media Type',
56
56
  416 => 'Range Not Satisfiable',
57
57
  417 => 'Expectation Failed',
58
- 418 => 'I\'m A Teapot',
59
58
  421 => 'Misdirected Request',
60
- 422 => 'Unprocessable Entity',
59
+ 422 => 'Unprocessable Content',
61
60
  423 => 'Locked',
62
61
  424 => 'Failed Dependency',
62
+ 425 => 'Too Early',
63
63
  426 => 'Upgrade Required',
64
64
  428 => 'Precondition Required',
65
65
  429 => 'Too Many Requests',
@@ -74,7 +74,7 @@ module Puma
74
74
  506 => 'Variant Also Negotiates',
75
75
  507 => 'Insufficient Storage',
76
76
  508 => 'Loop Detected',
77
- 510 => 'Not Extended',
77
+ 510 => 'Not Extended (OBSOLETED)',
78
78
  511 => 'Network Authentication Required'
79
79
  }.freeze
80
80
 
@@ -100,55 +100,40 @@ module Puma
100
100
  # too taxing on performance.
101
101
  module Const
102
102
 
103
- PUMA_VERSION = VERSION = "5.6.7".freeze
104
- CODE_NAME = "Birdie's Version".freeze
103
+ PUMA_VERSION = VERSION = "6.4.2"
104
+ CODE_NAME = "The Eagle of Durango"
105
105
 
106
- PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
106
+ PUMA_SERVER_STRING = ["puma", PUMA_VERSION, CODE_NAME].join(" ").freeze
107
107
 
108
108
  FAST_TRACK_KA_TIMEOUT = 0.2
109
109
 
110
- # The default number of seconds for another request within a persistent
111
- # session.
112
- PERSISTENT_TIMEOUT = 20
113
-
114
- # The default number of seconds to wait until we get the first data
115
- # for the request
116
- FIRST_DATA_TIMEOUT = 30
117
-
118
110
  # How long to wait when getting some write blocking on the socket when
119
111
  # sending data back
120
112
  WRITE_TIMEOUT = 10
121
113
 
122
- # How many requests to attempt inline before sending a client back to
123
- # the reactor to be subject to normal ordering. The idea here is that
124
- # we amortize the cost of going back to the reactor for a well behaved
125
- # but very "greedy" client across 10 requests. This prevents a not
126
- # well behaved client from monopolizing the thread forever.
127
- MAX_FAST_INLINE = 10
128
-
129
114
  # The original URI requested by the client.
130
- REQUEST_URI= 'REQUEST_URI'.freeze
131
- REQUEST_PATH = 'REQUEST_PATH'.freeze
132
- QUERY_STRING = 'QUERY_STRING'.freeze
133
- CONTENT_LENGTH = "CONTENT_LENGTH".freeze
115
+ REQUEST_URI= "REQUEST_URI"
116
+ REQUEST_PATH = "REQUEST_PATH"
117
+ QUERY_STRING = "QUERY_STRING"
118
+ CONTENT_LENGTH = "CONTENT_LENGTH"
134
119
 
135
- PATH_INFO = 'PATH_INFO'.freeze
120
+ PATH_INFO = "PATH_INFO"
136
121
 
137
- PUMA_TMP_BASE = "puma".freeze
122
+ PUMA_TMP_BASE = "puma"
138
123
 
139
124
  ERROR_RESPONSE = {
140
125
  # Indicate that we couldn't parse the request
141
- 400 => "HTTP/1.1 400 Bad Request\r\n\r\n".freeze,
126
+ 400 => "HTTP/1.1 400 Bad Request\r\n\r\n",
142
127
  # The standard empty 404 response for bad requests. Use Error4040Handler for custom stuff.
143
- 404 => "HTTP/1.1 404 Not Found\r\nConnection: close\r\nServer: Puma #{PUMA_VERSION}\r\n\r\nNOT FOUND".freeze,
128
+ 404 => "HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n",
144
129
  # The standard empty 408 response for requests that timed out.
145
- 408 => "HTTP/1.1 408 Request Timeout\r\nConnection: close\r\nServer: Puma #{PUMA_VERSION}\r\n\r\n".freeze,
130
+ 408 => "HTTP/1.1 408 Request Timeout\r\nConnection: close\r\n\r\n",
146
131
  # Indicate that there was an internal error, obviously.
147
- 500 => "HTTP/1.1 500 Internal Server Error\r\n\r\n".freeze,
132
+ 500 => "HTTP/1.1 500 Internal Server Error\r\n\r\n",
148
133
  # Incorrect or invalid header value
149
- 501 => "HTTP/1.1 501 Not Implemented\r\n\r\n".freeze,
134
+ 501 => "HTTP/1.1 501 Not Implemented\r\n\r\n",
150
135
  # A common header for indicating the server is too busy. Not used yet.
151
- 503 => "HTTP/1.1 503 Service Unavailable\r\n\r\nBUSY".freeze
136
+ 503 => "HTTP/1.1 503 Service Unavailable\r\n\r\n"
152
137
  }.freeze
153
138
 
154
139
  # The basic max request size we'll try to read.
@@ -161,84 +146,136 @@ module Puma
161
146
  # Maximum request body size before it is moved out of memory and into a tempfile for reading.
162
147
  MAX_BODY = MAX_HEADER
163
148
 
164
- REQUEST_METHOD = "REQUEST_METHOD".freeze
165
- HEAD = "HEAD".freeze
149
+ REQUEST_METHOD = "REQUEST_METHOD"
150
+ HEAD = "HEAD"
151
+
152
+ # based on https://www.rfc-editor.org/rfc/rfc9110.html#name-overview,
153
+ # with CONNECT removed, and PATCH added
154
+ SUPPORTED_HTTP_METHODS = %w[HEAD GET POST PUT DELETE OPTIONS TRACE PATCH].freeze
155
+
156
+ # list from https://www.iana.org/assignments/http-methods/http-methods.xhtml
157
+ # as of 04-May-23
158
+ IANA_HTTP_METHODS = %w[
159
+ ACL
160
+ BASELINE-CONTROL
161
+ BIND
162
+ CHECKIN
163
+ CHECKOUT
164
+ CONNECT
165
+ COPY
166
+ DELETE
167
+ GET
168
+ HEAD
169
+ LABEL
170
+ LINK
171
+ LOCK
172
+ MERGE
173
+ MKACTIVITY
174
+ MKCALENDAR
175
+ MKCOL
176
+ MKREDIRECTREF
177
+ MKWORKSPACE
178
+ MOVE
179
+ OPTIONS
180
+ ORDERPATCH
181
+ PATCH
182
+ POST
183
+ PRI
184
+ PROPFIND
185
+ PROPPATCH
186
+ PUT
187
+ REBIND
188
+ REPORT
189
+ SEARCH
190
+ TRACE
191
+ UNBIND
192
+ UNCHECKOUT
193
+ UNLINK
194
+ UNLOCK
195
+ UPDATE
196
+ UPDATEREDIRECTREF
197
+ VERSION-CONTROL
198
+ ].freeze
199
+
166
200
  # ETag is based on the apache standard of hex mtime-size-inode (inode is 0 on win32)
167
- LINE_END = "\r\n".freeze
168
- REMOTE_ADDR = "REMOTE_ADDR".freeze
169
- HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR".freeze
170
- HTTP_X_FORWARDED_SSL = "HTTP_X_FORWARDED_SSL".freeze
171
- HTTP_X_FORWARDED_SCHEME = "HTTP_X_FORWARDED_SCHEME".freeze
172
- HTTP_X_FORWARDED_PROTO = "HTTP_X_FORWARDED_PROTO".freeze
201
+ LINE_END = "\r\n"
202
+ REMOTE_ADDR = "REMOTE_ADDR"
203
+ HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR"
204
+ HTTP_X_FORWARDED_SSL = "HTTP_X_FORWARDED_SSL"
205
+ HTTP_X_FORWARDED_SCHEME = "HTTP_X_FORWARDED_SCHEME"
206
+ HTTP_X_FORWARDED_PROTO = "HTTP_X_FORWARDED_PROTO"
173
207
 
174
- SERVER_NAME = "SERVER_NAME".freeze
175
- SERVER_PORT = "SERVER_PORT".freeze
176
- HTTP_HOST = "HTTP_HOST".freeze
177
- PORT_80 = "80".freeze
178
- PORT_443 = "443".freeze
179
- LOCALHOST = "localhost".freeze
180
- LOCALHOST_IP = "127.0.0.1".freeze
208
+ SERVER_NAME = "SERVER_NAME"
209
+ SERVER_PORT = "SERVER_PORT"
210
+ HTTP_HOST = "HTTP_HOST"
211
+ PORT_80 = "80"
212
+ PORT_443 = "443"
213
+ LOCALHOST = "localhost"
214
+ LOCALHOST_IPV4 = "127.0.0.1"
215
+ LOCALHOST_IPV6 = "::1"
216
+ UNSPECIFIED_IPV4 = "0.0.0.0"
217
+ UNSPECIFIED_IPV6 = "::"
181
218
 
182
- SERVER_PROTOCOL = "SERVER_PROTOCOL".freeze
183
- HTTP_11 = "HTTP/1.1".freeze
219
+ SERVER_PROTOCOL = "SERVER_PROTOCOL"
220
+ HTTP_11 = "HTTP/1.1"
184
221
 
185
- SERVER_SOFTWARE = "SERVER_SOFTWARE".freeze
186
- GATEWAY_INTERFACE = "GATEWAY_INTERFACE".freeze
187
- CGI_VER = "CGI/1.2".freeze
222
+ SERVER_SOFTWARE = "SERVER_SOFTWARE"
223
+ GATEWAY_INTERFACE = "GATEWAY_INTERFACE"
224
+ CGI_VER = "CGI/1.2"
188
225
 
189
- STOP_COMMAND = "?".freeze
190
- HALT_COMMAND = "!".freeze
191
- RESTART_COMMAND = "R".freeze
226
+ STOP_COMMAND = "?"
227
+ HALT_COMMAND = "!"
228
+ RESTART_COMMAND = "R"
192
229
 
193
- RACK_INPUT = "rack.input".freeze
194
- RACK_URL_SCHEME = "rack.url_scheme".freeze
195
- RACK_AFTER_REPLY = "rack.after_reply".freeze
196
- PUMA_SOCKET = "puma.socket".freeze
197
- PUMA_CONFIG = "puma.config".freeze
198
- PUMA_PEERCERT = "puma.peercert".freeze
230
+ RACK_INPUT = "rack.input"
231
+ RACK_URL_SCHEME = "rack.url_scheme"
232
+ RACK_AFTER_REPLY = "rack.after_reply"
233
+ PUMA_SOCKET = "puma.socket"
234
+ PUMA_CONFIG = "puma.config"
235
+ PUMA_PEERCERT = "puma.peercert"
199
236
 
200
- HTTP = "http".freeze
201
- HTTPS = "https".freeze
237
+ HTTP = "http"
238
+ HTTPS = "https"
202
239
 
203
- HTTPS_KEY = "HTTPS".freeze
240
+ HTTPS_KEY = "HTTPS"
204
241
 
205
- HTTP_VERSION = "HTTP_VERSION".freeze
206
- HTTP_CONNECTION = "HTTP_CONNECTION".freeze
207
- HTTP_EXPECT = "HTTP_EXPECT".freeze
208
- CONTINUE = "100-continue".freeze
242
+ HTTP_VERSION = "HTTP_VERSION"
243
+ HTTP_CONNECTION = "HTTP_CONNECTION"
244
+ HTTP_EXPECT = "HTTP_EXPECT"
245
+ CONTINUE = "100-continue"
209
246
 
210
- HTTP_11_100 = "HTTP/1.1 100 Continue\r\n\r\n".freeze
211
- HTTP_11_200 = "HTTP/1.1 200 OK\r\n".freeze
212
- HTTP_10_200 = "HTTP/1.0 200 OK\r\n".freeze
247
+ HTTP_11_100 = "HTTP/1.1 100 Continue\r\n\r\n"
248
+ HTTP_11_200 = "HTTP/1.1 200 OK\r\n"
249
+ HTTP_10_200 = "HTTP/1.0 200 OK\r\n"
213
250
 
214
- CLOSE = "close".freeze
215
- KEEP_ALIVE = "keep-alive".freeze
251
+ CLOSE = "close"
252
+ KEEP_ALIVE = "keep-alive"
216
253
 
217
- CONTENT_LENGTH2 = "content-length".freeze
218
- CONTENT_LENGTH_S = "Content-Length: ".freeze
219
- TRANSFER_ENCODING = "transfer-encoding".freeze
220
- TRANSFER_ENCODING2 = "HTTP_TRANSFER_ENCODING".freeze
254
+ CONTENT_LENGTH2 = "content-length"
255
+ CONTENT_LENGTH_S = "Content-Length: "
256
+ TRANSFER_ENCODING = "transfer-encoding"
257
+ TRANSFER_ENCODING2 = "HTTP_TRANSFER_ENCODING"
221
258
 
222
- CONNECTION_CLOSE = "Connection: close\r\n".freeze
223
- CONNECTION_KEEP_ALIVE = "Connection: Keep-Alive\r\n".freeze
259
+ CONNECTION_CLOSE = "Connection: close\r\n"
260
+ CONNECTION_KEEP_ALIVE = "Connection: Keep-Alive\r\n"
224
261
 
225
- TRANSFER_ENCODING_CHUNKED = "Transfer-Encoding: chunked\r\n".freeze
226
- CLOSE_CHUNKED = "0\r\n\r\n".freeze
262
+ TRANSFER_ENCODING_CHUNKED = "Transfer-Encoding: chunked\r\n"
263
+ CLOSE_CHUNKED = "0\r\n\r\n"
227
264
 
228
- CHUNKED = "chunked".freeze
265
+ CHUNKED = "chunked"
229
266
 
230
- COLON = ": ".freeze
267
+ COLON = ": "
231
268
 
232
- NEWLINE = "\n".freeze
269
+ NEWLINE = "\n"
233
270
 
234
- HIJACK_P = "rack.hijack?".freeze
235
- HIJACK = "rack.hijack".freeze
236
- HIJACK_IO = "rack.hijack_io".freeze
271
+ HIJACK_P = "rack.hijack?"
272
+ HIJACK = "rack.hijack"
273
+ HIJACK_IO = "rack.hijack_io"
237
274
 
238
- EARLY_HINTS = "rack.early_hints".freeze
275
+ EARLY_HINTS = "rack.early_hints"
239
276
 
240
277
  # Illegal character in the key or value of response header
241
- DQUOTE = "\"".freeze
278
+ DQUOTE = "\""
242
279
  HTTP_HEADER_DELIMITER = Regexp.escape("(),/:;<=>?@[]{}\\").freeze
243
280
  ILLEGAL_HEADER_KEY_REGEX = /[\x00-\x20#{DQUOTE}#{HTTP_HEADER_DELIMITER}]/.freeze
244
281
  # header values can contain HTAB?
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'optparse'
4
- require_relative 'state_file'
5
4
  require_relative 'const'
6
5
  require_relative 'detect'
7
- require_relative 'configuration'
8
6
  require 'uri'
9
7
  require 'socket'
10
8
 
@@ -33,9 +31,6 @@ module Puma
33
31
  'worker-count-up' => 'SIGTTIN'
34
32
  }.freeze
35
33
 
36
- # @deprecated 6.0.0
37
- COMMANDS = CMD_PATH_SIG_MAP.keys.freeze
38
-
39
34
  # commands that cannot be used in a request
40
35
  NO_REQ_COMMANDS = %w[info reopen-log worker-count-down worker-count-up].freeze
41
36
 
@@ -129,6 +124,9 @@ module Puma
129
124
  end
130
125
 
131
126
  if @config_file
127
+ require_relative 'configuration'
128
+ require_relative 'log_writer'
129
+
132
130
  config = Puma::Configuration.new({ config_files: [@config_file] }, {})
133
131
  config.load
134
132
  @state ||= config.options[:state]
@@ -152,6 +150,8 @@ module Puma
152
150
  raise "State file not found: #{@state}"
153
151
  end
154
152
 
153
+ require_relative 'state_file'
154
+
155
155
  sf = Puma::StateFile.new
156
156
  sf.load @state
157
157
 
@@ -167,22 +167,26 @@ module Puma
167
167
  def send_request
168
168
  uri = URI.parse @control_url
169
169
 
170
+ host = uri.host
171
+
170
172
  # create server object by scheme
171
173
  server =
172
174
  case uri.scheme
173
175
  when 'ssl'
174
176
  require 'openssl'
177
+ host = host[1..-2] if host&.start_with? '['
175
178
  OpenSSL::SSL::SSLSocket.new(
176
- TCPSocket.new(uri.host, uri.port),
179
+ TCPSocket.new(host, uri.port),
177
180
  OpenSSL::SSL::SSLContext.new)
178
181
  .tap { |ssl| ssl.sync_close = true } # default is false
179
182
  .tap(&:connect)
180
183
  when 'tcp'
181
- TCPSocket.new uri.host, uri.port
184
+ host = host[1..-2] if host&.start_with? '['
185
+ TCPSocket.new host, uri.port
182
186
  when 'unix'
183
187
  # check for abstract UNIXSocket
184
188
  UNIXSocket.new(@control_url.start_with?('unix://@') ?
185
- "\0#{uri.host}#{uri.path}" : "#{uri.host}#{uri.path}")
189
+ "\0#{host}#{uri.path}" : "#{host}#{uri.path}")
186
190
  else
187
191
  raise "Invalid scheme: #{uri.scheme}"
188
192
  end
@@ -287,7 +291,7 @@ module Puma
287
291
 
288
292
  private
289
293
  def start
290
- require 'puma/cli'
294
+ require_relative 'cli'
291
295
 
292
296
  run_args = []
293
297
 
@@ -299,13 +303,13 @@ module Puma
299
303
  run_args += ["-C", @config_file] if @config_file
300
304
  run_args += ["-e", @environment] if @environment
301
305
 
302
- events = Puma::Events.new @stdout, @stderr
306
+ log_writer = Puma::LogWriter.new(@stdout, @stderr)
303
307
 
304
308
  # replace $0 because puma use it to generate restart command
305
309
  puma_cmd = $0.gsub(/pumactl$/, 'puma')
306
310
  $0 = puma_cmd if File.exist?(puma_cmd)
307
311
 
308
- cli = Puma::CLI.new run_args, events
312
+ cli = Puma::CLI.new run_args, log_writer
309
313
  cli.run
310
314
  end
311
315
  end
data/lib/puma/detect.rb CHANGED
@@ -8,15 +8,18 @@ module Puma
8
8
  # @version 5.2.1
9
9
  HAS_FORK = ::Process.respond_to? :fork
10
10
 
11
+ HAS_NATIVE_IO_WAIT = ::IO.public_instance_methods(false).include? :wait_readable
12
+
11
13
  IS_JRUBY = Object.const_defined? :JRUBY_VERSION
12
14
 
13
- IS_OSX = RUBY_PLATFORM.include? 'darwin'
15
+ IS_OSX = RUBY_DESCRIPTION.include? 'darwin'
16
+
17
+ IS_WINDOWS = RUBY_DESCRIPTION.match?(/mswin|ming|cygwin/)
14
18
 
15
- IS_WINDOWS = !!(RUBY_PLATFORM =~ /mswin|ming|cygwin/) ||
16
- IS_JRUBY && RUBY_DESCRIPTION.include?('mswin')
19
+ IS_LINUX = !(IS_OSX || IS_WINDOWS)
17
20
 
18
21
  # @version 5.2.0
19
- IS_MRI = (RUBY_ENGINE == 'ruby' || RUBY_ENGINE.nil?)
22
+ IS_MRI = RUBY_ENGINE == 'ruby'
20
23
 
21
24
  def self.jruby?
22
25
  IS_JRUBY