yahns 1.15.0 → 1.16.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 +5 -5
- data/Documentation/yahns-rackup.pod +4 -0
- data/Documentation/yahns_config.pod +1 -1
- data/GIT-VERSION-GEN +1 -1
- data/HACKING +1 -1
- data/README +1 -1
- data/extras/autoindex.rb +2 -2
- data/lib/yahns/acceptor.rb +3 -3
- data/lib/yahns/config.rb +7 -2
- data/lib/yahns/http_client.rb +25 -6
- data/lib/yahns/openssl_client.rb +33 -11
- data/lib/yahns/proxy_pass.rb +1 -1
- data/lib/yahns/rackup_handler.rb +3 -7
- data/lib/yahns/server.rb +23 -20
- data/test/helper.rb +4 -0
- data/test/server_helper.rb +19 -2
- data/test/test_bin.rb +29 -29
- data/test/test_config.rb +2 -2
- data/test/test_extras_try_gzip_static.rb +1 -1
- data/test/test_mt_accept.rb +0 -2
- data/test/test_proxy_pass.rb +1 -2
- data/test/test_proxy_pass_no_buffering.rb +1 -1
- data/test/test_rack_env.rb +58 -0
- data/test/test_server.rb +1 -1
- data/test/test_ssl.rb +2 -0
- data/yahns.gemspec +3 -0
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f5dcbf514b3bf6c9e92c8f0ca7d038019148217ffe6f3a88ab6ea7810333487e
|
4
|
+
data.tar.gz: 4bfd3e6b7a2806daf1e53094050d928a9c28cd1b330ef594a118c2b6bd9d7c86
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f8123dcd0921c5c224bdb76009c7d7b1e751da62e2f30690ab438f959e234710afdb1f1b57ecfe64dc8b437ac782f95b69348c7177ecfe1e302173bc494574a
|
7
|
+
data.tar.gz: 7f0e74b4271f4ec44bd2b800b0eb6fa4a570ecd538cf42f79c31ddf92c2552d98bade3a9396d8fd02ba9e16a2f145eb2a028b9050b01e931f90f42adcbf1767a
|
@@ -40,6 +40,10 @@ and PATH is meant to be a path to a UNIX domain socket.
|
|
40
40
|
Defaults to "0.0.0.0:9292" (all addresses on TCP port 9292).
|
41
41
|
Multiple addresses may be separated with commas.
|
42
42
|
|
43
|
+
For systemd users, a special value of "inherit" may be specified
|
44
|
+
to inherit FDs using the LISTEN_FDS and LISTEN_PID environment
|
45
|
+
variables described in L<sd_listen_fds(3)>
|
46
|
+
|
43
47
|
=item -O stderr_path=PATHNAME
|
44
48
|
|
45
49
|
Allow redirecting $stderr to a given path. Unlike doing this from
|
data/GIT-VERSION-GEN
CHANGED
data/HACKING
CHANGED
data/README
CHANGED
@@ -85,7 +85,7 @@ Hacking
|
|
85
85
|
We use git and follow the same development model as git itself
|
86
86
|
(mailing list-oriented, benevolent dictator).
|
87
87
|
|
88
|
-
git clone
|
88
|
+
git clone https://yhbt.net/yahns
|
89
89
|
|
90
90
|
Please use git-format-patch(1) and git-send-email(1) distributed with
|
91
91
|
the git(7) suite for generating and sending patches. Please format
|
data/extras/autoindex.rb
CHANGED
@@ -56,7 +56,7 @@ def call(env)
|
|
56
56
|
case env["REQUEST_METHOD"]
|
57
57
|
when "GET", "HEAD"
|
58
58
|
# try to serve the static file, first
|
59
|
-
status,
|
59
|
+
status, _, body = res = @app.call(env)
|
60
60
|
return res if status.to_i != 404
|
61
61
|
|
62
62
|
path_info = env["PATH_INFO"]
|
@@ -78,7 +78,7 @@ def call(env)
|
|
78
78
|
tryenv = env.dup
|
79
79
|
@index.each do |base|
|
80
80
|
tryenv["PATH_INFO"] = "#{path_info}#{base}"
|
81
|
-
status,
|
81
|
+
status, _, body = res = @app.call(tryenv)
|
82
82
|
return res if status.to_i != 404
|
83
83
|
end
|
84
84
|
|
data/lib/yahns/acceptor.rb
CHANGED
@@ -24,7 +24,7 @@ def ac_quit
|
|
24
24
|
close
|
25
25
|
return true
|
26
26
|
end
|
27
|
-
@
|
27
|
+
@quit = true
|
28
28
|
return true if __ac_quit_done?
|
29
29
|
|
30
30
|
@thrs.each do
|
@@ -42,10 +42,10 @@ def ac_quit
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def spawn_acceptor(nr, logger, client_class)
|
45
|
+
@quit = false
|
45
46
|
@thrs = nr.times.map do
|
46
47
|
Thread.new do
|
47
48
|
queue = client_class.queue
|
48
|
-
t = Thread.current
|
49
49
|
accept_flags = Kgio::SOCK_NONBLOCK | Kgio::SOCK_CLOEXEC
|
50
50
|
qev_flags = client_class.superclass::QEV_FLAGS
|
51
51
|
begin
|
@@ -64,7 +64,7 @@ def spawn_acceptor(nr, logger, client_class)
|
|
64
64
|
sleep 1 # let other threads do some work
|
65
65
|
rescue => e
|
66
66
|
Yahns::Log.exception(logger, "accept loop", e)
|
67
|
-
end until
|
67
|
+
end until @quit
|
68
68
|
end
|
69
69
|
end
|
70
70
|
end
|
data/lib/yahns/config.rb
CHANGED
@@ -328,8 +328,8 @@ def app(type, *args, &block)
|
|
328
328
|
"#{var}: #{file} did not register #{type} in #{self.class}::APP_CLASS"
|
329
329
|
|
330
330
|
# apps may have multiple configurator contexts
|
331
|
-
|
332
|
-
ctx =
|
331
|
+
app_cfg = @app_instances[klass.instance_key(*args)] = klass.new(*args)
|
332
|
+
ctx = app_cfg.config_context
|
333
333
|
if block_given?
|
334
334
|
@block = CfgBlock.new(:app, ctx)
|
335
335
|
instance_eval(&block)
|
@@ -438,4 +438,9 @@ def commit!(server)
|
|
438
438
|
|
439
439
|
@app_ctx.each { |app| app.logger ||= server.logger }
|
440
440
|
end
|
441
|
+
|
442
|
+
def register_inherited(name)
|
443
|
+
return unless @config_listeners.empty? && @app_ctx.size == 1
|
444
|
+
@config_listeners[name] = { :yahns_app_ctx => @app_ctx[0] }
|
445
|
+
end
|
441
446
|
end
|
data/lib/yahns/http_client.rb
CHANGED
@@ -298,10 +298,18 @@ def handle_error(e)
|
|
298
298
|
when Unicorn::HttpParserError # try to tell the client they're bad
|
299
299
|
400
|
300
300
|
else
|
301
|
+
n = 500
|
302
|
+
case e.class.to_s
|
303
|
+
when 'OpenSSL::SSL::SSLError'
|
304
|
+
if e.message.include?('wrong version number')
|
305
|
+
n = nil
|
306
|
+
e.set_backtrace([])
|
307
|
+
end
|
308
|
+
end
|
301
309
|
Yahns::Log.exception(@hs.env["rack.logger"], "app error", e)
|
302
|
-
|
310
|
+
n
|
303
311
|
end
|
304
|
-
kgio_trywrite(err_response(code))
|
312
|
+
kgio_trywrite(err_response(code)) if code
|
305
313
|
rescue
|
306
314
|
ensure
|
307
315
|
shutdown rescue nil
|
@@ -314,12 +322,23 @@ def app_hijacked?(env, res)
|
|
314
322
|
true
|
315
323
|
end
|
316
324
|
|
317
|
-
def
|
318
|
-
return 0 if count == 0
|
325
|
+
def do_pread(io, count, offset)
|
319
326
|
count = 0x4000 if count > 0x4000
|
320
327
|
buf = Thread.current[:yahns_sfbuf] ||= ''.dup
|
321
|
-
io.
|
322
|
-
|
328
|
+
if io.respond_to?(:pread)
|
329
|
+
io.pread(count, offset, buf)
|
330
|
+
else
|
331
|
+
io.pos = offset
|
332
|
+
io.read(count, buf)
|
333
|
+
end
|
334
|
+
rescue EOFError
|
335
|
+
warn "BUG: do_pread overreach:\n #{caller.join("\n ")}\n"
|
336
|
+
nil
|
337
|
+
end
|
338
|
+
|
339
|
+
def trysendio(io, offset, count)
|
340
|
+
return 0 if count == 0
|
341
|
+
str = do_pread(io, count, offset) or return # nil for EOF
|
323
342
|
n = 0
|
324
343
|
case rv = kgio_trywrite(str)
|
325
344
|
when String # partial write, keep trying
|
data/lib/yahns/openssl_client.rb
CHANGED
@@ -40,15 +40,31 @@ def yahns_init_ssl(ssl_ctx)
|
|
40
40
|
def kgio_trywrite(buf)
|
41
41
|
len = buf.bytesize
|
42
42
|
return if len == 0
|
43
|
-
|
43
|
+
|
44
|
+
case @ssl_blocked
|
45
|
+
when nil # likely
|
46
|
+
buf = @ssl_blocked = buf.dup
|
47
|
+
when Exception
|
48
|
+
raise @ssl_blocked
|
49
|
+
when String
|
50
|
+
if @ssl_blocked != buf
|
51
|
+
pfx = object_id
|
52
|
+
warn("#{pfx} BUG: ssl_blocked != buf\n" \
|
53
|
+
"#{pfx} ssl_blocked=#{@ssl_blocked.inspect}\n" \
|
54
|
+
"#{pfx} buf=#{buf.inspect}\n")
|
55
|
+
raise 'BUG: ssl_blocked} != buf'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
44
59
|
case rv = @ssl.write_nonblock(buf, exception: false)
|
45
60
|
when :wait_readable, :wait_writable
|
46
|
-
|
61
|
+
rv # do not clear ssl_blocked
|
47
62
|
when Integer
|
48
|
-
|
63
|
+
@ssl_blocked = len == rv ? nil : buf.byteslice(rv, len - rv)
|
49
64
|
end
|
50
|
-
|
51
|
-
|
65
|
+
rescue SystemCallError => e # ECONNRESET/EPIPE
|
66
|
+
e.set_backtrace([])
|
67
|
+
raise(@ssl_blocked = e)
|
52
68
|
end
|
53
69
|
|
54
70
|
def kgio_trywritev(buf)
|
@@ -75,22 +91,28 @@ def kgio_tryread(len, buf)
|
|
75
91
|
def trysendio(io, offset, count)
|
76
92
|
return 0 if count == 0
|
77
93
|
|
78
|
-
|
79
|
-
|
80
|
-
buf =
|
81
|
-
io.pos = offset
|
82
|
-
buf = io.read(count, buf) or return # nil for EOF
|
94
|
+
case buf = @ssl_blocked
|
95
|
+
when nil
|
96
|
+
buf = do_pread(io, count, offset) or return # nil for EOF
|
83
97
|
buf = @ssl_blocked = buf.dup
|
98
|
+
when Exception
|
99
|
+
raise buf
|
100
|
+
# when String # just use it as-is
|
84
101
|
end
|
85
102
|
|
86
103
|
# call write_nonblock directly since kgio_trywrite allocates
|
87
104
|
# an unnecessary string
|
105
|
+
len = buf.size
|
88
106
|
case rv = @ssl.write_nonblock(buf, exception: false)
|
89
107
|
when :wait_readable, :wait_writable
|
90
108
|
return rv # do not clear ssl_blocked
|
109
|
+
when Integer
|
110
|
+
@ssl_blocked = len == rv ? nil : buf.byteslice(rv, len - rv)
|
91
111
|
end
|
92
|
-
@ssl_blocked = nil
|
93
112
|
rv
|
113
|
+
rescue SystemCallError => e # ECONNRESET/EPIPE
|
114
|
+
e.set_backtrace([])
|
115
|
+
raise(@ssl_blocked = e)
|
94
116
|
end
|
95
117
|
|
96
118
|
def shutdown # we never call this with a how=SHUT_* arg
|
data/lib/yahns/proxy_pass.rb
CHANGED
@@ -57,7 +57,7 @@ def init_path_vars(path)
|
|
57
57
|
def call(env)
|
58
58
|
# 3-way handshake for TCP backends while we generate the request header
|
59
59
|
rr = Yahns::ReqRes.start(@sockaddr)
|
60
|
-
c = env['rack.hijack'].call
|
60
|
+
c = env['rack.hijack'].call # Yahns::HttpClient#call
|
61
61
|
|
62
62
|
req = Rack::Request.new(env)
|
63
63
|
req = @path.gsub(/\$(\w+)/) { req.__send__($1) }
|
data/lib/yahns/rackup_handler.rb
CHANGED
@@ -16,14 +16,10 @@ def self.run(app, o)
|
|
16
16
|
# fine for most apps, but we have SIGUSR2 restarts to support
|
17
17
|
working_directory(Yahns::START[:cwd])
|
18
18
|
|
19
|
-
app(:rack, app) do
|
19
|
+
app(:rack, app) do # Yahns::Config#app
|
20
20
|
addr = o[:listen] || "#{o[:Host]||default_host}:#{o[:Port]||8080}"
|
21
|
-
# allow listening to multiple addresses
|
22
|
-
|
23
|
-
addr.split(',').each { |l| listen(l) }
|
24
|
-
else
|
25
|
-
listen addr
|
26
|
-
end
|
21
|
+
# allow listening to multiple addresses (Yahns::Config#listen)
|
22
|
+
addr.split(',').each { |l| listen(l) } unless addr == 'inherit'
|
27
23
|
|
28
24
|
val = o[:client_timeout] and client_timeout(val)
|
29
25
|
end
|
data/lib/yahns/server.rb
CHANGED
@@ -237,24 +237,23 @@ def reexec
|
|
237
237
|
end
|
238
238
|
end
|
239
239
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
240
|
+
opt = {}
|
241
|
+
@listeners.each { |sock| opt[sock.fileno] = sock }
|
242
|
+
env = ENV.to_hash
|
243
|
+
env['YAHNS_FD'] = opt.keys.join(',')
|
244
|
+
opt[:close_others] = true
|
245
|
+
cmd = [ Yahns::START[0] ].concat(Yahns::START[:argv])
|
246
|
+
dir = @config.value(:working_directory) || Yahns::START[:cwd]
|
247
|
+
@logger.info "spawning #{cmd.inspect} (in #{dir})"
|
248
|
+
@reexec_pid = if @before_exec
|
249
|
+
fork do
|
250
|
+
Dir.chdir(dir)
|
251
|
+
@before_exec.call(cmd)
|
252
|
+
exec(env, *cmd, opt)
|
249
253
|
end
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
cmd = [ Yahns::START[0] ].concat(Yahns::START[:argv])
|
254
|
-
@logger.info "executing #{cmd.inspect} (in #{Dir.pwd})"
|
255
|
-
@before_exec.call(cmd) if @before_exec
|
256
|
-
cmd << redirects
|
257
|
-
exec(*cmd)
|
254
|
+
else
|
255
|
+
opt[:chdir] = dir
|
256
|
+
spawn(env, *cmd, opt)
|
258
257
|
end
|
259
258
|
end
|
260
259
|
|
@@ -328,7 +327,9 @@ def inherit_listeners!
|
|
328
327
|
opts = sock_opts(io)
|
329
328
|
io = server_cast(io, opts)
|
330
329
|
set_server_sockopt(io, opts)
|
331
|
-
|
330
|
+
name = sock_name(io)
|
331
|
+
@logger.info "inherited addr=#{name} fd=#{io.fileno}"
|
332
|
+
@config.register_inherited(name)
|
332
333
|
io
|
333
334
|
end
|
334
335
|
|
@@ -395,7 +396,9 @@ def fdmap_init
|
|
395
396
|
|
396
397
|
# call OpenSSL::SSL::SSLContext#setup explicitly here to detect
|
397
398
|
# errors and avoid race conditions. We avoid calling this in the
|
398
|
-
# parent process
|
399
|
+
# parent process (if we have multiple workers) in case the
|
400
|
+
# setup code starts TCP connections to memcached or similar
|
401
|
+
# for session caching.
|
399
402
|
ssl_ctx.setup
|
400
403
|
end
|
401
404
|
ctx_list << ctx
|
@@ -451,7 +454,7 @@ def quit_finish
|
|
451
454
|
@queues.each(&:close).clear
|
452
455
|
|
453
456
|
# we must not let quitter get GC-ed if we have any worker threads leftover
|
454
|
-
@
|
457
|
+
@quitter = quitter
|
455
458
|
|
456
459
|
quitter.close
|
457
460
|
rescue => e
|
data/test/helper.rb
CHANGED
data/test/server_helper.rb
CHANGED
@@ -31,7 +31,7 @@ def poke_until_dead(pid)
|
|
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
|
@@ -65,16 +65,33 @@ def server_helper_teardown
|
|
65
65
|
@srv.close if defined?(@srv) && !@srv.closed?
|
66
66
|
@ru.close! if defined?(@ru) && @ru
|
67
67
|
check_err if defined?(@err)
|
68
|
+
Timeout.timeout(30) do
|
69
|
+
Process.kill(:TERM, @tail_pid)
|
70
|
+
Process.waitpid(@tail_pid)
|
71
|
+
end if @tail_pid
|
68
72
|
end
|
69
73
|
|
70
74
|
def server_helper_setup
|
71
75
|
@srv = TCPServer.new(ENV["TEST_HOST"] || "127.0.0.1", 0)
|
72
76
|
@err = tmpfile(%w(srv .err))
|
73
77
|
@ru = nil
|
78
|
+
@tail_pid = nil
|
79
|
+
case tail = ENV['TAIL']
|
80
|
+
when '1'
|
81
|
+
tail = 'tail -f' # POSIX
|
82
|
+
when nil, '0'
|
83
|
+
tail = nil
|
84
|
+
# else : allow users to specify 'tail -F' or 'gtail -F' for GNU
|
85
|
+
end
|
86
|
+
if tail
|
87
|
+
cmd = tail.split(/\s+/)
|
88
|
+
cmd << @err.path
|
89
|
+
@tail_pid = spawn(*cmd)
|
90
|
+
end
|
74
91
|
end
|
75
92
|
|
76
93
|
def mkserver(cfg, srv = @srv)
|
77
|
-
|
94
|
+
xfork do
|
78
95
|
ENV["YAHNS_FD"] = srv.fileno.to_s
|
79
96
|
srv.autoclose = false
|
80
97
|
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
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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 @@ def bin_daemon(worker, inherit)
|
|
76
77
|
cfg.puts "end"
|
77
78
|
@cmd.concat(%W(-D -c #{cfg.path}))
|
78
79
|
addr = cloexec_pipe
|
79
|
-
pid =
|
80
|
+
pid = xfork do
|
80
81
|
opts = { close_others: true }
|
81
82
|
addr[0].close
|
82
83
|
if inherit
|
@@ -158,11 +159,10 @@ def usr2_dir(tmpdir, preload, worker)
|
|
158
159
|
# need to fork here since tests are MT and the FD can leak out and go to
|
159
160
|
# other processes which fork (but do not exec), causing ETXTBUSY on
|
160
161
|
# Process.spawn
|
161
|
-
pid =
|
162
|
-
ruby = "#!#{`which ruby`}"
|
162
|
+
pid = xfork do
|
163
163
|
File.open(exe, "w") { |y|
|
164
164
|
lines = File.readlines("bin/yahns")
|
165
|
-
lines[0] = ruby
|
165
|
+
lines[0] = "#!#{RbConfig.ruby}\n"
|
166
166
|
y.chmod(0755)
|
167
167
|
y.syswrite(lines.join)
|
168
168
|
}
|
@@ -190,7 +190,7 @@ def usr2_dir(tmpdir, preload, worker)
|
|
190
190
|
}
|
191
191
|
cmd = %W(#{exe} -D -c #{cfg.path})
|
192
192
|
cmd << { @srv => @srv, close_others: true }
|
193
|
-
pid =
|
193
|
+
pid = Process.spawn(env, *cmd)
|
194
194
|
res = Net::HTTP.start(host, port) { |h| h.get("/") }
|
195
195
|
assert_equal 200, res.code.to_i
|
196
196
|
orig = res.body
|
data/test/test_config.rb
CHANGED
@@ -13,7 +13,7 @@ def test_initialize
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def test_multi_conf_example
|
16
|
-
pid =
|
16
|
+
pid = xfork do
|
17
17
|
tmpdir = yahns_mktmpdir
|
18
18
|
|
19
19
|
# modify the example config file for testing
|
@@ -37,7 +37,7 @@ def test_multi_conf_example
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def test_rack_basic_conf_example
|
40
|
-
pid =
|
40
|
+
pid = xfork do
|
41
41
|
tmpdir = yahns_mktmpdir
|
42
42
|
|
43
43
|
# modify the example config file for testing
|
@@ -52,7 +52,7 @@ def test_gzip_static
|
|
52
52
|
File.symlink "COPYING", "#{tmpdir}/COPYING.relsymlink"
|
53
53
|
gplgz = "#{tmpdir}/COPYING.gz"
|
54
54
|
FileUtils.cp("COPYING", gpl)
|
55
|
-
_, status = Process.waitpid2(
|
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
|
data/test/test_mt_accept.rb
CHANGED
@@ -14,7 +14,6 @@ def test_mt_accept
|
|
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 @@ def test_mt_accept
|
|
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 }
|
data/test/test_proxy_pass.rb
CHANGED
@@ -6,6 +6,7 @@
|
|
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 @@ def test_unix_socket_no_path
|
|
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 @@ def test_proxy_pass
|
|
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 @@ def setup
|
|
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
|
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# Copyright (C) 2017 all contributors <yahns-public@yhbt.net>
|
2
|
+
# License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
|
3
|
+
# frozen_string_literal: true
|
4
|
+
require_relative 'server_helper'
|
5
|
+
require 'rack'
|
6
|
+
|
7
|
+
class TestRackEnv < Testcase
|
8
|
+
ENV["N"].to_i > 1 and parallelize_me!
|
9
|
+
include ServerHelper
|
10
|
+
alias setup server_helper_setup
|
11
|
+
alias teardown server_helper_teardown
|
12
|
+
|
13
|
+
def test_rack_env_logger
|
14
|
+
err, cfg, host, port = @err, Yahns::Config.new, @srv.addr[3], @srv.addr[1]
|
15
|
+
cfg.instance_eval do
|
16
|
+
stderr_path err.path
|
17
|
+
GTL.synchronize do
|
18
|
+
app = Rack::Builder.new do
|
19
|
+
use Rack::Lint # ensure Lint passes
|
20
|
+
run(lambda do |env|
|
21
|
+
logger = env['rack.logger']
|
22
|
+
%w(SERVER_NAME SERVER_PORT rack.url_scheme).each do |k|
|
23
|
+
logger.info("#{k}=#{env[k].inspect}")
|
24
|
+
end
|
25
|
+
[ 200, [ %w(Content-Length 3), %w(Content Type text/plain)],
|
26
|
+
[ "OK\n" ] ]
|
27
|
+
end)
|
28
|
+
end
|
29
|
+
app(:rack, app.to_app) { listen "#{host}:#{port}" }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
pid = mkserver(cfg)
|
33
|
+
Net::HTTP.start(host, port) do |http|
|
34
|
+
res = http.request(Net::HTTP::Get.new("/"))
|
35
|
+
assert_equal 200, res.code.to_i
|
36
|
+
assert_equal "OK\n", res.body
|
37
|
+
txt = File.read(err.path)
|
38
|
+
assert_match %r{\srack\.url_scheme=#{Regexp.escape('http'.inspect)}\s}s,
|
39
|
+
txt
|
40
|
+
assert_match %r{\sSERVER_NAME=#{Regexp.escape(host.inspect)}\s}s, txt
|
41
|
+
assert_match %r{\sSERVER_PORT=#{Regexp.escape(port.to_s.inspect)}\s}s, txt
|
42
|
+
end
|
43
|
+
err.truncate 0
|
44
|
+
err.rewind
|
45
|
+
c = TCPSocket.new(host, port)
|
46
|
+
c.write("GET / HTTP/1.0\r\nHost: example.com\r\n\r\n")
|
47
|
+
assert_match %r{\r\nOK\n\z}s, c.read
|
48
|
+
txt = File.read(err.path)
|
49
|
+
assert_match %r{\srack\.url_scheme=#{Regexp.escape('http'.inspect)}\s}s,
|
50
|
+
txt
|
51
|
+
assert_match %r{\sSERVER_NAME=#{Regexp.escape('example.com'.inspect)}\s}s,
|
52
|
+
txt
|
53
|
+
assert_match %r{\sSERVER_PORT=#{Regexp.escape('80'.inspect)}\s}s, txt
|
54
|
+
ensure
|
55
|
+
c.close if c
|
56
|
+
quit_wait(pid)
|
57
|
+
end
|
58
|
+
end
|
data/test/test_server.rb
CHANGED
data/test/test_ssl.rb
CHANGED
@@ -41,6 +41,7 @@ def teardown
|
|
41
41
|
def ssl_client(host, port)
|
42
42
|
ctx = OpenSSL::SSL::SSLContext.new
|
43
43
|
ctx.ciphers = "ADH"
|
44
|
+
ctx.security_level = 0
|
44
45
|
s = TCPSocket.new(host, port)
|
45
46
|
ssl = OpenSSL::SSL::SSLSocket.new(s, ctx)
|
46
47
|
ssl.connect
|
@@ -51,6 +52,7 @@ def ssl_client(host, port)
|
|
51
52
|
def srv_ctx
|
52
53
|
ctx = OpenSSL::SSL::SSLContext.new
|
53
54
|
ctx.ciphers = "ADH"
|
55
|
+
ctx.security_level = 0
|
54
56
|
ctx.tmp_dh_callback = proc { TEST_KEY_DH1024 }
|
55
57
|
ctx
|
56
58
|
end
|
data/yahns.gemspec
CHANGED
@@ -10,6 +10,9 @@
|
|
10
10
|
s.email = %q{yahns-public@yhbt.net}
|
11
11
|
s.executables = manifest.grep(%r{\Abin/}).map { |s| s.sub(%r{\Abin/}, "") }
|
12
12
|
s.files = manifest
|
13
|
+
|
14
|
+
s.required_ruby_version = '>= 2.0'
|
15
|
+
|
13
16
|
s.add_dependency(%q<kgio>, '~> 2.9')
|
14
17
|
s.add_dependency(%q<sleepy_penguin>, '~> 3.2')
|
15
18
|
s.add_dependency(%q<unicorn>, '>= 4.6.3', '< 6.0')
|
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.16.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: 2018-08-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: kgio
|
@@ -210,6 +210,7 @@ files:
|
|
210
210
|
- test/test_proxy_pass.rb
|
211
211
|
- test/test_proxy_pass_no_buffering.rb
|
212
212
|
- test/test_rack.rb
|
213
|
+
- test/test_rack_env.rb
|
213
214
|
- test/test_rack_hijack.rb
|
214
215
|
- test/test_reopen_logs.rb
|
215
216
|
- test/test_response.rb
|
@@ -233,7 +234,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
233
234
|
requirements:
|
234
235
|
- - ">="
|
235
236
|
- !ruby/object:Gem::Version
|
236
|
-
version: '0'
|
237
|
+
version: '2.0'
|
237
238
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
238
239
|
requirements:
|
239
240
|
- - ">="
|
@@ -241,7 +242,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
241
242
|
version: '0'
|
242
243
|
requirements: []
|
243
244
|
rubyforge_project:
|
244
|
-
rubygems_version: 2.
|
245
|
+
rubygems_version: 2.7.7
|
245
246
|
signing_key:
|
246
247
|
specification_version: 4
|
247
248
|
summary: sleepy, multi-threaded, non-blocking application server
|