puma 3.9.0 → 3.12.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 +5 -5
- data/History.md +98 -0
- data/README.md +140 -230
- data/docs/architecture.md +36 -0
- data/{DEPLOYMENT.md → docs/deployment.md} +0 -0
- 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/plugins.md +28 -0
- data/docs/restart.md +39 -0
- data/docs/signals.md +56 -3
- data/docs/systemd.md +112 -37
- data/ext/puma_http11/http11_parser.c +84 -84
- data/ext/puma_http11/http11_parser.rl +9 -9
- data/ext/puma_http11/mini_ssl.c +18 -4
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +13 -16
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +6 -0
- data/lib/puma.rb +8 -0
- data/lib/puma/app/status.rb +8 -0
- data/lib/puma/binder.rb +12 -8
- data/lib/puma/cli.rb +20 -7
- data/lib/puma/client.rb +28 -0
- data/lib/puma/cluster.rb +26 -7
- data/lib/puma/configuration.rb +19 -14
- data/lib/puma/const.rb +7 -2
- data/lib/puma/control_cli.rb +5 -5
- data/lib/puma/dsl.rb +34 -7
- data/lib/puma/jruby_restart.rb +0 -1
- data/lib/puma/launcher.rb +36 -19
- data/lib/puma/minissl.rb +49 -27
- data/lib/puma/plugin/tmp_restart.rb +0 -1
- data/lib/puma/reactor.rb +135 -0
- data/lib/puma/runner.rb +12 -1
- data/lib/puma/server.rb +84 -25
- data/lib/puma/single.rb +12 -3
- data/lib/puma/thread_pool.rb +47 -8
- data/lib/rack/handler/puma.rb +4 -1
- data/tools/jungle/README.md +12 -2
- data/tools/jungle/init.d/README.md +2 -0
- data/tools/jungle/init.d/puma +2 -2
- 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/trickletest.rb +1 -1
- metadata +21 -94
- 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/puma.gemspec +0 -52
@@ -29,7 +29,7 @@ static void snake_upcase_char(char *c)
|
|
29
29
|
/** Machine **/
|
30
30
|
|
31
31
|
%%{
|
32
|
-
|
32
|
+
|
33
33
|
machine puma_parser;
|
34
34
|
|
35
35
|
action mark { MARK(mark, fpc); }
|
@@ -37,7 +37,7 @@ static void snake_upcase_char(char *c)
|
|
37
37
|
|
38
38
|
action start_field { MARK(field_start, fpc); }
|
39
39
|
action snake_upcase_field { snake_upcase_char((char *)fpc); }
|
40
|
-
action write_field {
|
40
|
+
action write_field {
|
41
41
|
parser->field_len = LEN(field_start, fpc);
|
42
42
|
}
|
43
43
|
|
@@ -45,10 +45,10 @@ static void snake_upcase_char(char *c)
|
|
45
45
|
action write_value {
|
46
46
|
parser->http_field(parser, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, fpc));
|
47
47
|
}
|
48
|
-
action request_method {
|
48
|
+
action request_method {
|
49
49
|
parser->request_method(parser, PTR_TO(mark), LEN(mark, fpc));
|
50
50
|
}
|
51
|
-
action request_uri {
|
51
|
+
action request_uri {
|
52
52
|
parser->request_uri(parser, PTR_TO(mark), LEN(mark, fpc));
|
53
53
|
}
|
54
54
|
action fragment {
|
@@ -56,11 +56,11 @@ static void snake_upcase_char(char *c)
|
|
56
56
|
}
|
57
57
|
|
58
58
|
action start_query { MARK(query_start, fpc); }
|
59
|
-
action query_string {
|
59
|
+
action query_string {
|
60
60
|
parser->query_string(parser, PTR_TO(query_start), LEN(query_start, fpc));
|
61
61
|
}
|
62
62
|
|
63
|
-
action http_version {
|
63
|
+
action http_version {
|
64
64
|
parser->http_version(parser, PTR_TO(mark), LEN(mark, fpc));
|
65
65
|
}
|
66
66
|
|
@@ -68,8 +68,8 @@ static void snake_upcase_char(char *c)
|
|
68
68
|
parser->request_path(parser, PTR_TO(mark), LEN(mark,fpc));
|
69
69
|
}
|
70
70
|
|
71
|
-
action done {
|
72
|
-
parser->body_start = fpc - buffer + 1;
|
71
|
+
action done {
|
72
|
+
parser->body_start = fpc - buffer + 1;
|
73
73
|
parser->header_done(parser, fpc + 1, pe - fpc - 1);
|
74
74
|
fbreak;
|
75
75
|
}
|
@@ -109,7 +109,7 @@ size_t puma_parser_execute(puma_parser *parser, const char *buffer, size_t len,
|
|
109
109
|
pe = buffer+len;
|
110
110
|
|
111
111
|
/* assert(*pe == '\0' && "pointer does not end on NUL"); */
|
112
|
-
assert(pe - p == len - off && "pointers aren't same distance");
|
112
|
+
assert((size_t) (pe - p) == len - off && "pointers aren't same distance");
|
113
113
|
|
114
114
|
%% write exec;
|
115
115
|
|
data/ext/puma_http11/mini_ssl.c
CHANGED
@@ -161,6 +161,9 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
|
|
161
161
|
ID sym_verify_mode = rb_intern("verify_mode");
|
162
162
|
VALUE verify_mode = rb_funcall(mini_ssl_ctx, sym_verify_mode, 0);
|
163
163
|
|
164
|
+
ID sym_ssl_cipher_filter = rb_intern("ssl_cipher_filter");
|
165
|
+
VALUE ssl_cipher_filter = rb_funcall(mini_ssl_ctx, sym_ssl_cipher_filter, 0);
|
166
|
+
|
164
167
|
ctx = SSL_CTX_new(SSLv23_server_method());
|
165
168
|
conn->ctx = ctx;
|
166
169
|
|
@@ -175,7 +178,13 @@ VALUE engine_init_server(VALUE self, VALUE mini_ssl_ctx) {
|
|
175
178
|
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);
|
176
179
|
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
|
177
180
|
|
178
|
-
|
181
|
+
if (!NIL_P(ssl_cipher_filter)) {
|
182
|
+
StringValue(ssl_cipher_filter);
|
183
|
+
SSL_CTX_set_cipher_list(ctx, RSTRING_PTR(ssl_cipher_filter));
|
184
|
+
}
|
185
|
+
else {
|
186
|
+
SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL@STRENGTH");
|
187
|
+
}
|
179
188
|
|
180
189
|
DH *dh = get_dh1024();
|
181
190
|
SSL_CTX_set_tmp_dh(ctx, dh);
|
@@ -244,7 +253,7 @@ void raise_error(SSL* ssl, int result) {
|
|
244
253
|
const char* err_str;
|
245
254
|
int err = errno;
|
246
255
|
int ssl_err = SSL_get_error(ssl, result);
|
247
|
-
int verify_err = SSL_get_verify_result(ssl);
|
256
|
+
int verify_err = (int) SSL_get_verify_result(ssl);
|
248
257
|
|
249
258
|
if(SSL_ERROR_SYSCALL == ssl_err) {
|
250
259
|
snprintf(msg, sizeof(msg), "System error: %s - %d", strerror(err), err);
|
@@ -257,7 +266,7 @@ void raise_error(SSL* ssl, int result) {
|
|
257
266
|
err_str, verify_err);
|
258
267
|
|
259
268
|
} else {
|
260
|
-
err = ERR_get_error();
|
269
|
+
err = (int) ERR_get_error();
|
261
270
|
ERR_error_string_n(err, buf, sizeof(buf));
|
262
271
|
snprintf(msg, sizeof(msg), "OpenSSL error: %s - %d", buf, err);
|
263
272
|
|
@@ -411,6 +420,11 @@ VALUE noop(VALUE self) {
|
|
411
420
|
void Init_mini_ssl(VALUE puma) {
|
412
421
|
VALUE mod, eng;
|
413
422
|
|
423
|
+
/* Fake operation for documentation (RDoc, YARD) */
|
424
|
+
#if 0 == 1
|
425
|
+
puma = rb_define_module("Puma");
|
426
|
+
#endif
|
427
|
+
|
414
428
|
SSL_library_init();
|
415
429
|
OpenSSL_add_ssl_algorithms();
|
416
430
|
SSL_load_error_strings();
|
@@ -447,7 +461,7 @@ VALUE raise_error(VALUE self) {
|
|
447
461
|
}
|
448
462
|
|
449
463
|
void Init_mini_ssl(VALUE puma) {
|
450
|
-
VALUE mod
|
464
|
+
VALUE mod;
|
451
465
|
|
452
466
|
mod = rb_define_module_under(puma, "MiniSSL");
|
453
467
|
rb_define_class_under(mod, "SSLError", rb_eStandardError);
|
@@ -182,9 +182,6 @@ static final int puma_parser_start = 1;
|
|
182
182
|
static final int puma_parser_first_final = 47;
|
183
183
|
static final int puma_parser_error = 0;
|
184
184
|
|
185
|
-
static final int puma_parser_en_main = 1;
|
186
|
-
|
187
|
-
|
188
185
|
// line 69 "ext/puma_http11/http11_parser.java.rl"
|
189
186
|
|
190
187
|
public static interface ElementCB {
|
@@ -220,7 +217,7 @@ static final int puma_parser_en_main = 1;
|
|
220
217
|
public void init() {
|
221
218
|
cs = 0;
|
222
219
|
|
223
|
-
|
220
|
+
|
224
221
|
// line 225 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
|
225
222
|
{
|
226
223
|
cs = puma_parser_start;
|
@@ -252,7 +249,7 @@ static final int puma_parser_en_main = 1;
|
|
252
249
|
byte[] data = buffer.bytes();
|
253
250
|
parser.buffer = buffer;
|
254
251
|
|
255
|
-
|
252
|
+
|
256
253
|
// line 257 "ext/puma_http11/org/jruby/puma/Http11Parser.java"
|
257
254
|
{
|
258
255
|
int _klen;
|
@@ -347,7 +344,7 @@ case 1:
|
|
347
344
|
break;
|
348
345
|
case 3:
|
349
346
|
// line 17 "ext/puma_http11/http11_parser.java.rl"
|
350
|
-
{
|
347
|
+
{
|
351
348
|
parser.field_len = p-parser.field_start;
|
352
349
|
}
|
353
350
|
break;
|
@@ -357,7 +354,7 @@ case 1:
|
|
357
354
|
break;
|
358
355
|
case 5:
|
359
356
|
// line 22 "ext/puma_http11/http11_parser.java.rl"
|
360
|
-
{
|
357
|
+
{
|
361
358
|
if(parser.http_field != null) {
|
362
359
|
parser.http_field.call(parser.data, parser.field_start, parser.field_len, parser.mark, p-parser.mark);
|
363
360
|
}
|
@@ -365,21 +362,21 @@ case 1:
|
|
365
362
|
break;
|
366
363
|
case 6:
|
367
364
|
// line 27 "ext/puma_http11/http11_parser.java.rl"
|
368
|
-
{
|
369
|
-
if(parser.request_method != null)
|
365
|
+
{
|
366
|
+
if(parser.request_method != null)
|
370
367
|
parser.request_method.call(parser.data, parser.mark, p-parser.mark);
|
371
368
|
}
|
372
369
|
break;
|
373
370
|
case 7:
|
374
371
|
// line 31 "ext/puma_http11/http11_parser.java.rl"
|
375
|
-
{
|
372
|
+
{
|
376
373
|
if(parser.request_uri != null)
|
377
374
|
parser.request_uri.call(parser.data, parser.mark, p-parser.mark);
|
378
375
|
}
|
379
376
|
break;
|
380
377
|
case 8:
|
381
378
|
// line 35 "ext/puma_http11/http11_parser.java.rl"
|
382
|
-
{
|
379
|
+
{
|
383
380
|
if(parser.fragment != null)
|
384
381
|
parser.fragment.call(parser.data, parser.mark, p-parser.mark);
|
385
382
|
}
|
@@ -390,14 +387,14 @@ case 1:
|
|
390
387
|
break;
|
391
388
|
case 10:
|
392
389
|
// line 41 "ext/puma_http11/http11_parser.java.rl"
|
393
|
-
{
|
390
|
+
{
|
394
391
|
if(parser.query_string != null)
|
395
392
|
parser.query_string.call(parser.data, parser.query_start, p-parser.query_start);
|
396
393
|
}
|
397
394
|
break;
|
398
395
|
case 11:
|
399
396
|
// line 46 "ext/puma_http11/http11_parser.java.rl"
|
400
|
-
{
|
397
|
+
{
|
401
398
|
if(parser.http_version != null)
|
402
399
|
parser.http_version.call(parser.data, parser.mark, p-parser.mark);
|
403
400
|
}
|
@@ -411,8 +408,8 @@ case 1:
|
|
411
408
|
break;
|
412
409
|
case 13:
|
413
410
|
// line 56 "ext/puma_http11/http11_parser.java.rl"
|
414
|
-
{
|
415
|
-
parser.body_start = p + 1;
|
411
|
+
{
|
412
|
+
parser.body_start = p + 1;
|
416
413
|
if(parser.header_done != null)
|
417
414
|
parser.header_done.call(parser.data, p + 1, pe - p - 1);
|
418
415
|
{ p += 1; _goto_targ = 5; if (true) continue _goto;}
|
@@ -442,7 +439,7 @@ case 5:
|
|
442
439
|
|
443
440
|
parser.cs = cs;
|
444
441
|
parser.nread += (p - off);
|
445
|
-
|
442
|
+
|
446
443
|
assert p <= pe : "buffer overflow after parsing execute";
|
447
444
|
assert parser.nread <= len : "nread longer than length";
|
448
445
|
assert parser.body_start <= len : "body starts after buffer end";
|
@@ -170,6 +170,12 @@ public class MiniSSL extends RubyObject {
|
|
170
170
|
engine.setNeedClientAuth(true);
|
171
171
|
}
|
172
172
|
|
173
|
+
IRubyObject sslCipherListObject = miniSSLContext.callMethod(threadContext, "ssl_cipher_list");
|
174
|
+
if (!sslCipherListObject.isNil()) {
|
175
|
+
String[] sslCipherList = sslCipherListObject.convertToString().asJavaString().split(",");
|
176
|
+
engine.setEnabledCipherSuites(sslCipherList);
|
177
|
+
}
|
178
|
+
|
173
179
|
SSLSession session = engine.getSession();
|
174
180
|
inboundNetData = new MiniSSLBuffer(session.getPacketBufferSize());
|
175
181
|
outboundAppData = new MiniSSLBuffer(session.getApplicationBufferSize());
|
data/lib/puma.rb
CHANGED
data/lib/puma/app/status.rb
CHANGED
@@ -55,6 +55,14 @@ module Puma
|
|
55
55
|
return rack_response(200, OK_STATUS)
|
56
56
|
end
|
57
57
|
|
58
|
+
when /\/gc$/
|
59
|
+
GC.start
|
60
|
+
return rack_response(200, OK_STATUS)
|
61
|
+
|
62
|
+
when /\/gc-stats$/
|
63
|
+
json = "{" + GC.stat.map { |k, v| "\"#{k}\": #{v}" }.join(",") + "}"
|
64
|
+
return rack_response(200, json)
|
65
|
+
|
58
66
|
when /\/stats$/
|
59
67
|
return rack_response(200, @cli.stats)
|
60
68
|
else
|
data/lib/puma/binder.rb
CHANGED
@@ -120,7 +120,7 @@ module Puma
|
|
120
120
|
|
121
121
|
umask = nil
|
122
122
|
mode = nil
|
123
|
-
backlog =
|
123
|
+
backlog = 1024
|
124
124
|
|
125
125
|
if uri.query
|
126
126
|
params = Util.parse_query uri.query
|
@@ -162,6 +162,7 @@ module Puma
|
|
162
162
|
end
|
163
163
|
|
164
164
|
ctx.keystore_pass = params['keystore-pass']
|
165
|
+
ctx.ssl_cipher_list = params['ssl_cipher_list'] if params['ssl_cipher_list']
|
165
166
|
else
|
166
167
|
unless params['key']
|
167
168
|
@events.error "Please specify the SSL key via 'key='"
|
@@ -182,6 +183,7 @@ module Puma
|
|
182
183
|
end
|
183
184
|
|
184
185
|
ctx.ca = params['ca'] if params['ca']
|
186
|
+
ctx.ssl_cipher_filter = params['ssl_cipher_filter'] if params['ssl_cipher_filter']
|
185
187
|
end
|
186
188
|
|
187
189
|
if params['verify_mode']
|
@@ -245,9 +247,10 @@ module Puma
|
|
245
247
|
end
|
246
248
|
end
|
247
249
|
|
248
|
-
def
|
249
|
-
|
250
|
-
|
250
|
+
def loopback_addresses
|
251
|
+
Socket.ip_address_list.select do |addrinfo|
|
252
|
+
addrinfo.ipv6_loopback? || addrinfo.ipv4_loopback?
|
253
|
+
end.map { |addrinfo| addrinfo.ip_address }.uniq
|
251
254
|
end
|
252
255
|
|
253
256
|
# Tell the server to listen on host +host+, port +port+.
|
@@ -259,7 +262,7 @@ module Puma
|
|
259
262
|
#
|
260
263
|
def add_tcp_listener(host, port, optimize_for_latency=true, backlog=1024)
|
261
264
|
if host == "localhost"
|
262
|
-
|
265
|
+
loopback_addresses.each do |addr|
|
263
266
|
add_tcp_listener addr, port, optimize_for_latency, backlog
|
264
267
|
end
|
265
268
|
return
|
@@ -298,7 +301,7 @@ module Puma
|
|
298
301
|
MiniSSL.check
|
299
302
|
|
300
303
|
if host == "localhost"
|
301
|
-
|
304
|
+
loopback_addresses.each do |addr|
|
302
305
|
add_ssl_listener addr, port, ctx, optimize_for_latency, backlog
|
303
306
|
end
|
304
307
|
return
|
@@ -312,6 +315,7 @@ module Puma
|
|
312
315
|
s.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
|
313
316
|
s.listen backlog
|
314
317
|
|
318
|
+
|
315
319
|
ssl = MiniSSL::Server.new s, ctx
|
316
320
|
env = @proto_env.dup
|
317
321
|
env[HTTPS_KEY] = HTTPS
|
@@ -343,7 +347,7 @@ module Puma
|
|
343
347
|
|
344
348
|
# Tell the server to listen on +path+ as a UNIX domain socket.
|
345
349
|
#
|
346
|
-
def add_unix_listener(path, umask=nil, mode=nil, backlog=
|
350
|
+
def add_unix_listener(path, umask=nil, mode=nil, backlog=1024)
|
347
351
|
@unix_paths << path
|
348
352
|
|
349
353
|
# Let anyone connect by default
|
@@ -364,7 +368,7 @@ module Puma
|
|
364
368
|
end
|
365
369
|
|
366
370
|
s = UNIXServer.new(path)
|
367
|
-
s.listen backlog
|
371
|
+
s.listen backlog
|
368
372
|
@ios << s
|
369
373
|
ensure
|
370
374
|
File.umask old_mask
|
data/lib/puma/cli.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'optparse'
|
2
2
|
require 'uri'
|
3
3
|
|
4
|
+
require 'puma'
|
4
5
|
require 'puma/configuration'
|
5
6
|
require 'puma/launcher'
|
6
7
|
require 'puma/const'
|
@@ -83,6 +84,14 @@ module Puma
|
|
83
84
|
raise UnsupportedOption
|
84
85
|
end
|
85
86
|
|
87
|
+
def configure_control_url(command_line_arg)
|
88
|
+
if command_line_arg
|
89
|
+
@control_url = command_line_arg
|
90
|
+
elsif Puma.jruby?
|
91
|
+
unsupported "No default url available on JRuby"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
86
95
|
# Build the OptionParser object to handle the available options.
|
87
96
|
#
|
88
97
|
|
@@ -97,13 +106,13 @@ module Puma
|
|
97
106
|
file_config.load arg
|
98
107
|
end
|
99
108
|
|
100
|
-
o.on "--control URL", "The bind url to use for the control server"
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
109
|
+
o.on "--control-url URL", "The bind url to use for the control server. Use 'auto' to use temp unix server" do |arg|
|
110
|
+
configure_control_url(arg)
|
111
|
+
end
|
112
|
+
|
113
|
+
# alias --control-url for backwards-compatibility
|
114
|
+
o.on "--control URL", "DEPRECATED alias for --control-url" do |arg|
|
115
|
+
configure_control_url(arg)
|
107
116
|
end
|
108
117
|
|
109
118
|
o.on "--control-token TOKEN",
|
@@ -181,6 +190,10 @@ module Puma
|
|
181
190
|
user_config.tcp_mode!
|
182
191
|
end
|
183
192
|
|
193
|
+
o.on "--early-hints", "Enable early hints support" do
|
194
|
+
user_config.early_hints
|
195
|
+
end
|
196
|
+
|
184
197
|
o.on "-V", "--version", "Print the version information" do
|
185
198
|
puts "puma version #{Puma::Const::VERSION}"
|
186
199
|
exit 0
|
data/lib/puma/client.rb
CHANGED
@@ -21,6 +21,17 @@ module Puma
|
|
21
21
|
|
22
22
|
class ConnectionError < RuntimeError; end
|
23
23
|
|
24
|
+
# An instance of this class represents a unique request from a client.
|
25
|
+
# For example a web request from a browser or from CURL. This
|
26
|
+
#
|
27
|
+
# An instance of `Puma::Client` can be used as if it were an IO object
|
28
|
+
# for example it is passed into `IO.select` inside of the `Puma::Reactor`.
|
29
|
+
# This is accomplished by the `to_io` method which gets called on any
|
30
|
+
# non-IO objects being used with the IO api such as `IO.select.
|
31
|
+
#
|
32
|
+
# Instances of this class are responsible for knowing if
|
33
|
+
# the header and body are fully buffered via the `try_to_finish` method.
|
34
|
+
# They can be used to "time out" a response via the `timeout_at` reader.
|
24
35
|
class Client
|
25
36
|
include Puma::Const
|
26
37
|
extend Puma::Delegation
|
@@ -111,6 +122,7 @@ module Puma
|
|
111
122
|
begin
|
112
123
|
@io.close
|
113
124
|
rescue IOError
|
125
|
+
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
114
126
|
end
|
115
127
|
end
|
116
128
|
|
@@ -283,6 +295,14 @@ module Puma
|
|
283
295
|
raise ConnectionError, "Connection error detected during read"
|
284
296
|
end
|
285
297
|
|
298
|
+
# No data means a closed socket
|
299
|
+
unless data
|
300
|
+
@buffer = nil
|
301
|
+
@requests_served += 1
|
302
|
+
@ready = true
|
303
|
+
raise EOFError
|
304
|
+
end
|
305
|
+
|
286
306
|
if @buffer
|
287
307
|
@buffer << data
|
288
308
|
else
|
@@ -312,6 +332,14 @@ module Puma
|
|
312
332
|
raise e
|
313
333
|
end
|
314
334
|
|
335
|
+
# No data means a closed socket
|
336
|
+
unless data
|
337
|
+
@buffer = nil
|
338
|
+
@requests_served += 1
|
339
|
+
@ready = true
|
340
|
+
raise EOFError
|
341
|
+
end
|
342
|
+
|
315
343
|
if @buffer
|
316
344
|
@buffer << data
|
317
345
|
else
|