yahns 1.15.0 → 1.16.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|