unicorn 0.93.1 → 0.93.2
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.
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +1 -0
- data/LICENSE +3 -3
- data/README +1 -1
- data/Rakefile +1 -1
- data/TODO +0 -2
- data/lib/unicorn.rb +21 -0
- data/lib/unicorn/const.rb +1 -1
- data/lib/unicorn/tee_input.rb +41 -2
- data/test/unit/test_tee_input.rb +46 -0
- data/unicorn.gemspec +1 -1
- metadata +3 -3
data/GIT-VERSION-GEN
CHANGED
data/GNUmakefile
CHANGED
@@ -169,6 +169,7 @@ atom = <link rel="alternate" title="Atom feed" href="$(1)" \
|
|
169
169
|
doc: .document $(ext)/unicorn_http.c NEWS ChangeLog
|
170
170
|
for i in $(man1_bins); do > $$i; done
|
171
171
|
rdoc -Na -t "$(shell sed -ne '1s/^= //p' README)"
|
172
|
+
install -m644 COPYING doc/COPYING
|
172
173
|
install -m644 $(shell grep '^[A-Z]' .document) doc/
|
173
174
|
$(MAKE) -C Documentation install-html install-man
|
174
175
|
install -m644 $(man1_paths) doc/
|
data/LICENSE
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
Unicorn is copyrighted free software by
|
2
|
-
|
3
|
-
and/or modify it under either the terms of the
|
1
|
+
Unicorn is copyrighted free software by all contributors, see logs in
|
2
|
+
revision control for names and email addresses of all of them. You can
|
3
|
+
redistribute it and/or modify it under either the terms of the
|
4
4
|
{GPL2}[http://www.gnu.org/licenses/gpl-2.0.txt] (see link:COPYING) or
|
5
5
|
the conditions below:
|
6
6
|
|
data/README
CHANGED
@@ -59,7 +59,7 @@ both the the request and response in between Unicorn and slow clients.
|
|
59
59
|
|
60
60
|
== License
|
61
61
|
|
62
|
-
Unicorn is copyright 2009
|
62
|
+
Unicorn is copyright 2009 by all contributors (see logs in git).
|
63
63
|
It is based on Mongrel and carries the same license.
|
64
64
|
|
65
65
|
Mongrel is copyright 2007 Zed A. Shaw and contributors. It is licensed
|
data/Rakefile
CHANGED
data/TODO
CHANGED
data/lib/unicorn.rb
CHANGED
@@ -53,6 +53,27 @@ module Unicorn
|
|
53
53
|
|
54
54
|
# We populate this at startup so we can figure out how to reexecute
|
55
55
|
# and upgrade the currently running instance of Unicorn
|
56
|
+
# This Hash is considered a stable interface and changing its contents
|
57
|
+
# will allow you to switch between different installations of Unicorn
|
58
|
+
# or even different installations of the same applications without
|
59
|
+
# downtime. Keys of this constant Hash are described as follows:
|
60
|
+
#
|
61
|
+
# * 0 - the path to the unicorn/unicorn_rails executable
|
62
|
+
# * :argv - a deep copy of the ARGV array the executable originally saw
|
63
|
+
# * :cwd - the working directory of the application, this is where
|
64
|
+
# you originally started Unicorn.
|
65
|
+
#
|
66
|
+
# The following example may be used in your Unicorn config file to
|
67
|
+
# change your working directory during a config reload (HUP) without
|
68
|
+
# upgrading or restarting:
|
69
|
+
#
|
70
|
+
# Dir.chdir(Unicorn::HttpServer::START_CTX[:cwd] = path)
|
71
|
+
#
|
72
|
+
# To change your unicorn executable to a different path without downtime,
|
73
|
+
# you can set the following in your Unicorn config file, HUP and then
|
74
|
+
# continue with the traditional USR2 + QUIT upgrade steps:
|
75
|
+
#
|
76
|
+
# Unicorn::HttpServer::START_CTX[0] = "/home/bofh/1.9.2/bin/unicorn"
|
56
77
|
START_CTX = {
|
57
78
|
:argv => ARGV.map { |arg| arg.dup },
|
58
79
|
# don't rely on Dir.pwd here since it's not symlink-aware, and
|
data/lib/unicorn/const.rb
CHANGED
@@ -7,7 +7,7 @@ module Unicorn
|
|
7
7
|
# gave about a 3% to 10% performance improvement over using the strings directly.
|
8
8
|
# Symbols did not really improve things much compared to constants.
|
9
9
|
module Const
|
10
|
-
UNICORN_VERSION="0.93.
|
10
|
+
UNICORN_VERSION="0.93.2"
|
11
11
|
|
12
12
|
DEFAULT_HOST = "0.0.0.0" # default TCP listen host address
|
13
13
|
DEFAULT_PORT = 8080 # default TCP listen port
|
data/lib/unicorn/tee_input.rb
CHANGED
@@ -41,6 +41,26 @@ module Unicorn
|
|
41
41
|
@size = tmp_size
|
42
42
|
end
|
43
43
|
|
44
|
+
# call-seq:
|
45
|
+
# ios = env['rack.input']
|
46
|
+
# ios.read([length [, buffer ]]) => string, buffer, or nil
|
47
|
+
#
|
48
|
+
# Reads at most length bytes from the I/O stream, or to the end of
|
49
|
+
# file if length is omitted or is nil. length must be a non-negative
|
50
|
+
# integer or nil. If the optional buffer argument is present, it
|
51
|
+
# must reference a String, which will receive the data.
|
52
|
+
#
|
53
|
+
# At end of file, it returns nil or "" depend on length.
|
54
|
+
# ios.read() and ios.read(nil) returns "".
|
55
|
+
# ios.read(length [, buffer]) returns nil.
|
56
|
+
#
|
57
|
+
# If the Content-Length of the HTTP request is known (as is the common
|
58
|
+
# case for POST requests), then ios.read(length [, buffer]) will block
|
59
|
+
# until the specified length is read (or it is the last chunk).
|
60
|
+
# Otherwise, for uncommon "Transfer-Encoding: chunked" requests,
|
61
|
+
# ios.read(length [, buffer]) will return immediately if there is
|
62
|
+
# any data and only block when nothing is available (providing
|
63
|
+
# IO#readpartial semantics).
|
44
64
|
def read(*args)
|
45
65
|
socket or return @tmp.read(*args)
|
46
66
|
|
@@ -55,9 +75,9 @@ module Unicorn
|
|
55
75
|
rv = args.shift || @buf2.dup
|
56
76
|
diff = tmp_size - @tmp.pos
|
57
77
|
if 0 == diff
|
58
|
-
tee(length, rv)
|
78
|
+
ensure_length(tee(length, rv), length)
|
59
79
|
else
|
60
|
-
@tmp.read(diff > length ? length : diff, rv)
|
80
|
+
ensure_length(@tmp.read(diff > length ? length : diff, rv), length)
|
61
81
|
end
|
62
82
|
end
|
63
83
|
end
|
@@ -130,5 +150,24 @@ module Unicorn
|
|
130
150
|
StringIO === @tmp ? @tmp.size : @tmp.stat.size
|
131
151
|
end
|
132
152
|
|
153
|
+
# tee()s into +buf+ until it is of +length+ bytes (or until
|
154
|
+
# we've reached the Content-Length of the request body).
|
155
|
+
# Returns +buf+ (the exact object, not a duplicate)
|
156
|
+
# To continue supporting applications that need near-real-time
|
157
|
+
# streaming input bodies, this is a no-op for
|
158
|
+
# "Transfer-Encoding: chunked" requests.
|
159
|
+
def ensure_length(buf, length)
|
160
|
+
# @size is nil for chunked bodies, so we can't ensure length for those
|
161
|
+
# since they could be streaming bidirectionally and we don't want to
|
162
|
+
# block the caller in that case.
|
163
|
+
return buf if buf.nil? || @size.nil?
|
164
|
+
|
165
|
+
while buf.size < length && @size != @tmp.pos
|
166
|
+
buf << tee(length - buf.size, @buf2)
|
167
|
+
end
|
168
|
+
|
169
|
+
buf
|
170
|
+
end
|
171
|
+
|
133
172
|
end
|
134
173
|
end
|
data/test/unit/test_tee_input.rb
CHANGED
@@ -104,6 +104,22 @@ class TestTeeInput < Test::Unit::TestCase
|
|
104
104
|
assert_equal Unicorn::Const::MAX_BODY + 1, ti.size
|
105
105
|
end
|
106
106
|
|
107
|
+
def test_read_in_full_if_content_length
|
108
|
+
a, b = 300, 3
|
109
|
+
init_parser('.' * b, 300)
|
110
|
+
assert_equal 300, @parser.content_length
|
111
|
+
ti = Unicorn::TeeInput.new(@rd, @env, @parser, @buf)
|
112
|
+
pid = fork {
|
113
|
+
@wr.write('.' * 197)
|
114
|
+
sleep 1 # still a *potential* race here that would make the test moot...
|
115
|
+
@wr.write('.' * 100)
|
116
|
+
}
|
117
|
+
assert_equal a, ti.read(a).size
|
118
|
+
_, status = Process.waitpid2(pid)
|
119
|
+
assert status.success?
|
120
|
+
@wr.close
|
121
|
+
end
|
122
|
+
|
107
123
|
def test_big_body_multi
|
108
124
|
init_parser('.', Unicorn::Const::MAX_BODY + 1)
|
109
125
|
ti = Unicorn::TeeInput.new(@rd, @env, @parser, @buf)
|
@@ -167,6 +183,36 @@ class TestTeeInput < Test::Unit::TestCase
|
|
167
183
|
assert status.success?
|
168
184
|
end
|
169
185
|
|
186
|
+
def test_chunked_ping_pong
|
187
|
+
@parser = Unicorn::HttpParser.new
|
188
|
+
@buf = "POST / HTTP/1.1\r\n" \
|
189
|
+
"Host: localhost\r\n" \
|
190
|
+
"Transfer-Encoding: chunked\r\n" \
|
191
|
+
"\r\n"
|
192
|
+
assert_equal @env, @parser.headers(@env, @buf)
|
193
|
+
assert_equal "", @buf
|
194
|
+
chunks = %w(aa bbb cccc dddd eeee)
|
195
|
+
rd, wr = IO.pipe
|
196
|
+
|
197
|
+
pid = fork {
|
198
|
+
chunks.each do |chunk|
|
199
|
+
rd.read(1) == "." and
|
200
|
+
@wr.write("#{'%x' % [ chunk.size]}\r\n#{chunk}\r\n")
|
201
|
+
end
|
202
|
+
@wr.write("0\r\n")
|
203
|
+
}
|
204
|
+
ti = Unicorn::TeeInput.new(@rd, @env, @parser, @buf)
|
205
|
+
assert_nil @parser.content_length
|
206
|
+
assert_nil ti.instance_eval { @size }
|
207
|
+
assert ! @parser.body_eof?
|
208
|
+
chunks.each do |chunk|
|
209
|
+
wr.write('.')
|
210
|
+
assert_equal chunk, ti.read(16384)
|
211
|
+
end
|
212
|
+
_, status = Process.waitpid2(pid)
|
213
|
+
assert status.success?
|
214
|
+
end
|
215
|
+
|
170
216
|
private
|
171
217
|
|
172
218
|
def init_parser(body, size = nil)
|
data/unicorn.gemspec
CHANGED
@@ -14,7 +14,7 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.name = %q{unicorn}
|
15
15
|
s.version = ENV["VERSION"]
|
16
16
|
|
17
|
-
s.authors = ["
|
17
|
+
s.authors = ["Unicorn developers"]
|
18
18
|
s.date = Time.now.utc.strftime('%Y-%m-%d')
|
19
19
|
s.description = File.read("README").split(/\n\n/)[1]
|
20
20
|
s.email = %q{mongrel-unicorn@rubyforge.org}
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unicorn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.93.
|
4
|
+
version: 0.93.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- Unicorn developers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-10-
|
12
|
+
date: 2009-10-07 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|