puma 3.12.1 → 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.
- checksums.yaml +4 -4
- data/History.md +26 -5
- data/README.md +29 -9
- data/docs/architecture.md +1 -0
- data/docs/deployment.md +24 -4
- data/docs/restart.md +4 -2
- data/docs/systemd.md +27 -9
- data/ext/puma_http11/PumaHttp11Service.java +2 -0
- data/ext/puma_http11/mini_ssl.c +20 -4
- data/ext/puma_http11/org/jruby/puma/IOBuffer.java +72 -0
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +11 -4
- data/lib/puma/app/status.rb +3 -2
- data/lib/puma/binder.rb +9 -1
- data/lib/puma/client.rb +43 -25
- data/lib/puma/cluster.rb +38 -14
- data/lib/puma/configuration.rb +2 -1
- data/lib/puma/const.rb +6 -2
- data/lib/puma/control_cli.rb +10 -0
- data/lib/puma/dsl.rb +45 -3
- data/lib/puma/io_buffer.rb +1 -6
- data/lib/puma/launcher.rb +10 -11
- data/lib/puma/minissl.rb +13 -1
- data/lib/puma/reactor.rb +104 -53
- data/lib/puma/runner.rb +1 -1
- data/lib/puma/server.rb +25 -24
- data/lib/puma/single.rb +2 -2
- data/lib/puma/thread_pool.rb +5 -1
- data/lib/puma/util.rb +1 -6
- data/tools/jungle/init.d/puma +5 -5
- metadata +22 -11
- data/lib/puma/compat.rb +0 -14
- data/lib/puma/java_io_buffer.rb +0 -47
- data/lib/puma/rack/backports/uri/common_193.rb +0 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b22a5ddb0ac910e28c3789564c70be998eaa0dec5eca7c668c6a4478ab35012b
|
4
|
+
data.tar.gz: b98d67fb71305279ee8169c80546e46d4b63a4be522462545023f8917d82fa72
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1f7186d10e0783ffd899b65b25fdda553346074b3bad7416726a99a0f77709318a275e67856beb101ff75c9b75dba48af917d48504bf6f5fc15b64dd7c8a190a
|
7
|
+
data.tar.gz: 1881c9c149c4e631c9bec14cd92344785933c81bf4fb997721c61081d4a3f6f9a5bf4cbf0f8faca44110deaa7331b6177a67d734af3006b1e0b677a7782fc5f9
|
data/History.md
CHANGED
@@ -1,10 +1,31 @@
|
|
1
1
|
## Master
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
8
29
|
|
9
30
|
* 1 features
|
10
31
|
* Internal strings are frozen (#1649)
|
data/README.md
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
<p align="center">
|
2
|
-
<img src="
|
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)](
|
9
|
-
[![
|
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](
|
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
|
|
@@ -160,18 +160,31 @@ Need a bit of security? Use SSL sockets:
|
|
160
160
|
```
|
161
161
|
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert'
|
162
162
|
```
|
163
|
+
|
163
164
|
#### Controlling SSL Cipher Suites
|
164
|
-
|
165
|
-
|
165
|
+
|
166
|
+
Need to use or avoid specific SSL cipher suites? Use `ssl_cipher_filter` or `ssl_cipher_list` options.
|
167
|
+
|
168
|
+
##### Ruby:
|
169
|
+
|
166
170
|
```
|
167
171
|
$ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&ssl_cipher_filter=!aNULL:AES+SHA'
|
168
172
|
```
|
169
|
-
|
173
|
+
|
174
|
+
##### JRuby:
|
175
|
+
|
170
176
|
```
|
171
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'
|
172
178
|
```
|
179
|
+
|
173
180
|
See https://www.openssl.org/docs/man1.0.2/apps/ciphers.html for cipher filter format and full list of cipher suites.
|
174
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
|
+
|
175
188
|
### Control/Status Server
|
176
189
|
|
177
190
|
Puma has a built-in status/control app that can be used to query and control Puma itself.
|
@@ -249,6 +262,13 @@ reliability in production environments:
|
|
249
262
|
* [tools/jungle](https://github.com/puma/puma/tree/master/tools/jungle) for sysvinit (init.d) and upstart
|
250
263
|
* [docs/systemd](https://github.com/puma/puma/blob/master/docs/systemd.md)
|
251
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
|
+
|
252
272
|
## Contributing
|
253
273
|
|
254
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)
|
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'
|
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
|
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
|
-
|
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
|
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.
|
@@ -22,6 +22,8 @@ But again beware, upgrading an application sometimes involves upgrading the data
|
|
22
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
24
|
|
25
|
+
**Note**: Hot and phased restarts are only available on MRI, not on JRuby. They are also unavailable on Windows servers.
|
26
|
+
|
25
27
|
### Release Directory
|
26
28
|
|
27
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.
|
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
|
36
|
-
# Also replace the "<
|
37
|
-
|
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
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
ExecStart
|
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
|
|
@@ -247,6 +259,12 @@ PIDFile=<WD>/shared/tmp/pids/puma.pid
|
|
247
259
|
# reconsider if you actually need the forking config.
|
248
260
|
Restart=no
|
249
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
|
+
|
250
268
|
[Install]
|
251
269
|
WantedBy=multi-user.target
|
252
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
|
}
|
data/ext/puma_http11/mini_ssl.c
CHANGED
@@ -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
|
|
@@ -164,6 +165,10 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
|
|
164
165
|
ID sym_ssl_cipher_filter = rb_intern("ssl_cipher_filter");
|
165
166
|
VALUE ssl_cipher_filter = rb_funcall(mini_ssl_ctx, sym_ssl_cipher_filter, 0);
|
166
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
|
+
|
167
172
|
ctx = SSL_CTX_new(SSLv23_server_method());
|
168
173
|
conn->ctx = ctx;
|
169
174
|
|
@@ -175,7 +180,12 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
|
|
175
180
|
SSL_CTX_load_verify_locations(ctx, RSTRING_PTR(ca), NULL);
|
176
181
|
}
|
177
182
|
|
178
|
-
|
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);
|
179
189
|
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
|
180
190
|
|
181
191
|
if (!NIL_P(ssl_cipher_filter)) {
|
@@ -189,12 +199,18 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
|
|
189
199
|
DH *dh = get_dh1024();
|
190
200
|
SSL_CTX_set_tmp_dh(ctx, dh);
|
191
201
|
|
192
|
-
#
|
193
|
-
|
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);
|
194
206
|
if (ecdh) {
|
195
207
|
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
|
196
208
|
EC_KEY_free(ecdh);
|
197
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);
|
198
214
|
#endif
|
199
215
|
|
200
216
|
ssl = SSL_new(ctx);
|
@@ -217,7 +233,7 @@ VALUE engine_init_client(VALUE klass) {
|
|
217
233
|
VALUE obj;
|
218
234
|
ms_conn* conn = engine_alloc(klass, &obj);
|
219
235
|
|
220
|
-
conn->ctx = SSL_CTX_new(
|
236
|
+
conn->ctx = SSL_CTX_new(DTLS_method());
|
221
237
|
conn->ssl = SSL_new(conn->ctx);
|
222
238
|
SSL_set_app_data(conn->ssl, NULL);
|
223
239
|
SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
|
@@ -0,0 +1,72 @@
|
|
1
|
+
package org.jruby.puma;
|
2
|
+
|
3
|
+
import org.jruby.*;
|
4
|
+
import org.jruby.anno.JRubyMethod;
|
5
|
+
import org.jruby.runtime.ObjectAllocator;
|
6
|
+
import org.jruby.runtime.ThreadContext;
|
7
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
8
|
+
import org.jruby.util.ByteList;
|
9
|
+
|
10
|
+
/**
|
11
|
+
* @author kares
|
12
|
+
*/
|
13
|
+
public class IOBuffer extends RubyObject {
|
14
|
+
|
15
|
+
private static final ObjectAllocator ALLOCATOR = new ObjectAllocator() {
|
16
|
+
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
|
17
|
+
return new IOBuffer(runtime, klass);
|
18
|
+
}
|
19
|
+
};
|
20
|
+
|
21
|
+
public static void createIOBuffer(Ruby runtime) {
|
22
|
+
RubyModule mPuma = runtime.defineModule("Puma");
|
23
|
+
RubyClass cIOBuffer = mPuma.defineClassUnder("IOBuffer", runtime.getObject(), ALLOCATOR);
|
24
|
+
cIOBuffer.defineAnnotatedMethods(IOBuffer.class);
|
25
|
+
}
|
26
|
+
|
27
|
+
private static final int DEFAULT_SIZE = 4096;
|
28
|
+
|
29
|
+
final ByteList buffer = new ByteList(DEFAULT_SIZE);
|
30
|
+
|
31
|
+
IOBuffer(Ruby runtime, RubyClass klass) {
|
32
|
+
super(runtime, klass);
|
33
|
+
}
|
34
|
+
|
35
|
+
@JRubyMethod
|
36
|
+
public RubyInteger used(ThreadContext context) {
|
37
|
+
return context.runtime.newFixnum(buffer.getRealSize());
|
38
|
+
}
|
39
|
+
|
40
|
+
@JRubyMethod
|
41
|
+
public RubyInteger capacity(ThreadContext context) {
|
42
|
+
return context.runtime.newFixnum(buffer.unsafeBytes().length);
|
43
|
+
}
|
44
|
+
|
45
|
+
@JRubyMethod
|
46
|
+
public IRubyObject reset() {
|
47
|
+
buffer.setRealSize(0);
|
48
|
+
return this;
|
49
|
+
}
|
50
|
+
|
51
|
+
@JRubyMethod(name = { "to_s", "to_str" })
|
52
|
+
public RubyString to_s(ThreadContext context) {
|
53
|
+
return RubyString.newStringShared(context.runtime, buffer.unsafeBytes(), 0, buffer.getRealSize());
|
54
|
+
}
|
55
|
+
|
56
|
+
@JRubyMethod(name = "<<")
|
57
|
+
public IRubyObject add(IRubyObject str) {
|
58
|
+
addImpl(str.convertToString());
|
59
|
+
return this;
|
60
|
+
}
|
61
|
+
|
62
|
+
@JRubyMethod(rest = true)
|
63
|
+
public IRubyObject append(IRubyObject[] strs) {
|
64
|
+
for (IRubyObject str : strs) addImpl(str.convertToString());
|
65
|
+
return this;
|
66
|
+
}
|
67
|
+
|
68
|
+
private void addImpl(RubyString str) {
|
69
|
+
buffer.append(str.getByteList());
|
70
|
+
}
|
71
|
+
|
72
|
+
}
|
@@ -23,6 +23,7 @@ import javax.net.ssl.SSLPeerUnverifiedException;
|
|
23
23
|
import javax.net.ssl.SSLSession;
|
24
24
|
import java.io.FileInputStream;
|
25
25
|
import java.io.IOException;
|
26
|
+
import java.nio.Buffer;
|
26
27
|
import java.nio.ByteBuffer;
|
27
28
|
import java.security.KeyManagementException;
|
28
29
|
import java.security.KeyStore;
|
@@ -65,7 +66,7 @@ public class MiniSSL extends RubyObject {
|
|
65
66
|
|
66
67
|
public void clear() { buffer.clear(); }
|
67
68
|
public void compact() { buffer.compact(); }
|
68
|
-
public void flip() { buffer.flip(); }
|
69
|
+
public void flip() { ((Buffer) buffer).flip(); }
|
69
70
|
public boolean hasRemaining() { return buffer.hasRemaining(); }
|
70
71
|
public int position() { return buffer.position(); }
|
71
72
|
|
@@ -89,7 +90,7 @@ public class MiniSSL extends RubyObject {
|
|
89
90
|
public void resize(int newCapacity) {
|
90
91
|
if (newCapacity > buffer.capacity()) {
|
91
92
|
ByteBuffer dstTmp = ByteBuffer.allocate(newCapacity);
|
92
|
-
|
93
|
+
flip();
|
93
94
|
dstTmp.put(buffer);
|
94
95
|
buffer = dstTmp;
|
95
96
|
} else {
|
@@ -101,7 +102,7 @@ public class MiniSSL extends RubyObject {
|
|
101
102
|
* Drains the buffer to a ByteList, or returns null for an empty buffer
|
102
103
|
*/
|
103
104
|
public ByteList asByteList() {
|
104
|
-
|
105
|
+
flip();
|
105
106
|
if (!buffer.hasRemaining()) {
|
106
107
|
buffer.clear();
|
107
108
|
return null;
|
@@ -158,7 +159,13 @@ public class MiniSSL extends RubyObject {
|
|
158
159
|
sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
|
159
160
|
engine = sslCtx.createSSLEngine();
|
160
161
|
|
161
|
-
String[] protocols
|
162
|
+
String[] protocols;
|
163
|
+
if(miniSSLContext.callMethod(threadContext, "no_tlsv1").isTrue()) {
|
164
|
+
protocols = new String[] { "TLSv1.1", "TLSv1.2" };
|
165
|
+
} else {
|
166
|
+
protocols = new String[] { "TLSv1", "TLSv1.1", "TLSv1.2" };
|
167
|
+
}
|
168
|
+
|
162
169
|
engine.setEnabledProtocols(protocols);
|
163
170
|
engine.setUseClientMode(false);
|
164
171
|
|