unicorn-camilo 4.8.2.5.19 → 5.0.0
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/.document +0 -1
- data/.gitignore +2 -2
- data/{.wrongdoc.yml → .olddoc.yml} +7 -2
- data/Documentation/unicorn.1.txt +9 -2
- data/Documentation/unicorn_rails.1.txt +2 -2
- data/FAQ +9 -1
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +31 -46
- data/HACKING +13 -27
- data/ISSUES +80 -16
- data/KNOWN_ISSUES +10 -10
- data/Links +10 -7
- data/PHILOSOPHY +1 -1
- data/README +8 -13
- data/Rakefile +0 -44
- data/Sandbox +1 -1
- data/TUNING +6 -3
- data/archive/.gitignore +3 -0
- data/archive/slrnpull.conf +4 -0
- data/bin/unicorn +1 -1
- data/bin/unicorn_rails +1 -1
- data/examples/unicorn.conf.rb +11 -0
- data/ext/unicorn_http/httpdate.c +1 -1
- data/ext/unicorn_http/unicorn_http.rl +48 -150
- data/lib/unicorn.rb +9 -15
- data/lib/unicorn/configurator.rb +3 -20
- data/lib/unicorn/const.rb +2 -25
- data/lib/unicorn/http_request.rb +4 -1
- data/lib/unicorn/http_response.rb +1 -3
- data/lib/unicorn/http_server.rb +85 -86
- data/lib/unicorn/socket_helper.rb +33 -67
- data/lib/unicorn/tee_input.rb +8 -1
- data/lib/unicorn/tmpio.rb +2 -4
- data/lib/unicorn/util.rb +1 -0
- data/lib/unicorn/worker.rb +1 -13
- data/t/GNUmakefile +1 -5
- data/t/README +1 -1
- data/t/t0002-parser-error.sh +3 -3
- data/test/exec/test_exec.rb +1 -1
- data/test/test_helper.rb +2 -2
- data/test/unit/test_http_parser.rb +3 -3
- data/test/unit/test_http_parser_ng.rb +8 -117
- data/test/unit/test_request.rb +1 -1
- data/test/unit/test_response.rb +3 -9
- data/test/unit/test_server.rb +3 -3
- data/test/unit/test_signals.rb +1 -1
- data/test/unit/test_socket_helper.rb +5 -5
- data/test/unit/test_tee_input.rb +10 -0
- data/test/unit/test_upload.rb +1 -1
- data/test/unit/test_util.rb +1 -1
- data/unicorn.gemspec +7 -10
- metadata +15 -33
- data/examples/git.ru +0 -13
- data/lib/unicorn/app/exec_cgi.rb +0 -154
- data/lib/unicorn/app/inetd.rb +0 -109
- data/lib/unicorn/ssl_client.rb +0 -11
- data/lib/unicorn/ssl_configurator.rb +0 -104
- data/lib/unicorn/ssl_server.rb +0 -42
- data/local.mk.sample +0 -59
- data/script/isolate_for_tests +0 -31
- data/t/t0016-trust-x-forwarded-false.sh +0 -30
- data/t/t0017-trust-x-forwarded-true.sh +0 -30
- data/test/unit/test_http_parser_xftrust.rb +0 -38
- data/test/unit/test_sni_hostnames.rb +0 -47
data/test/unit/test_request.rb
CHANGED
data/test/unit/test_response.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
2
|
|
3
|
-
# Copyright (c) 2005 Zed A. Shaw
|
3
|
+
# Copyright (c) 2005 Zed A. Shaw
|
4
4
|
# You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
|
5
5
|
# the GPLv2+ (GPLv3+ preferred)
|
6
6
|
#
|
7
|
-
# Additional work donated by contributors. See
|
7
|
+
# Additional work donated by contributors. See git history
|
8
8
|
# for more information.
|
9
9
|
|
10
|
-
require 'test/test_helper'
|
10
|
+
require './test/test_helper'
|
11
11
|
require 'time'
|
12
12
|
|
13
13
|
include Unicorn
|
@@ -38,7 +38,6 @@ class ResponseTest < Test::Unit::TestCase
|
|
38
38
|
http_response_write(out,'200', {}, [])
|
39
39
|
assert ! out.closed?
|
40
40
|
assert out.length > 0, "output didn't have data"
|
41
|
-
assert_equal 1, out.string.split(/\r\n/).grep(/^Status: 200 OK/).size
|
42
41
|
end
|
43
42
|
|
44
43
|
def test_response_200
|
@@ -71,7 +70,6 @@ class ResponseTest < Test::Unit::TestCase
|
|
71
70
|
out = StringIO.new
|
72
71
|
http_response_write(out,200, {"X-Whatever" => "stuff"}, [])
|
73
72
|
assert ! out.closed?
|
74
|
-
assert_equal 1, out.string.split(/\r\n/).grep(/^Status: 200 OK/i).size
|
75
73
|
end
|
76
74
|
|
77
75
|
def test_body_closed
|
@@ -91,9 +89,5 @@ class ResponseTest < Test::Unit::TestCase
|
|
91
89
|
assert ! out.closed?
|
92
90
|
headers = out.string.split(/\r\n\r\n/).first.split(/\r\n/)
|
93
91
|
assert %r{\AHTTP/\d\.\d 666 I AM THE BEAST\z}.match(headers[0])
|
94
|
-
status = headers.grep(/\AStatus:/i).first
|
95
|
-
assert status
|
96
|
-
assert_equal "Status: 666 I AM THE BEAST", status
|
97
92
|
end
|
98
|
-
|
99
93
|
end
|
data/test/unit/test_server.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
2
|
|
3
|
-
# Copyright (c) 2005 Zed A. Shaw
|
3
|
+
# Copyright (c) 2005 Zed A. Shaw
|
4
4
|
# You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
|
5
5
|
# the GPLv2+ (GPLv3+ preferred)
|
6
6
|
#
|
7
|
-
# Additional work donated by contributors. See
|
7
|
+
# Additional work donated by contributors. See git history
|
8
8
|
# for more information.
|
9
9
|
|
10
|
-
require 'test/test_helper'
|
10
|
+
require './test/test_helper'
|
11
11
|
|
12
12
|
include Unicorn
|
13
13
|
|
data/test/unit/test_signals.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
2
|
|
3
|
-
require 'test/test_helper'
|
3
|
+
require './test/test_helper'
|
4
4
|
require 'tempfile'
|
5
5
|
|
6
6
|
class TestSocketHelper < Test::Unit::TestCase
|
@@ -182,16 +182,16 @@ class TestSocketHelper < Test::Unit::TestCase
|
|
182
182
|
sock = bind_listen "[#@test6_addr]:#{port}", :ipv6only => true
|
183
183
|
cur = sock.getsockopt(:IPPROTO_IPV6, :IPV6_V6ONLY).unpack('i')[0]
|
184
184
|
assert_equal 1, cur
|
185
|
-
|
186
|
-
end
|
185
|
+
rescue Errno::EAFNOSUPPORT
|
186
|
+
end
|
187
187
|
|
188
188
|
def test_reuseport
|
189
189
|
port = unused_port @test_addr
|
190
190
|
name = "#@test_addr:#{port}"
|
191
191
|
sock = bind_listen(name, :reuseport => true)
|
192
|
-
cur = sock.getsockopt(
|
192
|
+
cur = sock.getsockopt(:SOL_SOCKET, :SO_REUSEPORT).int
|
193
193
|
assert_operator cur, :>, 0
|
194
194
|
rescue Errno::ENOPROTOOPT
|
195
195
|
# kernel does not support SO_REUSEPORT (older Linux)
|
196
|
-
end
|
196
|
+
end if defined?(Socket::SO_REUSEPORT)
|
197
197
|
end
|
data/test/unit/test_tee_input.rb
CHANGED
@@ -29,6 +29,13 @@ class TestTeeInput < Test::Unit::TestCase
|
|
29
29
|
end while true
|
30
30
|
end
|
31
31
|
|
32
|
+
def check_tempfiles
|
33
|
+
tmp = @parser.env["rack.tempfiles"]
|
34
|
+
assert_instance_of Array, tmp
|
35
|
+
assert_operator tmp.size, :>=, 1
|
36
|
+
assert_instance_of Unicorn::TmpIO, tmp[0]
|
37
|
+
end
|
38
|
+
|
32
39
|
def test_gets_long
|
33
40
|
r = init_request("hello", 5 + (4096 * 4 * 3) + "#$/foo#$/".size)
|
34
41
|
ti = TeeInput.new(@rd, r)
|
@@ -106,6 +113,7 @@ class TestTeeInput < Test::Unit::TestCase
|
|
106
113
|
assert_kind_of File, ti.tmp
|
107
114
|
assert_equal 0, ti.tmp.pos
|
108
115
|
assert_equal Unicorn::Const::MAX_BODY + 1, ti.size
|
116
|
+
check_tempfiles
|
109
117
|
end
|
110
118
|
|
111
119
|
def test_read_in_full_if_content_length
|
@@ -148,6 +156,7 @@ class TestTeeInput < Test::Unit::TestCase
|
|
148
156
|
assert_nil ti.read(1)
|
149
157
|
pid, status = Process.waitpid2(pid)
|
150
158
|
assert status.success?
|
159
|
+
check_tempfiles
|
151
160
|
end
|
152
161
|
|
153
162
|
def test_chunked
|
@@ -183,6 +192,7 @@ class TestTeeInput < Test::Unit::TestCase
|
|
183
192
|
status = nil
|
184
193
|
pid, status = Process.waitpid2(pid)
|
185
194
|
assert status.success?
|
195
|
+
check_tempfiles
|
186
196
|
end
|
187
197
|
|
188
198
|
def test_chunked_ping_pong
|
data/test/unit/test_upload.rb
CHANGED
data/test/unit/test_util.rb
CHANGED
data/unicorn.gemspec
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
2
|
ENV["VERSION"] or abort "VERSION= must be specified"
|
3
3
|
manifest = File.readlines('.manifest').map! { |x| x.chomp! }
|
4
|
-
require '
|
5
|
-
extend
|
4
|
+
require 'olddoc'
|
5
|
+
extend Olddoc::Gemspec
|
6
6
|
name, summary, title = readme_metadata
|
7
7
|
|
8
8
|
# don't bother with tests that fork, not worth our time to get working
|
@@ -14,19 +14,16 @@ end.compact
|
|
14
14
|
|
15
15
|
Gem::Specification.new do |s|
|
16
16
|
s.name = %q{unicorn-camilo}
|
17
|
-
s.version = "
|
17
|
+
s.version = "5.0.0"
|
18
18
|
s.authors = ["#{name} hackers"]
|
19
19
|
s.summary = summary
|
20
|
-
s.date = Time.now.utc.strftime('%Y-%m-%d')
|
21
20
|
s.description = readme_description
|
22
|
-
s.email = %q{
|
21
|
+
s.email = %q{unicorn-public@bogomips.org}
|
23
22
|
s.executables = %w(unicorn unicorn_rails)
|
24
23
|
s.extensions = %w(ext/unicorn_http/extconf.rb)
|
25
24
|
s.extra_rdoc_files = extra_rdoc_files(manifest)
|
26
25
|
s.files = manifest
|
27
|
-
s.homepage =
|
28
|
-
s.rdoc_options = rdoc_options
|
29
|
-
s.rubyforge_project = %q{mongrel}
|
26
|
+
s.homepage = Olddoc.config['rdoc_url']
|
30
27
|
s.test_files = test_files
|
31
28
|
|
32
29
|
# for people that are absolutely stuck on Rails 2.3.2 and can't
|
@@ -37,8 +34,8 @@ Gem::Specification.new do |s|
|
|
37
34
|
s.add_dependency(%q<kgio>, '~> 2.6')
|
38
35
|
s.add_dependency(%q<raindrops>, '~> 0.7')
|
39
36
|
|
40
|
-
s.add_development_dependency('
|
41
|
-
s.add_development_dependency('
|
37
|
+
s.add_development_dependency('test-unit', '~> 3.0')
|
38
|
+
s.add_development_dependency('olddoc', '~> 1.0')
|
42
39
|
|
43
40
|
s.licenses = ["GPLv2+", "Ruby 1.8"]
|
44
41
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unicorn-camilo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Unicorn hackers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-05-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -53,40 +53,40 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0.7'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: test-unit
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '3.
|
61
|
+
version: '3.0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '3.
|
68
|
+
version: '3.0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: olddoc
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: 1.
|
75
|
+
version: '1.0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 1.
|
82
|
+
version: '1.0'
|
83
83
|
description: |-
|
84
84
|
\Unicorn is an HTTP server for Rack applications designed to only serve
|
85
85
|
fast clients on low-latency, high-bandwidth connections and take
|
86
86
|
advantage of features in Unix/Unix-like kernels. Slow clients should
|
87
87
|
only be served by placing a reverse proxy capable of fully buffering
|
88
88
|
both the the request and response in between \Unicorn and slow clients.
|
89
|
-
email:
|
89
|
+
email: unicorn-public@bogomips.org
|
90
90
|
executables:
|
91
91
|
- unicorn
|
92
92
|
- unicorn_rails
|
@@ -105,7 +105,6 @@ extra_rdoc_files:
|
|
105
105
|
- KNOWN_ISSUES
|
106
106
|
- TODO
|
107
107
|
- NEWS
|
108
|
-
- ChangeLog
|
109
108
|
- LATEST
|
110
109
|
- lib/unicorn.rb
|
111
110
|
- lib/unicorn/configurator.rb
|
@@ -126,11 +125,10 @@ files:
|
|
126
125
|
- ".gitignore"
|
127
126
|
- ".mailmap"
|
128
127
|
- ".manifest"
|
129
|
-
- ".
|
128
|
+
- ".olddoc.yml"
|
130
129
|
- Application_Timeouts
|
131
130
|
- CONTRIBUTORS
|
132
131
|
- COPYING
|
133
|
-
- ChangeLog
|
134
132
|
- DESIGN
|
135
133
|
- Documentation/.gitignore
|
136
134
|
- Documentation/GNUmakefile
|
@@ -154,11 +152,12 @@ files:
|
|
154
152
|
- Sandbox
|
155
153
|
- TODO
|
156
154
|
- TUNING
|
155
|
+
- archive/.gitignore
|
156
|
+
- archive/slrnpull.conf
|
157
157
|
- bin/unicorn
|
158
158
|
- bin/unicorn_rails
|
159
159
|
- examples/big_app_gc.rb
|
160
160
|
- examples/echo.ru
|
161
|
-
- examples/git.ru
|
162
161
|
- examples/init.sh
|
163
162
|
- examples/logger_mp_safe.rb
|
164
163
|
- examples/logrotate.conf
|
@@ -176,8 +175,6 @@ files:
|
|
176
175
|
- ext/unicorn_http/unicorn_http.rl
|
177
176
|
- ext/unicorn_http/unicorn_http_common.rl
|
178
177
|
- lib/unicorn.rb
|
179
|
-
- lib/unicorn/app/exec_cgi.rb
|
180
|
-
- lib/unicorn/app/inetd.rb
|
181
178
|
- lib/unicorn/app/old_rails.rb
|
182
179
|
- lib/unicorn/app/old_rails/static.rb
|
183
180
|
- lib/unicorn/cgi_wrapper.rb
|
@@ -190,19 +187,14 @@ files:
|
|
190
187
|
- lib/unicorn/oob_gc.rb
|
191
188
|
- lib/unicorn/preread_input.rb
|
192
189
|
- lib/unicorn/socket_helper.rb
|
193
|
-
- lib/unicorn/ssl_client.rb
|
194
|
-
- lib/unicorn/ssl_configurator.rb
|
195
|
-
- lib/unicorn/ssl_server.rb
|
196
190
|
- lib/unicorn/stream_input.rb
|
197
191
|
- lib/unicorn/tee_input.rb
|
198
192
|
- lib/unicorn/tmpio.rb
|
199
193
|
- lib/unicorn/util.rb
|
200
194
|
- lib/unicorn/version.rb
|
201
195
|
- lib/unicorn/worker.rb
|
202
|
-
- local.mk.sample
|
203
196
|
- man/man1/unicorn.1
|
204
197
|
- man/man1/unicorn_rails.1
|
205
|
-
- script/isolate_for_tests
|
206
198
|
- setup.rb
|
207
199
|
- t/.gitignore
|
208
200
|
- t/GNUmakefile
|
@@ -245,8 +237,6 @@ files:
|
|
245
237
|
- t/t0014-rewindable-input-true.sh
|
246
238
|
- t/t0014.ru
|
247
239
|
- t/t0015-configurator-internals.sh
|
248
|
-
- t/t0016-trust-x-forwarded-false.sh
|
249
|
-
- t/t0017-trust-x-forwarded-true.sh
|
250
240
|
- t/t0018-write-on-close.sh
|
251
241
|
- t/t0019-max_header_len.sh
|
252
242
|
- t/t0020-at_exit-handler.sh
|
@@ -273,12 +263,10 @@ files:
|
|
273
263
|
- test/unit/test_droplet.rb
|
274
264
|
- test/unit/test_http_parser.rb
|
275
265
|
- test/unit/test_http_parser_ng.rb
|
276
|
-
- test/unit/test_http_parser_xftrust.rb
|
277
266
|
- test/unit/test_request.rb
|
278
267
|
- test/unit/test_response.rb
|
279
268
|
- test/unit/test_server.rb
|
280
269
|
- test/unit/test_signals.rb
|
281
|
-
- test/unit/test_sni_hostnames.rb
|
282
270
|
- test/unit/test_socket_helper.rb
|
283
271
|
- test/unit/test_stream_input.rb
|
284
272
|
- test/unit/test_tee_input.rb
|
@@ -291,11 +279,7 @@ licenses:
|
|
291
279
|
- Ruby 1.8
|
292
280
|
metadata: {}
|
293
281
|
post_install_message:
|
294
|
-
rdoc_options:
|
295
|
-
- "-t"
|
296
|
-
- 'Unicorn: Rack HTTP server for fast clients and Unix'
|
297
|
-
- "-W"
|
298
|
-
- http://bogomips.org/unicorn.git/tree/%s
|
282
|
+
rdoc_options: []
|
299
283
|
require_paths:
|
300
284
|
- lib
|
301
285
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -309,8 +293,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
309
293
|
- !ruby/object:Gem::Version
|
310
294
|
version: '0'
|
311
295
|
requirements: []
|
312
|
-
rubyforge_project:
|
313
|
-
rubygems_version: 2.2.
|
296
|
+
rubyforge_project:
|
297
|
+
rubygems_version: 2.2.3
|
314
298
|
signing_key:
|
315
299
|
specification_version: 4
|
316
300
|
summary: Rack HTTP server for fast clients and Unix
|
@@ -318,9 +302,7 @@ test_files:
|
|
318
302
|
- test/unit/test_configurator.rb
|
319
303
|
- test/unit/test_http_parser.rb
|
320
304
|
- test/unit/test_http_parser_ng.rb
|
321
|
-
- test/unit/test_http_parser_xftrust.rb
|
322
305
|
- test/unit/test_request.rb
|
323
306
|
- test/unit/test_response.rb
|
324
307
|
- test/unit/test_server.rb
|
325
|
-
- test/unit/test_sni_hostnames.rb
|
326
308
|
- test/unit/test_util.rb
|
data/examples/git.ru
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
#\-E none
|
2
|
-
|
3
|
-
# See http://thread.gmane.org/gmane.comp.web.curl.general/10473/raw on
|
4
|
-
# how to setup git for this. A better version of the above patch was
|
5
|
-
# accepted and committed on June 15, 2009, so you can pull the latest
|
6
|
-
# curl CVS snapshot to try this out.
|
7
|
-
require 'unicorn/app/inetd'
|
8
|
-
|
9
|
-
use Rack::Lint
|
10
|
-
use Rack::Chunked # important!
|
11
|
-
run Unicorn::App::Inetd.new(
|
12
|
-
*%w(git daemon --verbose --inetd --export-all --base-path=/home/ew/unicorn)
|
13
|
-
)
|
data/lib/unicorn/app/exec_cgi.rb
DELETED
@@ -1,154 +0,0 @@
|
|
1
|
-
# -*- encoding: binary -*-
|
2
|
-
# :enddoc:
|
3
|
-
require 'unicorn'
|
4
|
-
|
5
|
-
module Unicorn::App
|
6
|
-
|
7
|
-
# This class is highly experimental (even more so than the rest of Unicorn)
|
8
|
-
# and has never run anything other than cgit.
|
9
|
-
class ExecCgi < Struct.new(:args)
|
10
|
-
|
11
|
-
CHUNK_SIZE = 16384
|
12
|
-
PASS_VARS = %w(
|
13
|
-
CONTENT_LENGTH
|
14
|
-
CONTENT_TYPE
|
15
|
-
GATEWAY_INTERFACE
|
16
|
-
AUTH_TYPE
|
17
|
-
PATH_INFO
|
18
|
-
PATH_TRANSLATED
|
19
|
-
QUERY_STRING
|
20
|
-
REMOTE_ADDR
|
21
|
-
REMOTE_HOST
|
22
|
-
REMOTE_IDENT
|
23
|
-
REMOTE_USER
|
24
|
-
REQUEST_METHOD
|
25
|
-
SERVER_NAME
|
26
|
-
SERVER_PORT
|
27
|
-
SERVER_PROTOCOL
|
28
|
-
SERVER_SOFTWARE
|
29
|
-
).map { |x| x.freeze } # frozen strings are faster for Hash assignments
|
30
|
-
|
31
|
-
class Body < Unicorn::TmpIO
|
32
|
-
def body_offset=(n)
|
33
|
-
sysseek(@body_offset = n)
|
34
|
-
end
|
35
|
-
|
36
|
-
def each
|
37
|
-
sysseek @body_offset
|
38
|
-
# don't use a preallocated buffer for sysread since we can't
|
39
|
-
# guarantee an actual socket is consuming the yielded string
|
40
|
-
# (or if somebody is pushing to an array for eventual concatenation
|
41
|
-
begin
|
42
|
-
yield sysread(CHUNK_SIZE)
|
43
|
-
rescue EOFError
|
44
|
-
break
|
45
|
-
end while true
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
# Intializes the app, example of usage in a config.ru
|
50
|
-
# map "/cgit" do
|
51
|
-
# run Unicorn::App::ExecCgi.new("/path/to/cgit.cgi")
|
52
|
-
# end
|
53
|
-
def initialize(*args)
|
54
|
-
self.args = args
|
55
|
-
first = args[0] or
|
56
|
-
raise ArgumentError, "need path to executable"
|
57
|
-
first[0] == ?/ or args[0] = ::File.expand_path(first)
|
58
|
-
File.executable?(args[0]) or
|
59
|
-
raise ArgumentError, "#{args[0]} is not executable"
|
60
|
-
end
|
61
|
-
|
62
|
-
# Calls the app
|
63
|
-
def call(env)
|
64
|
-
out, err = Body.new, Unicorn::TmpIO.new
|
65
|
-
inp = force_file_input(env)
|
66
|
-
pid = fork { run_child(inp, out, err, env) }
|
67
|
-
inp.close
|
68
|
-
pid, status = Process.waitpid2(pid)
|
69
|
-
write_errors(env, err, status) if err.stat.size > 0
|
70
|
-
err.close
|
71
|
-
|
72
|
-
return parse_output!(out) if status.success?
|
73
|
-
out.close
|
74
|
-
[ 500, { 'Content-Length' => '0', 'Content-Type' => 'text/plain' }, [] ]
|
75
|
-
end
|
76
|
-
|
77
|
-
private
|
78
|
-
|
79
|
-
def run_child(inp, out, err, env)
|
80
|
-
PASS_VARS.each do |key|
|
81
|
-
val = env[key] or next
|
82
|
-
ENV[key] = val
|
83
|
-
end
|
84
|
-
ENV['SCRIPT_NAME'] = args[0]
|
85
|
-
ENV['GATEWAY_INTERFACE'] = 'CGI/1.1'
|
86
|
-
env.keys.grep(/^HTTP_/) { |key| ENV[key] = env[key] }
|
87
|
-
|
88
|
-
$stdin.reopen(inp)
|
89
|
-
$stdout.reopen(out)
|
90
|
-
$stderr.reopen(err)
|
91
|
-
exec(*args)
|
92
|
-
end
|
93
|
-
|
94
|
-
# Extracts headers from CGI out, will change the offset of out.
|
95
|
-
# This returns a standard Rack-compatible return value:
|
96
|
-
# [ 200, HeadersHash, body ]
|
97
|
-
def parse_output!(out)
|
98
|
-
size = out.stat.size
|
99
|
-
out.sysseek(0)
|
100
|
-
head = out.sysread(CHUNK_SIZE)
|
101
|
-
offset = 2
|
102
|
-
head, body = head.split(/\n\n/, 2)
|
103
|
-
if body.nil?
|
104
|
-
head, body = head.split(/\r\n\r\n/, 2)
|
105
|
-
offset = 4
|
106
|
-
end
|
107
|
-
offset += head.length
|
108
|
-
out.body_offset = offset
|
109
|
-
size -= offset
|
110
|
-
prev = nil
|
111
|
-
headers = Rack::Utils::HeaderHash.new
|
112
|
-
head.split(/\r?\n/).each do |line|
|
113
|
-
case line
|
114
|
-
when /^([A-Za-z0-9-]+):\s*(.*)$/ then headers[prev = $1] = $2
|
115
|
-
when /^[ \t]/ then headers[prev] << "\n#{line}" if prev
|
116
|
-
end
|
117
|
-
end
|
118
|
-
status = headers.delete("Status") || 200
|
119
|
-
headers['Content-Length'] = size.to_s
|
120
|
-
[ status, headers, out ]
|
121
|
-
end
|
122
|
-
|
123
|
-
# ensures rack.input is a file handle that we can redirect stdin to
|
124
|
-
def force_file_input(env)
|
125
|
-
inp = env['rack.input']
|
126
|
-
# inp could be a StringIO or StringIO-like object
|
127
|
-
if inp.respond_to?(:size) && inp.size == 0
|
128
|
-
::File.open('/dev/null', 'rb')
|
129
|
-
else
|
130
|
-
tmp = Unicorn::TmpIO.new
|
131
|
-
|
132
|
-
buf = inp.read(CHUNK_SIZE)
|
133
|
-
begin
|
134
|
-
tmp.syswrite(buf)
|
135
|
-
end while inp.read(CHUNK_SIZE, buf)
|
136
|
-
tmp.sysseek(0)
|
137
|
-
tmp
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
# rack.errors this may not be an IO object, so we couldn't
|
142
|
-
# just redirect the CGI executable to that earlier.
|
143
|
-
def write_errors(env, err, status)
|
144
|
-
err.seek(0)
|
145
|
-
dst = env['rack.errors']
|
146
|
-
pid = status.pid
|
147
|
-
dst.write("#{pid}: #{args.inspect} status=#{status} stderr:\n")
|
148
|
-
err.each_line { |line| dst.write("#{pid}: #{line}") }
|
149
|
-
dst.flush
|
150
|
-
end
|
151
|
-
|
152
|
-
end
|
153
|
-
|
154
|
-
end
|