1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
| | require 'socket'
require 'unicorn'
require 'io/wait'
require 'tempfile'
require 'test/unit'
class TestCccTCPI < Test::Unit::TestCase
def test_ccc_tcpi
start_pid = $$
host = '127.0.0.1'
srv = TCPServer.new(host, 0)
port = srv.addr[1]
err = Tempfile.new('unicorn_ccc')
rd, wr = IO.pipe
pid = fork do
reqs = 0
rd.close
worker_pid = nil
app = lambda do |env|
worker_pid ||= begin
at_exit { wr.write(reqs.to_s) if worker_pid == $$ }
$$
end
reqs += 1
sleep(1) if env['PATH_INFO'] == '/sleep'
[ 200, [ %w(Content-Length 0), %w(Content-Type text/plain) ], [] ]
end
ENV['UNICORN_FD'] = srv.fileno.to_s
opts = {
listeners: [ "#{host}:#{port}" ],
stderr_path: err.path,
check_client_connection: true,
}
uni = Unicorn::HttpServer.new(app, opts)
uni.start.join
end
wr.close
# make sure the server is running, at least
client = TCPSocket.new(host, port)
client.write("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")
assert client.wait_readable(10), 'never got response from server'
res = client.read
assert_match %r{\AHTTP/1\.1 200}, res, 'got part of first response'
assert_match %r{\r\n\r\n\z}, res, 'got end of response, server is ready'
client.close
# start a slow request...
sleeper = TCPSocket.new(host, port)
sleeper.write("GET /sleep HTTP/1.1\r\nHost: example.com\r\n\r\n")
# and a bunch of aborted ones
nr = 100
nr.times do |i|
client = TCPSocket.new(host, port)
client.write("GET /collections/#{rand(10000)} HTTP/1.1\r\n" \
"Host: example.com\r\n\r\n")
client.close
end
sleeper.close
kpid = pid
pid = nil
Process.kill(:QUIT, kpid)
_, status = Process.waitpid2(kpid)
assert status.success?
reqs = rd.read.to_i
warn "server got #{reqs} requests with #{nr} CCC aborted\n" if $DEBUG
assert_operator reqs, :<, nr
assert_operator reqs, :>=, 2, 'first 2 requests got through, at least'
ensure
return if start_pid != $$
srv.close if srv
if pid
Process.kill(:QUIT, pid)
_, status = Process.waitpid2(pid)
assert status.success?
end
err.close! if err
rd.close if rd
end
end
|