yahns 0.0.0 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +2 -2
- data/lib/yahns/acceptor.rb +5 -3
- data/lib/yahns/cap_input.rb +22 -0
- data/lib/yahns/config.rb +8 -4
- data/lib/yahns/daemon.rb +1 -0
- data/lib/yahns/fdmap.rb +0 -8
- data/lib/yahns/http_client.rb +14 -6
- data/lib/yahns/http_context.rb +20 -4
- data/lib/yahns/http_response.rb +3 -3
- data/lib/yahns/max_body.rb +60 -0
- data/lib/yahns/max_body/rewindable_wrapper.rb +19 -0
- data/lib/yahns/max_body/wrapper.rb +71 -0
- data/lib/yahns/queue_egg.rb +2 -5
- data/lib/yahns/queue_epoll.rb +27 -29
- data/lib/yahns/server.rb +29 -19
- data/lib/yahns/server_mp.rb +3 -1
- data/lib/yahns/socket_helper.rb +1 -0
- data/lib/yahns/stream_input.rb +3 -4
- data/lib/yahns/wbuf_common.rb +1 -1
- data/test/helper.rb +45 -45
- data/test/server_helper.rb +3 -2
- data/test/test_bin.rb +96 -0
- data/test/test_client_max_body_size.rb +163 -0
- data/test/test_config.rb +39 -33
- data/test/test_rack_hijack.rb +74 -0
- data/test/test_reopen_logs.rb +64 -0
- data/test/test_server.rb +6 -2
- metadata +10 -4
- data/test/test_queue.rb +0 -59
data/test/test_config.rb
CHANGED
@@ -12,45 +12,51 @@ class TestConfig < Testcase
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def test_multi_conf_example
|
15
|
-
|
15
|
+
pid = fork do
|
16
|
+
tmpdir = Dir.mktmpdir
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
18
|
+
# modify the example config file for testing
|
19
|
+
path = "examples/yahns_multi.conf.rb"
|
20
|
+
cfgs = File.read(path)
|
21
|
+
cfgs.gsub!(%r{/path/to/}, "#{tmpdir}/")
|
22
|
+
conf = File.open("#{tmpdir}/yahns_multi.conf.rb", "w")
|
23
|
+
conf.sync = true
|
24
|
+
conf.write(cfgs)
|
25
|
+
File.open("#{tmpdir}/another.ru", "w") do |fp|
|
26
|
+
fp.puts("run Rack::Lobster.new\n")
|
27
|
+
end
|
28
|
+
FileUtils.mkpath("#{tmpdir}/another")
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
30
|
+
cfg = Yahns::Config.new(conf.path)
|
31
|
+
FileUtils.rm_rf(tmpdir)
|
32
|
+
exit!(Yahns::Config === cfg)
|
33
|
+
end
|
34
|
+
_, status = Process.waitpid2(pid)
|
35
|
+
assert status.success?
|
33
36
|
end
|
34
37
|
|
35
38
|
def test_rack_basic_conf_example
|
36
|
-
|
39
|
+
pid = fork do
|
40
|
+
tmpdir = Dir.mktmpdir
|
37
41
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
42
|
+
# modify the example config file for testing
|
43
|
+
path = "examples/yahns_rack_basic.conf.rb"
|
44
|
+
cfgs = File.read(path)
|
45
|
+
cfgs.gsub!(%r{/path/to/}, "#{tmpdir}/")
|
46
|
+
Dir.mkdir("#{tmpdir}/my_app")
|
47
|
+
Dir.mkdir("#{tmpdir}/my_logs")
|
48
|
+
Dir.mkdir("#{tmpdir}/my_pids")
|
49
|
+
conf = File.open("#{tmpdir}/yahns_rack_basic.conf.rb", "w")
|
50
|
+
conf.sync = true
|
51
|
+
conf.write(cfgs)
|
52
|
+
File.open("#{tmpdir}/my_app/config.ru", "w") do |fp|
|
53
|
+
fp.puts("run Rack::Lobster.new\n")
|
54
|
+
end
|
55
|
+
cfg = Yahns::Config.new(conf.path)
|
56
|
+
FileUtils.rm_rf(tmpdir) if tmpdir
|
57
|
+
exit!(Yahns::Config === cfg)
|
50
58
|
end
|
51
|
-
|
52
|
-
|
53
|
-
ensure
|
54
|
-
FileUtils.rm_rf(tmpdir) if tmpdir
|
59
|
+
_, status = Process.waitpid2(pid)
|
60
|
+
assert status.success?
|
55
61
|
end
|
56
62
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
|
2
|
+
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
|
3
|
+
require_relative 'server_helper'
|
4
|
+
|
5
|
+
class TestRackHijack < Testcase
|
6
|
+
parallelize_me!
|
7
|
+
include ServerHelper
|
8
|
+
alias setup server_helper_setup
|
9
|
+
alias teardown server_helper_teardown
|
10
|
+
|
11
|
+
class DieIfUsed
|
12
|
+
def each
|
13
|
+
abort "body.each called after response hijack\n"
|
14
|
+
end
|
15
|
+
|
16
|
+
def close
|
17
|
+
abort "body.close called after response hijack\n"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
HIJACK_APP = lambda { |env|
|
22
|
+
case env["PATH_INFO"]
|
23
|
+
when "/hijack_req"
|
24
|
+
io = env["rack.hijack"].call
|
25
|
+
if io.respond_to?(:read_nonblock) &&
|
26
|
+
env["rack.hijack_io"].respond_to?(:read_nonblock)
|
27
|
+
|
28
|
+
# exercise both, since we Rack::Lint may use different objects
|
29
|
+
env["rack.hijack_io"].write("HTTP/1.0 200 OK\r\n\r\n")
|
30
|
+
io.write("request.hijacked")
|
31
|
+
io.close
|
32
|
+
return [ 500, {}, DieIfUsed.new ]
|
33
|
+
end
|
34
|
+
[ 500, {}, [ "hijack BAD\n" ] ]
|
35
|
+
when "/hijack_res"
|
36
|
+
r = "response.hijacked"
|
37
|
+
[ 200,
|
38
|
+
{
|
39
|
+
"X-Test" => "zzz",
|
40
|
+
"Content-Length" => r.bytesize.to_s,
|
41
|
+
"rack.hijack" => proc { |x| x.write(r); x.close }
|
42
|
+
},
|
43
|
+
DieIfUsed.new
|
44
|
+
]
|
45
|
+
end
|
46
|
+
}
|
47
|
+
|
48
|
+
def test_hijack
|
49
|
+
err = @err
|
50
|
+
cfg = Yahns::Config.new
|
51
|
+
host, port = @srv.addr[3], @srv.addr[1]
|
52
|
+
cfg.instance_eval do
|
53
|
+
GTL.synchronize { app(:rack, HIJACK_APP) { listen "#{host}:#{port}" } }
|
54
|
+
logger(Logger.new(err.path))
|
55
|
+
end
|
56
|
+
srv = Yahns::Server.new(cfg)
|
57
|
+
pid = fork do
|
58
|
+
ENV["YAHNS_FD"] = @srv.fileno.to_s
|
59
|
+
srv.start.join
|
60
|
+
end
|
61
|
+
res = Net::HTTP.start(host, port) { |h| h.get("/hijack_req") }
|
62
|
+
assert_equal "request.hijacked", res.body
|
63
|
+
assert_equal 200, res.code.to_i
|
64
|
+
assert_equal "1.0", res.http_version
|
65
|
+
|
66
|
+
res = Net::HTTP.start(host, port) { |h| h.get("/hijack_res") }
|
67
|
+
assert_equal "response.hijacked", res.body
|
68
|
+
assert_equal 200, res.code.to_i
|
69
|
+
assert_equal "zzz", res["X-Test"]
|
70
|
+
assert_equal "1.1", res.http_version
|
71
|
+
ensure
|
72
|
+
quit_wait(pid)
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
|
2
|
+
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
|
3
|
+
require_relative 'server_helper'
|
4
|
+
require 'rack/commonlogger'
|
5
|
+
|
6
|
+
class TestReopenLogs < Testcase
|
7
|
+
parallelize_me!
|
8
|
+
include ServerHelper
|
9
|
+
alias setup server_helper_setup
|
10
|
+
alias teardown server_helper_teardown
|
11
|
+
|
12
|
+
def test_reopen_logs_noworker; reopen(false); end
|
13
|
+
def test_reopen_logs_worker; reopen(true); end
|
14
|
+
|
15
|
+
def reopen(worker)
|
16
|
+
err = @err
|
17
|
+
out = tmpfile(%w(log .out))
|
18
|
+
opath = out.path
|
19
|
+
cfg = Yahns::Config.new
|
20
|
+
host, port = @srv.addr[3], @srv.addr[1]
|
21
|
+
cfg.instance_eval do
|
22
|
+
stderr_path err.path
|
23
|
+
stdout_path opath
|
24
|
+
GTL.synchronize do
|
25
|
+
app = Rack::Builder.new do
|
26
|
+
use Rack::CommonLogger, $stdout
|
27
|
+
use Rack::ContentLength
|
28
|
+
use Rack::ContentType, "text/plain"
|
29
|
+
run lambda { |_| [ 200, {}, [ "#$$" ] ] }
|
30
|
+
end
|
31
|
+
app(:rack, app.to_app) { listen "#{host}:#{port}" }
|
32
|
+
end
|
33
|
+
worker_processes 1 if worker
|
34
|
+
end
|
35
|
+
pid = fork do
|
36
|
+
ENV["YAHNS_FD"] = @srv.fileno.to_s
|
37
|
+
Yahns::Server.new(cfg).start.join
|
38
|
+
end
|
39
|
+
Net::HTTP.start(host, port) do |http|
|
40
|
+
res = http.request(Net::HTTP::Get.new("/aaa"))
|
41
|
+
assert_equal 200, res.code.to_i
|
42
|
+
orig = res.body
|
43
|
+
Timeout.timeout(10) { Thread.pass until File.read(opath) =~ /aaa/ }
|
44
|
+
File.unlink(opath)
|
45
|
+
Process.kill(:USR1, pid)
|
46
|
+
Timeout.timeout(10) { sleep(0.01) until File.exist?(opath) }
|
47
|
+
|
48
|
+
# we need to repeat the HTTP request since the worker_processes
|
49
|
+
# may not have switched to the new file, yet.
|
50
|
+
Timeout.timeout(10) do
|
51
|
+
begin
|
52
|
+
res = http.request(Net::HTTP::Get.new("/bbb"))
|
53
|
+
assert_equal 200, res.code.to_i
|
54
|
+
assert_equal orig, res.body
|
55
|
+
end until File.read(opath) =~ /bbb/
|
56
|
+
end
|
57
|
+
end
|
58
|
+
rescue => e
|
59
|
+
Yahns::Log.exception(Logger.new($stderr), "test", e)
|
60
|
+
raise
|
61
|
+
ensure
|
62
|
+
quit_wait(pid)
|
63
|
+
end
|
64
|
+
end
|
data/test/test_server.rb
CHANGED
@@ -51,8 +51,11 @@ class TestServer < Testcase
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
Process.kill(:QUIT, pid)
|
54
|
-
"GET / HTTP/1.1\r\n\r\n".each_byte
|
55
|
-
|
54
|
+
"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n".each_byte do |x|
|
55
|
+
sleep(0.01)
|
56
|
+
c.write(x.chr)
|
57
|
+
end
|
58
|
+
buf = Timeout.timeout(30) { c.read }
|
56
59
|
assert_match(/Connection: close/, buf)
|
57
60
|
_, status = Timeout.timeout(10) { Process.waitpid2(pid) }
|
58
61
|
assert status.success?, status.inspect
|
@@ -287,6 +290,7 @@ class TestServer < Testcase
|
|
287
290
|
|
288
291
|
# Linux blocking accept() has fair behavior between multiple tasks
|
289
292
|
def test_mp_balance
|
293
|
+
skip("this fails occasionally on Linux, still...")
|
290
294
|
skip("linux-only test") unless RUBY_PLATFORM =~ /linux/
|
291
295
|
pid, host, port = new_mp_server(2)
|
292
296
|
seen = {}
|
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: 0.0.
|
4
|
+
version: 0.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- yahns hackers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-10-
|
11
|
+
date: 2013-10-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: kgio
|
@@ -96,6 +96,7 @@ files:
|
|
96
96
|
- examples/yahns_rack_basic.conf.rb
|
97
97
|
- lib/yahns.rb
|
98
98
|
- lib/yahns/acceptor.rb
|
99
|
+
- lib/yahns/cap_input.rb
|
99
100
|
- lib/yahns/client_expire.rb
|
100
101
|
- lib/yahns/client_expire_portable.rb
|
101
102
|
- lib/yahns/config.rb
|
@@ -105,6 +106,9 @@ files:
|
|
105
106
|
- lib/yahns/http_context.rb
|
106
107
|
- lib/yahns/http_response.rb
|
107
108
|
- lib/yahns/log.rb
|
109
|
+
- lib/yahns/max_body.rb
|
110
|
+
- lib/yahns/max_body/rewindable_wrapper.rb
|
111
|
+
- lib/yahns/max_body/wrapper.rb
|
108
112
|
- lib/yahns/queue.rb
|
109
113
|
- lib/yahns/queue_egg.rb
|
110
114
|
- lib/yahns/queue_epoll.rb
|
@@ -128,11 +132,13 @@ files:
|
|
128
132
|
- test/server_helper.rb
|
129
133
|
- test/test_bin.rb
|
130
134
|
- test/test_client_expire.rb
|
135
|
+
- test/test_client_max_body_size.rb
|
131
136
|
- test/test_config.rb
|
132
137
|
- test/test_fdmap.rb
|
133
138
|
- test/test_output_buffering.rb
|
134
|
-
- test/test_queue.rb
|
135
139
|
- test/test_rack.rb
|
140
|
+
- test/test_rack_hijack.rb
|
141
|
+
- test/test_reopen_logs.rb
|
136
142
|
- test/test_serve_static.rb
|
137
143
|
- test/test_server.rb
|
138
144
|
- test/test_stream_file.rb
|
@@ -158,7 +164,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
158
164
|
version: '0'
|
159
165
|
requirements: []
|
160
166
|
rubyforge_project:
|
161
|
-
rubygems_version: 2.1.
|
167
|
+
rubygems_version: 2.1.3
|
162
168
|
signing_key:
|
163
169
|
specification_version: 4
|
164
170
|
summary: sleepy, multi-threaded, non-blocking application server
|
data/test/test_queue.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
|
2
|
-
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
|
3
|
-
require_relative 'helper'
|
4
|
-
require 'timeout'
|
5
|
-
require 'stringio'
|
6
|
-
|
7
|
-
class TestQueue < Testcase
|
8
|
-
parallelize_me!
|
9
|
-
|
10
|
-
def setup
|
11
|
-
@q = Yahns::Queue.new
|
12
|
-
@err = StringIO.new
|
13
|
-
@logger = Logger.new(@err)
|
14
|
-
@q.fdmap = @fdmap = Yahns::Fdmap.new(@logger, 0.5)
|
15
|
-
assert @q.close_on_exec?
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_queue
|
19
|
-
r, w = IO.pipe
|
20
|
-
assert_equal 0, @fdmap.size
|
21
|
-
@q.queue_add(r, Yahns::Queue::QEV_RD)
|
22
|
-
assert_equal 1, @fdmap.size
|
23
|
-
def r.yahns_step
|
24
|
-
begin
|
25
|
-
case read_nonblock(11)
|
26
|
-
when "delete"
|
27
|
-
return :delete
|
28
|
-
end
|
29
|
-
rescue Errno::EAGAIN
|
30
|
-
return :wait_readable
|
31
|
-
rescue EOFError
|
32
|
-
return nil
|
33
|
-
end while true
|
34
|
-
end
|
35
|
-
w.write('.')
|
36
|
-
Timeout.timeout(10) do
|
37
|
-
Thread.pass until r.nread > 0
|
38
|
-
@q.spawn_worker_threads(@logger, 1, 1)
|
39
|
-
Thread.pass until r.nread == 0
|
40
|
-
|
41
|
-
w.write("delete")
|
42
|
-
Thread.pass until r.nread == 0
|
43
|
-
Thread.pass until @fdmap.size == 0
|
44
|
-
|
45
|
-
# should not raise
|
46
|
-
@q.queue_add(r, Yahns::Queue::QEV_RD)
|
47
|
-
assert_equal 1, @fdmap.size
|
48
|
-
w.close
|
49
|
-
Thread.pass until @fdmap.size == 0
|
50
|
-
end
|
51
|
-
assert r.closed?
|
52
|
-
ensure
|
53
|
-
[ r, w ].each { |io| io.close unless io.closed? }
|
54
|
-
end
|
55
|
-
|
56
|
-
def teardown
|
57
|
-
@q.close
|
58
|
-
end
|
59
|
-
end
|