unicorn 1.1.7 → 2.0.0pre1
Sign up to get free protection for your applications and to get access to all the features.
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +14 -5
- data/Rakefile +3 -28
- data/TODO +7 -0
- data/bin/unicorn +9 -13
- data/bin/unicorn_rails +12 -14
- data/examples/big_app_gc.rb +33 -2
- data/ext/unicorn_http/global_variables.h +3 -1
- data/ext/unicorn_http/unicorn_http.rl +15 -6
- data/lib/unicorn.rb +67 -820
- data/lib/unicorn/app/exec_cgi.rb +3 -4
- data/lib/unicorn/configurator.rb +20 -25
- data/lib/unicorn/const.rb +26 -25
- data/lib/unicorn/http_request.rb +64 -57
- data/lib/unicorn/http_response.rb +16 -35
- data/lib/unicorn/http_server.rb +700 -0
- data/lib/unicorn/launcher.rb +4 -3
- data/lib/unicorn/oob_gc.rb +50 -61
- data/lib/unicorn/socket_helper.rb +4 -4
- data/lib/unicorn/tee_input.rb +18 -26
- data/lib/unicorn/tmpio.rb +29 -0
- data/lib/unicorn/util.rb +51 -85
- data/lib/unicorn/worker.rb +40 -0
- data/local.mk.sample +0 -9
- data/script/isolate_for_tests +43 -0
- data/t/GNUmakefile +8 -1
- data/t/t0003-working_directory.sh +0 -5
- data/t/t0010-reap-logging.sh +55 -0
- data/t/t0303-rails3-alt-working_directory_config.ru.sh +0 -5
- data/t/test-rails3.sh +1 -1
- data/test/exec/test_exec.rb +1 -1
- data/test/unit/test_http_parser_ng.rb +11 -0
- data/test/unit/test_request.rb +12 -0
- data/test/unit/test_response.rb +23 -21
- data/test/unit/test_signals.rb +1 -1
- data/test/unit/test_tee_input.rb +21 -19
- data/unicorn.gemspec +3 -2
- metadata +47 -25
- data/t/oob_gc.ru +0 -21
- data/t/oob_gc_path.ru +0 -21
- data/t/t0012-reload-empty-config.sh +0 -82
- data/t/t0018-write-on-close.sh +0 -23
- data/t/t9001-oob_gc.sh +0 -47
- data/t/t9002-oob_gc-path.sh +0 -75
- data/t/write-on-close.ru +0 -11
data/local.mk.sample
CHANGED
@@ -37,15 +37,6 @@ else
|
|
37
37
|
RUBY := $(prefix)/bin/ruby --disable-gems
|
38
38
|
endif
|
39
39
|
|
40
|
-
# FIXME: use isolate more
|
41
|
-
ifndef RUBYLIB
|
42
|
-
gems := rack-1.1.0
|
43
|
-
gem_paths := $(addprefix $(HOME)/lib/ruby/gems/1.8/gems/,$(gems))
|
44
|
-
sp :=
|
45
|
-
sp +=
|
46
|
-
export RUBYLIB := $(subst $(sp),:,$(addsuffix /lib,$(gem_paths)))
|
47
|
-
endif
|
48
|
-
|
49
40
|
# pipefail is THE reason to use bash (v3+) or never revisions of ksh93
|
50
41
|
# SHELL := /bin/bash -e -o pipefail
|
51
42
|
SHELL := /bin/ksh93 -e -o pipefail
|
@@ -0,0 +1,43 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# scripts/Makefiles can read and eval the output of this script and
|
3
|
+
# use it as RUBYLIB
|
4
|
+
require 'rubygems'
|
5
|
+
require 'isolate'
|
6
|
+
fp = File.open(__FILE__, "rb")
|
7
|
+
fp.flock(File::LOCK_EX)
|
8
|
+
|
9
|
+
ruby_engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
|
10
|
+
opts = {
|
11
|
+
:system => false,
|
12
|
+
# we want "ruby-1.8.7" and not "ruby-1.8", so disable :multiruby
|
13
|
+
:multiruby => false,
|
14
|
+
:path => "tmp/isolate/#{ruby_engine}-#{RUBY_VERSION}",
|
15
|
+
}
|
16
|
+
|
17
|
+
pid = fork do
|
18
|
+
Isolate.now!(opts) do
|
19
|
+
gem 'sqlite3-ruby', '1.2.5'
|
20
|
+
gem 'kgio', '1.2.0'
|
21
|
+
gem 'rack', '1.1.0'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
_, status = Process.waitpid2(pid)
|
25
|
+
status.success? or abort status.inspect
|
26
|
+
lib_paths = Dir["#{opts[:path]}/gems/*-*/lib"].map { |x| File.expand_path(x) }
|
27
|
+
libs = "tmp/isolate/.#{ruby_engine}-#{RUBY_VERSION}.libs"
|
28
|
+
File.open("#{libs}.#$$", "w") { |fp| fp.puts lib_paths.join(':') }
|
29
|
+
File.rename("#{libs}.#$$", libs)
|
30
|
+
|
31
|
+
# pure Ruby gems can be shared across all Rubies
|
32
|
+
%w(3.0.0).each do |rails_ver|
|
33
|
+
opts[:path] = "tmp/isolate/rails-#{rails_ver}"
|
34
|
+
pid = fork do
|
35
|
+
Isolate.now!(opts) do
|
36
|
+
gem 'rails', rails_ver
|
37
|
+
end
|
38
|
+
end
|
39
|
+
_, status = Process.waitpid2(pid)
|
40
|
+
status.success? or abort status.inspect
|
41
|
+
more = Dir["#{opts[:path]}/gems/*-*/lib"].map { |x| File.expand_path(x) }
|
42
|
+
lib_paths.concat(more)
|
43
|
+
end
|
data/t/GNUmakefile
CHANGED
@@ -17,6 +17,13 @@ endif
|
|
17
17
|
RUBY_ENGINE := $(shell $(RUBY) -e 'puts((RUBY_ENGINE rescue "ruby"))')
|
18
18
|
export RUBY_ENGINE
|
19
19
|
|
20
|
+
isolate_libs := ../tmp/isolate/.$(RUBY_ENGINE)-$(RUBY_VERSION).libs
|
21
|
+
MYLIBS := $(shell cat $(isolate_libs))
|
22
|
+
ifeq ($(MY_LIBS),)
|
23
|
+
ignore := $(shell cd .. && $(RUBY) ./script/isolate_for_tests)
|
24
|
+
MYLIBS := $(shell cat $(isolate_libs))
|
25
|
+
endif
|
26
|
+
|
20
27
|
T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)
|
21
28
|
|
22
29
|
all:: $(T)
|
@@ -58,7 +65,7 @@ $(test_prefix)/.stamp:
|
|
58
65
|
$(T): export RUBY := $(RUBY)
|
59
66
|
$(T): export RAKE := $(RAKE)
|
60
67
|
$(T): export PATH := $(test_prefix)/bin:$(PATH)
|
61
|
-
$(T): export RUBYLIB := $(test_prefix)/lib:$(
|
68
|
+
$(T): export RUBYLIB := $(test_prefix)/lib:$(MYLIBS)
|
62
69
|
$(T): dep $(test_prefix)/.stamp trash/.gitignore
|
63
70
|
$(TRACER) $(SHELL) $(SH_TEST_OPTS) $@ $(TEST_OPTS)
|
64
71
|
|
@@ -0,0 +1,55 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
. ./test-lib.sh
|
3
|
+
t_plan 9 "reap worker logging messages"
|
4
|
+
|
5
|
+
t_begin "setup and start" && {
|
6
|
+
unicorn_setup
|
7
|
+
cat >> $unicorn_config <<EOF
|
8
|
+
after_fork { |s,w| File.open('$fifo','w') { |f| f.write '.' } }
|
9
|
+
EOF
|
10
|
+
unicorn -c $unicorn_config pid.ru &
|
11
|
+
test '.' = $(cat $fifo)
|
12
|
+
unicorn_wait_start
|
13
|
+
}
|
14
|
+
|
15
|
+
t_begin "kill 1st worker=0" && {
|
16
|
+
pid_1=$(curl http://$listen/)
|
17
|
+
kill -9 $pid_1
|
18
|
+
}
|
19
|
+
|
20
|
+
t_begin "wait for 2nd worker to start" && {
|
21
|
+
test '.' = $(cat $fifo)
|
22
|
+
}
|
23
|
+
|
24
|
+
t_begin "ensure log of 1st reap is an ERROR" && {
|
25
|
+
dbgcat r_err
|
26
|
+
grep 'ERROR.*reaped.*worker=0' $r_err | grep $pid_1
|
27
|
+
dbgcat r_err
|
28
|
+
> $r_err
|
29
|
+
}
|
30
|
+
|
31
|
+
t_begin "kill 2nd worker gracefully" && {
|
32
|
+
pid_2=$(curl http://$listen/)
|
33
|
+
kill -QUIT $pid_2
|
34
|
+
}
|
35
|
+
|
36
|
+
t_begin "wait for 3rd worker=0 to start " && {
|
37
|
+
test '.' = $(cat $fifo)
|
38
|
+
}
|
39
|
+
|
40
|
+
t_begin "ensure log of 2nd reap is a INFO" && {
|
41
|
+
grep 'INFO.*reaped.*worker=0' $r_err | grep $pid_2
|
42
|
+
> $r_err
|
43
|
+
}
|
44
|
+
|
45
|
+
t_begin "killing succeeds" && {
|
46
|
+
kill $unicorn_pid
|
47
|
+
wait
|
48
|
+
kill -0 $unicorn_pid && false
|
49
|
+
}
|
50
|
+
|
51
|
+
t_begin "check stderr" && {
|
52
|
+
check_stderr
|
53
|
+
}
|
54
|
+
|
55
|
+
t_done
|
data/t/test-rails3.sh
CHANGED
@@ -13,7 +13,7 @@ rails_gems=../tmp/isolate/rails-$RAILS_VERSION/gems
|
|
13
13
|
rails_bin="$rails_gems/rails-$RAILS_VERSION/bin/rails"
|
14
14
|
if ! test -d "$arch_gems" || ! test -d "$rails_gems" || ! test -x "$rails_bin"
|
15
15
|
then
|
16
|
-
( cd ../ &&
|
16
|
+
( cd ../ && ./script/isolate_for_tests )
|
17
17
|
fi
|
18
18
|
|
19
19
|
for i in $arch_gems/*-* $rails_gems/*-*
|
data/test/exec/test_exec.rb
CHANGED
@@ -440,6 +440,17 @@ class HttpParserNgTest < Test::Unit::TestCase
|
|
440
440
|
end
|
441
441
|
end
|
442
442
|
|
443
|
+
def test_backtrace_is_empty
|
444
|
+
begin
|
445
|
+
@parser.headers({}, "AAADFSFDSFD\r\n\r\n")
|
446
|
+
assert false, "should never get here line:#{__LINE__}"
|
447
|
+
rescue HttpParserError => e
|
448
|
+
assert_equal [], e.backtrace
|
449
|
+
return
|
450
|
+
end
|
451
|
+
assert false, "should never get here line:#{__LINE__}"
|
452
|
+
end
|
453
|
+
|
443
454
|
def test_ignore_version_header
|
444
455
|
http = "GET / HTTP/1.1\r\nVersion: hello\r\n\r\n"
|
445
456
|
req = {}
|
data/test/unit/test_request.rb
CHANGED
@@ -11,7 +11,11 @@ class RequestTest < Test::Unit::TestCase
|
|
11
11
|
|
12
12
|
class MockRequest < StringIO
|
13
13
|
alias_method :readpartial, :sysread
|
14
|
+
alias_method :kgio_read!, :sysread
|
14
15
|
alias_method :read_nonblock, :sysread
|
16
|
+
def kgio_addr
|
17
|
+
'127.0.0.1'
|
18
|
+
end
|
15
19
|
end
|
16
20
|
|
17
21
|
def setup
|
@@ -159,6 +163,14 @@ class RequestTest < Test::Unit::TestCase
|
|
159
163
|
buf = (' ' * bs).freeze
|
160
164
|
length = bs * count
|
161
165
|
client = Tempfile.new('big_put')
|
166
|
+
def client.kgio_addr; '127.0.0.1'; end
|
167
|
+
def client.kgio_read(*args)
|
168
|
+
readpartial(*args)
|
169
|
+
rescue EOFError
|
170
|
+
end
|
171
|
+
def client.kgio_read!(*args)
|
172
|
+
readpartial(*args)
|
173
|
+
end
|
162
174
|
client.syswrite(
|
163
175
|
"PUT / HTTP/1.1\r\n" \
|
164
176
|
"Host: foo\r\n" \
|
data/test/unit/test_response.rb
CHANGED
@@ -11,18 +11,20 @@ require 'test/test_helper'
|
|
11
11
|
include Unicorn
|
12
12
|
|
13
13
|
class ResponseTest < Test::Unit::TestCase
|
14
|
-
|
14
|
+
include Unicorn::HttpResponse
|
15
|
+
|
15
16
|
def test_response_headers
|
16
17
|
out = StringIO.new
|
17
|
-
|
18
|
-
assert
|
18
|
+
http_response_write(out,[200, {"X-Whatever" => "stuff"}, ["cool"]])
|
19
|
+
assert out.closed?
|
20
|
+
|
19
21
|
assert out.length > 0, "output didn't have data"
|
20
22
|
end
|
21
23
|
|
22
24
|
def test_response_string_status
|
23
25
|
out = StringIO.new
|
24
|
-
|
25
|
-
assert
|
26
|
+
http_response_write(out,['200', {}, []])
|
27
|
+
assert out.closed?
|
26
28
|
assert out.length > 0, "output didn't have data"
|
27
29
|
assert_equal 1, out.string.split(/\r\n/).grep(/^Status: 200 OK/).size
|
28
30
|
end
|
@@ -31,8 +33,8 @@ class ResponseTest < Test::Unit::TestCase
|
|
31
33
|
old_ofs = $,
|
32
34
|
$, = "\f\v"
|
33
35
|
out = StringIO.new
|
34
|
-
|
35
|
-
assert
|
36
|
+
http_response_write(out,[200, {"X-k" => "cd","X-y" => "z"}, ["cool"]])
|
37
|
+
assert out.closed?
|
36
38
|
resp = out.string
|
37
39
|
assert ! resp.include?("\f\v"), "output didn't use $, ($OFS)"
|
38
40
|
ensure
|
@@ -41,16 +43,16 @@ class ResponseTest < Test::Unit::TestCase
|
|
41
43
|
|
42
44
|
def test_response_200
|
43
45
|
io = StringIO.new
|
44
|
-
|
45
|
-
assert
|
46
|
+
http_response_write(io, [200, {}, []])
|
47
|
+
assert io.closed?
|
46
48
|
assert io.length > 0, "output didn't have data"
|
47
49
|
end
|
48
50
|
|
49
51
|
def test_response_with_default_reason
|
50
52
|
code = 400
|
51
53
|
io = StringIO.new
|
52
|
-
|
53
|
-
assert
|
54
|
+
http_response_write(io, [code, {}, []])
|
55
|
+
assert io.closed?
|
54
56
|
lines = io.string.split(/\r\n/)
|
55
57
|
assert_match(/.* Bad Request$/, lines.first,
|
56
58
|
"wrong default reason phrase")
|
@@ -58,8 +60,8 @@ class ResponseTest < Test::Unit::TestCase
|
|
58
60
|
|
59
61
|
def test_rack_multivalue_headers
|
60
62
|
out = StringIO.new
|
61
|
-
|
62
|
-
assert
|
63
|
+
http_response_write(out,[200, {"X-Whatever" => "stuff\nbleh"}, []])
|
64
|
+
assert out.closed?
|
63
65
|
assert_match(/^X-Whatever: stuff\r\nX-Whatever: bleh\r\n/, out.string)
|
64
66
|
end
|
65
67
|
|
@@ -67,8 +69,8 @@ class ResponseTest < Test::Unit::TestCase
|
|
67
69
|
# some broken clients still rely on it
|
68
70
|
def test_status_header_added
|
69
71
|
out = StringIO.new
|
70
|
-
|
71
|
-
assert
|
72
|
+
http_response_write(out,[200, {"X-Whatever" => "stuff"}, []])
|
73
|
+
assert out.closed?
|
72
74
|
assert_equal 1, out.string.split(/\r\n/).grep(/^Status: 200 OK/i).size
|
73
75
|
end
|
74
76
|
|
@@ -78,8 +80,8 @@ class ResponseTest < Test::Unit::TestCase
|
|
78
80
|
def test_status_header_ignores_app_hash
|
79
81
|
out = StringIO.new
|
80
82
|
header_hash = {"X-Whatever" => "stuff", 'StaTus' => "666" }
|
81
|
-
|
82
|
-
assert
|
83
|
+
http_response_write(out,[200, header_hash, []])
|
84
|
+
assert out.closed?
|
83
85
|
assert_equal 1, out.string.split(/\r\n/).grep(/^Status: 200 OK/i).size
|
84
86
|
assert_equal 1, out.string.split(/\r\n/).grep(/^Status:/i).size
|
85
87
|
end
|
@@ -89,16 +91,16 @@ class ResponseTest < Test::Unit::TestCase
|
|
89
91
|
body = StringIO.new(expect_body)
|
90
92
|
body.rewind
|
91
93
|
out = StringIO.new
|
92
|
-
|
93
|
-
assert
|
94
|
+
http_response_write(out,[200, {}, body])
|
95
|
+
assert out.closed?
|
94
96
|
assert body.closed?
|
95
97
|
assert_match(expect_body, out.string.split(/\r\n/).last)
|
96
98
|
end
|
97
99
|
|
98
100
|
def test_unknown_status_pass_through
|
99
101
|
out = StringIO.new
|
100
|
-
|
101
|
-
assert
|
102
|
+
http_response_write(out,["666 I AM THE BEAST", {}, [] ])
|
103
|
+
assert out.closed?
|
102
104
|
headers = out.string.split(/\r\n\r\n/).first.split(/\r\n/)
|
103
105
|
assert %r{\AHTTP/\d\.\d 666 I AM THE BEAST\z}.match(headers[0])
|
104
106
|
status = headers.grep(/\AStatus:/i).first
|
data/test/unit/test_signals.rb
CHANGED
@@ -166,7 +166,7 @@ class SignalsTest < Test::Unit::TestCase
|
|
166
166
|
expect = @bs * @count
|
167
167
|
assert_equal(expect, got, "expect=#{expect} got=#{got}")
|
168
168
|
assert_nothing_raised { sock.close }
|
169
|
-
end
|
169
|
+
end
|
170
170
|
|
171
171
|
def test_request_read
|
172
172
|
app = lambda { |env|
|
data/test/unit/test_tee_input.rb
CHANGED
@@ -5,11 +5,12 @@ require 'digest/sha1'
|
|
5
5
|
require 'unicorn'
|
6
6
|
|
7
7
|
class TestTeeInput < Test::Unit::TestCase
|
8
|
+
MockRequest = Struct.new(:env, :parser, :buf)
|
8
9
|
|
9
10
|
def setup
|
10
11
|
@rs = $/
|
11
12
|
@env = {}
|
12
|
-
@rd, @wr =
|
13
|
+
@rd, @wr = Kgio::UNIXSocket.pair
|
13
14
|
@rd.sync = @wr.sync = true
|
14
15
|
@start_pid = $$
|
15
16
|
end
|
@@ -27,8 +28,8 @@ class TestTeeInput < Test::Unit::TestCase
|
|
27
28
|
end
|
28
29
|
|
29
30
|
def test_gets_long
|
30
|
-
|
31
|
-
ti = Unicorn::TeeInput.new(@rd,
|
31
|
+
r = init_request("hello", 5 + (4096 * 4 * 3) + "#$/foo#$/".size)
|
32
|
+
ti = Unicorn::TeeInput.new(@rd, r)
|
32
33
|
status = line = nil
|
33
34
|
pid = fork {
|
34
35
|
@rd.close
|
@@ -48,8 +49,8 @@ class TestTeeInput < Test::Unit::TestCase
|
|
48
49
|
end
|
49
50
|
|
50
51
|
def test_gets_short
|
51
|
-
|
52
|
-
ti = Unicorn::TeeInput.new(@rd,
|
52
|
+
r = init_request("hello", 5 + "#$/foo".size)
|
53
|
+
ti = Unicorn::TeeInput.new(@rd, r)
|
53
54
|
status = line = nil
|
54
55
|
pid = fork {
|
55
56
|
@rd.close
|
@@ -67,8 +68,8 @@ class TestTeeInput < Test::Unit::TestCase
|
|
67
68
|
end
|
68
69
|
|
69
70
|
def test_small_body
|
70
|
-
|
71
|
-
ti = Unicorn::TeeInput.new(@rd,
|
71
|
+
r = init_request('hello')
|
72
|
+
ti = Unicorn::TeeInput.new(@rd, r)
|
72
73
|
assert_equal 0, @parser.content_length
|
73
74
|
assert @parser.body_eof?
|
74
75
|
assert_equal StringIO, ti.tmp.class
|
@@ -80,8 +81,8 @@ class TestTeeInput < Test::Unit::TestCase
|
|
80
81
|
end
|
81
82
|
|
82
83
|
def test_read_with_buffer
|
83
|
-
|
84
|
-
ti = Unicorn::TeeInput.new(@rd,
|
84
|
+
r = init_request('hello')
|
85
|
+
ti = Unicorn::TeeInput.new(@rd, r)
|
85
86
|
buf = ''
|
86
87
|
rv = ti.read(4, buf)
|
87
88
|
assert_equal 'hell', rv
|
@@ -95,8 +96,8 @@ class TestTeeInput < Test::Unit::TestCase
|
|
95
96
|
end
|
96
97
|
|
97
98
|
def test_big_body
|
98
|
-
|
99
|
-
ti = Unicorn::TeeInput.new(@rd,
|
99
|
+
r = init_request('.' * Unicorn::Const::MAX_BODY << 'a')
|
100
|
+
ti = Unicorn::TeeInput.new(@rd, r)
|
100
101
|
assert_equal 0, @parser.content_length
|
101
102
|
assert @parser.body_eof?
|
102
103
|
assert_kind_of File, ti.tmp
|
@@ -106,9 +107,9 @@ class TestTeeInput < Test::Unit::TestCase
|
|
106
107
|
|
107
108
|
def test_read_in_full_if_content_length
|
108
109
|
a, b = 300, 3
|
109
|
-
|
110
|
+
r = init_request('.' * b, 300)
|
110
111
|
assert_equal 300, @parser.content_length
|
111
|
-
ti = Unicorn::TeeInput.new(@rd,
|
112
|
+
ti = Unicorn::TeeInput.new(@rd, r)
|
112
113
|
pid = fork {
|
113
114
|
@wr.write('.' * 197)
|
114
115
|
sleep 1 # still a *potential* race here that would make the test moot...
|
@@ -121,8 +122,8 @@ class TestTeeInput < Test::Unit::TestCase
|
|
121
122
|
end
|
122
123
|
|
123
124
|
def test_big_body_multi
|
124
|
-
|
125
|
-
ti = Unicorn::TeeInput.new(@rd,
|
125
|
+
r = init_request('.', Unicorn::Const::MAX_BODY + 1)
|
126
|
+
ti = Unicorn::TeeInput.new(@rd, r)
|
126
127
|
assert_equal Unicorn::Const::MAX_BODY, @parser.content_length
|
127
128
|
assert ! @parser.body_eof?
|
128
129
|
assert_kind_of File, ti.tmp
|
@@ -163,7 +164,7 @@ class TestTeeInput < Test::Unit::TestCase
|
|
163
164
|
@wr.write("0\r\n\r\n")
|
164
165
|
}
|
165
166
|
@wr.close
|
166
|
-
ti = Unicorn::TeeInput.new(@rd, @env, @parser, @buf)
|
167
|
+
ti = Unicorn::TeeInput.new(@rd, MockRequest.new(@env, @parser, @buf))
|
167
168
|
assert_nil @parser.content_length
|
168
169
|
assert_nil ti.len
|
169
170
|
assert ! @parser.body_eof?
|
@@ -201,7 +202,7 @@ class TestTeeInput < Test::Unit::TestCase
|
|
201
202
|
end
|
202
203
|
@wr.write("0\r\n\r\n")
|
203
204
|
}
|
204
|
-
ti = Unicorn::TeeInput.new(@rd, @env, @parser, @buf)
|
205
|
+
ti = Unicorn::TeeInput.new(@rd, MockRequest.new(@env, @parser, @buf))
|
205
206
|
assert_nil @parser.content_length
|
206
207
|
assert_nil ti.len
|
207
208
|
assert ! @parser.body_eof?
|
@@ -230,7 +231,7 @@ class TestTeeInput < Test::Unit::TestCase
|
|
230
231
|
@wr.write("Hello: World\r\n\r\n")
|
231
232
|
}
|
232
233
|
@wr.close
|
233
|
-
ti = Unicorn::TeeInput.new(@rd, @env, @parser, @buf)
|
234
|
+
ti = Unicorn::TeeInput.new(@rd, MockRequest.new(@env, @parser, @buf))
|
234
235
|
assert_nil @parser.content_length
|
235
236
|
assert_nil ti.len
|
236
237
|
assert ! @parser.body_eof?
|
@@ -243,7 +244,7 @@ class TestTeeInput < Test::Unit::TestCase
|
|
243
244
|
|
244
245
|
private
|
245
246
|
|
246
|
-
def
|
247
|
+
def init_request(body, size = nil)
|
247
248
|
@parser = Unicorn::HttpParser.new
|
248
249
|
body = body.to_s.freeze
|
249
250
|
@buf = "POST / HTTP/1.1\r\n" \
|
@@ -252,6 +253,7 @@ private
|
|
252
253
|
"\r\n#{body}"
|
253
254
|
assert_equal @env, @parser.headers(@env, @buf)
|
254
255
|
assert_equal body, @buf
|
256
|
+
MockRequest.new(@env, @parser, @buf)
|
255
257
|
end
|
256
258
|
|
257
259
|
end
|