yahns 1.14.1 → 1.18.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +5 -5
  2. data/.document +2 -0
  3. data/.gitignore +0 -1
  4. data/.olddoc.yml +3 -2
  5. data/Documentation/GNUmakefile +1 -1
  6. data/Documentation/design_notes.txt +6 -3
  7. data/Documentation/yahns-rackup.pod +7 -3
  8. data/Documentation/yahns.pod +1 -1
  9. data/Documentation/yahns_config.pod +10 -10
  10. data/GIT-VERSION-FILE +1 -1
  11. data/GIT-VERSION-GEN +3 -3
  12. data/HACKING +13 -13
  13. data/NEWS +982 -829
  14. data/README +11 -12
  15. data/Rakefile +121 -5
  16. data/examples/https_proxy_pass.conf.rb +36 -0
  17. data/examples/logrotate.conf +1 -1
  18. data/examples/proxy_pass.ru +11 -0
  19. data/extras/autoindex.rb +20 -4
  20. data/extras/exec_cgi.rb +38 -24
  21. data/extras/proxy_pass.rb +7 -6
  22. data/extras/try_gzip_static.rb +4 -1
  23. data/lib/yahns/acceptor.rb +3 -3
  24. data/lib/yahns/chunk_body.rb +2 -1
  25. data/lib/yahns/config.rb +10 -5
  26. data/lib/yahns/daemon.rb +0 -1
  27. data/lib/yahns/http_client.rb +28 -18
  28. data/lib/yahns/http_response.rb +3 -4
  29. data/lib/yahns/openssl_client.rb +33 -11
  30. data/lib/yahns/proxy_http_response.rb +3 -1
  31. data/lib/yahns/proxy_pass.rb +68 -10
  32. data/lib/yahns/queue_epoll.rb +4 -0
  33. data/lib/yahns/queue_kqueue.rb +0 -6
  34. data/lib/yahns/queue_quitter_pipe.rb +4 -1
  35. data/lib/yahns/rackup_handler.rb +3 -7
  36. data/lib/yahns/server.rb +47 -27
  37. data/lib/yahns/server_mp.rb +3 -4
  38. data/lib/yahns/sigevent_efd.rb +0 -1
  39. data/lib/yahns/sigevent_pipe.rb +13 -6
  40. data/lib/yahns/socket_helper.rb +1 -1
  41. data/lib/yahns/stream_input.rb +3 -2
  42. data/lib/yahns/tee_input.rb +1 -3
  43. data/lib/yahns/version.rb +1 -1
  44. data/lib/yahns/wbuf.rb +10 -3
  45. data/lib/yahns/worker.rb +8 -0
  46. data/lib/yahns.rb +12 -7
  47. data/man/yahns-rackup.1 +17 -17
  48. data/man/yahns.1 +11 -15
  49. data/man/yahns_config.5 +31 -31
  50. data/test/helper.rb +6 -2
  51. data/test/server_helper.rb +20 -5
  52. data/test/test_bin.rb +33 -30
  53. data/test/test_config.rb +2 -2
  54. data/test/test_extras_exec_cgi.rb +24 -1
  55. data/test/test_extras_try_gzip_static.rb +1 -1
  56. data/test/test_mt_accept.rb +0 -2
  57. data/test/test_proxy_pass.rb +1 -2
  58. data/test/test_proxy_pass_no_buffering.rb +1 -1
  59. data/test/test_rack_env.rb +58 -0
  60. data/test/test_serve_static.rb +0 -1
  61. data/test/test_server.rb +1 -4
  62. data/test/test_ssl.rb +2 -0
  63. data/test/test_unix_socket.rb +1 -3
  64. data/test/test_wbuf.rb +1 -1
  65. data/yahns.gemspec +8 -5
  66. metadata +12 -9
data/man/yahns-rackup.1 CHANGED
@@ -1,4 +1,4 @@
1
- .\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.28)
1
+ .\" Automatically generated by Pod::Man 4.07 (Pod::Simple 3.32)
2
2
  .\"
3
3
  .\" Standard preamble:
4
4
  .\" ========================================================================
@@ -46,7 +46,7 @@
46
46
  .ie \n(.g .ds Aq \(aq
47
47
  .el .ds Aq '
48
48
  .\"
49
- .\" If the F register is turned on, we'll generate index entries on stderr for
49
+ .\" If the F register is >0, we'll generate index entries on stderr for
50
50
  .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
51
51
  .\" entries marked with X<> in POD. Of course, you'll have to process the
52
52
  .\" output yourself in some meaningful fashion.
@@ -54,20 +54,16 @@
54
54
  .\" Avoid warning from groff about undefined register 'F'.
55
55
  .de IX
56
56
  ..
57
- .nr rF 0
58
- .if \n(.g .if rF .nr rF 1
59
- .if (\n(rF:(\n(.g==0)) \{
60
- . if \nF \{
61
- . de IX
62
- . tm Index:\\$1\t\\n%\t"\\$2"
57
+ .if !\nF .nr F 0
58
+ .if \nF>0 \{\
59
+ . de IX
60
+ . tm Index:\\$1\t\\n%\t"\\$2"
63
61
  ..
64
- . if !\nF==2 \{
65
- . nr % 0
66
- . nr F 2
67
- . \}
62
+ . if !\nF==2 \{\
63
+ . nr % 0
64
+ . nr F 2
68
65
  . \}
69
66
  .\}
70
- .rr rF
71
67
  .\"
72
68
  .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
73
69
  .\" Fear. Run. Save yourself. No user-serviceable parts.
@@ -133,7 +129,7 @@
133
129
  .\" ========================================================================
134
130
  .\"
135
131
  .IX Title "YAHNS-RACKUP 1"
136
- .TH YAHNS-RACKUP 1 "1994-10-02" "yahns 1.13.0.6.g662f" "yahns user manual"
132
+ .TH YAHNS-RACKUP 1 "1994-10-02" "yahns 1.16.0.24.g39049" "yahns user manual"
137
133
  .\" For nroff, turn off justification. Always turn off hyphenation; it makes
138
134
  .\" way too many mistakes in technical documents.
139
135
  .if n .ad l
@@ -171,6 +167,10 @@ Listens on a given \s-1ADDRESS. ADDRESS\s0 may be in the form of
171
167
  and \s-1PATH\s0 is meant to be a path to a \s-1UNIX\s0 domain socket.
172
168
  Defaults to \*(L"0.0.0.0:9292\*(R" (all addresses on \s-1TCP\s0 port 9292).
173
169
  Multiple addresses may be separated with commas.
170
+ .Sp
171
+ For systemd users, a special value of \*(L"inherit\*(R" may be specified
172
+ to inherit FDs using the \s-1LISTEN_FDS\s0 and \s-1LISTEN_PID\s0 environment
173
+ variables described in \fIsd_listen_fds\fR\|(3)
174
174
  .IP "\-O stderr_path=PATHNAME" 4
175
175
  .IX Item "-O stderr_path=PATHNAME"
176
176
  Allow redirecting \f(CW$stderr\fR to a given path. Unlike doing this from
@@ -268,12 +268,12 @@ See rackup documentation for more details.
268
268
  .SH "CONTACT"
269
269
  .IX Header "CONTACT"
270
270
  All feedback welcome via plain-text mail to <mailto:yahns\-public@yhbt.net>
271
- No subscription is necessary to post to the mailing list.
272
- List archives are available at <https://yhbt.net/yahns\-public/>
271
+ No subscription is necessary to email us.
272
+ Mail archives are available at <https://yhbt.net/yahns\-public/>
273
273
  .SH "COPYRIGHT"
274
274
  .IX Header "COPYRIGHT"
275
275
  Copyright (C) 2013\-2016 all contributors <mailto:yahns\-public@yhbt.net>
276
- License: \s-1GPL\-3.0+ \s0<http://www.gnu.org/licenses/gpl\-3.0.txt>
276
+ License: \s-1GPL\-3.0+ \s0<https://www.gnu.org/licenses/gpl\-3.0.txt>
277
277
  .SH "SEE ALSO"
278
278
  .IX Header "SEE ALSO"
279
279
  \&\fIyahns\fR\|(1), \fIyahns_config\fR\|(5),
data/man/yahns.1 CHANGED
@@ -1,4 +1,4 @@
1
- .\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.28)
1
+ .\" Automatically generated by Pod::Man 4.07 (Pod::Simple 3.32)
2
2
  .\"
3
3
  .\" Standard preamble:
4
4
  .\" ========================================================================
@@ -46,7 +46,7 @@
46
46
  .ie \n(.g .ds Aq \(aq
47
47
  .el .ds Aq '
48
48
  .\"
49
- .\" If the F register is turned on, we'll generate index entries on stderr for
49
+ .\" If the F register is >0, we'll generate index entries on stderr for
50
50
  .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
51
51
  .\" entries marked with X<> in POD. Of course, you'll have to process the
52
52
  .\" output yourself in some meaningful fashion.
@@ -54,20 +54,16 @@
54
54
  .\" Avoid warning from groff about undefined register 'F'.
55
55
  .de IX
56
56
  ..
57
- .nr rF 0
58
- .if \n(.g .if rF .nr rF 1
59
- .if (\n(rF:(\n(.g==0)) \{
60
- . if \nF \{
61
- . de IX
62
- . tm Index:\\$1\t\\n%\t"\\$2"
57
+ .if !\nF .nr F 0
58
+ .if \nF>0 \{\
59
+ . de IX
60
+ . tm Index:\\$1\t\\n%\t"\\$2"
63
61
  ..
64
- . if !\nF==2 \{
65
- . nr % 0
66
- . nr F 2
67
- . \}
62
+ . if !\nF==2 \{\
63
+ . nr % 0
64
+ . nr F 2
68
65
  . \}
69
66
  .\}
70
- .rr rF
71
67
  .\"
72
68
  .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
73
69
  .\" Fear. Run. Save yourself. No user-serviceable parts.
@@ -133,7 +129,7 @@
133
129
  .\" ========================================================================
134
130
  .\"
135
131
  .IX Title "YAHNS 1"
136
- .TH YAHNS 1 "1994-10-02" "yahns 1.13.0.6.g662f" "yahns user manual"
132
+ .TH YAHNS 1 "1994-10-02" "yahns 1.16.0.24.g39049" "yahns user manual"
137
133
  .\" For nroff, turn off justification. Always turn off hyphenation; it makes
138
134
  .\" way too many mistakes in technical documents.
139
135
  .if n .ad l
@@ -205,7 +201,7 @@ See \fIyahns_config\fR\|(5) for documentation on the configuration file format.
205
201
  .SH "CONTACT"
206
202
  .IX Header "CONTACT"
207
203
  All feedback welcome via plain-text mail to <mailto:yahns\-public@yhbt.net>
208
- No subscription is necessary to post to the mailing list.
204
+ No subscription is necessary to email us.
209
205
  Mail archives are available at <https://yhbt.net/yahns\-public/>
210
206
  .SH "COPYRIGHT"
211
207
  .IX Header "COPYRIGHT"
data/man/yahns_config.5 CHANGED
@@ -1,4 +1,4 @@
1
- .\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.28)
1
+ .\" Automatically generated by Pod::Man 4.10 (Pod::Simple 3.35)
2
2
  .\"
3
3
  .\" Standard preamble:
4
4
  .\" ========================================================================
@@ -46,7 +46,7 @@
46
46
  .ie \n(.g .ds Aq \(aq
47
47
  .el .ds Aq '
48
48
  .\"
49
- .\" If the F register is turned on, we'll generate index entries on stderr for
49
+ .\" If the F register is >0, we'll generate index entries on stderr for
50
50
  .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
51
51
  .\" entries marked with X<> in POD. Of course, you'll have to process the
52
52
  .\" output yourself in some meaningful fashion.
@@ -56,12 +56,12 @@
56
56
  ..
57
57
  .nr rF 0
58
58
  .if \n(.g .if rF .nr rF 1
59
- .if (\n(rF:(\n(.g==0)) \{
60
- . if \nF \{
59
+ .if (\n(rF:(\n(.g==0)) \{\
60
+ . if \nF \{\
61
61
  . de IX
62
62
  . tm Index:\\$1\t\\n%\t"\\$2"
63
63
  ..
64
- . if !\nF==2 \{
64
+ . if !\nF==2 \{\
65
65
  . nr % 0
66
66
  . nr F 2
67
67
  . \}
@@ -133,7 +133,7 @@
133
133
  .\" ========================================================================
134
134
  .\"
135
135
  .IX Title "YAHNS_CONFIG 5"
136
- .TH YAHNS_CONFIG 5 "1994-10-02" "yahns 1.13.0.6.g662f" "yahns user manual"
136
+ .TH YAHNS_CONFIG 5 "1994-10-02" "yahns 1.17.0.5.g4e5f" "yahns user manual"
137
137
  .\" For nroff, turn off justification. Always turn off hyphenation; it makes
138
138
  .\" way too many mistakes in technical documents.
139
139
  .if n .ad l
@@ -174,7 +174,7 @@ For Rack \s-1HTTP\s0 applications, see \*(L"\s-1RACK APP ARGUMENTS\*(R"\s0 for m
174
174
  information.
175
175
  .IP "before_exec &BLOCK" 4
176
176
  .IX Item "before_exec &BLOCK"
177
- This runs &BLOCK before Kernel#exec (\fIexecve\fR\|(2) wrapper). The command
177
+ This runs &BLOCK before Kernel#exec (\fBexecve\fR\|(2) wrapper). The command
178
178
  array to be passed to Kernel#exec may be modified within this hook:
179
179
  .Sp
180
180
  .Vb 3
@@ -287,7 +287,7 @@ Default: / if daemonized, current working directory if not
287
287
  .IP "max_events \s-1INTEGER\s0" 4
288
288
  .IX Item "max_events INTEGER"
289
289
  This controls the number of events a worker thread will fetch at
290
- once via \fIepoll_wait\fR\|(2) or \fIkevent\fR\|(2).
290
+ once via \fBepoll_wait\fR\|(2) or \fBkevent\fR\|(2).
291
291
  There is no good reason to change this
292
292
  unless you use very few (e.g. 1) worker_threads. Leaving this at
293
293
  1 will give the fairest load balancing behavior with epoll or kqueue.
@@ -332,7 +332,7 @@ Default: false
332
332
  This controls the maximum size of a request body before it is
333
333
  buffered to the filesystem (instead of memory). This has no effect
334
334
  if input_buffering is false. This also governs the size of an
335
- individual \fIread\fR\|(2) system call when reading a request body.
335
+ individual \fBread\fR\|(2) system call when reading a request body.
336
336
  .Sp
337
337
  There is generally no need to change this value and this directive
338
338
  may be removed in the future.
@@ -340,7 +340,7 @@ may be removed in the future.
340
340
  Default: 8192 bytes (8 kilobytes)
341
341
  .IP "client_header_buffer_size \s-1INTEGER\s0" 4
342
342
  .IX Item "client_header_buffer_size INTEGER"
343
- This controls the size of a single \fIread\fR\|(2) syscall for reading
343
+ This controls the size of a single \fBread\fR\|(2) syscall for reading
344
344
  client request headers. Increase this as needed if your application
345
345
  uses large cookies or long URLs. Lowering this may reduce \s-1GC\s0 and
346
346
  memory allocator overhead.
@@ -463,12 +463,12 @@ this means Unix domain sockets must not be placed in /tmp
463
463
  The following \s-1OPTIONS\s0 may be specified (but are generally not needed):
464
464
  .IP "backlog: \s-1INTEGER\s0" 4
465
465
  .IX Item "backlog: INTEGER"
466
- This is the backlog of the \fIlisten\fR\|(2) syscall.
466
+ This is the backlog of the \fBlisten\fR\|(2) syscall.
467
467
  .Sp
468
468
  Some operating systems allow negative values here to specify the
469
469
  maximum allowable value. In most cases, this number is only
470
470
  recommendation and there are other OS-specific tunables and
471
- variables that can affect this number. See the \fIlisten\fR\|(2)
471
+ variables that can affect this number. See the \fBlisten\fR\|(2)
472
472
  syscall documentation of your \s-1OS\s0 for the exact semantics of
473
473
  this.
474
474
  .Sp
@@ -495,7 +495,7 @@ Default: Operating-system dependent
495
495
  Maximum receive and send buffer sizes (in bytes) of sockets.
496
496
  .Sp
497
497
  These correspond to the \s-1SO_RCVBUF\s0 and \s-1SO_SNDBUF\s0 settings which
498
- can be set via the \fIsetsockopt\fR\|(2) syscall. Some kernels
498
+ can be set via the \fBsetsockopt\fR\|(2) syscall. Some kernels
499
499
  (e.g. Linux 2.4+) have intelligent auto-tuning mechanisms and
500
500
  there is no need (and it is sometimes detrimental) to specify them.
501
501
  .Sp
@@ -511,8 +511,8 @@ This enables multiple, independently-started yahns instances to
511
511
  bind to the same port (as long as all the processes enable this).
512
512
  .Sp
513
513
  This option must be used when yahns first binds the listen socket.
514
- It cannot be enabled when a socket is inherited via \s-1SIGUSR2
515
- \&\s0(but it will remain on if inherited), and it cannot be enabled
514
+ It cannot be enabled when a socket is inherited via \s-1SIGUSR2\s0
515
+ (but it will remain on if inherited), and it cannot be enabled
516
516
  directly via \s-1SIGHUP.\s0
517
517
  .Sp
518
518
  Note: there is a chance of connections being dropped if
@@ -529,7 +529,7 @@ To enable \s-1TLS\s0 connections, you must configure this yourself.
529
529
  See documentation for OpenSSL::SSL::SSLContext
530
530
  for more information:
531
531
  .Sp
532
- <http://docs.ruby\-lang.org/en/trunk/OpenSSL/SSL/SSLContext.html>
532
+ <https://docs.ruby\-lang.org/en/trunk/OpenSSL/SSL/SSLContext.html>
533
533
  .Sp
534
534
  Default: none
535
535
  .Sp
@@ -539,22 +539,22 @@ An example which seems to work is:
539
539
  \& require \*(Aqopenssl\*(Aq
540
540
  \& ssl_ctx = OpenSSL::SSL::SSLContext.new
541
541
  \& ssl_ctx.cert = OpenSSL::X509::Certificate.new(
542
- \& IO.read(\*(Aq/etc/ssl/certs/example.crt\*(Aq)
542
+ \& File.read(\*(Aq/etc/ssl/certs/example.crt\*(Aq)
543
543
  \& )
544
544
  \& ssl_ctx.extra_chain_cert = [
545
545
  \& OpenSSL::X509::Certificate.new(
546
- \& IO.read(\*(Aq/etc/ssl/certs/chain.crt\*(Aq)
546
+ \& File.read(\*(Aq/etc/ssl/certs/chain.crt\*(Aq)
547
547
  \& )
548
548
  \& ]
549
549
  \& ssl_ctx.key = OpenSSL::PKey::RSA.new(
550
- \& IO.read(\*(Aq/etc/ssl/private/example.key\*(Aq)
550
+ \& File.read(\*(Aq/etc/ssl/private/example.key\*(Aq)
551
551
  \& )
552
552
  \&
553
553
  \& # use defaults provided by Ruby on top of OpenSSL,
554
- \& # but disable client certificate verification as it is rare:
554
+ \& # but disable client certificate verification as it is rare for servers:
555
555
  \& ssl_ctx.set_params(verify_mode: OpenSSL::SSL::VERIFY_NONE)
556
556
  \&
557
- \& # Built\-in session cache (only works if worker_processes is nil or 1)
557
+ \& # Built\-in session cache (only useful if worker_processes is nil or 1)
558
558
  \& ssl_ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_SERVER
559
559
  \&
560
560
  \& app(:rack, "/path/to/my/app/config.ru") do
@@ -676,7 +676,7 @@ here means yahns will enable yahns to use a master/worker process
676
676
  model instead of a single process.
677
677
  .Sp
678
678
  If an optional &BLOCK is given, it may be used to configure
679
- \&\fIpthread_atfork\fR\|(3)\-style hooks.
679
+ \&\fBpthread_atfork\fR\|(3)\-style hooks.
680
680
  See \*(L"\s-1WORKER_PROCESSES\-LEVEL DIRECTIVES\*(R"\s0 for details.
681
681
  .Sp
682
682
  Using worker_processes is strongly recommended if your application
@@ -692,7 +692,7 @@ Note: all of the atfork_* hooks described here are available inside the
692
692
  \&\*(L"app\*(R" blocks, too.
693
693
  .IP "atfork_prepare &BLOCK" 4
694
694
  .IX Item "atfork_prepare &BLOCK"
695
- This &BLOCK is executed in the parent before \fIfork\fR\|(2) operation.
695
+ This &BLOCK is executed in the parent before \fBfork\fR\|(2) operation.
696
696
  This may be useful for app directives which specify \*(L"preload: true\*(R"
697
697
  to disconnect from databases or otherwise close open file descriptors
698
698
  to prevent them from being shared with the children.
@@ -700,12 +700,12 @@ to prevent them from being shared with the children.
700
700
  Default: none
701
701
  .IP "atfork_parent &BLOCK" 4
702
702
  .IX Item "atfork_parent &BLOCK"
703
- This &BLOCK is executed in the parent after the \fIfork\fR\|(2) operation.
703
+ This &BLOCK is executed in the parent after the \fBfork\fR\|(2) operation.
704
704
  .Sp
705
705
  Default: none
706
706
  .IP "atfork_child &BLOCK" 4
707
707
  .IX Item "atfork_child &BLOCK"
708
- This &BLOCK is executed in the child after the \fIfork\fR\|(2) operation.
708
+ This &BLOCK is executed in the child after the \fBfork\fR\|(2) operation.
709
709
  .Sp
710
710
  This may be useful for app directives which specify \*(L"preload: true\*(R"
711
711
  to reconnect to databases or reopen closed file descriptors which
@@ -714,7 +714,7 @@ were closed in the atfork_prepare hook.
714
714
  Default: none
715
715
  .SH "RACK APP ARGUMENTS"
716
716
  .IX Header "RACK APP ARGUMENTS"
717
- Rack applications take a \s-1PATHNAME\s0 to the \fIrackup\fR\|(1) config file
717
+ Rack applications take a \s-1PATHNAME\s0 to the \fBrackup\fR\|(1) config file
718
718
  (e.g. \*(L"config.ru\*(R") as its first argument.
719
719
  .PP
720
720
  The only supported keyword argument is:
@@ -737,17 +737,17 @@ compatibility.
737
737
  See the examples/ directory in the git source tree.
738
738
  .PP
739
739
  .Vb 1
740
- \& git clone git://yhbt.net/yahns.git
740
+ \& git clone https://yhbt.net/yahns.git
741
741
  .Ve
742
742
  .SH "CONTACT"
743
743
  .IX Header "CONTACT"
744
744
  All feedback welcome via plain-text mail to <mailto:yahns\-public@yhbt.net>
745
- No subscription is necessary to post to the mailing list.
746
- List archives are available at <https://yhbt.net/yahns\-public/>
745
+ No subscription is necessary to email us.
746
+ Mail archives are available at <https://yhbt.net/yahns\-public/>
747
747
  .SH "COPYRIGHT"
748
748
  .IX Header "COPYRIGHT"
749
749
  Copyright (C) 2013\-2016 all contributors <mailto:yahns\-public@yhbt.net>
750
- License: \s-1GPL\-3.0+ \s0<http://www.gnu.org/licenses/gpl\-3.0.txt>
750
+ License: \s-1GPL\-3.0+\s0 <https://www.gnu.org/licenses/gpl\-3.0.txt>
751
751
  .SH "SEE ALSO"
752
752
  .IX Header "SEE ALSO"
753
- \&\fIyahns\fR\|(1)
753
+ \&\fByahns\fR\|(1)
data/test/helper.rb CHANGED
@@ -125,7 +125,7 @@ class IO
125
125
  end if ! IO.method_defined?(:nread) && RUBY_PLATFORM =~ /linux/
126
126
 
127
127
  def cloexec_pipe
128
- IO.pipe.each { |io| io.close_on_exec = true }
128
+ IO.pipe
129
129
  end
130
130
 
131
131
  def require_exec(cmd)
@@ -136,6 +136,10 @@ def require_exec(cmd)
136
136
  false
137
137
  end
138
138
 
139
+ def xfork
140
+ GTL.synchronize { fork { yield } }
141
+ end
142
+
139
143
  class DieIfUsed
140
144
  @@n = 0
141
145
  def each
@@ -154,7 +158,7 @@ def skip_skb_mem
154
158
  [ [ '/proc/sys/net/ipv4/tcp_rmem', "4096 87380 6291456\n" ],
155
159
  [ '/proc/sys/net/ipv4/tcp_wmem', "4096 16384 4194304\n" ]
156
160
  ].each do |file, expect|
157
- val = IO.read(file)
161
+ val = File.read(file)
158
162
  val == expect or skip "#{file} had: #{val}expected: #{expect}"
159
163
  end
160
164
  end
@@ -31,7 +31,7 @@ module ServerHelper
31
31
 
32
32
  def quit_wait(pid)
33
33
  pid or return
34
- err = $!
34
+ err = $! and warn "Terminating on #{err.inspect} (#{err.class})"
35
35
  Process.kill(:QUIT, pid)
36
36
  _, status = Timeout.timeout(10) { Process.waitpid2(pid) }
37
37
  assert status.success?, status.inspect
@@ -52,9 +52,7 @@ module ServerHelper
52
52
  # only use for newly bound sockets
53
53
  def get_tcp_client(host, port, tries = 500)
54
54
  begin
55
- c = TCPSocket.new(host, port)
56
- c.close_on_exec = true
57
- return c
55
+ return TCPSocket.new(host, port)
58
56
  rescue Errno::ECONNREFUSED
59
57
  raise if tries < 0
60
58
  tries -= 1
@@ -65,16 +63,33 @@ module ServerHelper
65
63
  @srv.close if defined?(@srv) && !@srv.closed?
66
64
  @ru.close! if defined?(@ru) && @ru
67
65
  check_err if defined?(@err)
66
+ Timeout.timeout(30) do
67
+ Process.kill(:TERM, @tail_pid)
68
+ Process.waitpid(@tail_pid)
69
+ end if @tail_pid
68
70
  end
69
71
 
70
72
  def server_helper_setup
71
73
  @srv = TCPServer.new(ENV["TEST_HOST"] || "127.0.0.1", 0)
72
74
  @err = tmpfile(%w(srv .err))
73
75
  @ru = nil
76
+ @tail_pid = nil
77
+ case tail = ENV['TAIL']
78
+ when '1'
79
+ tail = 'tail -f' # POSIX
80
+ when nil, '0'
81
+ tail = nil
82
+ # else : allow users to specify 'tail -F' or 'gtail -F' for GNU
83
+ end
84
+ if tail
85
+ cmd = tail.split(/\s+/)
86
+ cmd << @err.path
87
+ @tail_pid = spawn(*cmd)
88
+ end
74
89
  end
75
90
 
76
91
  def mkserver(cfg, srv = @srv)
77
- fork do
92
+ xfork do
78
93
  ENV["YAHNS_FD"] = srv.fileno.to_s
79
94
  srv.autoclose = false
80
95
  yield if block_given?
data/test/test_bin.rb CHANGED
@@ -9,40 +9,41 @@ class TestBin < Testcase
9
9
 
10
10
  def setup
11
11
  server_helper_setup
12
- @cmd = %W(ruby -I lib bin/yahns)
12
+ @cmd = %W(#{RbConfig.ruby} -I lib bin/yahns)
13
13
  end
14
14
 
15
15
  def test_listen_fd3
16
16
  return unless RUBY_VERSION.to_f > 2.3 # Fixed in ruby/trunk r51209, actually
17
- @srv.setsockopt(:SOL_SOCKET, :SO_KEEPALIVE, 0)
18
17
  host, port = @srv.addr[3], @srv.addr[1]
19
18
 
20
19
  ru = tmpfile(%w(test_bin_daemon .ru))
21
20
  ru.write("require 'rack/lobster'; run Rack::Lobster.new\n")
22
- cmd = %W(ruby -I lib bin/yahns-rackup
23
- -E none -p #{port} -o #{host} #{ru.path})
24
- pid = fork do # emulate a systemd environment
25
- env = {
26
- 'LISTEN_PID' => $$.to_s,
27
- 'LISTEN_FDS' => '1',
28
- }
29
- exec env, *cmd, 3 => @srv, err: @err.path
30
- end
31
- Net::HTTP.start(host, port) do |http|
32
- req = Net::HTTP::Get.new("/")
33
- res = http.request(req)
34
- assert_equal 200, res.code.to_i
35
- assert_equal "keep-alive", res["Connection"]
21
+ cmd = %W(#{RbConfig.ruby} -I lib bin/yahns-rackup -E none #{ru.path})
22
+ [ %w(-O listen=inherit), %W(-p #{port} -o #{host}) ].each do |opt|
23
+ @srv.setsockopt(:SOL_SOCKET, :SO_KEEPALIVE, 0)
24
+ begin
25
+ pid = xfork do # emulate a systemd environment
26
+ env = { 'LISTEN_PID' => $$.to_s, 'LISTEN_FDS' => '1' }
27
+ cmd.concat(opt)
28
+ exec env, *cmd, 3 => @srv, err: @err.path
29
+ end
30
+ Net::HTTP.start(host, port) do |http|
31
+ req = Net::HTTP::Get.new("/")
32
+ res = http.request(req)
33
+ assert_equal 200, res.code.to_i
34
+ assert_equal "keep-alive", res["Connection"]
35
+ end
36
+ assert @srv.getsockopt(:SOL_SOCKET, :SO_KEEPALIVE).bool,
37
+ 'ensure the inheriting process applies TCP socket options'
38
+ ensure
39
+ if pid
40
+ Process.kill(:QUIT, pid)
41
+ _, status = Process.waitpid2(pid)
42
+ assert status.success?, status.inspect
43
+ end
44
+ end
36
45
  end
37
-
38
- assert_equal 1, @srv.getsockopt(:SOL_SOCKET, :SO_KEEPALIVE).int,
39
- 'ensure the inheriting process applies TCP socket options'
40
46
  ensure
41
- if pid
42
- Process.kill(:QUIT, pid)
43
- _, status = Process.waitpid2(pid)
44
- assert status.success?, status.inspect
45
- end
46
47
  ru.close! if ru
47
48
  end
48
49
 
@@ -76,7 +77,7 @@ class TestBin < Testcase
76
77
  cfg.puts "end"
77
78
  @cmd.concat(%W(-D -c #{cfg.path}))
78
79
  addr = cloexec_pipe
79
- pid = fork do
80
+ pid = xfork do
80
81
  opts = { close_others: true }
81
82
  addr[0].close
82
83
  if inherit
@@ -98,7 +99,10 @@ class TestBin < Testcase
98
99
  # Even with a synchronous FD_CLOEXEC, there's a chance of a race
99
100
  # because the server does not bind right away.
100
101
  unless inherit
101
- @srv.shutdown
102
+ begin
103
+ @srv.shutdown
104
+ rescue Errno::ENOTCONN
105
+ end
102
106
  @srv.close
103
107
  end
104
108
  exec(*@cmd)
@@ -158,11 +162,10 @@ class TestBin < Testcase
158
162
  # need to fork here since tests are MT and the FD can leak out and go to
159
163
  # other processes which fork (but do not exec), causing ETXTBUSY on
160
164
  # Process.spawn
161
- pid = fork do
162
- ruby = "#!#{`which ruby`}"
165
+ pid = xfork do
163
166
  File.open(exe, "w") { |y|
164
167
  lines = File.readlines("bin/yahns")
165
- lines[0] = ruby
168
+ lines[0] = "#!#{RbConfig.ruby}\n"
166
169
  y.chmod(0755)
167
170
  y.syswrite(lines.join)
168
171
  }
@@ -190,7 +193,7 @@ class TestBin < Testcase
190
193
  }
191
194
  cmd = %W(#{exe} -D -c #{cfg.path})
192
195
  cmd << { @srv => @srv, close_others: true }
193
- pid = GTL.synchronize { Process.spawn(env, *cmd) }
196
+ pid = Process.spawn(env, *cmd)
194
197
  res = Net::HTTP.start(host, port) { |h| h.get("/") }
195
198
  assert_equal 200, res.code.to_i
196
199
  orig = res.body
data/test/test_config.rb CHANGED
@@ -13,7 +13,7 @@ class TestConfig < Testcase
13
13
  end
14
14
 
15
15
  def test_multi_conf_example
16
- pid = fork do
16
+ pid = xfork do
17
17
  tmpdir = yahns_mktmpdir
18
18
 
19
19
  # modify the example config file for testing
@@ -37,7 +37,7 @@ class TestConfig < Testcase
37
37
  end
38
38
 
39
39
  def test_rack_basic_conf_example
40
- pid = fork do
40
+ pid = xfork do
41
41
  tmpdir = yahns_mktmpdir
42
42
 
43
43
  # modify the example config file for testing
@@ -170,7 +170,7 @@ class TestExtrasExecCGI < Testcase
170
170
  assert_match %r{\A\d+\n\z}, body
171
171
  exec_pid = body.to_i
172
172
  poke_until_dead exec_pid
173
- assert_raises(EOFError) { c.read_nonblock(666) }
173
+ assert_raises(EOFError) { c.readpartial(666) }
174
174
  else
175
175
  raise "BUG in test, bad rtype"
176
176
  end
@@ -179,4 +179,27 @@ class TestExtrasExecCGI < Testcase
179
179
  c.close if c
180
180
  quit_wait(pid)
181
181
  end
182
+
183
+ def test_rlimit_options
184
+ err, cfg, host, port = @err, Yahns::Config.new, @srv.addr[3], @srv.addr[1]
185
+ tout = 1
186
+ opts = { rlimit_cpu: tout, rlimit_core: 0 }
187
+ cmd = [ '/bin/sh', '-c', 'while :; do :;done', opts ]
188
+ pid = mkserver(cfg) do
189
+ require './extras/exec_cgi'
190
+ cfg.instance_eval do
191
+ stack = Rack::ContentLength.new(Rack::Chunked.new(ExecCgi.new(*cmd)))
192
+ app(:rack, stack) { listen "#{host}:#{port}" }
193
+ stderr_path err.path
194
+ worker_processes 1
195
+ end
196
+ end
197
+ c = get_tcp_client(host, port)
198
+ c.write "GET / HTTP/1.0\r\n\r\n"
199
+ assert_same c, c.wait(tout + 5)
200
+ assert_match %r{ 500 Internal Server Error\b}, c.readpartial(4096)
201
+ c.close
202
+ ensure
203
+ quit_wait(pid)
204
+ end
182
205
  end
@@ -52,7 +52,7 @@ class TestExtrasTryGzipStatic < Testcase
52
52
  File.symlink "COPYING", "#{tmpdir}/COPYING.relsymlink"
53
53
  gplgz = "#{tmpdir}/COPYING.gz"
54
54
  FileUtils.cp("COPYING", gpl)
55
- _, status = Process.waitpid2(fork do
55
+ _, status = Process.waitpid2(xfork do
56
56
  File.open(gplgz, "w") do |fp|
57
57
  Zlib::GzipWriter.wrap(fp.dup) { |io| io.write(GPL_TEXT) }
58
58
  end
@@ -14,7 +14,6 @@ class TestMtAccept < Testcase
14
14
  skip "Linux kernel required" unless RUBY_PLATFORM =~ /linux/
15
15
  skip "/proc not mounted" unless File.directory?("/proc")
16
16
  err, cfg, host, port = @err, Yahns::Config.new, @srv.addr[3], @srv.addr[1]
17
- opts = { threads: 1 }
18
17
  cfg.instance_eval do
19
18
  GTL.synchronize do
20
19
  app(:rack, Rack::Lobster.new) { listen "#{host}:#{port}", threads: 1 }
@@ -29,7 +28,6 @@ class TestMtAccept < Testcase
29
28
  quit_wait(pid)
30
29
 
31
30
  cfg = Yahns::Config.new
32
- opts = { threads: 1 }
33
31
  cfg.instance_eval do
34
32
  GTL.synchronize do
35
33
  app(:rack, Rack::Lobster.new) { listen "#{host}:#{port}", threads: 2 }
@@ -6,6 +6,7 @@ require 'json'
6
6
  require 'digest'
7
7
  begin
8
8
  require 'kcar'
9
+ require 'yahns/proxy_pass'
9
10
  rescue LoadError
10
11
  end
11
12
 
@@ -188,7 +189,6 @@ class TestProxyPass < Testcase
188
189
  pid = mkserver(cfg) do
189
190
  @srv.autoclose = @srv2.autoclose = false
190
191
  ENV["YAHNS_FD"] = "#{@srv.fileno},#{@srv2.fileno}"
191
- require 'yahns/proxy_pass'
192
192
  cfg.instance_eval do
193
193
  app(:rack, Yahns::ProxyPass.new("unix:#{unix_path}:/$fullpath")) do
194
194
  listen "#{host}:#{port}"
@@ -251,7 +251,6 @@ class TestProxyPass < Testcase
251
251
  err, cfg, host, port = @err, Yahns::Config.new, @srv.addr[3], @srv.addr[1]
252
252
  host2, port2 = @srv2.addr[3], @srv2.addr[1]
253
253
  pid = mkserver(cfg) do
254
- require 'yahns/proxy_pass'
255
254
  @srv2.close
256
255
  cfg.instance_eval do
257
256
  app(:rack, Yahns::ProxyPass.new("http://#{host2}:#{port2}")) do
@@ -4,6 +4,7 @@
4
4
  require_relative 'server_helper'
5
5
  begin
6
6
  require 'kcar'
7
+ require 'yahns/proxy_pass'
7
8
  rescue LoadError
8
9
  end
9
10
  require 'digest/md5'
@@ -39,7 +40,6 @@ class TestProxyPassNoBuffering < Testcase
39
40
  @srv2 = TCPServer.new(ENV["TEST_HOST"] || "127.0.0.1", 0)
40
41
  server_helper_setup
41
42
  skip "kcar missing yahns/proxy_pass" unless defined?(Kcar)
42
- require 'yahns/proxy_pass'
43
43
  @tmpdir = yahns_mktmpdir
44
44
  end
45
45