puma 3.11.3 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (54) hide show
  1. checksums.yaml +5 -5
  2. data/History.md +61 -0
  3. data/README.md +41 -11
  4. data/docs/architecture.md +2 -1
  5. data/docs/deployment.md +24 -4
  6. data/docs/restart.md +5 -3
  7. data/docs/systemd.md +37 -9
  8. data/ext/puma_http11/PumaHttp11Service.java +2 -0
  9. data/ext/puma_http11/mini_ssl.c +42 -5
  10. data/ext/puma_http11/org/jruby/puma/IOBuffer.java +72 -0
  11. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +17 -4
  12. data/lib/puma.rb +8 -0
  13. data/lib/puma/app/status.rb +3 -2
  14. data/lib/puma/binder.rb +22 -10
  15. data/lib/puma/cli.rb +18 -7
  16. data/lib/puma/client.rb +54 -22
  17. data/lib/puma/cluster.rb +54 -15
  18. data/lib/puma/commonlogger.rb +2 -0
  19. data/lib/puma/configuration.rb +4 -1
  20. data/lib/puma/const.rb +8 -2
  21. data/lib/puma/control_cli.rb +23 -11
  22. data/lib/puma/convenient.rb +2 -0
  23. data/lib/puma/daemon_ext.rb +2 -0
  24. data/lib/puma/delegation.rb +2 -0
  25. data/lib/puma/detect.rb +2 -0
  26. data/lib/puma/dsl.rb +63 -11
  27. data/lib/puma/events.rb +2 -0
  28. data/lib/puma/io_buffer.rb +3 -6
  29. data/lib/puma/jruby_restart.rb +2 -0
  30. data/lib/puma/launcher.rb +15 -13
  31. data/lib/puma/minissl.rb +20 -4
  32. data/lib/puma/null_io.rb +2 -0
  33. data/lib/puma/plugin.rb +2 -0
  34. data/lib/puma/rack/builder.rb +2 -1
  35. data/lib/puma/reactor.rb +215 -30
  36. data/lib/puma/runner.rb +11 -2
  37. data/lib/puma/server.rb +63 -26
  38. data/lib/puma/single.rb +14 -3
  39. data/lib/puma/state_file.rb +2 -0
  40. data/lib/puma/tcp_logger.rb +2 -0
  41. data/lib/puma/thread_pool.rb +50 -5
  42. data/lib/puma/util.rb +2 -6
  43. data/lib/rack/handler/puma.rb +4 -0
  44. data/tools/jungle/README.md +10 -4
  45. data/tools/jungle/init.d/README.md +2 -0
  46. data/tools/jungle/init.d/puma +7 -7
  47. data/tools/jungle/init.d/run-puma +1 -1
  48. data/tools/jungle/rc.d/README.md +74 -0
  49. data/tools/jungle/rc.d/puma +61 -0
  50. data/tools/jungle/rc.d/puma.conf +10 -0
  51. metadata +23 -9
  52. data/lib/puma/compat.rb +0 -14
  53. data/lib/puma/java_io_buffer.rb +0 -45
  54. data/lib/puma/rack/backports/uri/common_193.rb +0 -33
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 4804608b8eb91d9bfd64c81497f624c5c623fdda
4
- data.tar.gz: 76eac44fc46d7a7d53fc83d5d67eb0d1cdbb14c3
2
+ SHA256:
3
+ metadata.gz: b22a5ddb0ac910e28c3789564c70be998eaa0dec5eca7c668c6a4478ab35012b
4
+ data.tar.gz: b98d67fb71305279ee8169c80546e46d4b63a4be522462545023f8917d82fa72
5
5
  SHA512:
6
- metadata.gz: 0ffda6912f5ab5aad0cd430dcfb73b8f4ac97764c205b6396ff545d7672ab828f626da30e881a8789a4dcee5e8a4346e383a3b69569cc2be7bde604165251c0a
7
- data.tar.gz: ef1bc4ef2372bfec240b4a36f60035c978ba45c8423db18c7372c3ca0f52a7dc90ba83ef9dfa2a5b20f85a832d0f4ba9a5ced2d41a165a6bd8b49d021c007721
6
+ metadata.gz: 1f7186d10e0783ffd899b65b25fdda553346074b3bad7416726a99a0f77709318a275e67856beb101ff75c9b75dba48af917d48504bf6f5fc15b64dd7c8a190a
7
+ data.tar.gz: 1881c9c149c4e631c9bec14cd92344785933c81bf4fb997721c61081d4a3f6f9a5bf4cbf0f8faca44110deaa7331b6177a67d734af3006b1e0b677a7782fc5f9
data/History.md CHANGED
@@ -1,3 +1,64 @@
1
+ ## Master
2
+
3
+ x features
4
+ x bugfixes
5
+
6
+ ## 4.0.0 / 2019-06-25
7
+
8
+ 9 features
9
+ * Add support for disabling TLSv1.0 (#1562)
10
+ * Request body read time metric (#1569)
11
+ * Add out_of_band hook (#1648)
12
+ * Re-implement (native) IOBuffer for JRuby (#1691)
13
+ * Min worker timeout (#1716)
14
+ * Add option to suppress SignalException on SIGTERM (#1690)
15
+ * Allow mutual TLS CA to be set using `ssl_bind` DSL (#1689)
16
+ * Reactor now uses nio4r instead of `select` (#1728)
17
+ 9 x bugfixes
18
+ * Do not accept new requests on shutdown (#1685, #1808)
19
+ * Fix 3 corner cases when request body is chunked (#1508)
20
+ * Change pid existence check's condition branches (#1650)
21
+ * Don't call .stop on a server that doesn't exist (#1655)
22
+ * Implemented NID_X9_62_prime256v1 (P-256) curve over P-521 (#1671)
23
+ * Fix @notify.close can't modify frozen IOError (RuntimeError) (#1583)
24
+ * Fix Java 8 support (#1773)
25
+ * Fix error `uninitialized constant Puma::Cluster` (#1731)
26
+ * Fix `not_token` being able to be set to true (#1803)
27
+
28
+ ## 3.12.1 / 2019-03-19
29
+
30
+ * 1 features
31
+ * Internal strings are frozen (#1649)
32
+ * 3 bugfixes
33
+ * Fix chunked ending check (#1607)
34
+ * Rack handler should use provided default host (#1700)
35
+ * Better support for detecting runtimes that support `fork` (#1630)
36
+
37
+ ## 3.12.0 / 2018-07-13
38
+
39
+ * 5 features:
40
+ * You can now specify which SSL ciphers the server should support, default is unchanged (#1478)
41
+ * The setting for Puma's `max_threads` is now in `Puma.stats` (#1604)
42
+ * Pool capacity is now in `Puma.stats` (#1579)
43
+ * Installs restricted to Ruby 2.2+ (#1506)
44
+ * `--control` is now deprecated in favor of `--control-url` (#1487)
45
+
46
+ * 2 bugfixes:
47
+ * Workers will no longer accept more web requests than they have capacity to process. This prevents an issue where one worker would accept lots of requests while starving other workers (#1563)
48
+ * In a test env puma now emits the stack on an exception (#1557)
49
+
50
+ ## 3.11.4 / 2018-04-12
51
+
52
+ * 2 features:
53
+ * Manage puma as a service using rc.d (#1529)
54
+ * Server stats are now available from a top level method (#1532)
55
+ * 5 bugfixes:
56
+ * Fix parsing CLI options (#1482)
57
+ * Order of stderr and stdout is made before redirecting to a log file (#1511)
58
+ * Init.d fix of `ps -p` to check if pid exists (#1545)
59
+ * Early hints bugfix (#1550)
60
+ * Purge interrupt queue when closing socket fails (#1553)
61
+
1
62
  ## 3.11.3 / 2018-03-05
2
63
 
3
64
  * 3 bugfixes:
data/README.md CHANGED
@@ -1,14 +1,14 @@
1
1
  <p align="center">
2
- <img src="http://puma.io/images/logos/puma-logo-large.png">
2
+ <img src="https://puma.io/images/logos/puma-logo-large.png">
3
3
  </p>
4
4
 
5
5
  # Puma: A Ruby Web Server Built For Concurrency
6
6
 
7
7
  [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/puma/puma?utm\_source=badge&utm\_medium=badge&utm\_campaign=pr-badge)
8
- [![Build Status](https://secure.travis-ci.org/puma/puma.svg)](http://travis-ci.org/puma/puma)
9
- [![AppVeyor](https://img.shields.io/appveyor/ci/nateberkopec/puma.svg)](https://ci.appveyor.com/project/nateberkopec/puma)
10
- [![Dependency Status](https://gemnasium.com/puma/puma.svg)](https://gemnasium.com/puma/puma)
8
+ [![Travis Build Status](https://secure.travis-ci.org/puma/puma.svg)](https://travis-ci.org/puma/puma)
9
+ [![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/0xnxc7a26u9b2bub/branch/master?svg=true)](https://ci.appveyor.com/project/puma/puma/branch/master)
11
10
  [![Code Climate](https://codeclimate.com/github/puma/puma.svg)](https://codeclimate.com/github/puma/puma)
11
+ [![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)
12
12
 
13
13
  Puma is a **simple, fast, threaded, and highly concurrent HTTP 1.1 server for Ruby/Rack applications** in development and production.
14
14
 
@@ -16,7 +16,7 @@ Puma is a **simple, fast, threaded, and highly concurrent HTTP 1.1 server for Ru
16
16
 
17
17
  Under the hood, Puma processes requests using a C-optimized Ragel extension (inherited from Mongrel) that provides fast, accurate HTTP 1.1 protocol parsing in a portable way. Puma then serves the request in a thread from an internal thread pool. Since each request is served in a separate thread, truly concurrent Ruby implementations (JRuby, Rubinius) will use all available CPU cores.
18
18
 
19
- Puma was designed to be the go-to server for [Rubinius](http://rubini.us), but also works well with JRuby and MRI.
19
+ Puma was designed to be the go-to server for [Rubinius](https://rubini.us), but also works well with JRuby and MRI.
20
20
 
21
21
  On MRI, there is a Global VM Lock (GVL) that ensures only one thread can run Ruby code at a time. But if you're doing a lot of blocking IO (such as HTTP calls to external APIs like Twitter), Puma still improves MRI's throughput by allowing blocking IO to be run concurrently.
22
22
 
@@ -25,7 +25,7 @@ On MRI, there is a Global VM Lock (GVL) that ensures only one thread can run Rub
25
25
  ```
26
26
  $ gem install puma
27
27
  $ puma <any rackup (*.ru) file>
28
- ```
28
+ ```
29
29
 
30
30
  ## Frameworks
31
31
 
@@ -157,17 +157,40 @@ $ puma -b 'unix:///var/run/puma.sock?umask=0111'
157
157
  ```
158
158
 
159
159
  Need a bit of security? Use SSL sockets:
160
-
161
160
  ```
162
161
  $ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert'
163
162
  ```
164
163
 
164
+ #### Controlling SSL Cipher Suites
165
+
166
+ Need to use or avoid specific SSL cipher suites? Use `ssl_cipher_filter` or `ssl_cipher_list` options.
167
+
168
+ ##### Ruby:
169
+
170
+ ```
171
+ $ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&ssl_cipher_filter=!aNULL:AES+SHA'
172
+ ```
173
+
174
+ ##### JRuby:
175
+
176
+ ```
177
+ $ puma -b 'ssl://127.0.0.1:9292?keystore=path_to_keystore&keystore-pass=keystore_password&ssl_cipher_list=TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA'
178
+ ```
179
+
180
+ See https://www.openssl.org/docs/man1.0.2/apps/ciphers.html for cipher filter format and full list of cipher suites.
181
+
182
+ Don't want to use insecure TLSv1.0 ?
183
+
184
+ ```
185
+ $ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&no_tlsv1=true'
186
+ ```
187
+
165
188
  ### Control/Status Server
166
189
 
167
190
  Puma has a built-in status/control app that can be used to query and control Puma itself.
168
191
 
169
192
  ```
170
- $ puma --control tcp://127.0.0.1:9293 --control-token foo
193
+ $ puma --control-url tcp://127.0.0.1:9293 --control-token foo
171
194
  ```
172
195
 
173
196
  Puma will start the control server on localhost port 9293. All requests to the control server will need to include `token=foo` as a query parameter. This allows for simple authentication. Check out [status.rb](https://github.com/puma/puma/blob/master/lib/puma/app/status.rb) to see what the app has available.
@@ -175,7 +198,7 @@ Puma will start the control server on localhost port 9293. All requests to the c
175
198
  You can also interact with the control server via `pumactl`. This command will restart Puma:
176
199
 
177
200
  ```
178
- $ pumactl -C 'tcp://127.0.0.1:9293' --control-token foo restart
201
+ $ pumactl --control-url 'tcp://127.0.0.1:9293' --control-token foo restart
179
202
  ```
180
203
 
181
204
  To see a list of `pumactl` options, use `pumactl --help`.
@@ -217,10 +240,10 @@ Some platforms do not support all Puma features.
217
240
 
218
241
  ## Known Bugs
219
242
 
220
- For MRI versions 2.2.7, 2.2.8, 2.3.4 and 2.4.1, you may see ```stream closed in another thread (IOError)```. It may be caused by a [Ruby bug](https://bugs.ruby-lang.org/issues/13632). It can be fixed with the gem https://rubygems.org/gems/stopgap_13632:
243
+ For MRI versions 2.2.7, 2.2.8, 2.2.9, 2.2.10 2.3.4 and 2.4.1, you may see ```stream closed in another thread (IOError)```. It may be caused by a [Ruby bug](https://bugs.ruby-lang.org/issues/13632). It can be fixed with the gem https://rubygems.org/gems/stopgap_13632:
221
244
 
222
245
  ```ruby
223
- if %w(2.2.7 2.2.8 2.3.4 2.4.1).include? RUBY_VERSION
246
+ if %w(2.2.7 2.2.8 2.2.9 2.2.10 2.3.4 2.4.1).include? RUBY_VERSION
224
247
  begin
225
248
  require 'stopgap_13632'
226
249
  rescue LoadError
@@ -239,6 +262,13 @@ reliability in production environments:
239
262
  * [tools/jungle](https://github.com/puma/puma/tree/master/tools/jungle) for sysvinit (init.d) and upstart
240
263
  * [docs/systemd](https://github.com/puma/puma/blob/master/docs/systemd.md)
241
264
 
265
+ ## Community Plugins
266
+
267
+ * [puma-heroku](https://github.com/evanphx/puma-heroku) — default Puma configuration for running on Heroku
268
+ * [puma-metrics](https://github.com/harmjanblok/puma-metrics) — export Puma metrics to Prometheus
269
+ * [puma-plugin-statsd](https://github.com/yob/puma-plugin-statsd) — send Puma metrics to statsd
270
+ * [puma-plugin-systemd](https://github.com/sj26/puma-plugin-systemd) — deeper integration with systemd for notify, status and watchdog
271
+
242
272
  ## Contributing
243
273
 
244
274
  To run the test suite:
data/docs/architecture.md CHANGED
@@ -20,6 +20,7 @@ Clustered mode is shown/discussed here. Single mode is analogous to having a sin
20
20
  * By default, a single, separate thread is used to receive HTTP requests across the socket.
21
21
  * When at least one worker thread is available for work, a connection is accepted and placed in this request buffer
22
22
  * This thread waits for entire HTTP requests to be received over the connection
23
+ * The time spent waiting for the HTTP request body to be received is exposed to the Rack app as `env['puma.request_body_wait']` (milliseconds)
23
24
  * Once received, the connection is pushed into the "todo" set
24
25
  * Worker threads pop work off the "todo" set for processing
25
26
  * The thread processes the request via the rack application (which generates the HTTP response)
@@ -33,4 +34,4 @@ Clustered mode is shown/discussed here. Single mode is analogous to having a sin
33
34
  The `queue_requests` option is `true` by default, enabling the separate thread used to buffer requests as described above.
34
35
 
35
36
  If set to `false`, this buffer will not be used for connections while waiting for the request to arrive.
36
- In this mode, when a connection is accepted, it is added to the "todo" queue immediately, and a worker will syncronously do any waiting necessarry to read the HTTP request from the socket.
37
+ In this mode, when a connection is accepted, it is added to the "todo" queue immediately, and a worker will synchronously do any waiting necessary to read the HTTP request from the socket.
data/docs/deployment.md CHANGED
@@ -38,22 +38,42 @@ Here are some rules of thumb:
38
38
  * As you grow more confident in the thread safety of your app, you can tune the
39
39
  workers down and the threads up.
40
40
 
41
+ #### Ubuntu / Systemd (Systemctl) Installation
42
+
43
+ See [systemd.md](systemd.md)
44
+
41
45
  #### Worker utilization
42
46
 
43
- **How do you know if you're got enough (or too many workers)?**
47
+ **How do you know if you've got enough (or too many workers)?**
44
48
 
45
49
  A good question. Due to MRI's GIL, only one thread can be executing Ruby code at a time.
46
50
  But since so many apps are waiting on IO from DBs, etc., they can utilize threads
47
51
  to make better use of the process.
48
52
 
49
53
  The rule of thumb is you never want processes that are pegged all the time. This
50
- means that there is more work to do that the process can get through. On the other
54
+ means that there is more work to do than the process can get through. On the other
51
55
  hand, if you have processes that sit around doing nothing, then they're just eating
52
56
  up resources.
53
57
 
54
- Watching your CPU utilization over time and aim for about 70% on average. This means
58
+ Watch your CPU utilization over time and aim for about 70% on average. This means
55
59
  you've got capacity still but aren't starving threads.
56
60
 
61
+ **Measuring utilization**
62
+
63
+ Using a timestamp header from an upstream proxy server (eg. nginx or haproxy), it's
64
+ possible to get an indication of how long requests have been waiting for a Puma
65
+ thread to become available.
66
+
67
+ * Have your upstream proxy set a header with the time it received the request:
68
+ * nginx: `proxy_set_header X-Request-Start "${msec}";`
69
+ * haproxy: `http-request set-header X-Request-Start "%t";`
70
+ * In your Rack middleware, determine the amount of time elapsed since `X-Request-Start`.
71
+ * To improve accuracy, you will want to subtract time spent waiting for slow clients:
72
+ * `env['puma.request_body_wait']` contains the number of milliseconds Puma spent
73
+ waiting for the client to send the request body.
74
+ * haproxy: `%Th` (TLS handshake time) and `%Ti` (idle time before request) can
75
+ can also be added as headers.
76
+
57
77
  ## Daemonizing
58
78
 
59
79
  I prefer to not daemonize my servers and use something like `runit` or `upstart` to
@@ -62,7 +82,7 @@ makes it easy to figure out what is going on. Additionally, unlike `unicorn`,
62
82
  puma does not require daemonization to do zero-downtime restarts.
63
83
 
64
84
  I see people using daemonization because they start puma directly via capistrano
65
- task and thus want it to live on past the `cap deploy`. To this people I said:
85
+ task and thus want it to live on past the `cap deploy`. To these people I say:
66
86
  You need to be using a process monitor. Nothing is making sure puma stays up in
67
87
  this scenario! You're just waiting for something weird to happen, puma to die,
68
88
  and to get paged at 3am. Do yourself a favor, at least the process monitoring
data/docs/restart.md CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  To perform a restart, there are 3 builtin mechanisms:
4
4
 
5
- * Send the `puma` process the `SIGUSR2` signal
6
- * Send the `puma` process the `SIGUSR1` signal (rolling restart, cluster mode only)
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
7
  * Use the status server and issue `/restart`
8
8
 
9
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.
@@ -20,7 +20,9 @@ When you run pumactl phased-restart, Puma kills workers one-by-one, meaning that
20
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
22
 
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 below).
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
+
25
+ **Note**: Hot and phased restarts are only available on MRI, not on JRuby. They are also unavailable on Windows servers.
24
26
 
25
27
  ### Release Directory
26
28
 
data/docs/systemd.md CHANGED
@@ -32,21 +32,26 @@ Type=simple
32
32
  # Preferably configure a non-privileged user
33
33
  # User=
34
34
 
35
- # The path to the puma application root
36
- # Also replace the "<WD>" place holders below with this path.
37
- WorkingDirectory=
35
+ # The path to the your application code root directory.
36
+ # Also replace the "<YOUR_APP_PATH>" place holders below with this path.
37
+ # Example /home/username/myapp
38
+ WorkingDirectory=<YOUR_APP_PATH>
38
39
 
39
40
  # Helpful for debugging socket activation, etc.
40
41
  # Environment=PUMA_DEBUG=1
41
42
 
42
- # The command to start Puma. This variant uses a binstub generated via
43
- # `bundle binstubs puma --path ./sbin` in the WorkingDirectory
44
- # (replace "<WD>" below)
45
- ExecStart=<WD>/sbin/puma -b tcp://0.0.0.0:9292 -b ssl://0.0.0.0:9293?key=key.pem&cert=cert.pem
43
+ # SystemD will not run puma even if it is in your path. You must specify
44
+ # an absolute URL to puma. For example /usr/local/bin/puma
45
+ # Alternatively, create a binstub with `bundle binstubs puma --path ./sbin` in the WorkingDirectory
46
+ ExecStart=/<FULLPATH>/bin/puma -C <YOUR_APP_PATH>/puma.rb
47
+
48
+ # Variant: Rails start.
49
+ # ExecStart=/<FULLPATH>/bin/puma -C <YOUR_APP_PATH>/config/puma.rb ../config.ru
46
50
 
47
- # Variant: Use config file with `bind` directives instead:
48
- # ExecStart=<WD>/sbin/puma -C config.rb
49
51
  # Variant: Use `bundle exec --keep-file-descriptors puma` instead of binstub
52
+ # Variant: Specify directives inline.
53
+ # ExecStart=/<FULLPATH>/puma -b tcp://0.0.0.0:9292 -b ssl://0.0.0.0:9293?key=key.pem&cert=cert.pem
54
+
50
55
 
51
56
  Restart=always
52
57
 
@@ -66,6 +71,13 @@ listening sockets open across puma restarts and achieves graceful
66
71
  restarts, including when upgraded puma, and is compatible with both
67
72
  clustered mode and application preload.
68
73
 
74
+ **Note:** Any wrapper scripts which `exec`, or other indirections in
75
+ `ExecStart`, may result in activated socket file descriptors being closed
76
+ before they reach the puma master process. For example, if using `bundle exec`,
77
+ pass the `--keep-file-descriptors` flag. `bundle exec` can be avoided by using a
78
+ `puma` executable generated by `bundle binstubs puma`. This is tracked in
79
+ [#1499].
80
+
69
81
  **Note:** Socket activation doesn't currently work on jruby. This is
70
82
  tracked in [#1367].
71
83
 
@@ -102,6 +114,16 @@ for additional configuration details.
102
114
  Note that the above configurations will work with Puma in either
103
115
  single process or cluster mode.
104
116
 
117
+ ### Sockets and symlinks
118
+
119
+ When using releases folders, you should set the socket path using the
120
+ shared folder path (ex. `/srv/projet/shared/tmp/puma.sock`), not the
121
+ release folder path (`/srv/projet/releases/1234/tmp/puma.sock`).
122
+
123
+ Puma will detect the release path socket as different than the one provided by
124
+ systemd and attempt to bind it again, resulting in the exception
125
+ `There is already a server bound to:`.
126
+
105
127
  ## Usage
106
128
 
107
129
  Without socket activation, use `systemctl` as root (e.g. via `sudo`) as
@@ -237,6 +259,12 @@ PIDFile=<WD>/shared/tmp/pids/puma.pid
237
259
  # reconsider if you actually need the forking config.
238
260
  Restart=no
239
261
 
262
+ # `puma_ctl restart` wouldn't work without this. It's because `pumactl`
263
+ # changes PID on restart and systemd stops the service afterwards
264
+ # because of the PID change. This option prevents stopping after PID
265
+ # change.
266
+ RemainAfterExit=yes
267
+
240
268
  [Install]
241
269
  WantedBy=multi-user.target
242
270
  ~~~~
@@ -6,11 +6,13 @@ import org.jruby.Ruby;
6
6
  import org.jruby.runtime.load.BasicLibraryService;
7
7
 
8
8
  import org.jruby.puma.Http11;
9
+ import org.jruby.puma.IOBuffer;
9
10
  import org.jruby.puma.MiniSSL;
10
11
 
11
12
  public class PumaHttp11Service implements BasicLibraryService {
12
13
  public boolean basicLoad(final Ruby runtime) throws IOException {
13
14
  Http11.createHttp11(runtime);
15
+ IOBuffer.createIOBuffer(runtime);
14
16
  MiniSSL.createMiniSSL(runtime);
15
17
  return true;
16
18
  }
@@ -142,6 +142,7 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
142
142
  VALUE obj;
143
143
  SSL_CTX* ctx;
144
144
  SSL* ssl;
145
+ int ssl_options;
145
146
 
146
147
  ms_conn* conn = engine_alloc(self, &obj);
147
148
 
@@ -161,6 +162,13 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
161
162
  ID sym_verify_mode = rb_intern("verify_mode");
162
163
  VALUE verify_mode = rb_funcall(mini_ssl_ctx, sym_verify_mode, 0);
163
164
 
165
+ ID sym_ssl_cipher_filter = rb_intern("ssl_cipher_filter");
166
+ VALUE ssl_cipher_filter = rb_funcall(mini_ssl_ctx, sym_ssl_cipher_filter, 0);
167
+
168
+ ID sym_no_tlsv1 = rb_intern("no_tlsv1");
169
+ VALUE no_tlsv1 = rb_funcall(mini_ssl_ctx, sym_no_tlsv1, 0);
170
+
171
+
164
172
  ctx = SSL_CTX_new(SSLv23_server_method());
165
173
  conn->ctx = ctx;
166
174
 
@@ -172,20 +180,37 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
172
180
  SSL_CTX_load_verify_locations(ctx, RSTRING_PTR(ca), NULL);
173
181
  }
174
182
 
175
- SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_COMPRESSION);
183
+ ssl_options = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_COMPRESSION;
184
+
185
+ if(RTEST(no_tlsv1)) {
186
+ ssl_options |= SSL_OP_NO_TLSv1;
187
+ }
188
+ SSL_CTX_set_options(ctx, ssl_options);
176
189
  SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
177
190
 
178
- SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL@STRENGTH");
191
+ if (!NIL_P(ssl_cipher_filter)) {
192
+ StringValue(ssl_cipher_filter);
193
+ SSL_CTX_set_cipher_list(ctx, RSTRING_PTR(ssl_cipher_filter));
194
+ }
195
+ else {
196
+ SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL@STRENGTH");
197
+ }
179
198
 
180
199
  DH *dh = get_dh1024();
181
200
  SSL_CTX_set_tmp_dh(ctx, dh);
182
201
 
183
- #ifndef OPENSSL_NO_ECDH
184
- EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_secp521r1);
202
+ #if OPENSSL_VERSION_NUMBER < 0x10002000L
203
+ // Remove this case if OpenSSL 1.0.1 (now EOL) support is no
204
+ // longer needed.
205
+ EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
185
206
  if (ecdh) {
186
207
  SSL_CTX_set_tmp_ecdh(ctx, ecdh);
187
208
  EC_KEY_free(ecdh);
188
209
  }
210
+ #elif OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
211
+ // Prior to OpenSSL 1.1.0, servers must manually enable server-side ECDH
212
+ // negotiation.
213
+ SSL_CTX_set_ecdh_auto(ctx, 1);
189
214
  #endif
190
215
 
191
216
  ssl = SSL_new(ctx);
@@ -208,7 +233,7 @@ VALUE engine_init_client(VALUE klass) {
208
233
  VALUE obj;
209
234
  ms_conn* conn = engine_alloc(klass, &obj);
210
235
 
211
- conn->ctx = SSL_CTX_new(DTLSv1_method());
236
+ conn->ctx = SSL_CTX_new(DTLS_method());
212
237
  conn->ssl = SSL_new(conn->ctx);
213
238
  SSL_set_app_data(conn->ssl, NULL);
214
239
  SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
@@ -424,6 +449,18 @@ void Init_mini_ssl(VALUE puma) {
424
449
  mod = rb_define_module_under(puma, "MiniSSL");
425
450
  eng = rb_define_class_under(mod, "Engine", rb_cObject);
426
451
 
452
+ // OpenSSL Build / Runtime/Load versions
453
+
454
+ /* Version of OpenSSL that Puma was compiled with */
455
+ rb_define_const(mod, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT));
456
+
457
+ #if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000
458
+ /* Version of OpenSSL that Puma loaded with */
459
+ rb_define_const(mod, "OPENSSL_LIBRARY_VERSION", rb_str_new2(OpenSSL_version(OPENSSL_VERSION)));
460
+ #else
461
+ rb_define_const(mod, "OPENSSL_LIBRARY_VERSION", rb_str_new2(SSLeay_version(SSLEAY_VERSION)));
462
+ #endif
463
+
427
464
  rb_define_singleton_method(mod, "check", noop, 0);
428
465
 
429
466
  eError = rb_define_class_under(mod, "SSLError", rb_eStandardError);