puma 5.0.0.beta1-java → 5.0.3-java

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.

Potentially problematic release.


This version of puma might be problematic. Click here for more details.

Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +1188 -559
  3. data/README.md +15 -8
  4. data/bin/puma-wild +3 -9
  5. data/docs/architecture.md +3 -3
  6. data/docs/deployment.md +10 -7
  7. data/docs/jungle/README.md +0 -4
  8. data/docs/jungle/rc.d/puma +2 -2
  9. data/docs/nginx.md +1 -1
  10. data/docs/restart.md +46 -23
  11. data/docs/signals.md +7 -7
  12. data/docs/systemd.md +1 -1
  13. data/ext/puma_http11/ext_help.h +1 -1
  14. data/ext/puma_http11/http11_parser.c +3 -1
  15. data/ext/puma_http11/http11_parser.rl +3 -1
  16. data/ext/puma_http11/mini_ssl.c +53 -38
  17. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  18. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +77 -18
  19. data/ext/puma_http11/puma_http11.c +22 -11
  20. data/lib/puma.rb +16 -0
  21. data/lib/puma/app/status.rb +47 -44
  22. data/lib/puma/binder.rb +40 -12
  23. data/lib/puma/client.rb +68 -82
  24. data/lib/puma/cluster.rb +30 -187
  25. data/lib/puma/cluster/worker.rb +170 -0
  26. data/lib/puma/cluster/worker_handle.rb +83 -0
  27. data/lib/puma/commonlogger.rb +2 -2
  28. data/lib/puma/configuration.rb +9 -7
  29. data/lib/puma/const.rb +2 -1
  30. data/lib/puma/control_cli.rb +2 -0
  31. data/lib/puma/detect.rb +9 -0
  32. data/lib/puma/dsl.rb +77 -39
  33. data/lib/puma/error_logger.rb +97 -0
  34. data/lib/puma/events.rb +37 -31
  35. data/lib/puma/launcher.rb +20 -10
  36. data/lib/puma/minissl.rb +55 -10
  37. data/lib/puma/minissl/context_builder.rb +0 -3
  38. data/lib/puma/puma_http11.jar +0 -0
  39. data/lib/puma/queue_close.rb +26 -0
  40. data/lib/puma/reactor.rb +77 -373
  41. data/lib/puma/request.rb +438 -0
  42. data/lib/puma/runner.rb +7 -19
  43. data/lib/puma/server.rb +229 -506
  44. data/lib/puma/single.rb +3 -2
  45. data/lib/puma/state_file.rb +1 -1
  46. data/lib/puma/thread_pool.rb +32 -5
  47. data/lib/puma/util.rb +12 -0
  48. metadata +12 -10
  49. data/docs/jungle/upstart/README.md +0 -61
  50. data/docs/jungle/upstart/puma-manager.conf +0 -31
  51. data/docs/jungle/upstart/puma.conf +0 -69
  52. data/lib/puma/accept_nonblock.rb +0 -29
data/README.md CHANGED
@@ -4,11 +4,11 @@
4
4
 
5
5
  # Puma: A Ruby Web Server Built For Concurrency
6
6
 
7
- [![Actions Build Status](https://github.com/puma/puma/workflows/CI/badge.svg?branch=master)](https://github.com/puma/puma/actions)
8
-
7
+ [![Actions MRI](https://github.com/puma/puma/workflows/MRI/badge.svg?branch=master)](https://github.com/puma/puma/actions?query=workflow%3AMRI)
8
+ [![Actions non MRI](https://github.com/puma/puma/workflows/non_MRI/badge.svg?branch=master)](https://github.com/puma/puma/actions?query=workflow%3Anon_MRI)
9
9
  [![Code Climate](https://codeclimate.com/github/puma/puma.svg)](https://codeclimate.com/github/puma/puma)
10
10
  [![SemVer](https://api.dependabot.com/badges/compatibility_score?dependency-name=puma&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=puma&package-manager=bundler&version-scheme=semver)
11
- [![StackOverflow](http://img.shields.io/badge/stackoverflow-Puma-blue.svg)]( http://stackoverflow.com/questions/tagged/puma )
11
+ [![StackOverflow](https://img.shields.io/badge/stackoverflow-Puma-blue.svg)]( https://stackoverflow.com/questions/tagged/puma )
12
12
 
13
13
  Puma is a **simple, fast, multi-threaded, and highly concurrent HTTP 1.1 server for Ruby/Rack applications**.
14
14
 
@@ -27,9 +27,17 @@ $ gem install puma
27
27
  $ puma
28
28
  ```
29
29
 
30
- Without arguments, puma will look for a rackup (.ru) file in
30
+ Without arguments, puma will look for a rackup (.ru) file in
31
31
  working directory called `config.ru`.
32
32
 
33
+ ## SSL Connection Support
34
+
35
+ Puma will install/compile with support for ssl sockets, assuming OpenSSL
36
+ development files are installed on the system.
37
+
38
+ If the system does not have OpenSSL development files installed, Puma will
39
+ install/compile, but it will not allow ssl connections.
40
+
33
41
  ## Frameworks
34
42
 
35
43
  ### Rails
@@ -135,7 +143,7 @@ Preloading can’t be used with phased restart, since phased restart kills and r
135
143
  If puma encounters an error outside of the context of your application, it will respond with a 500 and a simple
136
144
  textual error message (see `lowlevel_error` in [this file](https://github.com/puma/puma/blob/master/lib/puma/server.rb)).
137
145
  You can specify custom behavior for this scenario. For example, you can report the error to your third-party
138
- error-tracking service (in this example, [rollbar](http://rollbar.com)):
146
+ error-tracking service (in this example, [rollbar](https://rollbar.com)):
139
147
 
140
148
  ```ruby
141
149
  lowlevel_error_handler do |e|
@@ -266,18 +274,17 @@ end
266
274
 
267
275
  Puma has support for Capistrano with an [external gem](https://github.com/seuros/capistrano-puma).
268
276
 
269
- It is common to use process monitors with Puma. Modern process monitors like systemd or upstart
277
+ It is common to use process monitors with Puma. Modern process monitors like systemd or rc.d
270
278
  provide continuous monitoring and restarts for increased
271
279
  reliability in production environments:
272
280
 
273
- * [docs/jungle](https://github.com/puma/puma/tree/master/docs/jungle) for rc.d and upstart
281
+ * [docs/jungle](https://github.com/puma/puma/tree/master/docs/jungle) for rc.d
274
282
  * [docs/systemd](https://github.com/puma/puma/blob/master/docs/systemd.md)
275
283
 
276
284
  ## Community Extensions
277
285
 
278
286
  ### Plugins
279
287
 
280
- * [puma-heroku](https://github.com/puma/puma-heroku) — default Puma configuration for running on Heroku
281
288
  * [puma-metrics](https://github.com/harmjanblok/puma-metrics) — export Puma metrics to Prometheus
282
289
  * [puma-plugin-statsd](https://github.com/yob/puma-plugin-statsd) — send Puma metrics to statsd
283
290
  * [puma-plugin-systemd](https://github.com/sj26/puma-plugin-systemd) — deeper integration with systemd for notify, status and watchdog
@@ -5,24 +5,18 @@
5
5
 
6
6
  require 'rubygems'
7
7
 
8
- gems = ARGV.shift
8
+ cli_arg = ARGV.shift
9
9
 
10
10
  inc = ""
11
11
 
12
- if gems == "-I"
12
+ if cli_arg == "-I"
13
13
  inc = ARGV.shift
14
14
  $LOAD_PATH.concat inc.split(":")
15
- gems = ARGV.shift
16
- end
17
-
18
- gems.split(",").each do |s|
19
- name, ver = s.split(":",2)
20
- gem name, ver
21
15
  end
22
16
 
23
17
  module Puma; end
24
18
 
25
- Puma.const_set("WILD_ARGS", ["-I", inc, gems])
19
+ Puma.const_set("WILD_ARGS", ["-I", inc])
26
20
 
27
21
  require 'puma/cli'
28
22
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Overview
4
4
 
5
- ![http://bit.ly/2iJuFky](images/puma-general-arch.png)
5
+ ![https://bit.ly/2iJuFky](images/puma-general-arch.png)
6
6
 
7
7
  Puma is a threaded web server, processing requests across a TCP or UNIX socket.
8
8
 
@@ -12,7 +12,7 @@ Clustered mode is shown/discussed here. Single mode is analogous to having a sin
12
12
 
13
13
  ## Connection pipeline
14
14
 
15
- ![http://bit.ly/2zwzhEK](images/puma-connection-flow.png)
15
+ ![https://bit.ly/2zwzhEK](images/puma-connection-flow.png)
16
16
 
17
17
  * Upon startup, Puma listens on a TCP or UNIX socket.
18
18
  * The backlog of this socket is configured (with a default of 1024), determining how many established but unaccepted connections can exist concurrently.
@@ -29,7 +29,7 @@ Clustered mode is shown/discussed here. Single mode is analogous to having a sin
29
29
 
30
30
  ### Disabling `queue_requests`
31
31
 
32
- ![http://bit.ly/2zxCJ1Z](images/puma-connection-flow-no-reactor.png)
32
+ ![https://bit.ly/2zxCJ1Z](images/puma-connection-flow-no-reactor.png)
33
33
 
34
34
  The `queue_requests` option is `true` by default, enabling the separate thread used to buffer requests as described above.
35
35
 
@@ -1,4 +1,4 @@
1
- # Deployment engineering for puma
1
+ # Deployment engineering for Puma
2
2
 
3
3
  Puma is software that is expected to be run in a deployed environment eventually.
4
4
  You can certainly use it as your dev server only, but most people look to use
@@ -7,12 +7,11 @@ it in their production deployments as well.
7
7
  To that end, this is meant to serve as a foundation of wisdom how to do that
8
8
  in a way that increases happiness and decreases downtime.
9
9
 
10
- ## Specifying puma
10
+ ## Specifying Puma
11
11
 
12
12
  Most people want to do this by putting `gem "puma"` into their Gemfile, so we'll
13
13
  go ahead and assume that. Go add it now... we'll wait.
14
14
 
15
-
16
15
  Welcome back!
17
16
 
18
17
  ## Single vs Cluster mode
@@ -20,7 +19,10 @@ Welcome back!
20
19
  Puma was originally conceived as a thread-only webserver, but grew the ability to
21
20
  also use processes in version 2.
22
21
 
23
- Here are some rules of thumb:
22
+ To run `puma` in single mode (e.g. for a development environment) you will need to
23
+ set the number of workers to 0, anything above will run in cluster mode.
24
+
25
+ Here are some rules of thumb for cluster mode:
24
26
 
25
27
  ### MRI
26
28
 
@@ -66,7 +68,8 @@ thread to become available.
66
68
 
67
69
  * Have your upstream proxy set a header with the time it received the request:
68
70
  * nginx: `proxy_set_header X-Request-Start "${msec}";`
69
- * haproxy: `http-request set-header X-Request-Start "%t";`
71
+ * haproxy >= 1.9: `http-request set-header X-Request-Start t=%[date()]%[date_us()]`
72
+ * haproxy < 1.9: `http-request set-header X-Request-Start t=%[date()]`
70
73
  * In your Rack middleware, determine the amount of time elapsed since `X-Request-Start`.
71
74
  * To improve accuracy, you will want to subtract time spent waiting for slow clients:
72
75
  * `env['puma.request_body_wait']` contains the number of milliseconds Puma spent
@@ -78,7 +81,7 @@ thread to become available.
78
81
 
79
82
  Daemonization was removed in Puma 5.0. For alternatives, continue reading.
80
83
 
81
- I prefer to not daemonize my servers and use something like `runit` or `upstart` to
84
+ I prefer to not daemonize my servers and use something like `runit` or `systemd` to
82
85
  monitor them as child processes. This gives them fast response to crashes and
83
86
  makes it easy to figure out what is going on. Additionally, unlike `unicorn`,
84
87
  puma does not require daemonization to do zero-downtime restarts.
@@ -88,7 +91,7 @@ task and thus want it to live on past the `cap deploy`. To these people I say:
88
91
  You need to be using a process monitor. Nothing is making sure puma stays up in
89
92
  this scenario! You're just waiting for something weird to happen, puma to die,
90
93
  and to get paged at 3am. Do yourself a favor, at least the process monitoring
91
- your OS comes with, be it `sysvinit`, `upstart`, or `systemd`. Or branch out
94
+ your OS comes with, be it `sysvinit` or `systemd`. Or branch out
92
95
  and use `runit` or hell, even `monit`.
93
96
 
94
97
  ## Restarting
@@ -1,9 +1,5 @@
1
1
  # Puma as a service
2
2
 
3
- ## Upstart
4
-
5
- See `/docs/jungle/upstart` for Ubuntu's upstart scripts.
6
-
7
3
  ## Systemd
8
4
 
9
5
  See [/docs/systemd](https://github.com/puma/puma/blob/master/docs/systemd.md).
@@ -23,7 +23,7 @@ puma_start()
23
23
  rb_ver=$(/usr/local/bin/jq -r ".servers[$i].ruby_version" /usr/local/etc/puma.conf)
24
24
  case $rb_env in
25
25
  "rbenv")
26
- su - $user -c "cd $dir && rbenv shell $rb_ver && bundle exec puma -C $dir/config/puma.rb -d"
26
+ cd $dir && rbenv shell $rb_ver && /usr/sbin/daemon -u $user bundle exec puma -C $dir/config/puma.rb
27
27
  ;;
28
28
  *)
29
29
  ;;
@@ -48,7 +48,7 @@ puma_restart()
48
48
  rb_ver=$(/usr/local/bin/jq -r ".servers[$i].ruby_version" /usr/local/etc/puma.conf)
49
49
  case $rb_env in
50
50
  "rbenv")
51
- su - $user -c "cd $dir && pkill ruby && rbenv shell $ruby_version && bundle exec puma -C $dir/config/puma.rb -d"
51
+ cd $dir && rbenv shell $rb_ver && /usr/sbin/daemon -u $user bundle exec puma -C $dir/config/puma.rb
52
52
  ;;
53
53
  *)
54
54
  ;;
@@ -31,7 +31,7 @@ server {
31
31
 
32
32
  location / {
33
33
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
34
- proxy_set_header Host $http_host;
34
+ proxy_set_header Host $host;
35
35
 
36
36
  # If the file exists as a static file serve it directly without
37
37
  # running all the other rewrite tests on it
@@ -1,41 +1,64 @@
1
- # Restarts
1
+ Puma provides three distinct kinds of restart operations, each for different use cases. Hot restarts and phased restarts are described here. The third kind of restart operation is called "refork" and is described in the documentation for [`fork_worker`](fork_worker.md).
2
2
 
3
- To perform a restart, there are 3 builtin mechanisms:
3
+ ## Hot restart
4
4
 
5
- * Send the `puma` process the `SIGUSR2` signal (normal restart)
6
- * Send the `puma` process the `SIGUSR1` signal (restart in phases (a "rolling restart"), cluster mode only)
7
- * Use the status server and issue `/restart`
5
+ To perform a "hot" restart, Puma performs an `exec` operation to start the process up again, so no memory is shared between the old process and the new process. As a result, it is safe to issue a restart any place where you would manually stop Puma and start it again. In particular, it is safe to upgrade Puma itself using a hot restart.
8
6
 
9
- No code is shared between the current and restarted process, so it should be safe to issue a restart any place where you would manually stop Puma and start it again.
7
+ If the new process is unable to load, it will simply exit. You should therefore run Puma under a process monitor when using it in production.
10
8
 
11
- If the new process is unable to load, it will simply exit. You should therefore run Puma under a process monitor (see below) when using it in production.
9
+ ### How-to
12
10
 
13
- ### Normal vs Hot vs Phased Restart
11
+ Any of the following will cause a Puma server to perform a hot restart:
14
12
 
15
- A hot restart means that no requests will be lost while deploying your new code, since the server socket is kept open between restarts.
13
+ * Send the `puma` process the `SIGUSR2` signal
14
+ * Issue a `GET` request to the Puma status/control server with the path `/restart`
15
+ * Issue `pumactl restart` (this uses the control server method if available, otherwise sends the `SIGUSR2` signal to the process)
16
16
 
17
- But beware, hot restart does not mean that the incoming requests won’t hang for multiple seconds while your new code has not fully deployed. If you need a zero downtime and zero hanging requests deploy, you must use phased restart.
17
+ ### Supported configurations
18
18
 
19
- When you run pumactl phased-restart, Puma kills workers one-by-one, meaning that at least another worker is still available to serve requests, which lead to zero hanging requests (yay!).
19
+ * Works in cluster mode and in single mode
20
+ * Supported on all platforms
20
21
 
21
- But again beware, upgrading an application sometimes involves upgrading the database schema. With phased restart, there may be a moment during the deployment where processes belonging to the previous version and processes belonging to the new version both exist at the same time. Any database schema upgrades you perform must therefore be backwards-compatible with the old application version.
22
+ ### Client experience
22
23
 
23
- If you perform a lot of database migrations, you probably should not use phased restart and use a normal/hot restart instead (`pumactl restart`). That way, no code is shared while deploying (in that case, `preload_app!` might help for quicker deployment, see ["Clustered Mode" in the README](../README.md#clustered-mode)).
24
+ * All platforms: for clients with an in-flight request, those clients will be served responses before the connection is closed gracefully. Puma gracefully disconnects any idle HTTP persistent connections before restarting.
25
+ * On MRI or TruffleRuby on Linux and BSD: Clients who connect just before the server restarts may experience increased latency while the server stops and starts again, but their connections will not be closed prematurely.
26
+ * On Windows and on JRuby: Clients who connect just before a restart may experience "connection reset" errors.
24
27
 
25
- **Note**: Hot and phased restarts are only available on MRI, not on JRuby. They are also unavailable on Windows servers.
28
+ ### Additional notes
26
29
 
27
- ### Release Directory
30
+ * Only one version of the application is running at a time.
31
+ * `on_restart` is invoked just before the server shuts down. This can be used to clean up resources (like long-lived database connections) gracefully. Since Ruby 2.0, it is not typically necessary to explicitly close file descriptors on restart. This is because any file descriptor opened by Ruby will have the `FD_CLOEXEC` flag set, meaning that file descriptors are closed on `exec`. `on_restart` is useful, though, if your application needs to perform any more graceful protocol-specific shutdown procedures before closing connections.
28
32
 
29
- If your symlink releases into a common working directory (i.e., `/current` from Capistrano), Puma won't pick up your new changes when running phased restarts without additional configuration. You should set your working directory within Puma's config to specify the directory it should use. This is a change from earlier versions of Puma (< 2.15) that would infer the directory for you.
33
+ ## Phased restart
30
34
 
31
- ```ruby
32
- # config/puma.rb
35
+ Phased restarts replace all running workers in a Puma cluster. This is a useful way to gracefully upgrade the application that Puma is serving. A phased restart works by first killing an old worker, then starting a new worker, waiting until the new worker has successfully started before proceeding to the next worker. This process continues until all workers have been replaced. The master process is not restarted.
33
36
 
34
- directory '/var/www/current'
35
- ```
37
+ ### How-to
36
38
 
37
- ### Cleanup Code
39
+ Any of the following will cause a Puma server to perform a phased restart:
38
40
 
39
- Puma isn't able to understand all the resources that your app may use, so it provides a hook in the configuration file you pass to `-C` called `on_restart`. The block passed to `on_restart` will be called, unsurprisingly, just before Puma restarts itself.
41
+ * Send the `puma` process the `SIGUSR1` signal
42
+ * Issue a `GET` request to the Puma status/control server with the path `/phased-restart`
43
+ * Issue `pumactl phased-restart` (this uses the control server method if available, otherwise sends the `SIGUSR1` signal to the process)
40
44
 
41
- You should place code to close global log files, redis connections, etc. in this block so that their file descriptors don't leak into the restarted process. Failure to do so will result in slowly running out of descriptors and eventually obscure crashes as the server is restarted many times.
45
+ ### Supported configurations
46
+
47
+ * Works in cluster mode only
48
+ * To support upgrading the application that Puma is serving, ensure `prune_bundler` is enabled and that `preload_app` is disabled (it is disabled by default).
49
+ * Supported on all platforms where cluster mode is supported
50
+
51
+ ### Client experience
52
+
53
+ * In-flight requests are always served responses before the connection is closed gracefully
54
+ * Idle persistent connections are gracefully disconnected
55
+ * New connections are not lost, and clients will not experience any increase in latency (as long as the number of configured workers is greater than one)
56
+
57
+ ### Additional notes
58
+
59
+ * When a phased restart begins, the Puma master process changes its current working directory to the directory specified by the `directory` option. If `directory` is set to symlink, this is automatically re-evaluated, so this mechanism can be used to upgrade the application.
60
+ * On a single server, it's possible that two versions of the application are running concurrently during a phased restart.
61
+ * `on_restart` is not invoked
62
+ * Phased restarts can be slow for Puma clusters with many workers. Hot restarts often complete more quickly, but at the cost of increased latency during the restart.
63
+ * Phased restarts cannot be used to upgrade any gems loaded by the Puma master process, including `puma` itself, anything in `extra_runtime_dependencies`, or dependencies thereof. Upgrading other gems is safe.
64
+ * If you remove the gems from old releases as part of your deployment strategy, there are additional considerations. Do not put any gems into `extra_runtime_dependencies` that have native extensions or have dependencies that have native extensions (one common example is `puma_worker_killer` and its dependency on `ffi`). Workers will fail on boot during a phased restart. The underlying issue is recorded in [an issue on the rubygems project](https://github.com/rubygems/rubygems/issues/4004). Hot restarts are your only option here if you need these dependencies.
@@ -1,8 +1,8 @@
1
- The [unix signal](http://en.wikipedia.org/wiki/Unix_signal) is a method of sending messages between [processes](http://en.wikipedia.org/wiki/Process_(computing)). When a signal is sent, the operating system interrupts the target process's normal flow of execution. There are standard signals that are used to stop a process but there are also custom signals that can be used for other purposes. This document is an attempt to list all supported signals that Puma will respond to. In general, signals need only be sent to the master process of a cluster.
1
+ The [unix signal](https://en.wikipedia.org/wiki/Unix_signal) is a method of sending messages between [processes](https://en.wikipedia.org/wiki/Process_(computing)). When a signal is sent, the operating system interrupts the target process's normal flow of execution. There are standard signals that are used to stop a process but there are also custom signals that can be used for other purposes. This document is an attempt to list all supported signals that Puma will respond to. In general, signals need only be sent to the master process of a cluster.
2
2
 
3
3
  ## Sending Signals
4
4
 
5
- If you are new to signals it can be useful to see how they can be used. When a process is created in a *nix like operating system it will have a [PID - or process identifier](http://en.wikipedia.org/wiki/Process_identifier) that can be used to send signals to the process. For demonstration we will create an infinitely running process by tailing a file:
5
+ If you are new to signals it can be useful to see how they can be used. When a process is created in a *nix like operating system it will have a [PID - or process identifier](https://en.wikipedia.org/wiki/Process_identifier) that can be used to send signals to the process. For demonstration we will create an infinitely running process by tailing a file:
6
6
 
7
7
  ```sh
8
8
  $ echo "foo" >> my.log
@@ -17,13 +17,13 @@ $ ps aux | grep tail
17
17
  schneems 87152 0.0 0.0 2432772 492 s032 S+ 12:46PM 0:00.00 tail -f my.log
18
18
  ```
19
19
 
20
- You can send a signal in Ruby using the [Process module](http://www.ruby-doc.org/core-2.1.1/Process.html#kill-method):
20
+ You can send a signal in Ruby using the [Process module](https://www.ruby-doc.org/core-2.1.1/Process.html#kill-method):
21
21
 
22
22
  ```
23
23
  $ irb
24
24
  > puts pid
25
25
  => 87152
26
- Process.detach(pid) # http://ruby-doc.org/core-2.1.1/Process.html#method-c-detach
26
+ Process.detach(pid) # https://ruby-doc.org/core-2.1.1/Process.html#method-c-detach
27
27
  Process.kill("TERM", pid)
28
28
  ```
29
29
 
@@ -38,10 +38,10 @@ Puma cluster responds to these signals:
38
38
  - `TERM` send `TERM` to worker. Worker will attempt to finish then exit.
39
39
  - `USR2` restart workers. This also reloads puma configuration file, if there is one.
40
40
  - `USR1` restart workers in phases, a rolling restart. This will not reload configuration file.
41
- - `HUP` reopen log files defined in stdout_redirect configuration parameter. If there is no stdout_redirect option provided it will behave like `INT`
42
- - `INT` equivalent of sending Ctrl-C to cluster. Will attempt to finish then exit.
41
+ - `HUP ` reopen log files defined in stdout_redirect configuration parameter. If there is no stdout_redirect option provided it will behave like `INT`
42
+ - `INT ` equivalent of sending Ctrl-C to cluster. Will attempt to finish then exit.
43
43
  - `CHLD`
44
- - `URG` refork workers in phases from worker 0, if `fork_workers` option is enabled.
44
+ - `URG ` refork workers in phases from worker 0, if `fork_workers` option is enabled.
45
45
 
46
46
  ## Callbacks order in case of different signals
47
47
 
@@ -76,7 +76,7 @@ pass the `--keep-file-descriptors` flag. `bundle exec` can be avoided by using a
76
76
  `puma` executable generated by `bundle binstubs puma`. This is tracked in
77
77
  [#1499].
78
78
 
79
- **Note:** Socket activation doesn't currently work on jruby. This is
79
+ **Note:** Socket activation doesn't currently work on JRuby. This is
80
80
  tracked in [#1367].
81
81
 
82
82
  To use socket activation, configure one or more `ListenStream` sockets
@@ -2,7 +2,7 @@
2
2
  #define ext_help_h
3
3
 
4
4
  #define RAISE_NOT_NULL(T) if(T == NULL) rb_raise(rb_eArgError, "%s", "NULL found for " # T " when shouldn't be.");
5
- #define DATA_GET(from,type,name) Data_Get_Struct(from,type,name); RAISE_NOT_NULL(name);
5
+ #define DATA_GET(from,type,data_type,name) TypedData_Get_Struct(from,type,data_type,name); RAISE_NOT_NULL(name);
6
6
  #define REQUIRE_TYPE(V, T) if(TYPE(V) != T) rb_raise(rb_eTypeError, "%s", "Wrong argument type for " # V " required " # T);
7
7
  #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
8
8
 
@@ -14,12 +14,14 @@
14
14
 
15
15
  /*
16
16
  * capitalizes all lower-case ASCII characters,
17
- * converts dashes to underscores.
17
+ * converts dashes to underscores, and underscores to commas.
18
18
  */
19
19
  static void snake_upcase_char(char *c)
20
20
  {
21
21
  if (*c >= 'a' && *c <= 'z')
22
22
  *c &= ~0x20;
23
+ else if (*c == '_')
24
+ *c = ',';
23
25
  else if (*c == '-')
24
26
  *c = '_';
25
27
  }
@@ -12,12 +12,14 @@
12
12
 
13
13
  /*
14
14
  * capitalizes all lower-case ASCII characters,
15
- * converts dashes to underscores.
15
+ * converts dashes to underscores, and underscores to commas.
16
16
  */
17
17
  static void snake_upcase_char(char *c)
18
18
  {
19
19
  if (*c >= 'a' && *c <= 'z')
20
20
  *c &= ~0x20;
21
+ else if (*c == '_')
22
+ *c = ',';
21
23
  else if (*c == '-')
22
24
  *c = '_';
23
25
  }
@@ -2,12 +2,7 @@
2
2
 
3
3
  #include <ruby.h>
4
4
  #include <ruby/version.h>
5
-
6
- #if RUBY_API_VERSION_MAJOR == 1
7
- #include <rubyio.h>
8
- #else
9
5
  #include <ruby/io.h>
10
- #endif
11
6
 
12
7
  #ifdef HAVE_OPENSSL_BIO_H
13
8
 
@@ -33,7 +28,8 @@ typedef struct {
33
28
  int bytes;
34
29
  } ms_cert_buf;
35
30
 
36
- void engine_free(ms_conn* conn) {
31
+ void engine_free(void *ptr) {
32
+ ms_conn *conn = ptr;
37
33
  ms_cert_buf* cert_buf = (ms_cert_buf*)SSL_get_app_data(conn->ssl);
38
34
  if(cert_buf) {
39
35
  OPENSSL_free(cert_buf->buf);
@@ -45,10 +41,16 @@ void engine_free(ms_conn* conn) {
45
41
  free(conn);
46
42
  }
47
43
 
44
+ const rb_data_type_t engine_data_type = {
45
+ "MiniSSL/ENGINE",
46
+ { 0, engine_free, 0 },
47
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
48
+ };
49
+
48
50
  ms_conn* engine_alloc(VALUE klass, VALUE* obj) {
49
51
  ms_conn* conn;
50
52
 
51
- *obj = Data_Make_Struct(klass, ms_conn, 0, engine_free, conn);
53
+ *obj = TypedData_Make_Struct(klass, ms_conn, &engine_data_type, conn);
52
54
 
53
55
  conn->read = BIO_new(BIO_s_mem());
54
56
  BIO_set_nbio(conn->read, 1);
@@ -198,7 +200,7 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
198
200
  else {
199
201
  min = TLS1_VERSION;
200
202
  }
201
-
203
+
202
204
  SSL_CTX_set_min_proto_version(ctx, min);
203
205
 
204
206
  SSL_CTX_set_options(ctx, ssl_options);
@@ -281,7 +283,7 @@ VALUE engine_inject(VALUE self, VALUE str) {
281
283
  ms_conn* conn;
282
284
  long used;
283
285
 
284
- Data_Get_Struct(self, ms_conn, conn);
286
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
285
287
 
286
288
  StringValue(str);
287
289
 
@@ -301,6 +303,7 @@ void raise_error(SSL* ssl, int result) {
301
303
  char msg[512];
302
304
  const char* err_str;
303
305
  int err = errno;
306
+ int mask = 4095;
304
307
  int ssl_err = SSL_get_error(ssl, result);
305
308
  int verify_err = (int) SSL_get_verify_result(ssl);
306
309
 
@@ -317,8 +320,8 @@ void raise_error(SSL* ssl, int result) {
317
320
  } else {
318
321
  err = (int) ERR_get_error();
319
322
  ERR_error_string_n(err, buf, sizeof(buf));
320
- snprintf(msg, sizeof(msg), "OpenSSL error: %s - %d", buf, err);
321
-
323
+ int errexp = err & mask;
324
+ snprintf(msg, sizeof(msg), "OpenSSL error: %s - %d", buf, errexp);
322
325
  }
323
326
  } else {
324
327
  snprintf(msg, sizeof(msg), "Unknown OpenSSL error: %d", ssl_err);
@@ -333,7 +336,7 @@ VALUE engine_read(VALUE self) {
333
336
  char buf[512];
334
337
  int bytes, error;
335
338
 
336
- Data_Get_Struct(self, ms_conn, conn);
339
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
337
340
 
338
341
  ERR_clear_error();
339
342
 
@@ -360,7 +363,7 @@ VALUE engine_write(VALUE self, VALUE str) {
360
363
  ms_conn* conn;
361
364
  int bytes;
362
365
 
363
- Data_Get_Struct(self, ms_conn, conn);
366
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
364
367
 
365
368
  StringValue(str);
366
369
 
@@ -384,7 +387,7 @@ VALUE engine_extract(VALUE self) {
384
387
  size_t pending;
385
388
  char buf[512];
386
389
 
387
- Data_Get_Struct(self, ms_conn, conn);
390
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
388
391
 
389
392
  pending = BIO_pending(conn->write);
390
393
  if(pending > 0) {
@@ -403,7 +406,7 @@ VALUE engine_shutdown(VALUE self) {
403
406
  ms_conn* conn;
404
407
  int ok;
405
408
 
406
- Data_Get_Struct(self, ms_conn, conn);
409
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
407
410
 
408
411
  ERR_clear_error();
409
412
 
@@ -418,7 +421,7 @@ VALUE engine_shutdown(VALUE self) {
418
421
  VALUE engine_init(VALUE self) {
419
422
  ms_conn* conn;
420
423
 
421
- Data_Get_Struct(self, ms_conn, conn);
424
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
422
425
 
423
426
  return SSL_in_init(conn->ssl) ? Qtrue : Qfalse;
424
427
  }
@@ -431,7 +434,7 @@ VALUE engine_peercert(VALUE self) {
431
434
  ms_cert_buf* cert_buf = NULL;
432
435
  VALUE rb_cert_buf;
433
436
 
434
- Data_Get_Struct(self, ms_conn, conn);
437
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
435
438
 
436
439
  cert = SSL_get_peer_certificate(conn->ssl);
437
440
  if(!cert) {
@@ -462,6 +465,16 @@ VALUE engine_peercert(VALUE self) {
462
465
  return rb_cert_buf;
463
466
  }
464
467
 
468
+ /* @see Puma::MiniSSL::Socket#ssl_version_state
469
+ * @version 5.0.0
470
+ */
471
+ static VALUE
472
+ engine_ssl_vers_st(VALUE self) {
473
+ ms_conn* conn;
474
+ TypedData_Get_Struct(self, ms_conn, &engine_data_type, conn);
475
+ return rb_ary_new3(2, rb_str_new2(SSL_get_version(conn->ssl)), rb_str_new2(SSL_state_string(conn->ssl)));
476
+ }
477
+
465
478
  VALUE noop(VALUE self) {
466
479
  return Qnil;
467
480
  }
@@ -493,27 +506,27 @@ void Init_mini_ssl(VALUE puma) {
493
506
  #else
494
507
  rb_define_const(mod, "OPENSSL_LIBRARY_VERSION", rb_str_new2(SSLeay_version(SSLEAY_VERSION)));
495
508
  #endif
496
-
497
- #if defined(OPENSSL_NO_SSL3) || defined(OPENSSL_NO_SSL3_METHOD)
498
- /* True if SSL3 is not available */
499
- rb_define_const(mod, "OPENSSL_NO_SSL3", Qtrue);
500
- #else
501
- rb_define_const(mod, "OPENSSL_NO_SSL3", Qfalse);
502
- #endif
503
-
504
- #if defined(OPENSSL_NO_TLS1) || defined(OPENSSL_NO_TLS1_METHOD)
505
- /* True if TLS1 is not available */
506
- rb_define_const(mod, "OPENSSL_NO_TLS1", Qtrue);
507
- #else
508
- rb_define_const(mod, "OPENSSL_NO_TLS1", Qfalse);
509
- #endif
510
-
511
- #if defined(OPENSSL_NO_TLS1_1) || defined(OPENSSL_NO_TLS1_1_METHOD)
512
- /* True if TLS1_1 is not available */
513
- rb_define_const(mod, "OPENSSL_NO_TLS1_1", Qtrue);
514
- #else
515
- rb_define_const(mod, "OPENSSL_NO_TLS1_1", Qfalse);
516
- #endif
509
+
510
+ #if defined(OPENSSL_NO_SSL3) || defined(OPENSSL_NO_SSL3_METHOD)
511
+ /* True if SSL3 is not available */
512
+ rb_define_const(mod, "OPENSSL_NO_SSL3", Qtrue);
513
+ #else
514
+ rb_define_const(mod, "OPENSSL_NO_SSL3", Qfalse);
515
+ #endif
516
+
517
+ #if defined(OPENSSL_NO_TLS1) || defined(OPENSSL_NO_TLS1_METHOD)
518
+ /* True if TLS1 is not available */
519
+ rb_define_const(mod, "OPENSSL_NO_TLS1", Qtrue);
520
+ #else
521
+ rb_define_const(mod, "OPENSSL_NO_TLS1", Qfalse);
522
+ #endif
523
+
524
+ #if defined(OPENSSL_NO_TLS1_1) || defined(OPENSSL_NO_TLS1_1_METHOD)
525
+ /* True if TLS1_1 is not available */
526
+ rb_define_const(mod, "OPENSSL_NO_TLS1_1", Qtrue);
527
+ #else
528
+ rb_define_const(mod, "OPENSSL_NO_TLS1_1", Qfalse);
529
+ #endif
517
530
 
518
531
  rb_define_singleton_method(mod, "check", noop, 0);
519
532
 
@@ -533,6 +546,8 @@ void Init_mini_ssl(VALUE puma) {
533
546
  rb_define_method(eng, "init?", engine_init, 0);
534
547
 
535
548
  rb_define_method(eng, "peercert", engine_peercert, 0);
549
+
550
+ rb_define_method(eng, "ssl_vers_st", engine_ssl_vers_st, 0);
536
551
  }
537
552
 
538
553
  #else