unicorn 5.4.1 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.manifest +7 -5
- data/.olddoc.yml +12 -7
- data/Application_Timeouts +4 -4
- data/Documentation/.gitignore +1 -3
- data/Documentation/unicorn.1 +222 -0
- data/Documentation/unicorn_rails.1 +207 -0
- data/FAQ +1 -1
- data/GIT-VERSION-FILE +1 -1
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +112 -57
- data/HACKING +1 -1
- data/ISSUES +21 -23
- data/KNOWN_ISSUES +2 -2
- data/LATEST +22 -28
- data/LICENSE +2 -2
- data/Links +13 -11
- data/NEWS +65 -0
- data/README +25 -11
- data/SIGNALS +1 -1
- data/Sandbox +4 -4
- data/archive/slrnpull.conf +1 -1
- data/bin/unicorn +3 -1
- data/bin/unicorn_rails +2 -2
- data/examples/big_app_gc.rb +1 -1
- data/examples/logrotate.conf +3 -3
- data/examples/nginx.conf +4 -3
- data/examples/unicorn.conf.minimal.rb +2 -2
- data/examples/unicorn.conf.rb +2 -2
- data/examples/unicorn@.service +7 -0
- data/ext/unicorn_http/common_field_optimization.h +24 -6
- data/ext/unicorn_http/extconf.rb +35 -0
- data/ext/unicorn_http/global_variables.h +2 -2
- data/ext/unicorn_http/httpdate.c +2 -2
- data/ext/unicorn_http/unicorn_http.c +257 -224
- data/ext/unicorn_http/unicorn_http.rl +47 -14
- data/lib/unicorn/configurator.rb +25 -4
- data/lib/unicorn/http_request.rb +12 -3
- data/lib/unicorn/http_server.rb +43 -12
- data/lib/unicorn/launcher.rb +1 -1
- data/lib/unicorn/oob_gc.rb +5 -5
- data/lib/unicorn/socket_helper.rb +1 -0
- data/lib/unicorn/tmpio.rb +8 -2
- data/lib/unicorn/util.rb +1 -1
- data/lib/unicorn/version.rb +1 -1
- data/lib/unicorn/worker.rb +16 -2
- data/lib/unicorn.rb +23 -9
- data/man/man1/unicorn.1 +89 -88
- data/man/man1/unicorn_rails.1 +78 -83
- data/t/GNUmakefile +3 -72
- data/t/README +4 -4
- data/t/t0301-no-default-middleware-ignored-in-config.sh +25 -0
- data/t/t0301.ru +13 -0
- data/test/benchmark/README +14 -4
- data/test/benchmark/ddstream.ru +50 -0
- data/test/benchmark/readinput.ru +40 -0
- data/test/benchmark/uconnect.perl +66 -0
- data/test/exec/test_exec.rb +14 -12
- data/test/test_helper.rb +38 -30
- data/test/unit/test_ccc.rb +4 -3
- data/test/unit/test_http_parser.rb +16 -0
- data/test/unit/test_http_parser_ng.rb +81 -0
- data/test/unit/test_server.rb +81 -7
- data/test/unit/test_signals.rb +6 -6
- data/test/unit/test_socket_helper.rb +1 -1
- data/test/unit/test_upload.rb +9 -14
- data/test/unit/test_util.rb +25 -0
- data/unicorn.gemspec +8 -7
- metadata +15 -13
- data/Documentation/GNUmakefile +0 -30
- data/Documentation/unicorn.1.txt +0 -187
- data/Documentation/unicorn_rails.1.txt +0 -175
- data/t/hijack.ru +0 -55
- data/t/t0200-rack-hijack.sh +0 -51
data/test/unit/test_ccc.rb
CHANGED
@@ -3,6 +3,7 @@ require 'unicorn'
|
|
3
3
|
require 'io/wait'
|
4
4
|
require 'tempfile'
|
5
5
|
require 'test/unit'
|
6
|
+
require './test/test_helper'
|
6
7
|
|
7
8
|
class TestCccTCPI < Test::Unit::TestCase
|
8
9
|
def test_ccc_tcpi
|
@@ -42,7 +43,7 @@ class TestCccTCPI < Test::Unit::TestCase
|
|
42
43
|
wr.close
|
43
44
|
|
44
45
|
# make sure the server is running, at least
|
45
|
-
client =
|
46
|
+
client = tcp_socket(host, port)
|
46
47
|
client.write("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")
|
47
48
|
assert client.wait(10), 'never got response from server'
|
48
49
|
res = client.read
|
@@ -51,13 +52,13 @@ class TestCccTCPI < Test::Unit::TestCase
|
|
51
52
|
client.close
|
52
53
|
|
53
54
|
# start a slow request...
|
54
|
-
sleeper =
|
55
|
+
sleeper = tcp_socket(host, port)
|
55
56
|
sleeper.write("GET /sleep HTTP/1.1\r\nHost: example.com\r\n\r\n")
|
56
57
|
|
57
58
|
# and a bunch of aborted ones
|
58
59
|
nr = 100
|
59
60
|
nr.times do |i|
|
60
|
-
client =
|
61
|
+
client = tcp_socket(host, port)
|
61
62
|
client.write("GET /collections/#{rand(10000)} HTTP/1.1\r\n" \
|
62
63
|
"Host: example.com\r\n\r\n")
|
63
64
|
client.close
|
@@ -865,4 +865,20 @@ class HttpParserTest < Test::Unit::TestCase
|
|
865
865
|
rescue LoadError
|
866
866
|
# not all Ruby implementations have objspace
|
867
867
|
end
|
868
|
+
|
869
|
+
def test_dedupe
|
870
|
+
parser = HttpParser.new
|
871
|
+
# n.b. String#freeze optimization doesn't work under modern test-unit
|
872
|
+
exp = -'HTTP_HOST'
|
873
|
+
get = "GET / HTTP/1.1\r\nHost: example.com\r\nHavpbea-fhpxf: true\r\n\r\n"
|
874
|
+
assert parser.add_parse(get)
|
875
|
+
key = parser.env.keys.detect { |k| k == exp }
|
876
|
+
assert_same exp, key
|
877
|
+
|
878
|
+
if RUBY_VERSION.to_r >= 2.6 # 2.6.0-rc1+
|
879
|
+
exp = -'HTTP_HAVPBEA_FHPXF'
|
880
|
+
key = parser.env.keys.detect { |k| k == exp }
|
881
|
+
assert_same exp, key
|
882
|
+
end
|
883
|
+
end if RUBY_VERSION.to_r >= 2.5 && RUBY_ENGINE == 'ruby'
|
868
884
|
end
|
@@ -11,6 +11,20 @@ class HttpParserNgTest < Test::Unit::TestCase
|
|
11
11
|
@parser = HttpParser.new
|
12
12
|
end
|
13
13
|
|
14
|
+
# RFC 7230 allows gzip/deflate/compress Transfer-Encoding,
|
15
|
+
# but "chunked" must be last if used
|
16
|
+
def test_is_chunked
|
17
|
+
[ 'chunked,chunked', 'chunked,gzip', 'chunked,gzip,chunked' ].each do |x|
|
18
|
+
assert_raise(HttpParserError) { HttpParser.is_chunked?(x) }
|
19
|
+
end
|
20
|
+
[ 'gzip, chunked', 'gzip,chunked', 'gzip ,chunked' ].each do |x|
|
21
|
+
assert HttpParser.is_chunked?(x)
|
22
|
+
end
|
23
|
+
[ 'gzip', 'xhunked', 'xchunked' ].each do |x|
|
24
|
+
assert !HttpParser.is_chunked?(x)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
14
28
|
def test_parser_max_len
|
15
29
|
assert_raises(RangeError) do
|
16
30
|
HttpParser.max_header_len = 0xffffffff + 1
|
@@ -566,6 +580,73 @@ class HttpParserNgTest < Test::Unit::TestCase
|
|
566
580
|
end
|
567
581
|
end
|
568
582
|
|
583
|
+
def test_duplicate_content_length
|
584
|
+
str = "PUT / HTTP/1.1\r\n" \
|
585
|
+
"Content-Length: 1\r\n" \
|
586
|
+
"Content-Length: 9\r\n" \
|
587
|
+
"\r\n"
|
588
|
+
assert_raises(HttpParserError) { @parser.headers({}, str) }
|
589
|
+
end
|
590
|
+
|
591
|
+
def test_chunked_overrides_content_length
|
592
|
+
order = [ 'Transfer-Encoding: chunked', 'Content-Length: 666' ]
|
593
|
+
%w(a b).each do |x|
|
594
|
+
str = "PUT /#{x} HTTP/1.1\r\n" \
|
595
|
+
"#{order.join("\r\n")}" \
|
596
|
+
"\r\n\r\na\r\nhelloworld\r\n0\r\n\r\n"
|
597
|
+
order.reverse!
|
598
|
+
env = @parser.headers({}, str)
|
599
|
+
assert_nil @parser.content_length
|
600
|
+
assert_equal 'chunked', env['HTTP_TRANSFER_ENCODING']
|
601
|
+
assert_equal '666', env['CONTENT_LENGTH'],
|
602
|
+
'Content-Length logged so the app can log a possible client bug/attack'
|
603
|
+
@parser.filter_body(dst = '', str)
|
604
|
+
assert_equal 'helloworld', dst
|
605
|
+
@parser.parse # handle the non-existent trailer
|
606
|
+
assert @parser.next?
|
607
|
+
end
|
608
|
+
end
|
609
|
+
|
610
|
+
def test_chunked_order_good
|
611
|
+
str = "PUT /x HTTP/1.1\r\n" \
|
612
|
+
"Transfer-Encoding: gzip\r\n" \
|
613
|
+
"Transfer-Encoding: chunked\r\n" \
|
614
|
+
"\r\n"
|
615
|
+
env = @parser.headers({}, str)
|
616
|
+
assert_equal 'gzip,chunked', env['HTTP_TRANSFER_ENCODING']
|
617
|
+
assert_nil @parser.content_length
|
618
|
+
|
619
|
+
@parser.clear
|
620
|
+
str = "PUT /x HTTP/1.1\r\n" \
|
621
|
+
"Transfer-Encoding: gzip, chunked\r\n" \
|
622
|
+
"\r\n"
|
623
|
+
env = @parser.headers({}, str)
|
624
|
+
assert_equal 'gzip, chunked', env['HTTP_TRANSFER_ENCODING']
|
625
|
+
assert_nil @parser.content_length
|
626
|
+
end
|
627
|
+
|
628
|
+
def test_chunked_order_bad
|
629
|
+
str = "PUT /x HTTP/1.1\r\n" \
|
630
|
+
"Transfer-Encoding: chunked\r\n" \
|
631
|
+
"Transfer-Encoding: gzip\r\n" \
|
632
|
+
"\r\n"
|
633
|
+
assert_raise(HttpParserError) { @parser.headers({}, str) }
|
634
|
+
end
|
635
|
+
|
636
|
+
def test_double_chunked
|
637
|
+
str = "PUT /x HTTP/1.1\r\n" \
|
638
|
+
"Transfer-Encoding: chunked\r\n" \
|
639
|
+
"Transfer-Encoding: chunked\r\n" \
|
640
|
+
"\r\n"
|
641
|
+
assert_raise(HttpParserError) { @parser.headers({}, str) }
|
642
|
+
|
643
|
+
@parser.clear
|
644
|
+
str = "PUT /x HTTP/1.1\r\n" \
|
645
|
+
"Transfer-Encoding: chunked,chunked\r\n" \
|
646
|
+
"\r\n"
|
647
|
+
assert_raise(HttpParserError) { @parser.headers({}, str) }
|
648
|
+
end
|
649
|
+
|
569
650
|
def test_backtrace_is_empty
|
570
651
|
begin
|
571
652
|
@parser.headers({}, "AAADFSFDSFD\r\n\r\n")
|
data/test/unit/test_server.rb
CHANGED
@@ -23,6 +23,34 @@ class TestHandler
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
+
class TestEarlyHintsHandler
|
27
|
+
def call(env)
|
28
|
+
while env['rack.input'].read(4096)
|
29
|
+
end
|
30
|
+
env['rack.early_hints'].call(
|
31
|
+
"Link" => "</style.css>; rel=preload; as=style\n</script.js>; rel=preload"
|
32
|
+
)
|
33
|
+
[200, { 'Content-Type' => 'text/plain' }, ['hello!\n']]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class TestRackAfterReply
|
38
|
+
def initialize
|
39
|
+
@called = false
|
40
|
+
end
|
41
|
+
|
42
|
+
def call(env)
|
43
|
+
while env['rack.input'].read(4096)
|
44
|
+
end
|
45
|
+
|
46
|
+
env["rack.after_reply"] << -> { @called = true }
|
47
|
+
|
48
|
+
[200, { 'Content-Type' => 'text/plain' }, ["after_reply_called: #{@called}"]]
|
49
|
+
rescue Unicorn::ClientShutdown, Unicorn::HttpParserError => e
|
50
|
+
$stderr.syswrite("#{e.class}: #{e.message} #{e.backtrace.empty?}\n")
|
51
|
+
raise e
|
52
|
+
end
|
53
|
+
end
|
26
54
|
|
27
55
|
class WebServerTest < Test::Unit::TestCase
|
28
56
|
|
@@ -84,6 +112,52 @@ class WebServerTest < Test::Unit::TestCase
|
|
84
112
|
tmp.close!
|
85
113
|
end
|
86
114
|
|
115
|
+
def test_early_hints
|
116
|
+
teardown
|
117
|
+
redirect_test_io do
|
118
|
+
@server = HttpServer.new(TestEarlyHintsHandler.new,
|
119
|
+
:listeners => [ "127.0.0.1:#@port"],
|
120
|
+
:early_hints => true)
|
121
|
+
@server.start
|
122
|
+
end
|
123
|
+
|
124
|
+
sock = tcp_socket('127.0.0.1', @port)
|
125
|
+
sock.syswrite("GET / HTTP/1.0\r\n\r\n")
|
126
|
+
|
127
|
+
responses = sock.read(4096)
|
128
|
+
assert_match %r{\AHTTP/1.[01] 103\b}, responses
|
129
|
+
assert_match %r{^Link: </style\.css>}, responses
|
130
|
+
assert_match %r{^Link: </script\.js>}, responses
|
131
|
+
|
132
|
+
assert_match %r{^HTTP/1.[01] 200\b}, responses
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_after_reply
|
136
|
+
teardown
|
137
|
+
|
138
|
+
redirect_test_io do
|
139
|
+
@server = HttpServer.new(TestRackAfterReply.new,
|
140
|
+
:listeners => [ "127.0.0.1:#@port"])
|
141
|
+
@server.start
|
142
|
+
end
|
143
|
+
|
144
|
+
sock = tcp_socket('127.0.0.1', @port)
|
145
|
+
sock.syswrite("GET / HTTP/1.0\r\n\r\n")
|
146
|
+
|
147
|
+
responses = sock.read(4096)
|
148
|
+
assert_match %r{\AHTTP/1.[01] 200\b}, responses
|
149
|
+
assert_match %r{^after_reply_called: false}, responses
|
150
|
+
|
151
|
+
sock = tcp_socket('127.0.0.1', @port)
|
152
|
+
sock.syswrite("GET / HTTP/1.0\r\n\r\n")
|
153
|
+
|
154
|
+
responses = sock.read(4096)
|
155
|
+
assert_match %r{\AHTTP/1.[01] 200\b}, responses
|
156
|
+
assert_match %r{^after_reply_called: true}, responses
|
157
|
+
|
158
|
+
sock.close
|
159
|
+
end
|
160
|
+
|
87
161
|
def test_broken_app
|
88
162
|
teardown
|
89
163
|
app = lambda { |env| raise RuntimeError, "hello" }
|
@@ -92,7 +166,7 @@ class WebServerTest < Test::Unit::TestCase
|
|
92
166
|
@server = HttpServer.new(app, :listeners => [ "127.0.0.1:#@port"] )
|
93
167
|
@server.start
|
94
168
|
end
|
95
|
-
sock =
|
169
|
+
sock = tcp_socket('127.0.0.1', @port)
|
96
170
|
sock.syswrite("GET / HTTP/1.0\r\n\r\n")
|
97
171
|
assert_match %r{\AHTTP/1.[01] 500\b}, sock.sysread(4096)
|
98
172
|
assert_nil sock.close
|
@@ -105,7 +179,7 @@ class WebServerTest < Test::Unit::TestCase
|
|
105
179
|
|
106
180
|
def test_client_shutdown_writes
|
107
181
|
bs = 15609315 * rand
|
108
|
-
sock =
|
182
|
+
sock = tcp_socket('127.0.0.1', @port)
|
109
183
|
sock.syswrite("PUT /hello HTTP/1.1\r\n")
|
110
184
|
sock.syswrite("Host: example.com\r\n")
|
111
185
|
sock.syswrite("Transfer-Encoding: chunked\r\n")
|
@@ -132,7 +206,7 @@ class WebServerTest < Test::Unit::TestCase
|
|
132
206
|
|
133
207
|
def test_client_shutdown_write_truncates
|
134
208
|
bs = 15609315 * rand
|
135
|
-
sock =
|
209
|
+
sock = tcp_socket('127.0.0.1', @port)
|
136
210
|
sock.syswrite("PUT /hello HTTP/1.1\r\n")
|
137
211
|
sock.syswrite("Host: example.com\r\n")
|
138
212
|
sock.syswrite("Transfer-Encoding: chunked\r\n")
|
@@ -158,7 +232,7 @@ class WebServerTest < Test::Unit::TestCase
|
|
158
232
|
|
159
233
|
def test_client_malformed_body
|
160
234
|
bs = 15653984
|
161
|
-
sock =
|
235
|
+
sock = tcp_socket('127.0.0.1', @port)
|
162
236
|
sock.syswrite("PUT /hello HTTP/1.1\r\n")
|
163
237
|
sock.syswrite("Host: example.com\r\n")
|
164
238
|
sock.syswrite("Transfer-Encoding: chunked\r\n")
|
@@ -180,7 +254,7 @@ class WebServerTest < Test::Unit::TestCase
|
|
180
254
|
|
181
255
|
def do_test(string, chunk, close_after=nil, shutdown_delay=0)
|
182
256
|
# Do not use instance variables here, because it needs to be thread safe
|
183
|
-
socket =
|
257
|
+
socket = tcp_socket("127.0.0.1", @port);
|
184
258
|
request = StringIO.new(string)
|
185
259
|
chunks_out = 0
|
186
260
|
|
@@ -225,14 +299,14 @@ class WebServerTest < Test::Unit::TestCase
|
|
225
299
|
end
|
226
300
|
|
227
301
|
def test_bad_client_400
|
228
|
-
sock =
|
302
|
+
sock = tcp_socket('127.0.0.1', @port)
|
229
303
|
sock.syswrite("GET / HTTP/1.0\r\nHost: foo\rbar\r\n\r\n")
|
230
304
|
assert_match %r{\AHTTP/1.[01] 400\b}, sock.sysread(4096)
|
231
305
|
assert_nil sock.close
|
232
306
|
end
|
233
307
|
|
234
308
|
def test_http_0_9
|
235
|
-
sock =
|
309
|
+
sock = tcp_socket('127.0.0.1', @port)
|
236
310
|
sock.syswrite("GET /hello\r\n")
|
237
311
|
assert_match 'hello!\n', sock.sysread(4096)
|
238
312
|
assert_nil sock.close
|
data/test/unit/test_signals.rb
CHANGED
@@ -52,7 +52,7 @@ class SignalsTest < Test::Unit::TestCase
|
|
52
52
|
redirect_test_io { HttpServer.new(app, opts).start.join }
|
53
53
|
}
|
54
54
|
wait_workers_ready("test_stderr.#{pid}.log", 1)
|
55
|
-
sock =
|
55
|
+
sock = tcp_socket('127.0.0.1', @port)
|
56
56
|
sock.syswrite("GET / HTTP/1.0\r\n\r\n")
|
57
57
|
buf = sock.readpartial(4096)
|
58
58
|
assert_nil sock.close
|
@@ -79,7 +79,7 @@ class SignalsTest < Test::Unit::TestCase
|
|
79
79
|
}
|
80
80
|
wr.close
|
81
81
|
wait_workers_ready("test_stderr.#{pid}.log", 1)
|
82
|
-
sock =
|
82
|
+
sock = tcp_socket('127.0.0.1', @port)
|
83
83
|
sock.syswrite("GET / HTTP/1.0\r\n\r\n")
|
84
84
|
buf = rd.readpartial(1)
|
85
85
|
wait_master_ready("test_stderr.#{pid}.log")
|
@@ -102,7 +102,7 @@ class SignalsTest < Test::Unit::TestCase
|
|
102
102
|
}
|
103
103
|
t0 = Time.now
|
104
104
|
wait_workers_ready("test_stderr.#{pid}.log", 1)
|
105
|
-
sock =
|
105
|
+
sock = tcp_socket('127.0.0.1', @port)
|
106
106
|
sock.syswrite("GET / HTTP/1.0\r\n\r\n")
|
107
107
|
|
108
108
|
buf = nil
|
@@ -125,7 +125,7 @@ class SignalsTest < Test::Unit::TestCase
|
|
125
125
|
}
|
126
126
|
redirect_test_io { @server = HttpServer.new(app, @server_opts).start }
|
127
127
|
wait_workers_ready("test_stderr.#{$$}.log", 1)
|
128
|
-
sock =
|
128
|
+
sock = tcp_socket('127.0.0.1', @port)
|
129
129
|
sock.syswrite("GET / HTTP/1.0\r\n\r\n")
|
130
130
|
buf = ''
|
131
131
|
header_len = pid = nil
|
@@ -163,13 +163,13 @@ class SignalsTest < Test::Unit::TestCase
|
|
163
163
|
redirect_test_io { @server = HttpServer.new(app, @server_opts).start }
|
164
164
|
|
165
165
|
wait_workers_ready("test_stderr.#{$$}.log", 1)
|
166
|
-
sock =
|
166
|
+
sock = tcp_socket('127.0.0.1', @port)
|
167
167
|
sock.syswrite("GET / HTTP/1.0\r\n\r\n")
|
168
168
|
pid = sock.sysread(4096)[/\r\nX-Pid: (\d+)\r\n/, 1].to_i
|
169
169
|
assert_nil sock.close
|
170
170
|
|
171
171
|
assert pid > 0, "pid not positive: #{pid.inspect}"
|
172
|
-
sock =
|
172
|
+
sock = tcp_socket('127.0.0.1', @port)
|
173
173
|
sock.syswrite("PUT / HTTP/1.0\r\n")
|
174
174
|
sock.syswrite("Content-Length: #{@bs * @count}\r\n\r\n")
|
175
175
|
1000.times { Process.kill(:HUP, pid) }
|
@@ -116,7 +116,7 @@ class TestSocketHelper < Test::Unit::TestCase
|
|
116
116
|
client.syswrite('abcde')
|
117
117
|
exit 0
|
118
118
|
end
|
119
|
-
s =
|
119
|
+
s = unix_socket(@unix_listener_path)
|
120
120
|
IO.select([s])
|
121
121
|
assert_equal 'abcde', s.sysread(5)
|
122
122
|
pid, status = Process.waitpid2(pid)
|
data/test/unit/test_upload.rb
CHANGED
@@ -60,7 +60,7 @@ class UploadTest < Test::Unit::TestCase
|
|
60
60
|
|
61
61
|
def test_put
|
62
62
|
start_server(@sha1_app)
|
63
|
-
sock =
|
63
|
+
sock = tcp_socket(@addr, @port)
|
64
64
|
sock.syswrite("PUT / HTTP/1.0\r\nContent-Length: #{length}\r\n\r\n")
|
65
65
|
@count.times do |i|
|
66
66
|
buf = @random.sysread(@bs)
|
@@ -77,7 +77,7 @@ class UploadTest < Test::Unit::TestCase
|
|
77
77
|
def test_put_content_md5
|
78
78
|
md5 = Digest::MD5.new
|
79
79
|
start_server(@sha1_app)
|
80
|
-
sock =
|
80
|
+
sock = tcp_socket(@addr, @port)
|
81
81
|
sock.syswrite("PUT / HTTP/1.0\r\nTransfer-Encoding: chunked\r\n" \
|
82
82
|
"Trailer: Content-MD5\r\n\r\n")
|
83
83
|
@count.times do |i|
|
@@ -103,7 +103,7 @@ class UploadTest < Test::Unit::TestCase
|
|
103
103
|
@count, @bs = 2, 128
|
104
104
|
start_server(@sha1_app)
|
105
105
|
assert_equal 256, length
|
106
|
-
sock =
|
106
|
+
sock = tcp_socket(@addr, @port)
|
107
107
|
hdr = "PUT / HTTP/1.0\r\nContent-Length: #{length}\r\n\r\n"
|
108
108
|
@count.times do
|
109
109
|
buf = @random.sysread(@bs)
|
@@ -122,7 +122,7 @@ class UploadTest < Test::Unit::TestCase
|
|
122
122
|
|
123
123
|
def test_put_keepalive_truncates_small_overwrite
|
124
124
|
start_server(@sha1_app)
|
125
|
-
sock =
|
125
|
+
sock = tcp_socket(@addr, @port)
|
126
126
|
to_upload = length + 1
|
127
127
|
sock.syswrite("PUT / HTTP/1.0\r\nContent-Length: #{to_upload}\r\n\r\n")
|
128
128
|
@count.times do
|
@@ -155,7 +155,7 @@ class UploadTest < Test::Unit::TestCase
|
|
155
155
|
tmp.write(nr.to_s)
|
156
156
|
[ 200, @hdr, [] ]
|
157
157
|
})
|
158
|
-
sock =
|
158
|
+
sock = tcp_socket(@addr, @port)
|
159
159
|
buf = ' ' * @bs
|
160
160
|
sock.syswrite("PUT / HTTP/1.0\r\nContent-Length: #{length}\r\n\r\n")
|
161
161
|
|
@@ -236,15 +236,10 @@ class UploadTest < Test::Unit::TestCase
|
|
236
236
|
resp = Tempfile.new('resp')
|
237
237
|
resp.sync = true
|
238
238
|
|
239
|
-
rd, wr = IO.pipe
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
rd.close
|
244
|
-
wr.close
|
245
|
-
STDOUT.reopen(resp)
|
246
|
-
exec cmd
|
247
|
-
}
|
239
|
+
rd, wr = IO.pipe.each do |io|
|
240
|
+
io.sync = io.close_on_exec = true
|
241
|
+
end
|
242
|
+
pid = spawn(*cmd, { 0 => rd, 1 => resp })
|
248
243
|
rd.close
|
249
244
|
|
250
245
|
tmp.rewind
|
data/test/unit/test_util.rb
CHANGED
@@ -102,4 +102,29 @@ class TestUtil < Test::Unit::TestCase
|
|
102
102
|
}
|
103
103
|
tmp.close!
|
104
104
|
end
|
105
|
+
|
106
|
+
def test_pipe
|
107
|
+
r, w = Unicorn.pipe
|
108
|
+
assert r
|
109
|
+
assert w
|
110
|
+
|
111
|
+
return if RUBY_PLATFORM !~ /linux/
|
112
|
+
|
113
|
+
begin
|
114
|
+
f_getpipe_sz = 1032
|
115
|
+
IO.pipe do |a, b|
|
116
|
+
a_sz = a.fcntl(f_getpipe_sz)
|
117
|
+
b.fcntl(f_getpipe_sz)
|
118
|
+
assert_kind_of Integer, a_sz
|
119
|
+
r_sz = r.fcntl(f_getpipe_sz)
|
120
|
+
assert_equal Raindrops::PAGE_SIZE, r_sz
|
121
|
+
assert_operator a_sz, :>=, r_sz
|
122
|
+
end
|
123
|
+
rescue Errno::EINVAL
|
124
|
+
# Linux <= 2.6.34
|
125
|
+
end
|
126
|
+
ensure
|
127
|
+
w.close
|
128
|
+
r.close
|
129
|
+
end
|
105
130
|
end
|