puma 3.8.2 → 4.3.12
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 +5 -5
- data/History.md +305 -0
- data/LICENSE +0 -0
- data/README.md +162 -224
- data/bin/puma-wild +0 -0
- data/docs/architecture.md +37 -0
- data/{DEPLOYMENT.md → docs/deployment.md} +24 -4
- data/docs/images/puma-connection-flow-no-reactor.png +0 -0
- data/docs/images/puma-connection-flow.png +0 -0
- data/docs/images/puma-general-arch.png +0 -0
- data/docs/nginx.md +0 -0
- data/docs/plugins.md +38 -0
- data/docs/restart.md +41 -0
- data/docs/signals.md +56 -3
- data/docs/systemd.md +130 -37
- data/docs/tcp_mode.md +96 -0
- data/ext/puma_http11/PumaHttp11Service.java +2 -0
- data/ext/puma_http11/ext_help.h +0 -0
- data/ext/puma_http11/extconf.rb +21 -0
- data/ext/puma_http11/http11_parser.c +134 -144
- data/ext/puma_http11/http11_parser.h +0 -0
- data/ext/puma_http11/http11_parser.java.rl +21 -37
- data/ext/puma_http11/http11_parser.rl +12 -10
- data/ext/puma_http11/http11_parser_common.rl +4 -4
- data/ext/puma_http11/io_buffer.c +0 -0
- data/ext/puma_http11/mini_ssl.c +165 -34
- data/ext/puma_http11/org/jruby/puma/Http11.java +106 -114
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +85 -101
- data/ext/puma_http11/org/jruby/puma/IOBuffer.java +72 -0
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +30 -6
- data/ext/puma_http11/puma_http11.c +3 -0
- data/lib/puma/accept_nonblock.rb +7 -1
- data/lib/puma/app/status.rb +42 -26
- data/lib/puma/binder.rb +57 -74
- data/lib/puma/cli.rb +26 -7
- data/lib/puma/client.rb +307 -191
- data/lib/puma/cluster.rb +78 -34
- data/lib/puma/commonlogger.rb +2 -0
- data/lib/puma/configuration.rb +24 -16
- data/lib/puma/const.rb +41 -20
- data/lib/puma/control_cli.rb +46 -19
- data/lib/puma/detect.rb +2 -0
- data/lib/puma/dsl.rb +329 -68
- data/lib/puma/events.rb +6 -2
- data/lib/puma/io_buffer.rb +3 -6
- data/lib/puma/jruby_restart.rb +2 -1
- data/lib/puma/launcher.rb +125 -61
- data/lib/puma/minissl/context_builder.rb +76 -0
- data/lib/puma/minissl.rb +85 -28
- data/lib/puma/null_io.rb +2 -0
- data/lib/puma/plugin/tmp_restart.rb +2 -1
- data/lib/puma/plugin.rb +7 -2
- data/lib/puma/rack/builder.rb +4 -1
- data/lib/puma/rack/urlmap.rb +2 -0
- data/lib/puma/rack_default.rb +2 -0
- data/lib/puma/reactor.rb +224 -34
- data/lib/puma/runner.rb +27 -6
- data/lib/puma/server.rb +212 -68
- data/lib/puma/single.rb +16 -5
- data/lib/puma/state_file.rb +2 -0
- data/lib/puma/tcp_logger.rb +2 -0
- data/lib/puma/thread_pool.rb +67 -36
- data/lib/puma/util.rb +2 -6
- data/lib/puma.rb +16 -0
- data/lib/rack/handler/puma.rb +16 -5
- data/tools/docker/Dockerfile +16 -0
- data/tools/jungle/README.md +12 -2
- data/tools/jungle/init.d/README.md +2 -0
- data/tools/jungle/init.d/puma +8 -8
- data/tools/jungle/init.d/run-puma +1 -1
- data/tools/jungle/rc.d/README.md +74 -0
- data/tools/jungle/rc.d/puma +61 -0
- data/tools/jungle/rc.d/puma.conf +10 -0
- data/tools/jungle/upstart/README.md +0 -0
- data/tools/jungle/upstart/puma-manager.conf +0 -0
- data/tools/jungle/upstart/puma.conf +0 -0
- data/tools/trickletest.rb +1 -2
- metadata +32 -93
- data/.github/issue_template.md +0 -20
- data/Gemfile +0 -12
- data/Manifest.txt +0 -78
- data/Rakefile +0 -158
- data/Release.md +0 -9
- data/gemfiles/2.1-Gemfile +0 -12
- data/lib/puma/compat.rb +0 -14
- data/lib/puma/convenient.rb +0 -23
- data/lib/puma/daemon_ext.rb +0 -31
- data/lib/puma/delegation.rb +0 -11
- data/lib/puma/java_io_buffer.rb +0 -45
- data/lib/puma/rack/backports/uri/common_193.rb +0 -33
- data/puma.gemspec +0 -52
@@ -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
|
+
}
|
@@ -6,6 +6,7 @@ import org.jruby.RubyModule;
|
|
6
6
|
import org.jruby.RubyObject;
|
7
7
|
import org.jruby.RubyString;
|
8
8
|
import org.jruby.anno.JRubyMethod;
|
9
|
+
import org.jruby.javasupport.JavaEmbedUtils;
|
9
10
|
import org.jruby.runtime.Block;
|
10
11
|
import org.jruby.runtime.ObjectAllocator;
|
11
12
|
import org.jruby.runtime.ThreadContext;
|
@@ -18,15 +19,18 @@ import javax.net.ssl.SSLContext;
|
|
18
19
|
import javax.net.ssl.SSLEngine;
|
19
20
|
import javax.net.ssl.SSLEngineResult;
|
20
21
|
import javax.net.ssl.SSLException;
|
22
|
+
import javax.net.ssl.SSLPeerUnverifiedException;
|
21
23
|
import javax.net.ssl.SSLSession;
|
22
24
|
import java.io.FileInputStream;
|
23
25
|
import java.io.IOException;
|
26
|
+
import java.nio.Buffer;
|
24
27
|
import java.nio.ByteBuffer;
|
25
28
|
import java.security.KeyManagementException;
|
26
29
|
import java.security.KeyStore;
|
27
30
|
import java.security.KeyStoreException;
|
28
31
|
import java.security.NoSuchAlgorithmException;
|
29
32
|
import java.security.UnrecoverableKeyException;
|
33
|
+
import java.security.cert.CertificateEncodingException;
|
30
34
|
import java.security.cert.CertificateException;
|
31
35
|
|
32
36
|
import static javax.net.ssl.SSLEngineResult.Status;
|
@@ -62,7 +66,7 @@ public class MiniSSL extends RubyObject {
|
|
62
66
|
|
63
67
|
public void clear() { buffer.clear(); }
|
64
68
|
public void compact() { buffer.compact(); }
|
65
|
-
public void flip() { buffer.flip(); }
|
69
|
+
public void flip() { ((Buffer) buffer).flip(); }
|
66
70
|
public boolean hasRemaining() { return buffer.hasRemaining(); }
|
67
71
|
public int position() { return buffer.position(); }
|
68
72
|
|
@@ -86,7 +90,7 @@ public class MiniSSL extends RubyObject {
|
|
86
90
|
public void resize(int newCapacity) {
|
87
91
|
if (newCapacity > buffer.capacity()) {
|
88
92
|
ByteBuffer dstTmp = ByteBuffer.allocate(newCapacity);
|
89
|
-
|
93
|
+
flip();
|
90
94
|
dstTmp.put(buffer);
|
91
95
|
buffer = dstTmp;
|
92
96
|
} else {
|
@@ -98,7 +102,7 @@ public class MiniSSL extends RubyObject {
|
|
98
102
|
* Drains the buffer to a ByteList, or returns null for an empty buffer
|
99
103
|
*/
|
100
104
|
public ByteList asByteList() {
|
101
|
-
|
105
|
+
flip();
|
102
106
|
if (!buffer.hasRemaining()) {
|
103
107
|
buffer.clear();
|
104
108
|
return null;
|
@@ -155,7 +159,17 @@ public class MiniSSL extends RubyObject {
|
|
155
159
|
sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
|
156
160
|
engine = sslCtx.createSSLEngine();
|
157
161
|
|
158
|
-
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
|
+
|
169
|
+
if(miniSSLContext.callMethod(threadContext, "no_tlsv1_1").isTrue()) {
|
170
|
+
protocols = new String[] { "TLSv1.2" };
|
171
|
+
}
|
172
|
+
|
159
173
|
engine.setEnabledProtocols(protocols);
|
160
174
|
engine.setUseClientMode(false);
|
161
175
|
|
@@ -167,6 +181,12 @@ public class MiniSSL extends RubyObject {
|
|
167
181
|
engine.setNeedClientAuth(true);
|
168
182
|
}
|
169
183
|
|
184
|
+
IRubyObject sslCipherListObject = miniSSLContext.callMethod(threadContext, "ssl_cipher_list");
|
185
|
+
if (!sslCipherListObject.isNil()) {
|
186
|
+
String[] sslCipherList = sslCipherListObject.convertToString().asJavaString().split(",");
|
187
|
+
engine.setEnabledCipherSuites(sslCipherList);
|
188
|
+
}
|
189
|
+
|
170
190
|
SSLSession session = engine.getSession();
|
171
191
|
inboundNetData = new MiniSSLBuffer(session.getPacketBufferSize());
|
172
192
|
outboundAppData = new MiniSSLBuffer(session.getApplicationBufferSize());
|
@@ -333,7 +353,11 @@ public class MiniSSL extends RubyObject {
|
|
333
353
|
}
|
334
354
|
|
335
355
|
@JRubyMethod
|
336
|
-
public IRubyObject peercert() {
|
337
|
-
|
356
|
+
public IRubyObject peercert() throws CertificateEncodingException {
|
357
|
+
try {
|
358
|
+
return JavaEmbedUtils.javaToRuby(getRuntime(), engine.getSession().getPeerCertificates()[0].getEncoded());
|
359
|
+
} catch (SSLPeerUnverifiedException ex) {
|
360
|
+
return getRuntime().getNil();
|
361
|
+
}
|
338
362
|
}
|
339
363
|
}
|
@@ -10,6 +10,7 @@
|
|
10
10
|
#include "ext_help.h"
|
11
11
|
#include <assert.h>
|
12
12
|
#include <string.h>
|
13
|
+
#include <ctype.h>
|
13
14
|
#include "http11_parser.h"
|
14
15
|
|
15
16
|
#ifndef MANAGED_STRINGS
|
@@ -200,6 +201,8 @@ void http_field(puma_parser* hp, const char *field, size_t flen,
|
|
200
201
|
f = rb_str_new(hp->buf, new_size);
|
201
202
|
}
|
202
203
|
|
204
|
+
while (vlen > 0 && isspace(value[vlen - 1])) vlen--;
|
205
|
+
|
203
206
|
/* check for duplicate header */
|
204
207
|
v = rb_hash_aref(hp->request, f);
|
205
208
|
|
data/lib/puma/accept_nonblock.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'openssl'
|
2
4
|
|
3
5
|
module OpenSSL
|
@@ -13,7 +15,11 @@ module OpenSSL
|
|
13
15
|
ssl.accept if @start_immediately
|
14
16
|
ssl
|
15
17
|
rescue SSLError => ex
|
16
|
-
|
18
|
+
if ssl
|
19
|
+
ssl.close
|
20
|
+
else
|
21
|
+
sock.close
|
22
|
+
end
|
17
23
|
raise ex
|
18
24
|
end
|
19
25
|
end
|
data/lib/puma/app/status.rb
CHANGED
@@ -1,26 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Puma
|
2
4
|
module App
|
5
|
+
# Check out {#call}'s source code to see what actions this web application
|
6
|
+
# can respond to.
|
3
7
|
class Status
|
4
|
-
def initialize(cli)
|
5
|
-
@cli = cli
|
6
|
-
@auth_token = nil
|
7
|
-
end
|
8
8
|
OK_STATUS = '{ "status": "ok" }'.freeze
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
return true unless @auth_token
|
14
|
-
env['QUERY_STRING'].to_s.split(/&;/).include?("token=#{@auth_token}")
|
15
|
-
end
|
16
|
-
|
17
|
-
def rack_response(status, body, content_type='application/json')
|
18
|
-
headers = {
|
19
|
-
'Content-Type' => content_type,
|
20
|
-
'Content-Length' => body.bytesize.to_s
|
21
|
-
}
|
22
|
-
|
23
|
-
[status, headers, [body]]
|
10
|
+
def initialize(cli, token = nil)
|
11
|
+
@cli = cli
|
12
|
+
@auth_token = token
|
24
13
|
end
|
25
14
|
|
26
15
|
def call(env)
|
@@ -28,39 +17,66 @@ module Puma
|
|
28
17
|
return rack_response(403, 'Invalid auth token', 'text/plain')
|
29
18
|
end
|
30
19
|
|
20
|
+
if env['PATH_INFO'] =~ /\/(gc-stats|stats|thread-backtraces)$/
|
21
|
+
require 'json'
|
22
|
+
end
|
23
|
+
|
31
24
|
case env['PATH_INFO']
|
32
25
|
when /\/stop$/
|
33
26
|
@cli.stop
|
34
|
-
|
27
|
+
rack_response(200, OK_STATUS)
|
35
28
|
|
36
29
|
when /\/halt$/
|
37
30
|
@cli.halt
|
38
|
-
|
31
|
+
rack_response(200, OK_STATUS)
|
39
32
|
|
40
33
|
when /\/restart$/
|
41
34
|
@cli.restart
|
42
|
-
|
35
|
+
rack_response(200, OK_STATUS)
|
43
36
|
|
44
37
|
when /\/phased-restart$/
|
45
38
|
if !@cli.phased_restart
|
46
|
-
|
39
|
+
rack_response(404, '{ "error": "phased restart not available" }')
|
47
40
|
else
|
48
|
-
|
41
|
+
rack_response(200, OK_STATUS)
|
49
42
|
end
|
50
43
|
|
51
44
|
when /\/reload-worker-directory$/
|
52
45
|
if !@cli.send(:reload_worker_directory)
|
53
|
-
|
46
|
+
rack_response(404, '{ "error": "reload_worker_directory not available" }')
|
54
47
|
else
|
55
|
-
|
48
|
+
rack_response(200, OK_STATUS)
|
56
49
|
end
|
57
50
|
|
51
|
+
when /\/gc$/
|
52
|
+
GC.start
|
53
|
+
rack_response(200, OK_STATUS)
|
54
|
+
|
55
|
+
when /\/gc-stats$/
|
56
|
+
rack_response(200, GC.stat.to_json)
|
57
|
+
|
58
58
|
when /\/stats$/
|
59
|
-
|
59
|
+
rack_response(200, @cli.stats)
|
60
60
|
else
|
61
61
|
rack_response 404, "Unsupported action", 'text/plain'
|
62
62
|
end
|
63
63
|
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def authenticate(env)
|
68
|
+
return true unless @auth_token
|
69
|
+
env['QUERY_STRING'].to_s.split(/&;/).include?("token=#{@auth_token}")
|
70
|
+
end
|
71
|
+
|
72
|
+
def rack_response(status, body, content_type='application/json')
|
73
|
+
headers = {
|
74
|
+
'Content-Type' => content_type,
|
75
|
+
'Content-Length' => body.bytesize.to_s
|
76
|
+
}
|
77
|
+
|
78
|
+
[status, headers, [body]]
|
79
|
+
end
|
64
80
|
end
|
65
81
|
end
|
66
82
|
end
|
data/lib/puma/binder.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'uri'
|
2
4
|
require 'socket'
|
3
5
|
|
4
6
|
require 'puma/const'
|
5
7
|
require 'puma/util'
|
8
|
+
require 'puma/minissl/context_builder'
|
6
9
|
|
7
10
|
module Puma
|
8
11
|
class Binder
|
@@ -40,7 +43,7 @@ module Puma
|
|
40
43
|
@ios = []
|
41
44
|
end
|
42
45
|
|
43
|
-
attr_reader :
|
46
|
+
attr_reader :ios
|
44
47
|
|
45
48
|
def env(sock)
|
46
49
|
@envs.fetch(sock, @proto_env)
|
@@ -48,7 +51,6 @@ module Puma
|
|
48
51
|
|
49
52
|
def close
|
50
53
|
@ios.each { |i| i.close }
|
51
|
-
@unix_paths.each { |i| File.unlink i }
|
52
54
|
end
|
53
55
|
|
54
56
|
def import_from_env
|
@@ -90,19 +92,29 @@ module Puma
|
|
90
92
|
case uri.scheme
|
91
93
|
when "tcp"
|
92
94
|
if fd = @inherited_fds.delete(str)
|
93
|
-
logger.log "* Inherited #{str}"
|
94
95
|
io = inherit_tcp_listener uri.host, uri.port, fd
|
96
|
+
logger.log "* Inherited #{str}"
|
95
97
|
elsif sock = @activated_sockets.delete([ :tcp, uri.host, uri.port ])
|
96
|
-
logger.log "* Activated #{str}"
|
97
98
|
io = inherit_tcp_listener uri.host, uri.port, sock
|
99
|
+
logger.log "* Activated #{str}"
|
98
100
|
else
|
99
101
|
params = Util.parse_query uri.query
|
100
102
|
|
101
103
|
opt = params.key?('low_latency')
|
102
104
|
bak = params.fetch('backlog', 1024).to_i
|
103
105
|
|
104
|
-
logger.log "* Listening on #{str}"
|
105
106
|
io = add_tcp_listener uri.host, uri.port, opt, bak
|
107
|
+
|
108
|
+
@ios.each do |i|
|
109
|
+
next unless TCPServer === i
|
110
|
+
addr = if i.local_address.ipv6?
|
111
|
+
"[#{i.local_address.ip_unpack[0]}]:#{i.local_address.ip_unpack[1]}"
|
112
|
+
else
|
113
|
+
i.local_address.ip_unpack.join(':')
|
114
|
+
end
|
115
|
+
|
116
|
+
logger.log "* Listening on tcp://#{addr}"
|
117
|
+
end
|
106
118
|
end
|
107
119
|
|
108
120
|
@listeners << [str, io] if io
|
@@ -110,17 +122,15 @@ module Puma
|
|
110
122
|
path = "#{uri.host}#{uri.path}".gsub("%20", " ")
|
111
123
|
|
112
124
|
if fd = @inherited_fds.delete(str)
|
113
|
-
logger.log "* Inherited #{str}"
|
114
125
|
io = inherit_unix_listener path, fd
|
126
|
+
logger.log "* Inherited #{str}"
|
115
127
|
elsif sock = @activated_sockets.delete([ :unix, path ])
|
116
|
-
logger.log "* Activated #{str}"
|
117
128
|
io = inherit_unix_listener path, sock
|
129
|
+
logger.log "* Activated #{str}"
|
118
130
|
else
|
119
|
-
logger.log "* Listening on #{str}"
|
120
|
-
|
121
131
|
umask = nil
|
122
132
|
mode = nil
|
123
|
-
backlog =
|
133
|
+
backlog = 1024
|
124
134
|
|
125
135
|
if uri.query
|
126
136
|
params = Util.parse_query uri.query
|
@@ -139,74 +149,23 @@ module Puma
|
|
139
149
|
end
|
140
150
|
|
141
151
|
io = add_unix_listener path, umask, mode, backlog
|
152
|
+
logger.log "* Listening on #{str}"
|
142
153
|
end
|
143
154
|
|
144
155
|
@listeners << [str, io]
|
145
156
|
when "ssl"
|
146
157
|
params = Util.parse_query uri.query
|
147
|
-
|
148
|
-
|
149
|
-
MiniSSL.check
|
150
|
-
|
151
|
-
ctx = MiniSSL::Context.new
|
152
|
-
|
153
|
-
if defined?(JRUBY_VERSION)
|
154
|
-
unless params['keystore']
|
155
|
-
@events.error "Please specify the Java keystore via 'keystore='"
|
156
|
-
end
|
157
|
-
|
158
|
-
ctx.keystore = params['keystore']
|
159
|
-
|
160
|
-
unless params['keystore-pass']
|
161
|
-
@events.error "Please specify the Java keystore password via 'keystore-pass='"
|
162
|
-
end
|
163
|
-
|
164
|
-
ctx.keystore_pass = params['keystore-pass']
|
165
|
-
else
|
166
|
-
unless params['key']
|
167
|
-
@events.error "Please specify the SSL key via 'key='"
|
168
|
-
end
|
169
|
-
|
170
|
-
ctx.key = params['key']
|
171
|
-
|
172
|
-
unless params['cert']
|
173
|
-
@events.error "Please specify the SSL cert via 'cert='"
|
174
|
-
end
|
175
|
-
|
176
|
-
ctx.cert = params['cert']
|
177
|
-
|
178
|
-
if ['peer', 'force_peer'].include?(params['verify_mode'])
|
179
|
-
unless params['ca']
|
180
|
-
@events.error "Please specify the SSL ca via 'ca='"
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
ctx.ca = params['ca'] if params['ca']
|
185
|
-
end
|
186
|
-
|
187
|
-
if params['verify_mode']
|
188
|
-
ctx.verify_mode = case params['verify_mode']
|
189
|
-
when "peer"
|
190
|
-
MiniSSL::VERIFY_PEER
|
191
|
-
when "force_peer"
|
192
|
-
MiniSSL::VERIFY_PEER | MiniSSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
193
|
-
when "none"
|
194
|
-
MiniSSL::VERIFY_NONE
|
195
|
-
else
|
196
|
-
@events.error "Please specify a valid verify_mode="
|
197
|
-
MiniSSL::VERIFY_NONE
|
198
|
-
end
|
199
|
-
end
|
158
|
+
ctx = MiniSSL::ContextBuilder.new(params, @events).context
|
200
159
|
|
201
160
|
if fd = @inherited_fds.delete(str)
|
202
161
|
logger.log "* Inherited #{str}"
|
203
162
|
io = inherit_ssl_listener fd, ctx
|
204
163
|
elsif sock = @activated_sockets.delete([ :tcp, uri.host, uri.port ])
|
205
|
-
logger.log "* Activated #{str}"
|
206
164
|
io = inherit_ssl_listener sock, ctx
|
165
|
+
logger.log "* Activated #{str}"
|
207
166
|
else
|
208
|
-
logger.log "* Listening on #{str}"
|
209
167
|
io = add_ssl_listener uri.host, uri.port, ctx
|
168
|
+
logger.log "* Listening on #{str}"
|
210
169
|
end
|
211
170
|
|
212
171
|
@listeners << [str, io] if io
|
@@ -245,9 +204,10 @@ module Puma
|
|
245
204
|
end
|
246
205
|
end
|
247
206
|
|
248
|
-
def
|
249
|
-
|
250
|
-
|
207
|
+
def loopback_addresses
|
208
|
+
Socket.ip_address_list.select do |addrinfo|
|
209
|
+
addrinfo.ipv6_loopback? || addrinfo.ipv4_loopback?
|
210
|
+
end.map { |addrinfo| addrinfo.ip_address }.uniq
|
251
211
|
end
|
252
212
|
|
253
213
|
# Tell the server to listen on host +host+, port +port+.
|
@@ -259,7 +219,7 @@ module Puma
|
|
259
219
|
#
|
260
220
|
def add_tcp_listener(host, port, optimize_for_latency=true, backlog=1024)
|
261
221
|
if host == "localhost"
|
262
|
-
|
222
|
+
loopback_addresses.each do |addr|
|
263
223
|
add_tcp_listener addr, port, optimize_for_latency, backlog
|
264
224
|
end
|
265
225
|
return
|
@@ -298,7 +258,7 @@ module Puma
|
|
298
258
|
MiniSSL.check
|
299
259
|
|
300
260
|
if host == "localhost"
|
301
|
-
|
261
|
+
loopback_addresses.each do |addr|
|
302
262
|
add_ssl_listener addr, port, ctx, optimize_for_latency, backlog
|
303
263
|
end
|
304
264
|
return
|
@@ -312,6 +272,7 @@ module Puma
|
|
312
272
|
s.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
|
313
273
|
s.listen backlog
|
314
274
|
|
275
|
+
|
315
276
|
ssl = MiniSSL::Server.new s, ctx
|
316
277
|
env = @proto_env.dup
|
317
278
|
env[HTTPS_KEY] = HTTPS
|
@@ -343,8 +304,8 @@ module Puma
|
|
343
304
|
|
344
305
|
# Tell the server to listen on +path+ as a UNIX domain socket.
|
345
306
|
#
|
346
|
-
def add_unix_listener(path, umask=nil, mode=nil, backlog=
|
347
|
-
@unix_paths << path
|
307
|
+
def add_unix_listener(path, umask=nil, mode=nil, backlog=1024)
|
308
|
+
@unix_paths << path unless File.exist? path
|
348
309
|
|
349
310
|
# Let anyone connect by default
|
350
311
|
umask ||= 0
|
@@ -364,7 +325,7 @@ module Puma
|
|
364
325
|
end
|
365
326
|
|
366
327
|
s = UNIXServer.new(path)
|
367
|
-
s.listen backlog
|
328
|
+
s.listen backlog
|
368
329
|
@ios << s
|
369
330
|
ensure
|
370
331
|
File.umask old_mask
|
@@ -382,7 +343,7 @@ module Puma
|
|
382
343
|
end
|
383
344
|
|
384
345
|
def inherit_unix_listener(path, fd)
|
385
|
-
@unix_paths << path
|
346
|
+
@unix_paths << path unless File.exist? path
|
386
347
|
|
387
348
|
if fd.kind_of? TCPServer
|
388
349
|
s = fd
|
@@ -398,5 +359,27 @@ module Puma
|
|
398
359
|
s
|
399
360
|
end
|
400
361
|
|
362
|
+
def close_listeners
|
363
|
+
@listeners.each do |l, io|
|
364
|
+
io.close
|
365
|
+
uri = URI.parse(l)
|
366
|
+
next unless uri.scheme == 'unix'
|
367
|
+
unix_path = "#{uri.host}#{uri.path}"
|
368
|
+
File.unlink unix_path if @unix_paths.include? unix_path
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
def close_unix_paths
|
373
|
+
@unix_paths.each { |up| File.unlink(up) if File.exist? up }
|
374
|
+
end
|
375
|
+
|
376
|
+
def redirects_for_restart
|
377
|
+
redirects = {:close_others => true}
|
378
|
+
@listeners.each_with_index do |(l, io), i|
|
379
|
+
ENV["PUMA_INHERIT_#{i}"] = "#{io.to_i}:#{l}"
|
380
|
+
redirects[io.to_i] = io.to_i
|
381
|
+
end
|
382
|
+
redirects
|
383
|
+
end
|
401
384
|
end
|
402
385
|
end
|
data/lib/puma/cli.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'optparse'
|
2
4
|
require 'uri'
|
3
5
|
|
6
|
+
require 'puma'
|
4
7
|
require 'puma/configuration'
|
5
8
|
require 'puma/launcher'
|
6
9
|
require 'puma/const'
|
@@ -83,6 +86,14 @@ module Puma
|
|
83
86
|
raise UnsupportedOption
|
84
87
|
end
|
85
88
|
|
89
|
+
def configure_control_url(command_line_arg)
|
90
|
+
if command_line_arg
|
91
|
+
@control_url = command_line_arg
|
92
|
+
elsif Puma.jruby?
|
93
|
+
unsupported "No default url available on JRuby"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
86
97
|
# Build the OptionParser object to handle the available options.
|
87
98
|
#
|
88
99
|
|
@@ -97,13 +108,13 @@ module Puma
|
|
97
108
|
file_config.load arg
|
98
109
|
end
|
99
110
|
|
100
|
-
o.on "--control URL", "The bind url to use for the control server"
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
111
|
+
o.on "--control-url URL", "The bind url to use for the control server. Use 'auto' to use temp unix server" do |arg|
|
112
|
+
configure_control_url(arg)
|
113
|
+
end
|
114
|
+
|
115
|
+
# alias --control-url for backwards-compatibility
|
116
|
+
o.on "--control URL", "DEPRECATED alias for --control-url" do |arg|
|
117
|
+
configure_control_url(arg)
|
107
118
|
end
|
108
119
|
|
109
120
|
o.on "--control-token TOKEN",
|
@@ -150,6 +161,10 @@ module Puma
|
|
150
161
|
user_config.prune_bundler
|
151
162
|
end
|
152
163
|
|
164
|
+
o.on "--extra-runtime-dependencies GEM1,GEM2", "Defines any extra needed gems when using --prune-bundler" do |arg|
|
165
|
+
user_config.extra_runtime_dependencies arg.split(',')
|
166
|
+
end
|
167
|
+
|
153
168
|
o.on "-q", "--quiet", "Do not log requests internally (default true)" do
|
154
169
|
user_config.quiet
|
155
170
|
end
|
@@ -181,6 +196,10 @@ module Puma
|
|
181
196
|
user_config.tcp_mode!
|
182
197
|
end
|
183
198
|
|
199
|
+
o.on "--early-hints", "Enable early hints support" do
|
200
|
+
user_config.early_hints
|
201
|
+
end
|
202
|
+
|
184
203
|
o.on "-V", "--version", "Print the version information" do
|
185
204
|
puts "puma version #{Puma::Const::VERSION}"
|
186
205
|
exit 0
|