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.
- checksums.yaml +4 -4
- data/History.md +1188 -559
- data/README.md +15 -8
- data/bin/puma-wild +3 -9
- data/docs/architecture.md +3 -3
- data/docs/deployment.md +10 -7
- data/docs/jungle/README.md +0 -4
- data/docs/jungle/rc.d/puma +2 -2
- data/docs/nginx.md +1 -1
- data/docs/restart.md +46 -23
- data/docs/signals.md +7 -7
- data/docs/systemd.md +1 -1
- data/ext/puma_http11/ext_help.h +1 -1
- data/ext/puma_http11/http11_parser.c +3 -1
- data/ext/puma_http11/http11_parser.rl +3 -1
- data/ext/puma_http11/mini_ssl.c +53 -38
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +77 -18
- data/ext/puma_http11/puma_http11.c +22 -11
- data/lib/puma.rb +16 -0
- data/lib/puma/app/status.rb +47 -44
- data/lib/puma/binder.rb +40 -12
- data/lib/puma/client.rb +68 -82
- data/lib/puma/cluster.rb +30 -187
- data/lib/puma/cluster/worker.rb +170 -0
- data/lib/puma/cluster/worker_handle.rb +83 -0
- data/lib/puma/commonlogger.rb +2 -2
- data/lib/puma/configuration.rb +9 -7
- data/lib/puma/const.rb +2 -1
- data/lib/puma/control_cli.rb +2 -0
- data/lib/puma/detect.rb +9 -0
- data/lib/puma/dsl.rb +77 -39
- data/lib/puma/error_logger.rb +97 -0
- data/lib/puma/events.rb +37 -31
- data/lib/puma/launcher.rb +20 -10
- data/lib/puma/minissl.rb +55 -10
- data/lib/puma/minissl/context_builder.rb +0 -3
- data/lib/puma/puma_http11.jar +0 -0
- data/lib/puma/queue_close.rb +26 -0
- data/lib/puma/reactor.rb +77 -373
- data/lib/puma/request.rb +438 -0
- data/lib/puma/runner.rb +7 -19
- data/lib/puma/server.rb +229 -506
- data/lib/puma/single.rb +3 -2
- data/lib/puma/state_file.rb +1 -1
- data/lib/puma/thread_pool.rb +32 -5
- data/lib/puma/util.rb +12 -0
- metadata +12 -10
- data/docs/jungle/upstart/README.md +0 -61
- data/docs/jungle/upstart/puma-manager.conf +0 -31
- data/docs/jungle/upstart/puma.conf +0 -69
- 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
|
-
[](https://github.com/puma/puma/actions?query=workflow%3AMRI)
|
8
|
+
[](https://github.com/puma/puma/actions?query=workflow%3Anon_MRI)
|
9
9
|
[](https://codeclimate.com/github/puma/puma)
|
10
10
|
[](https://dependabot.com/compatibility-score.html?dependency-name=puma&package-manager=bundler&version-scheme=semver)
|
11
|
-
[]( 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](
|
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
|
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
|
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
|
data/bin/puma-wild
CHANGED
@@ -5,24 +5,18 @@
|
|
5
5
|
|
6
6
|
require 'rubygems'
|
7
7
|
|
8
|
-
|
8
|
+
cli_arg = ARGV.shift
|
9
9
|
|
10
10
|
inc = ""
|
11
11
|
|
12
|
-
if
|
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
|
19
|
+
Puma.const_set("WILD_ARGS", ["-I", inc])
|
26
20
|
|
27
21
|
require 'puma/cli'
|
28
22
|
|
data/docs/architecture.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
## Overview
|
4
4
|
|
5
|
-

|
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
|
-

|
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
|
-

|
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
|
|
data/docs/deployment.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Deployment engineering for
|
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
|
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
|
-
|
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
|
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 `
|
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
|
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
|
data/docs/jungle/README.md
CHANGED
data/docs/jungle/rc.d/puma
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
;;
|
data/docs/nginx.md
CHANGED
@@ -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 $
|
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
|
data/docs/restart.md
CHANGED
@@ -1,41 +1,64 @@
|
|
1
|
-
|
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
|
-
|
3
|
+
## Hot restart
|
4
4
|
|
5
|
-
|
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
|
-
|
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
|
-
|
9
|
+
### How-to
|
12
10
|
|
13
|
-
|
11
|
+
Any of the following will cause a Puma server to perform a hot restart:
|
14
12
|
|
15
|
-
|
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
|
-
|
17
|
+
### Supported configurations
|
18
18
|
|
19
|
-
|
19
|
+
* Works in cluster mode and in single mode
|
20
|
+
* Supported on all platforms
|
20
21
|
|
21
|
-
|
22
|
+
### Client experience
|
22
23
|
|
23
|
-
|
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
|
-
|
28
|
+
### Additional notes
|
26
29
|
|
27
|
-
|
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
|
-
|
33
|
+
## Phased restart
|
30
34
|
|
31
|
-
|
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
|
-
|
35
|
-
```
|
37
|
+
### How-to
|
36
38
|
|
37
|
-
|
39
|
+
Any of the following will cause a Puma server to perform a phased restart:
|
38
40
|
|
39
|
-
|
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
|
-
|
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.
|
data/docs/signals.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
The [unix signal](
|
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](
|
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](
|
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) #
|
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`
|
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
|
|
data/docs/systemd.md
CHANGED
@@ -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
|
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
|
data/ext/puma_http11/ext_help.h
CHANGED
@@ -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)
|
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
|
}
|
data/ext/puma_http11/mini_ssl.c
CHANGED
@@ -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(
|
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 =
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|