yahns 0.0.0 → 0.0.1
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/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
|