yahns 1.16.0 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Documentation/GNUmakefile +1 -1
- data/Documentation/yahns-rackup.pod +2 -2
- data/Documentation/yahns.pod +1 -1
- data/Documentation/yahns_config.pod +2 -2
- data/GIT-VERSION-GEN +2 -2
- data/HACKING +6 -7
- data/README +9 -14
- data/extras/autoindex.rb +18 -2
- data/extras/exec_cgi.rb +38 -24
- data/extras/proxy_pass.rb +2 -2
- data/lib/yahns.rb +4 -2
- data/lib/yahns/config.rb +3 -3
- data/lib/yahns/daemon.rb +0 -1
- data/lib/yahns/http_client.rb +4 -13
- data/lib/yahns/http_response.rb +2 -3
- data/lib/yahns/queue_kqueue.rb +0 -6
- data/lib/yahns/queue_quitter_pipe.rb +4 -1
- data/lib/yahns/server.rb +14 -1
- data/lib/yahns/server_mp.rb +2 -4
- data/lib/yahns/sigevent_efd.rb +0 -1
- data/lib/yahns/sigevent_pipe.rb +13 -6
- data/lib/yahns/socket_helper.rb +1 -1
- data/lib/yahns/wbuf.rb +10 -3
- data/lib/yahns/worker.rb +8 -0
- data/test/helper.rb +1 -1
- data/test/server_helper.rb +1 -3
- data/test/test_bin.rb +4 -1
- data/test/test_extras_exec_cgi.rb +24 -1
- data/test/test_serve_static.rb +0 -1
- data/test/test_server.rb +0 -3
- data/test/test_unix_socket.rb +1 -3
- data/test/test_wbuf.rb +1 -1
- data/yahns.gemspec +1 -1
- metadata +4 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 728a55c5f8af10a1f3dff8d71444a89d5cb5990ecc00613266c5f62405b5eec0
|
|
4
|
+
data.tar.gz: a7eff02b1cb3fea5470ef6232ee624a50e57a91ffcea234e31a1fcd829920c52
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cfa4b7b2842701c03611c666d85be9cf22c975d10e69d8f9642181b4241cc80919ef6a9e012996e34012f49bc0dad024a766bff0718278aed8957d4421fd953d
|
|
7
|
+
data.tar.gz: 965ed79f974891574b2cba0c31f44bc61160f4cbfb59488d528f38eca0e5e8198259447b2ca45fc5e4386d6216ed09f27c8a30bbd0fae753ebfbabb9f443fb49
|
data/Documentation/GNUmakefile
CHANGED
|
@@ -166,8 +166,8 @@ See rackup documentation for more details.
|
|
|
166
166
|
=head1 CONTACT
|
|
167
167
|
|
|
168
168
|
All feedback welcome via plain-text mail to L<mailto:yahns-public@yhbt.net>
|
|
169
|
-
No subscription is necessary to
|
|
170
|
-
|
|
169
|
+
No subscription is necessary to email us.
|
|
170
|
+
Mail archives are available at L<https://yhbt.net/yahns-public/>
|
|
171
171
|
|
|
172
172
|
=head1 COPYRIGHT
|
|
173
173
|
|
data/Documentation/yahns.pod
CHANGED
|
@@ -83,7 +83,7 @@ See L<yahns_config(5)> for documentation on the configuration file format.
|
|
|
83
83
|
=head1 CONTACT
|
|
84
84
|
|
|
85
85
|
All feedback welcome via plain-text mail to L<mailto:yahns-public@yhbt.net>
|
|
86
|
-
No subscription is necessary to
|
|
86
|
+
No subscription is necessary to email us.
|
|
87
87
|
Mail archives are available at L<https://yhbt.net/yahns-public/>
|
|
88
88
|
|
|
89
89
|
=head1 COPYRIGHT
|
|
@@ -661,8 +661,8 @@ See the examples/ directory in the git source tree.
|
|
|
661
661
|
=head1 CONTACT
|
|
662
662
|
|
|
663
663
|
All feedback welcome via plain-text mail to L<mailto:yahns-public@yhbt.net>
|
|
664
|
-
No subscription is necessary to
|
|
665
|
-
|
|
664
|
+
No subscription is necessary to email us.
|
|
665
|
+
Mail archives are available at L<https://yhbt.net/yahns-public/>
|
|
666
666
|
|
|
667
667
|
=head1 COPYRIGHT
|
|
668
668
|
|
data/GIT-VERSION-GEN
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
-
# Copyright (C) 2013-
|
|
2
|
+
# Copyright (C) 2013-2019 all contributors <yahns-public@yhbt.net>
|
|
3
3
|
# License: GPL-3.0+ (https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
4
4
|
# frozen_string_literal: true
|
|
5
5
|
CONSTANT = "Yahns::VERSION"
|
|
6
6
|
RVF = "lib/yahns/version.rb"
|
|
7
7
|
GVF = "GIT-VERSION-FILE"
|
|
8
|
-
DEF_VER = "v1.
|
|
8
|
+
DEF_VER = "v1.17.0"
|
|
9
9
|
vn = DEF_VER.dup
|
|
10
10
|
|
|
11
11
|
# First see if there is a version file (included in release tarballs),
|
data/HACKING
CHANGED
|
@@ -9,7 +9,7 @@ development dependencies
|
|
|
9
9
|
* git - https://www.git-scm.com/
|
|
10
10
|
* ruby - https://www.ruby-lang.org/en/
|
|
11
11
|
|
|
12
|
-
git clone https://yhbt.net/yahns
|
|
12
|
+
git clone https://yhbt.net/yahns.git
|
|
13
13
|
|
|
14
14
|
tests
|
|
15
15
|
-----
|
|
@@ -42,15 +42,14 @@ installing from git
|
|
|
42
42
|
contact
|
|
43
43
|
-------
|
|
44
44
|
|
|
45
|
-
We use git(7) and develop yahns
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
formatted using git-request-pull(1).
|
|
45
|
+
We use git(7) and develop yahns using email like git.git hackers do.
|
|
46
|
+
Please send patches via git-send-email(1) to us at <yahns-public@yhbt.net>.
|
|
47
|
+
Pull requests should be formatted using git-request-pull(1).
|
|
49
48
|
|
|
50
49
|
All mail is archived publically at: https://yhbt.net/yahns-public/
|
|
51
50
|
Anonymous contributions will always be welcome.
|
|
52
|
-
No subscription is necessary to
|
|
53
|
-
Please remember to
|
|
51
|
+
No subscription is necessary to email us.
|
|
52
|
+
Please remember to reply-to-all as we do not encourage subscription.
|
|
54
53
|
|
|
55
54
|
Copyright (C) 2013-2016 all contributors <yahns-public@yhbt.net>
|
|
56
55
|
License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
|
data/README
CHANGED
|
@@ -16,6 +16,7 @@ Features
|
|
|
16
16
|
* suitable for slow clients, fast clients, or a mixture of both
|
|
17
17
|
* HTTP/0.9 support
|
|
18
18
|
* HTTP/1.1 persistent connections and pipelining
|
|
19
|
+
* HTTPS for HTTP/1.1 support
|
|
19
20
|
* decodes HTTP chunked encoding for requests
|
|
20
21
|
* parses HTTP/1.1 trailers in requests
|
|
21
22
|
* supports streaming responses with lazy buffering for slow clients
|
|
@@ -55,37 +56,31 @@ Contact
|
|
|
55
56
|
|
|
56
57
|
We are happy to see feedback of all types via plain-text email.
|
|
57
58
|
Please send comments, user/dev discussion, patches, bug reports,
|
|
58
|
-
and pull requests to
|
|
59
|
+
and pull requests to our public inbox at:
|
|
59
60
|
|
|
60
61
|
yahns-public@yhbt.net
|
|
61
62
|
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
Please use reply-to-all as we do not require any sort of subscription.
|
|
64
|
+
We archive all of our mail publically at:
|
|
64
65
|
|
|
65
|
-
|
|
66
|
+
https://yhbt.net/yahns-public/
|
|
67
|
+
nntp://news.public-inbox.org/inbox.comp.lang.ruby.yahns
|
|
66
68
|
|
|
67
|
-
yahns-public+subscribe@yhbt.net
|
|
68
|
-
|
|
69
|
-
We suck at delivering email, so relying on the archives might be
|
|
70
|
-
a better bet:
|
|
71
|
-
|
|
72
|
-
Mailing list archives browsable via HTTPS: https://yhbt.net/yahns-public/
|
|
73
|
-
Or NNTP: nntp://news.public-inbox.org/inbox.comp.lang.ruby.yahns
|
|
74
69
|
Atom feed: https://yhbt.net/yahns-public/new.atom
|
|
75
70
|
|
|
76
71
|
This README is our homepage, we would rather be working on HTTP servers
|
|
77
72
|
all day than worrying about the next browser vulnerability because
|
|
78
73
|
HTML/CSS/JS is too complicated for us.
|
|
79
74
|
|
|
80
|
-
* https://yhbt.net/yahns/
|
|
75
|
+
* https://yhbt.net/yahns.git/about/
|
|
81
76
|
|
|
82
77
|
Hacking
|
|
83
78
|
-------
|
|
84
79
|
|
|
85
80
|
We use git and follow the same development model as git itself
|
|
86
|
-
(
|
|
81
|
+
(email-oriented, benevolent dictator).
|
|
87
82
|
|
|
88
|
-
git clone https://yhbt.net/yahns
|
|
83
|
+
git clone https://yhbt.net/yahns.git
|
|
89
84
|
|
|
90
85
|
Please use git-format-patch(1) and git-send-email(1) distributed with
|
|
91
86
|
the git(7) suite for generating and sending patches. Please format
|
data/extras/autoindex.rb
CHANGED
|
@@ -14,6 +14,21 @@ class Autoindex
|
|
|
14
14
|
FN = %{<a href="%s">%s</a>}
|
|
15
15
|
TFMT = "%Y-%m-%d %H:%M"
|
|
16
16
|
|
|
17
|
+
# default to a dark, web-safe (216 color) palette for power-savings.
|
|
18
|
+
# Color-capable browsers can respect the prefers-color-scheme:light
|
|
19
|
+
# @media query (browser support a work-in-progress)
|
|
20
|
+
STYLE = <<''.gsub(/^\s*/m, '').delete!("\n")
|
|
21
|
+
@media screen {
|
|
22
|
+
*{background:#000;color:#ccc}
|
|
23
|
+
a{color:#69f;text-decoration:none}
|
|
24
|
+
a:visited{color:#96f}
|
|
25
|
+
}
|
|
26
|
+
@media screen AND (prefers-color-scheme:light) {
|
|
27
|
+
*{background:#fff;color:#333}
|
|
28
|
+
a{color:#00f;text-decoration:none}
|
|
29
|
+
a:visited{color:#808}
|
|
30
|
+
}
|
|
31
|
+
|
|
17
32
|
def initialize(app, *args)
|
|
18
33
|
app.respond_to?(:root) or raise ArgumentError,
|
|
19
34
|
"wrapped app #{app.inspect} does not respond to #root"
|
|
@@ -139,8 +154,9 @@ def call(env)
|
|
|
139
154
|
path_info_html = path_info_ue.split(%r{/}, -1).map! do |part|
|
|
140
155
|
Rack::Utils.escape_html(part)
|
|
141
156
|
end.join("/")
|
|
142
|
-
body = "<html><head><title>Index of #{path_info_html}</title
|
|
143
|
-
"<
|
|
157
|
+
body = "<html><head><title>Index of #{path_info_html}</title>" \
|
|
158
|
+
"<style>#{STYLE}</style>" \
|
|
159
|
+
"</head><body><h1>Index of #{path_info_html}</h1><hr><pre>\n" \
|
|
144
160
|
"#{dirs.concat(files).join("\n")}" \
|
|
145
161
|
"</pre><hr></body></html>\n"
|
|
146
162
|
h = { "Content-Type" => "text/html", "Content-Length" => body.size.to_s }
|
data/extras/exec_cgi.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# -*- encoding: binary -*-
|
|
2
|
-
# Copyright (C) 2013-
|
|
3
|
-
# License:
|
|
2
|
+
# Copyright (C) 2013-2018 all contributors <yahns-public@yhbt.net>
|
|
3
|
+
# License: GPL-2.0+ <https://www.gnu.org/licenses/gpl-2.0.txt>
|
|
4
4
|
# frozen_string_literal: true
|
|
5
5
|
#
|
|
6
6
|
# if running under yahns, worker_processes is recommended to avoid conflicting
|
|
@@ -18,21 +18,31 @@
|
|
|
18
18
|
# use Rack::Chunked
|
|
19
19
|
# # other Rack middlewares can go here...
|
|
20
20
|
#
|
|
21
|
-
#
|
|
21
|
+
# # cgit: https://git.zx2c4.com/cgit/
|
|
22
|
+
# run ExecCgi.new('/path/to/cgit.cgi', opts)
|
|
22
23
|
#
|
|
23
24
|
class ExecCgi
|
|
24
|
-
class MyIO
|
|
25
|
+
class MyIO
|
|
25
26
|
attr_writer :my_pid
|
|
26
27
|
attr_writer :body_tip
|
|
28
|
+
attr_reader :rd
|
|
29
|
+
|
|
30
|
+
def initialize(rd)
|
|
31
|
+
@rd = rd
|
|
32
|
+
end
|
|
27
33
|
|
|
28
34
|
def each
|
|
29
|
-
buf = @body_tip
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
buf = @body_tip
|
|
36
|
+
yield buf unless buf.empty?
|
|
37
|
+
|
|
38
|
+
case tmp = @rd.read_nonblock(8192, buf, exception: false)
|
|
39
|
+
when :wait_readable
|
|
40
|
+
@rd.wait_readable
|
|
41
|
+
when nil
|
|
42
|
+
break
|
|
43
|
+
else # String
|
|
34
44
|
yield tmp
|
|
35
|
-
end
|
|
45
|
+
end while true
|
|
36
46
|
self
|
|
37
47
|
ensure
|
|
38
48
|
# do this sooner, since the response body may be buffered, we want
|
|
@@ -46,8 +56,8 @@ def close
|
|
|
46
56
|
# Note: this object (and any client-specific objects) will never
|
|
47
57
|
# be shared across different threads, so we do not need extra
|
|
48
58
|
# mutual exclusion here.
|
|
49
|
-
return if closed?
|
|
50
|
-
|
|
59
|
+
return if @rd.closed?
|
|
60
|
+
@rd.close
|
|
51
61
|
begin
|
|
52
62
|
Process.waitpid(@my_pid)
|
|
53
63
|
rescue Errno::ECHILD
|
|
@@ -72,7 +82,7 @@ def close
|
|
|
72
82
|
SERVER_PROTOCOL
|
|
73
83
|
SERVER_SOFTWARE
|
|
74
84
|
SCRIPT_NAME
|
|
75
|
-
)
|
|
85
|
+
)
|
|
76
86
|
|
|
77
87
|
def initialize(*args)
|
|
78
88
|
@env = Hash === args[0] ? args.shift : {}
|
|
@@ -82,6 +92,7 @@ def initialize(*args)
|
|
|
82
92
|
first[0] == ?/ or args[0] = ::File.expand_path(first)
|
|
83
93
|
File.executable?(args[0]) or
|
|
84
94
|
raise ArgumentError, "#{args[0]} is not executable"
|
|
95
|
+
@opts = Hash === args[-1] ? args.pop : {}
|
|
85
96
|
end
|
|
86
97
|
|
|
87
98
|
# Calls the app
|
|
@@ -90,20 +101,23 @@ def call(env)
|
|
|
90
101
|
cgi_env = { "GATEWAY_INTERFACE" => "CGI/1.1" }
|
|
91
102
|
PASS_VARS.each { |key| val = env[key] and cgi_env[key] = val }
|
|
92
103
|
env.each { |key,val| cgi_env[key] = val if key =~ /\AHTTP_/ }
|
|
93
|
-
pipe = MyIO.pipe
|
|
94
|
-
errbody = pipe[0]
|
|
95
|
-
errbody.my_pid = Process.spawn(cgi_env.merge!(@env), *@args,
|
|
96
|
-
out: pipe[1], close_others: true)
|
|
97
|
-
pipe[1].close
|
|
98
|
-
pipe = pipe[0]
|
|
99
104
|
|
|
100
|
-
|
|
105
|
+
rd, wr = IO.pipe
|
|
106
|
+
io = MyIO.new(rd)
|
|
107
|
+
errbody = io
|
|
108
|
+
errbody.my_pid = spawn(cgi_env.merge!(@env), *@args,
|
|
109
|
+
@opts.merge(out: wr, close_others: true))
|
|
110
|
+
wr.close
|
|
111
|
+
|
|
112
|
+
begin
|
|
113
|
+
head = rd.readpartial(8192)
|
|
101
114
|
until head =~ /\r?\n\r?\n/
|
|
102
|
-
tmp =
|
|
115
|
+
tmp = rd.readpartial(8192)
|
|
103
116
|
head << tmp
|
|
117
|
+
tmp.clear
|
|
104
118
|
end
|
|
105
119
|
head, body = head.split(/\r?\n\r?\n/, 2)
|
|
106
|
-
|
|
120
|
+
io.body_tip = body
|
|
107
121
|
|
|
108
122
|
env["HTTP_VERSION"] ||= "HTTP/1.0" # stop Rack::Chunked for HTTP/0.9
|
|
109
123
|
|
|
@@ -117,8 +131,8 @@ def call(env)
|
|
|
117
131
|
end
|
|
118
132
|
status = headers.delete("Status") || 200
|
|
119
133
|
errbody = nil
|
|
120
|
-
[ status, headers,
|
|
121
|
-
|
|
134
|
+
[ status, headers, io ]
|
|
135
|
+
rescue EOFError
|
|
122
136
|
[ 500, { "Content-Length" => "0", "Content-Type" => "text/plain" }, [] ]
|
|
123
137
|
end
|
|
124
138
|
ensure
|
data/extras/proxy_pass.rb
CHANGED
|
@@ -36,7 +36,7 @@ class UpstreamSocket < Kgio::Socket # :nodoc:
|
|
|
36
36
|
attr_writer :expiry
|
|
37
37
|
|
|
38
38
|
# called automatically by kgio_read!
|
|
39
|
-
def
|
|
39
|
+
def wait_readable(timeout = nil)
|
|
40
40
|
super(timeout || wait_time)
|
|
41
41
|
end
|
|
42
42
|
|
|
@@ -59,7 +59,7 @@ def req_write(buf, timeout)
|
|
|
59
59
|
@expiry = Time.now + timeout
|
|
60
60
|
case rv = kgio_trywrite(buf)
|
|
61
61
|
when :wait_writable
|
|
62
|
-
|
|
62
|
+
wait_writable(wait_time)
|
|
63
63
|
when nil
|
|
64
64
|
return
|
|
65
65
|
when String
|
data/lib/yahns.rb
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
require 'unicorn' # pulls in raindrops, kgio, fcntl, etc, stringio, and logger
|
|
7
7
|
require 'sleepy_penguin'
|
|
8
|
+
require 'io/wait'
|
|
8
9
|
|
|
9
10
|
# kill off some unicorn internals we don't need
|
|
10
11
|
# we'll probably just make kcar into a server parser so we don't depend
|
|
@@ -16,8 +17,9 @@
|
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
# yahns exposes no user-visible API outside of the config file.
|
|
19
|
-
# See https://yhbt.net/yahns/yahns_config.txt
|
|
20
|
-
#
|
|
20
|
+
# See https://yhbt.net/yahns.git/tree/examples/yahns_config.txt
|
|
21
|
+
# for the config documentation
|
|
22
|
+
# and https://yhbt.net/yahns.git/about/ for the homepage.
|
|
21
23
|
# Internals are subject to change.
|
|
22
24
|
|
|
23
25
|
module Yahns
|
data/lib/yahns/config.rb
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
# frozen_string_literal: true
|
|
5
5
|
#
|
|
6
6
|
# Implements a DSL for configuring a yahns server.
|
|
7
|
-
# See https://yhbt.net/yahns/examples/yahns_multi.conf.rb
|
|
8
|
-
# example configuration file.
|
|
7
|
+
# See https://yhbt.net/yahns.git/tree/examples/yahns_multi.conf.rb
|
|
8
|
+
# for a full example configuration file.
|
|
9
9
|
class Yahns::Config # :nodoc:
|
|
10
10
|
# public within yahns itself, NOT a public interface for users outside
|
|
11
11
|
# of yahns. See yahns/rack for usage example
|
|
@@ -409,7 +409,7 @@ def errors(val)
|
|
|
409
409
|
if String === val
|
|
410
410
|
# we've already bound working_directory by the time we get here
|
|
411
411
|
val = File.open(File.expand_path(val), "ab")
|
|
412
|
-
val.
|
|
412
|
+
val.sync = true
|
|
413
413
|
else
|
|
414
414
|
rt = [ :puts, :write, :flush ] # match Rack::Lint
|
|
415
415
|
rt.all? { |m| val.respond_to?(m) } or raise ArgumentError,
|
data/lib/yahns/daemon.rb
CHANGED
|
@@ -32,7 +32,6 @@ def self.daemon(yahns_server)
|
|
|
32
32
|
# We cannot use Yahns::Sigevent (eventfd) here because we need
|
|
33
33
|
# to detect EOF on unexpected death, not just read/write
|
|
34
34
|
rd, wr = IO.pipe
|
|
35
|
-
rd.close_on_exec = wr.close_on_exec = true
|
|
36
35
|
grandparent = $$
|
|
37
36
|
if fork
|
|
38
37
|
wr.close # grandparent does not write
|
data/lib/yahns/http_client.rb
CHANGED
|
@@ -235,25 +235,17 @@ def app_call(input)
|
|
|
235
235
|
http_response_write(res, opt)
|
|
236
236
|
end
|
|
237
237
|
|
|
238
|
-
# called automatically by kgio_write
|
|
239
|
-
def kgio_wait_writable(timeout = self.class.client_timeout)
|
|
240
|
-
super timeout
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
# called automatically by kgio_read
|
|
244
|
-
def kgio_wait_readable(timeout = self.class.client_timeout)
|
|
245
|
-
super timeout
|
|
246
|
-
end
|
|
247
|
-
|
|
248
238
|
# used by StreamInput (and thus TeeInput) for input_buffering {false|:lazy}
|
|
249
239
|
def yahns_read(bytes, buf)
|
|
250
240
|
case rv = kgio_tryread(bytes, buf)
|
|
251
241
|
when String, nil
|
|
252
242
|
return rv
|
|
253
243
|
when :wait_readable
|
|
254
|
-
|
|
244
|
+
wait_readable(self.class.client_timeout) or
|
|
245
|
+
raise Yahns::ClientTimeout, "waiting for read", []
|
|
255
246
|
when :wait_writable
|
|
256
|
-
|
|
247
|
+
wait_writable(self.class.client_timeout) or
|
|
248
|
+
raise Yahns::ClientTimeout, "waiting for write", []
|
|
257
249
|
end while true
|
|
258
250
|
end
|
|
259
251
|
|
|
@@ -332,7 +324,6 @@ def do_pread(io, count, offset)
|
|
|
332
324
|
io.read(count, buf)
|
|
333
325
|
end
|
|
334
326
|
rescue EOFError
|
|
335
|
-
warn "BUG: do_pread overreach:\n #{caller.join("\n ")}\n"
|
|
336
327
|
nil
|
|
337
328
|
end
|
|
338
329
|
|
data/lib/yahns/http_response.rb
CHANGED
|
@@ -46,10 +46,9 @@ def response_start
|
|
|
46
46
|
@hs.response_start_sent ? ''.freeze : 'HTTP/1.1 '.freeze
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
def response_wait_write(rv)
|
|
50
|
-
# call the kgio_wait_readable or kgio_wait_writable method
|
|
51
|
-
ok = __send__("kgio_#{rv}") and return ok
|
|
49
|
+
def response_wait_write(rv) # rv = [:wait_writable | :wait_readable ]
|
|
52
50
|
k = self.class
|
|
51
|
+
ok = __send__(rv, k.client_timeout) and return ok
|
|
53
52
|
k.logger.info("fd=#{fileno} ip=#@kgio_addr timeout on :#{rv} after "\
|
|
54
53
|
"#{k.client_timeout}s")
|
|
55
54
|
false
|
data/lib/yahns/queue_kqueue.rb
CHANGED
|
@@ -17,12 +17,6 @@ class Yahns::Queue < SleepyPenguin::Kqueue::IO # :nodoc:
|
|
|
17
17
|
|
|
18
18
|
ADD_ONESHOT = Ev::ADD | Ev::ONESHOT # private
|
|
19
19
|
|
|
20
|
-
def self.new
|
|
21
|
-
rv = super
|
|
22
|
-
rv.close_on_exec = true
|
|
23
|
-
rv
|
|
24
|
-
end
|
|
25
|
-
|
|
26
20
|
# for HTTP and HTTPS servers, we rely on the io writing to us, first
|
|
27
21
|
# flags: QEV_RD/QEV_WR (usually QEV_RD)
|
|
28
22
|
def queue_add(io, flags)
|
|
@@ -7,7 +7,6 @@ class Yahns::QueueQuitter # :nodoc:
|
|
|
7
7
|
attr_reader :to_io
|
|
8
8
|
def initialize
|
|
9
9
|
@reader, @to_io = IO.pipe
|
|
10
|
-
@to_io.close_on_exec = true
|
|
11
10
|
end
|
|
12
11
|
|
|
13
12
|
def yahns_step
|
|
@@ -22,4 +21,8 @@ def close
|
|
|
22
21
|
@reader.close
|
|
23
22
|
@to_io.close
|
|
24
23
|
end
|
|
24
|
+
|
|
25
|
+
def closed?
|
|
26
|
+
@to_io.closed?
|
|
27
|
+
end
|
|
25
28
|
end
|
data/lib/yahns/server.rb
CHANGED
|
@@ -476,7 +476,7 @@ def reap_reexec
|
|
|
476
476
|
end
|
|
477
477
|
|
|
478
478
|
def sp_sig_handle(alive)
|
|
479
|
-
@sev.
|
|
479
|
+
@sev.wait_readable(alive ? nil : 0.01)
|
|
480
480
|
@sev.yahns_step
|
|
481
481
|
case sig = @sig_queue.shift
|
|
482
482
|
when :QUIT, :TERM, :INT
|
|
@@ -500,6 +500,19 @@ def dropping(fdmap)
|
|
|
500
500
|
if drop_acceptors[0] || fdmap.size > 0
|
|
501
501
|
timeout = @shutdown_expire < Yahns.now ? -1 : @shutdown_timeout
|
|
502
502
|
n = fdmap.desperate_expire(timeout)
|
|
503
|
+
return false if n == 0 && @listeners.empty? # all done!
|
|
504
|
+
|
|
505
|
+
# FIXME: sometimes shutdowns take a long time when using proxy_pass
|
|
506
|
+
# Still not sure what's going on and it takes a while to reproduce..
|
|
507
|
+
if timeout == -1
|
|
508
|
+
@logger.error(
|
|
509
|
+
"exiting on shutdown_timeout=#@shutdown_timeout #{fdmap.size} FD(s) remain"
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
system('lsof', '-n', '-p', "#$$") if RUBY_PLATFORM =~ /linux/
|
|
513
|
+
return false
|
|
514
|
+
end
|
|
515
|
+
|
|
503
516
|
$0 = "yahns quitting, #{n} FD(s) remain"
|
|
504
517
|
true
|
|
505
518
|
else
|
data/lib/yahns/server_mp.rb
CHANGED
|
@@ -31,8 +31,6 @@ def worker_atfork_internal(worker)
|
|
|
31
31
|
# daemon_pipe may be true for non-initial workers
|
|
32
32
|
@daemon_pipe = @daemon_pipe.close if @daemon_pipe.respond_to?(:close)
|
|
33
33
|
|
|
34
|
-
srand # in case this pops up again: https://bugs.ruby-lang.org/issues/4338
|
|
35
|
-
|
|
36
34
|
# The OpenSSL PRNG is seeded with only the pid, and apps with frequently
|
|
37
35
|
# dying workers can recycle pids
|
|
38
36
|
OpenSSL::Random.seed(rand.to_s) if defined?(OpenSSL::Random)
|
|
@@ -91,7 +89,7 @@ def join
|
|
|
91
89
|
@logger.info "master process ready"
|
|
92
90
|
daemon_ready
|
|
93
91
|
begin
|
|
94
|
-
@sev.
|
|
92
|
+
@sev.wait_readable
|
|
95
93
|
@sev.yahns_step
|
|
96
94
|
reap_all
|
|
97
95
|
case @sig_queue.shift
|
|
@@ -159,7 +157,7 @@ def run_mp_worker(worker)
|
|
|
159
157
|
def mp_sig_handle(watch, alive)
|
|
160
158
|
# not performance critical
|
|
161
159
|
watch.delete_if { |io| io.to_io.closed? }
|
|
162
|
-
if r =
|
|
160
|
+
if r = select(watch, nil, nil, alive ? nil : 0.1)
|
|
163
161
|
r[0].each(&:yahns_step)
|
|
164
162
|
end
|
|
165
163
|
case @sig_queue.shift
|
data/lib/yahns/sigevent_efd.rb
CHANGED
data/lib/yahns/sigevent_pipe.rb
CHANGED
|
@@ -5,21 +5,24 @@
|
|
|
5
5
|
class Yahns::Sigevent # :nodoc:
|
|
6
6
|
attr_reader :to_io
|
|
7
7
|
def initialize
|
|
8
|
-
@to_io, @wr =
|
|
9
|
-
@to_io.close_on_exec = @wr.close_on_exec = true
|
|
8
|
+
@to_io, @wr = IO.pipe
|
|
10
9
|
end
|
|
11
10
|
|
|
12
|
-
def
|
|
13
|
-
@to_io.
|
|
11
|
+
def wait_readable(*args)
|
|
12
|
+
@to_io.wait_readable(*args)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def fileno
|
|
16
|
+
@to_io.fileno
|
|
14
17
|
end
|
|
15
18
|
|
|
16
19
|
def sev_signal
|
|
17
|
-
@wr.
|
|
20
|
+
@wr.write_nonblock(".", exception: false)
|
|
18
21
|
end
|
|
19
22
|
|
|
20
23
|
def yahns_step
|
|
21
24
|
# 11 byte strings -> no malloc on YARV
|
|
22
|
-
while String === @to_io.
|
|
25
|
+
while String === @to_io.read_nonblock(11, exception: false)
|
|
23
26
|
end
|
|
24
27
|
:wait_readable
|
|
25
28
|
end
|
|
@@ -28,4 +31,8 @@ def close
|
|
|
28
31
|
@to_io.close
|
|
29
32
|
@wr.close
|
|
30
33
|
end
|
|
34
|
+
|
|
35
|
+
def closed?
|
|
36
|
+
@to_io.closed?
|
|
37
|
+
end
|
|
31
38
|
end
|
data/lib/yahns/socket_helper.rb
CHANGED
|
@@ -19,7 +19,7 @@ def so_reuseport
|
|
|
19
19
|
|
|
20
20
|
def set_server_sockopt(sock, opt)
|
|
21
21
|
opt = {backlog: 1024}.merge!(opt)
|
|
22
|
-
sock.close_on_exec = true
|
|
22
|
+
sock.close_on_exec = true # needed for inherited sockets
|
|
23
23
|
|
|
24
24
|
TCPSocket === sock and sock.setsockopt(:IPPROTO_TCP, :TCP_NODELAY, 1)
|
|
25
25
|
sock.setsockopt(:SOL_SOCKET, :SO_KEEPALIVE, 1)
|
data/lib/yahns/wbuf.rb
CHANGED
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
class Yahns::Wbuf # :nodoc:
|
|
32
32
|
include Yahns::WbufCommon
|
|
33
33
|
attr_reader :busy
|
|
34
|
+
IO_WRITEV = RUBY_VERSION.to_r >= 2.5 # IO#write uses writev
|
|
34
35
|
|
|
35
36
|
def initialize(body, persist)
|
|
36
37
|
@tmpio = nil
|
|
@@ -40,9 +41,15 @@ def initialize(body, persist)
|
|
|
40
41
|
@busy = false
|
|
41
42
|
end
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
if IO_WRITEV
|
|
45
|
+
def wbuf_writev(buf)
|
|
46
|
+
@tmpio.write(*buf)
|
|
47
|
+
end
|
|
48
|
+
else
|
|
49
|
+
def wbuf_writev(buf)
|
|
50
|
+
@tmpio.kgio_writev(buf)
|
|
51
|
+
buf.inject(0) { |n, s| n += s.size }
|
|
52
|
+
end
|
|
46
53
|
end
|
|
47
54
|
|
|
48
55
|
def wbuf_write(c, buf)
|
data/lib/yahns/worker.rb
CHANGED
|
@@ -9,6 +9,14 @@ class Yahns::Worker # :nodoc:
|
|
|
9
9
|
def initialize(nr)
|
|
10
10
|
@nr = nr
|
|
11
11
|
@to_io, @wr = Kgio::Pipe.new
|
|
12
|
+
|
|
13
|
+
begin
|
|
14
|
+
# F_SETPIPE_SZ = 1031, PAGE_SIZE = 4096
|
|
15
|
+
# (fcntl will handle minimum size on platforms where PAGE_SIZE > 4096)
|
|
16
|
+
@to_io.fcntl(1031, 4096)
|
|
17
|
+
rescue Errno::EINVAL
|
|
18
|
+
# old kernel
|
|
19
|
+
end if RUBY_PLATFORM =~ /\blinux\b/
|
|
12
20
|
end
|
|
13
21
|
|
|
14
22
|
def atfork_child
|
data/test/helper.rb
CHANGED
data/test/server_helper.rb
CHANGED
|
@@ -52,9 +52,7 @@ def quit_wait(pid)
|
|
|
52
52
|
# only use for newly bound sockets
|
|
53
53
|
def get_tcp_client(host, port, tries = 500)
|
|
54
54
|
begin
|
|
55
|
-
|
|
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
|
data/test/test_bin.rb
CHANGED
|
@@ -99,7 +99,10 @@ def bin_daemon(worker, inherit)
|
|
|
99
99
|
# Even with a synchronous FD_CLOEXEC, there's a chance of a race
|
|
100
100
|
# because the server does not bind right away.
|
|
101
101
|
unless inherit
|
|
102
|
-
|
|
102
|
+
begin
|
|
103
|
+
@srv.shutdown
|
|
104
|
+
rescue Errno::ENOTCONN
|
|
105
|
+
end
|
|
103
106
|
@srv.close
|
|
104
107
|
end
|
|
105
108
|
exec(*@cmd)
|
|
@@ -170,7 +170,7 @@ def _blocked_zombie(block_on, rtype)
|
|
|
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.
|
|
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 @@ def _blocked_zombie(block_on, rtype)
|
|
|
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
|
data/test/test_serve_static.rb
CHANGED
data/test/test_server.rb
CHANGED
|
@@ -182,7 +182,6 @@ def test_check_client_connection
|
|
|
182
182
|
tmpdir = yahns_mktmpdir
|
|
183
183
|
sock = "#{tmpdir}/sock"
|
|
184
184
|
unix_srv = UNIXServer.new(sock)
|
|
185
|
-
unix_srv.close_on_exec = true
|
|
186
185
|
msgs = %w(ZZ zz)
|
|
187
186
|
err = @err
|
|
188
187
|
cfg = Yahns::Config.new
|
|
@@ -234,7 +233,6 @@ def a.each
|
|
|
234
233
|
bpipe[0].close
|
|
235
234
|
a = UNIXSocket.new(sock)
|
|
236
235
|
b = UNIXSocket.new(sock)
|
|
237
|
-
b.close_on_exec = a.close_on_exec = true
|
|
238
236
|
a.write("GET /sleep HTTP/1.0\r\n\r\n")
|
|
239
237
|
r = IO.select([a], nil, nil, 4)
|
|
240
238
|
assert r, "nothing ready"
|
|
@@ -681,7 +679,6 @@ def test_errors
|
|
|
681
679
|
assert_equal "INFO HIHI\n", re.read
|
|
682
680
|
|
|
683
681
|
c = UNIXSocket.new(sock)
|
|
684
|
-
c.close_on_exec = true
|
|
685
682
|
c.write "GET /\r\n\r\n"
|
|
686
683
|
assert_equal c, c.wait(30)
|
|
687
684
|
assert_equal "OK", c.read
|
data/test/test_unix_socket.rb
CHANGED
data/test/test_wbuf.rb
CHANGED
data/yahns.gemspec
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yahns
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.17.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- yahns hackers
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2019-04-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: kgio
|
|
@@ -222,7 +222,7 @@ files:
|
|
|
222
222
|
- test/test_unix_socket.rb
|
|
223
223
|
- test/test_wbuf.rb
|
|
224
224
|
- yahns.gemspec
|
|
225
|
-
homepage: https://yhbt.net/yahns/
|
|
225
|
+
homepage: https://yhbt.net/yahns.git/about/
|
|
226
226
|
licenses:
|
|
227
227
|
- GPL-3.0+
|
|
228
228
|
metadata: {}
|
|
@@ -241,8 +241,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
241
241
|
- !ruby/object:Gem::Version
|
|
242
242
|
version: '0'
|
|
243
243
|
requirements: []
|
|
244
|
-
|
|
245
|
-
rubygems_version: 2.7.7
|
|
244
|
+
rubygems_version: 3.0.2
|
|
246
245
|
signing_key:
|
|
247
246
|
specification_version: 4
|
|
248
247
|
summary: sleepy, multi-threaded, non-blocking application server
|