puma 1.6.3 → 2.0.0.b1
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.
- data/History.txt +13 -0
- data/Manifest.txt +18 -0
- data/Rakefile +6 -0
- data/docs/config.md +0 -0
- data/docs/nginx.md +85 -0
- data/examples/puma/keystore.jks +0 -0
- data/ext/puma_http11/PumaHttp11Service.java +2 -0
- data/ext/puma_http11/extconf.rb +3 -0
- data/ext/puma_http11/io_buffer.c +146 -0
- data/ext/puma_http11/mini_ssl.c +189 -0
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +289 -0
- data/ext/puma_http11/puma_http11.c +6 -0
- data/lib/puma/accept_nonblock.rb +23 -0
- data/lib/puma/binder.rb +253 -0
- data/lib/puma/cli.rb +212 -114
- data/lib/puma/client.rb +28 -3
- data/lib/puma/configuration.rb +11 -4
- data/lib/puma/const.rb +12 -1
- data/lib/puma/delegation.rb +11 -0
- data/lib/puma/events.rb +18 -0
- data/lib/puma/io_buffer.rb +7 -0
- data/lib/puma/java_io_buffer.rb +45 -0
- data/lib/puma/minissl.rb +124 -0
- data/lib/puma/puma_http11.bundle +0 -0
- data/lib/puma/puma_http11.jar +0 -0
- data/lib/puma/reactor.rb +4 -1
- data/lib/puma/server.rb +67 -144
- data/lib/puma/thread_pool.rb +5 -2
- data/puma.gemspec +5 -5
- data/test/test_integration.rb +53 -2
- data/test/test_iobuffer.rb +38 -0
- data/test/test_puma_server.rb +12 -7
- data/tools/jungle/README.md +54 -0
- data/tools/jungle/puma +332 -0
- data/tools/jungle/run-puma +3 -0
- metadata +24 -5
@@ -0,0 +1,289 @@
|
|
1
|
+
package org.jruby.puma;
|
2
|
+
|
3
|
+
import org.jruby.Ruby;
|
4
|
+
import org.jruby.RubyClass;
|
5
|
+
import org.jruby.RubyHash;
|
6
|
+
import org.jruby.RubyModule;
|
7
|
+
import org.jruby.RubyNumeric;
|
8
|
+
import org.jruby.RubyObject;
|
9
|
+
import org.jruby.RubyString;
|
10
|
+
|
11
|
+
import org.jruby.anno.JRubyMethod;
|
12
|
+
|
13
|
+
import org.jruby.runtime.Block;
|
14
|
+
import org.jruby.runtime.ObjectAllocator;
|
15
|
+
import org.jruby.runtime.ThreadContext;
|
16
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
17
|
+
|
18
|
+
import org.jruby.exceptions.RaiseException;
|
19
|
+
|
20
|
+
import org.jruby.util.ByteList;
|
21
|
+
|
22
|
+
|
23
|
+
import javax.net.ssl.*;
|
24
|
+
import javax.net.ssl.SSLEngineResult.*;
|
25
|
+
import java.io.*;
|
26
|
+
import java.security.*;
|
27
|
+
import java.nio.*;
|
28
|
+
|
29
|
+
public class MiniSSL extends RubyObject {
|
30
|
+
private static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
|
31
|
+
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
|
32
|
+
return new MiniSSL(runtime, klass);
|
33
|
+
}
|
34
|
+
};
|
35
|
+
|
36
|
+
public static void createMiniSSL(Ruby runtime) {
|
37
|
+
RubyModule mPuma = runtime.defineModule("Puma");
|
38
|
+
RubyModule ssl = mPuma.defineModuleUnder("MiniSSL");
|
39
|
+
|
40
|
+
mPuma.defineClassUnder("SSLError",
|
41
|
+
runtime.getClass("IOError"),
|
42
|
+
runtime.getClass("IOError").getAllocator());
|
43
|
+
|
44
|
+
RubyClass eng = ssl.defineClassUnder("Engine",runtime.getObject(),ALLOCATOR);
|
45
|
+
eng.defineAnnotatedMethods(MiniSSL.class);
|
46
|
+
}
|
47
|
+
|
48
|
+
private Ruby runtime;
|
49
|
+
private SSLContext sslc;
|
50
|
+
|
51
|
+
private SSLEngine engine;
|
52
|
+
|
53
|
+
private ByteBuffer peerAppData;
|
54
|
+
private ByteBuffer peerNetData;
|
55
|
+
private ByteBuffer netData;
|
56
|
+
private ByteBuffer dummy;
|
57
|
+
|
58
|
+
public MiniSSL(Ruby runtime, RubyClass klass) {
|
59
|
+
super(runtime, klass);
|
60
|
+
|
61
|
+
this.runtime = runtime;
|
62
|
+
}
|
63
|
+
|
64
|
+
@JRubyMethod(meta = true)
|
65
|
+
public static IRubyObject server(ThreadContext context, IRubyObject recv, IRubyObject key, IRubyObject cert) {
|
66
|
+
RubyClass klass = (RubyClass) recv;
|
67
|
+
IRubyObject newInstance = klass.newInstance(context,
|
68
|
+
new IRubyObject[] { key, cert },
|
69
|
+
Block.NULL_BLOCK);
|
70
|
+
|
71
|
+
return newInstance;
|
72
|
+
}
|
73
|
+
|
74
|
+
@JRubyMethod
|
75
|
+
public IRubyObject initialize(IRubyObject key, IRubyObject cert)
|
76
|
+
throws java.security.KeyStoreException,
|
77
|
+
java.io.FileNotFoundException,
|
78
|
+
java.io.IOException,
|
79
|
+
java.io.FileNotFoundException,
|
80
|
+
java.security.NoSuchAlgorithmException,
|
81
|
+
java.security.KeyManagementException,
|
82
|
+
java.security.cert.CertificateException,
|
83
|
+
java.security.UnrecoverableKeyException
|
84
|
+
{
|
85
|
+
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
|
86
|
+
KeyStore ts = KeyStore.getInstance(KeyStore.getDefaultType());
|
87
|
+
|
88
|
+
char[] pass = "blahblah".toCharArray();
|
89
|
+
|
90
|
+
ks.load(new FileInputStream(key.convertToString().asJavaString()),
|
91
|
+
pass);
|
92
|
+
ts.load(new FileInputStream(cert.convertToString().asJavaString()),
|
93
|
+
pass);
|
94
|
+
|
95
|
+
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
96
|
+
kmf.init(ks, pass);
|
97
|
+
|
98
|
+
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
|
99
|
+
tmf.init(ts);
|
100
|
+
|
101
|
+
SSLContext sslCtx = SSLContext.getInstance("TLS");
|
102
|
+
|
103
|
+
sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
|
104
|
+
|
105
|
+
sslc = sslCtx;
|
106
|
+
|
107
|
+
engine = sslc.createSSLEngine();
|
108
|
+
engine.setUseClientMode(false);
|
109
|
+
// engine.setNeedClientAuth(true);
|
110
|
+
|
111
|
+
SSLSession session = engine.getSession();
|
112
|
+
peerNetData = ByteBuffer.allocate(session.getPacketBufferSize());
|
113
|
+
peerAppData = ByteBuffer.allocate(session.getApplicationBufferSize());
|
114
|
+
netData = ByteBuffer.allocate(session.getPacketBufferSize());
|
115
|
+
peerNetData.limit(0);
|
116
|
+
peerAppData.limit(0);
|
117
|
+
netData.limit(0);
|
118
|
+
|
119
|
+
peerNetData.clear();
|
120
|
+
peerAppData.clear();
|
121
|
+
netData.clear();
|
122
|
+
|
123
|
+
dummy = ByteBuffer.allocate(0);
|
124
|
+
|
125
|
+
return this;
|
126
|
+
}
|
127
|
+
|
128
|
+
@JRubyMethod
|
129
|
+
public IRubyObject inject(IRubyObject arg) {
|
130
|
+
byte[] bytes = arg.convertToString().getBytes();
|
131
|
+
|
132
|
+
peerNetData.limit(peerNetData.limit() + bytes.length);
|
133
|
+
|
134
|
+
log("capacity: " + peerNetData.capacity() + " limit: " + peerNetData.limit());
|
135
|
+
|
136
|
+
peerNetData.put(bytes);
|
137
|
+
|
138
|
+
log("netData: " + peerNetData.position() + "/" + peerAppData.limit());
|
139
|
+
return this;
|
140
|
+
}
|
141
|
+
|
142
|
+
@JRubyMethod
|
143
|
+
public IRubyObject read() throws javax.net.ssl.SSLException, Exception {
|
144
|
+
peerAppData.clear();
|
145
|
+
peerNetData.flip();
|
146
|
+
SSLEngineResult res;
|
147
|
+
|
148
|
+
log("available read: " + peerNetData.position() + "/ " + peerNetData.limit());
|
149
|
+
|
150
|
+
if(!peerNetData.hasRemaining()) {
|
151
|
+
return getRuntime().getNil();
|
152
|
+
}
|
153
|
+
|
154
|
+
do {
|
155
|
+
res = engine.unwrap(peerNetData, peerAppData);
|
156
|
+
} while(res.getStatus() == SSLEngineResult.Status.OK &&
|
157
|
+
res.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP &&
|
158
|
+
res.bytesProduced() == 0);
|
159
|
+
|
160
|
+
log("read: ", res);
|
161
|
+
|
162
|
+
if(peerNetData.hasRemaining()) {
|
163
|
+
log("STILL HAD peerNetData!");
|
164
|
+
}
|
165
|
+
|
166
|
+
peerNetData.position(0);
|
167
|
+
peerNetData.limit(0);
|
168
|
+
|
169
|
+
HandshakeStatus hsStatus = runDelegatedTasks(res, engine);
|
170
|
+
|
171
|
+
if(res.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
|
172
|
+
return getRuntime().getNil();
|
173
|
+
}
|
174
|
+
|
175
|
+
if(hsStatus == HandshakeStatus.NEED_WRAP) {
|
176
|
+
netData.clear();
|
177
|
+
log("netData: " + netData.limit());
|
178
|
+
engine.wrap(dummy, netData);
|
179
|
+
return getRuntime().getNil();
|
180
|
+
}
|
181
|
+
|
182
|
+
if(hsStatus == HandshakeStatus.NEED_UNWRAP) {
|
183
|
+
return getRuntime().getNil();
|
184
|
+
|
185
|
+
// log("peerNet: " + peerNetData.position() + "/" + peerNetData.limit());
|
186
|
+
// log("peerApp: " + peerAppData.position() + "/" + peerAppData.limit());
|
187
|
+
|
188
|
+
// peerNetData.compact();
|
189
|
+
|
190
|
+
// log("peerNet: " + peerNetData.position() + "/" + peerNetData.limit());
|
191
|
+
// do {
|
192
|
+
// res = engine.unwrap(peerNetData, peerAppData);
|
193
|
+
// } while(res.getStatus() == SSLEngineResult.Status.OK &&
|
194
|
+
// res.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP &&
|
195
|
+
// res.bytesProduced() == 0);
|
196
|
+
// return getRuntime().getNil();
|
197
|
+
}
|
198
|
+
|
199
|
+
// if(peerAppData.position() == 0 &&
|
200
|
+
// res.getStatus() == SSLEngineResult.Status.OK &&
|
201
|
+
// peerNetData.hasRemaining()) {
|
202
|
+
// res = engine.unwrap(peerNetData, peerAppData);
|
203
|
+
// }
|
204
|
+
|
205
|
+
byte[] bss = new byte[peerAppData.limit()];
|
206
|
+
|
207
|
+
peerAppData.get(bss);
|
208
|
+
|
209
|
+
RubyString str = getRuntime().newString("");
|
210
|
+
str.setValue(new ByteList(bss));
|
211
|
+
|
212
|
+
return str;
|
213
|
+
}
|
214
|
+
|
215
|
+
private static HandshakeStatus runDelegatedTasks(SSLEngineResult result,
|
216
|
+
SSLEngine engine) throws Exception {
|
217
|
+
|
218
|
+
HandshakeStatus hsStatus = result.getHandshakeStatus();
|
219
|
+
|
220
|
+
if(hsStatus == HandshakeStatus.NEED_TASK) {
|
221
|
+
Runnable runnable;
|
222
|
+
while ((runnable = engine.getDelegatedTask()) != null) {
|
223
|
+
log("\trunning delegated task...");
|
224
|
+
runnable.run();
|
225
|
+
}
|
226
|
+
hsStatus = engine.getHandshakeStatus();
|
227
|
+
if (hsStatus == HandshakeStatus.NEED_TASK) {
|
228
|
+
throw new Exception(
|
229
|
+
"handshake shouldn't need additional tasks");
|
230
|
+
}
|
231
|
+
log("\tnew HandshakeStatus: " + hsStatus);
|
232
|
+
}
|
233
|
+
|
234
|
+
return hsStatus;
|
235
|
+
}
|
236
|
+
|
237
|
+
|
238
|
+
private static void log(String str, SSLEngineResult result) {
|
239
|
+
System.out.println("The format of the SSLEngineResult is: \n" +
|
240
|
+
"\t\"getStatus() / getHandshakeStatus()\" +\n" +
|
241
|
+
"\t\"bytesConsumed() / bytesProduced()\"\n");
|
242
|
+
|
243
|
+
HandshakeStatus hsStatus = result.getHandshakeStatus();
|
244
|
+
log(str +
|
245
|
+
result.getStatus() + "/" + hsStatus + ", " +
|
246
|
+
result.bytesConsumed() + "/" + result.bytesProduced() +
|
247
|
+
" bytes");
|
248
|
+
if (hsStatus == HandshakeStatus.FINISHED) {
|
249
|
+
log("\t...ready for application data");
|
250
|
+
}
|
251
|
+
}
|
252
|
+
|
253
|
+
private static void log(String str) {
|
254
|
+
System.out.println(str);
|
255
|
+
}
|
256
|
+
|
257
|
+
|
258
|
+
|
259
|
+
@JRubyMethod
|
260
|
+
public IRubyObject write(IRubyObject arg) throws javax.net.ssl.SSLException {
|
261
|
+
log("write from: " + netData.position());
|
262
|
+
|
263
|
+
byte[] bls = arg.convertToString().getBytes();
|
264
|
+
ByteBuffer src = ByteBuffer.wrap(bls);
|
265
|
+
|
266
|
+
SSLEngineResult res = engine.wrap(src, netData);
|
267
|
+
|
268
|
+
return getRuntime().newFixnum(res.bytesConsumed());
|
269
|
+
}
|
270
|
+
|
271
|
+
@JRubyMethod
|
272
|
+
public IRubyObject extract() {
|
273
|
+
netData.flip();
|
274
|
+
|
275
|
+
if(!netData.hasRemaining()) {
|
276
|
+
return getRuntime().getNil();
|
277
|
+
}
|
278
|
+
|
279
|
+
byte[] bss = new byte[netData.limit()];
|
280
|
+
|
281
|
+
netData.get(bss);
|
282
|
+
netData.clear();
|
283
|
+
|
284
|
+
RubyString str = getRuntime().newString("");
|
285
|
+
str.setValue(new ByteList(bss));
|
286
|
+
|
287
|
+
return str;
|
288
|
+
}
|
289
|
+
}
|
@@ -456,6 +456,9 @@ VALUE HttpParser_body(VALUE self) {
|
|
456
456
|
return http->body;
|
457
457
|
}
|
458
458
|
|
459
|
+
void Init_io_buffer(VALUE puma);
|
460
|
+
void Init_mini_ssl(VALUE mod);
|
461
|
+
|
459
462
|
void Init_puma_http11()
|
460
463
|
{
|
461
464
|
|
@@ -482,4 +485,7 @@ void Init_puma_http11()
|
|
482
485
|
rb_define_method(cHttpParser, "nread", HttpParser_nread, 0);
|
483
486
|
rb_define_method(cHttpParser, "body", HttpParser_body, 0);
|
484
487
|
init_common_fields();
|
488
|
+
|
489
|
+
Init_io_buffer(mPuma);
|
490
|
+
Init_mini_ssl(mPuma);
|
485
491
|
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
|
3
|
+
module OpenSSL
|
4
|
+
module SSL
|
5
|
+
class SSLServer
|
6
|
+
unless public_method_defined? :accept_nonblock
|
7
|
+
def accept_nonblock
|
8
|
+
sock = @svr.accept_nonblock
|
9
|
+
|
10
|
+
begin
|
11
|
+
ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
|
12
|
+
ssl.sync_close = true
|
13
|
+
ssl.accept if @start_immediately
|
14
|
+
ssl
|
15
|
+
rescue SSLError => ex
|
16
|
+
sock.close
|
17
|
+
raise ex
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/puma/binder.rb
ADDED
@@ -0,0 +1,253 @@
|
|
1
|
+
require 'puma/const'
|
2
|
+
|
3
|
+
module Puma
|
4
|
+
class Binder
|
5
|
+
include Puma::Const
|
6
|
+
|
7
|
+
def initialize(events)
|
8
|
+
@events = events
|
9
|
+
@listeners = []
|
10
|
+
@inherited_fds = {}
|
11
|
+
@unix_paths = []
|
12
|
+
|
13
|
+
@proto_env = {
|
14
|
+
"rack.version".freeze => Rack::VERSION,
|
15
|
+
"rack.errors".freeze => events.stderr,
|
16
|
+
"rack.multithread".freeze => true,
|
17
|
+
"rack.multiprocess".freeze => false,
|
18
|
+
"rack.run_once".freeze => true,
|
19
|
+
"SCRIPT_NAME".freeze => ENV['SCRIPT_NAME'] || "",
|
20
|
+
|
21
|
+
# Rack blows up if this is an empty string, and Rack::Lint
|
22
|
+
# blows up if it's nil. So 'text/plain' seems like the most
|
23
|
+
# sensible default value.
|
24
|
+
"CONTENT_TYPE".freeze => "text/plain",
|
25
|
+
|
26
|
+
"QUERY_STRING".freeze => "",
|
27
|
+
SERVER_PROTOCOL => HTTP_11,
|
28
|
+
SERVER_SOFTWARE => PUMA_VERSION,
|
29
|
+
GATEWAY_INTERFACE => CGI_VER
|
30
|
+
}
|
31
|
+
|
32
|
+
@envs = {}
|
33
|
+
@ios = []
|
34
|
+
end
|
35
|
+
|
36
|
+
attr_reader :listeners, :ios
|
37
|
+
|
38
|
+
def env(sock)
|
39
|
+
@envs.fetch(sock, @proto_env)
|
40
|
+
end
|
41
|
+
|
42
|
+
def close
|
43
|
+
@ios.each { |i| i.close }
|
44
|
+
@unix_paths.each { |i| File.unlink i }
|
45
|
+
end
|
46
|
+
|
47
|
+
def import_from_env
|
48
|
+
remove = []
|
49
|
+
|
50
|
+
ENV.each do |k,v|
|
51
|
+
if k =~ /PUMA_INHERIT_\d+/
|
52
|
+
fd, url = v.split(":", 2)
|
53
|
+
@inherited_fds[url] = fd.to_i
|
54
|
+
remove << k
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
remove.each do |k|
|
59
|
+
ENV.delete k
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def parse(binds, logger)
|
64
|
+
binds.each do |str|
|
65
|
+
uri = URI.parse str
|
66
|
+
case uri.scheme
|
67
|
+
when "tcp"
|
68
|
+
if fd = @inherited_fds.delete(str)
|
69
|
+
logger.log "* Inherited #{str}"
|
70
|
+
io = inherit_tcp_listener uri.host, uri.port, fd
|
71
|
+
else
|
72
|
+
logger.log "* Listening on #{str}"
|
73
|
+
io = add_tcp_listener uri.host, uri.port
|
74
|
+
end
|
75
|
+
|
76
|
+
@listeners << [str, io]
|
77
|
+
when "unix"
|
78
|
+
path = "#{uri.host}#{uri.path}"
|
79
|
+
|
80
|
+
if fd = @inherited_fds.delete(str)
|
81
|
+
logger.log "* Inherited #{str}"
|
82
|
+
io = inherit_unix_listener path, fd
|
83
|
+
else
|
84
|
+
logger.log "* Listening on #{str}"
|
85
|
+
|
86
|
+
umask = nil
|
87
|
+
|
88
|
+
if uri.query
|
89
|
+
params = Rack::Utils.parse_query uri.query
|
90
|
+
if u = params['umask']
|
91
|
+
# Use Integer() to respect the 0 prefix as octal
|
92
|
+
umask = Integer(u)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
io = add_unix_listener path, umask
|
97
|
+
end
|
98
|
+
|
99
|
+
@listeners << [str, io]
|
100
|
+
when "ssl"
|
101
|
+
if IS_JRUBY
|
102
|
+
@events.error "SSL not supported on JRuby"
|
103
|
+
raise UnsupportedOption
|
104
|
+
end
|
105
|
+
|
106
|
+
params = Rack::Utils.parse_query uri.query
|
107
|
+
require 'puma/minissl'
|
108
|
+
|
109
|
+
ctx = MiniSSL::Context.new
|
110
|
+
unless params['key']
|
111
|
+
@events.error "Please specify the SSL key via 'key='"
|
112
|
+
end
|
113
|
+
|
114
|
+
ctx.key = params['key']
|
115
|
+
|
116
|
+
unless params['cert']
|
117
|
+
@events.error "Please specify the SSL cert via 'cert='"
|
118
|
+
end
|
119
|
+
|
120
|
+
ctx.cert = params['cert']
|
121
|
+
|
122
|
+
ctx.verify_mode = MiniSSL::VERIFY_NONE
|
123
|
+
|
124
|
+
if fd = @inherited_fds.delete(str)
|
125
|
+
logger.log "* Inherited #{str}"
|
126
|
+
io = inherited_ssl_listener fd, ctx
|
127
|
+
else
|
128
|
+
logger.log "* Listening on #{str}"
|
129
|
+
io = add_ssl_listener uri.host, uri.port, ctx
|
130
|
+
end
|
131
|
+
|
132
|
+
@listeners << [str, io]
|
133
|
+
else
|
134
|
+
logger.error "Invalid URI: #{str}"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# If we inherited fds but didn't use them (because of a
|
139
|
+
# configuration change), then be sure to close them.
|
140
|
+
@inherited_fds.each do |str, fd|
|
141
|
+
logger.log "* Closing unused inherited connection: #{str}"
|
142
|
+
|
143
|
+
begin
|
144
|
+
IO.for_fd(fd).close
|
145
|
+
rescue SystemCallError
|
146
|
+
end
|
147
|
+
|
148
|
+
# We have to unlink a unix socket path that's not being used
|
149
|
+
uri = URI.parse str
|
150
|
+
if uri.scheme == "unix"
|
151
|
+
path = "#{uri.host}#{uri.path}"
|
152
|
+
File.unlink path
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
# Tell the server to listen on host +host+, port +port+.
|
159
|
+
# If +optimize_for_latency+ is true (the default) then clients connecting
|
160
|
+
# will be optimized for latency over throughput.
|
161
|
+
#
|
162
|
+
# +backlog+ indicates how many unaccepted connections the kernel should
|
163
|
+
# allow to accumulate before returning connection refused.
|
164
|
+
#
|
165
|
+
def add_tcp_listener(host, port, optimize_for_latency=true, backlog=1024)
|
166
|
+
s = TCPServer.new(host, port)
|
167
|
+
if optimize_for_latency
|
168
|
+
s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
169
|
+
end
|
170
|
+
s.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
|
171
|
+
s.listen backlog
|
172
|
+
@ios << s
|
173
|
+
s
|
174
|
+
end
|
175
|
+
|
176
|
+
def inherit_tcp_listener(host, port, fd)
|
177
|
+
if fd.kind_of? TCPServer
|
178
|
+
s = fd
|
179
|
+
else
|
180
|
+
s = TCPServer.for_fd(fd)
|
181
|
+
end
|
182
|
+
|
183
|
+
@ios << s
|
184
|
+
s
|
185
|
+
end
|
186
|
+
|
187
|
+
def add_ssl_listener(host, port, ctx,
|
188
|
+
optimize_for_latency=true, backlog=1024)
|
189
|
+
if IS_JRUBY
|
190
|
+
@events.error "SSL not supported on JRuby"
|
191
|
+
raise UnsupportedOption
|
192
|
+
end
|
193
|
+
|
194
|
+
require 'puma/minissl'
|
195
|
+
|
196
|
+
s = TCPServer.new(host, port)
|
197
|
+
if optimize_for_latency
|
198
|
+
s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
199
|
+
end
|
200
|
+
s.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
|
201
|
+
s.listen backlog
|
202
|
+
|
203
|
+
ssl = MiniSSL::Server.new s, ctx
|
204
|
+
env = @proto_env.dup
|
205
|
+
env[HTTPS_KEY] = HTTPS
|
206
|
+
@envs[ssl] = env
|
207
|
+
|
208
|
+
@ios << ssl
|
209
|
+
s
|
210
|
+
end
|
211
|
+
|
212
|
+
def inherited_ssl_listener(fd, ctx)
|
213
|
+
if IS_JRUBY
|
214
|
+
@events.error "SSL not supported on JRuby"
|
215
|
+
raise UnsupportedOption
|
216
|
+
end
|
217
|
+
|
218
|
+
require 'puma/minissl'
|
219
|
+
s = TCPServer.for_fd(fd)
|
220
|
+
@ios << MiniSSL::Server.new(s, ctx)
|
221
|
+
s
|
222
|
+
end
|
223
|
+
|
224
|
+
# Tell the server to listen on +path+ as a UNIX domain socket.
|
225
|
+
#
|
226
|
+
def add_unix_listener(path, umask=nil)
|
227
|
+
@unix_paths << path
|
228
|
+
|
229
|
+
# Let anyone connect by default
|
230
|
+
umask ||= 0
|
231
|
+
|
232
|
+
begin
|
233
|
+
old_mask = File.umask(umask)
|
234
|
+
s = UNIXServer.new(path)
|
235
|
+
@ios << s
|
236
|
+
ensure
|
237
|
+
File.umask old_mask
|
238
|
+
end
|
239
|
+
|
240
|
+
s
|
241
|
+
end
|
242
|
+
|
243
|
+
def inherit_unix_listener(path, fd)
|
244
|
+
@unix_paths << path
|
245
|
+
|
246
|
+
s = UNIXServer.for_fd fd
|
247
|
+
@ios << s
|
248
|
+
|
249
|
+
s
|
250
|
+
end
|
251
|
+
|
252
|
+
end
|
253
|
+
end
|