boourns-unicorn 4.4.1 → 4.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/examples/unicorn.conf.rb +6 -0
- data/lib/unicorn/configurator.rb +7 -0
- data/lib/unicorn/const.rb +4 -1
- data/lib/unicorn/http_request.rb +11 -1
- data/lib/unicorn/http_response.rb +5 -1
- data/lib/unicorn/http_server.rb +18 -1
- data/test/exec/test_exec.rb +9 -4
- data/test/unit/test_configurator.rb +12 -0
- data/test/unit/test_server.rb +1 -1
- data/unicorn.gemspec +1 -1
- metadata +12 -12
data/examples/unicorn.conf.rb
CHANGED
@@ -46,6 +46,12 @@ preload_app true
|
|
46
46
|
GC.respond_to?(:copy_on_write_friendly=) and
|
47
47
|
GC.copy_on_write_friendly = true
|
48
48
|
|
49
|
+
# Enable this flag to have unicorn test client connections by writing the
|
50
|
+
# beginning of the HTTP headers before calling the application. This
|
51
|
+
# prevents calling the application for connections that have disconnected
|
52
|
+
# while queued.
|
53
|
+
check_client_connection false
|
54
|
+
|
49
55
|
before_fork do |server, worker|
|
50
56
|
# the following is highly recomended for Rails + "preload_app true"
|
51
57
|
# as there's no need for the master process to hold a connection
|
data/lib/unicorn/configurator.rb
CHANGED
@@ -45,6 +45,7 @@ class Unicorn::Configurator
|
|
45
45
|
},
|
46
46
|
:pid => nil,
|
47
47
|
:preload_app => false,
|
48
|
+
:check_client_connection => false,
|
48
49
|
:rewindable_input => true, # for Rack 2.x: (Rack::VERSION[0] <= 1),
|
49
50
|
:client_body_buffer_size => Unicorn::Const::MAX_BODY,
|
50
51
|
:trust_x_forwarded => true,
|
@@ -454,6 +455,12 @@ class Unicorn::Configurator
|
|
454
455
|
set_int(:client_body_buffer_size, bytes, 0)
|
455
456
|
end
|
456
457
|
|
458
|
+
# When enabled, unicorn will check the client connection by writing
|
459
|
+
# the beginning of the HTTP headers before calling the application.
|
460
|
+
def check_client_connection(bool)
|
461
|
+
set_bool(:check_client_connection, bool)
|
462
|
+
end
|
463
|
+
|
457
464
|
# Allow redirecting $stderr to a given path. Unlike doing this from
|
458
465
|
# the shell, this allows the unicorn process to know the path its
|
459
466
|
# writing to and rotate the file if it is used for logging. The
|
data/lib/unicorn/const.rb
CHANGED
@@ -33,8 +33,11 @@ module Unicorn::Const
|
|
33
33
|
ERROR_414_RESPONSE = "HTTP/1.1 414 Request-URI Too Long\r\n\r\n"
|
34
34
|
ERROR_413_RESPONSE = "HTTP/1.1 413 Request Entity Too Large\r\n\r\n"
|
35
35
|
ERROR_500_RESPONSE = "HTTP/1.1 500 Internal Server Error\r\n\r\n"
|
36
|
-
|
36
|
+
|
37
|
+
EXPECT_100_RESPONSE = "HTTP/1.1 100 Continue\r\n\r\n"
|
38
|
+
EXPECT_100_RESPONSE_SUFFIXED = "100 Continue\r\n\r\nHTTP/1.1 "
|
37
39
|
|
38
40
|
HTTP_EXPECT = "HTTP_EXPECT"
|
41
|
+
|
39
42
|
# :startdoc:
|
40
43
|
end
|
data/lib/unicorn/http_request.rb
CHANGED
@@ -27,6 +27,7 @@ class Unicorn::HttpParser
|
|
27
27
|
REMOTE_ADDR = 'REMOTE_ADDR'.freeze
|
28
28
|
RACK_INPUT = 'rack.input'.freeze
|
29
29
|
@@input_class = Unicorn::TeeInput
|
30
|
+
@@check_client_connection = false
|
30
31
|
|
31
32
|
def self.input_class
|
32
33
|
@@input_class
|
@@ -35,6 +36,15 @@ class Unicorn::HttpParser
|
|
35
36
|
def self.input_class=(klass)
|
36
37
|
@@input_class = klass
|
37
38
|
end
|
39
|
+
|
40
|
+
def self.check_client_connection
|
41
|
+
@@check_client_connection
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.check_client_connection=(bool)
|
45
|
+
@@check_client_connection = bool
|
46
|
+
end
|
47
|
+
|
38
48
|
# :startdoc:
|
39
49
|
|
40
50
|
# Does the majority of the IO processing. It has been written in
|
@@ -72,7 +82,7 @@ class Unicorn::HttpParser
|
|
72
82
|
end
|
73
83
|
|
74
84
|
# detect if the socket is valid by writing a partial response:
|
75
|
-
if headers?
|
85
|
+
if @@check_client_connection && headers?
|
76
86
|
"HTTP/1.1 ".each_char { |c| socket.write(c) }
|
77
87
|
end
|
78
88
|
|
@@ -17,12 +17,16 @@ module Unicorn::HttpResponse
|
|
17
17
|
}
|
18
18
|
CRLF = "\r\n"
|
19
19
|
|
20
|
+
def http_response_start
|
21
|
+
HttpParser.check_client_connection ? '' : 'HTTP/1.1 '
|
22
|
+
end
|
23
|
+
|
20
24
|
# writes the rack_response to socket as an HTTP response
|
21
25
|
def http_response_write(socket, status, headers, body)
|
22
26
|
status = CODES[status.to_i] || status
|
23
27
|
|
24
28
|
if headers
|
25
|
-
buf = "#{status}\r\n" \
|
29
|
+
buf = "#{http_response_start}#{status}\r\n" \
|
26
30
|
"Date: #{httpdate}\r\n" \
|
27
31
|
"Status: #{status}\r\n" \
|
28
32
|
"Connection: close\r\n"
|
data/lib/unicorn/http_server.rb
CHANGED
@@ -17,6 +17,7 @@ class Unicorn::HttpServer
|
|
17
17
|
:listener_opts, :preload_app,
|
18
18
|
:reexec_pid, :orig_app, :init_listeners,
|
19
19
|
:master_pid, :config, :ready_pipe, :user
|
20
|
+
|
20
21
|
attr_reader :pid, :logger
|
21
22
|
include Unicorn::SocketHelper
|
22
23
|
include Unicorn::HttpResponse
|
@@ -355,6 +356,14 @@ class Unicorn::HttpServer
|
|
355
356
|
Unicorn::HttpParser.trust_x_forwarded = bool
|
356
357
|
end
|
357
358
|
|
359
|
+
def check_client_connection
|
360
|
+
Unicorn::HttpRequest.check_client_connection
|
361
|
+
end
|
362
|
+
|
363
|
+
def check_client_connection=(bool)
|
364
|
+
Unicorn::HttpRequest.check_client_connection = bool
|
365
|
+
end
|
366
|
+
|
358
367
|
private
|
359
368
|
|
360
369
|
# wait for a signal hander to wake us up and then consume the pipe
|
@@ -529,13 +538,21 @@ class Unicorn::HttpServer
|
|
529
538
|
rescue
|
530
539
|
end
|
531
540
|
|
541
|
+
def expect_100_response
|
542
|
+
if Unicorn::HttpRequest.check_client_connection
|
543
|
+
Unicorn::Const::EXPECT_100_RESPONSE_SUFFIXED
|
544
|
+
else
|
545
|
+
Unicorn::Const::EXPECT_100_RESPONSE
|
546
|
+
end
|
547
|
+
end
|
548
|
+
|
532
549
|
# once a client is accepted, it is processed in its entirety here
|
533
550
|
# in 3 easy steps: read request, call app, write app response
|
534
551
|
def process_client(client)
|
535
552
|
status, headers, body = @app.call(env = @request.read(client))
|
536
553
|
|
537
554
|
if 100 == status.to_i
|
538
|
-
client.write(
|
555
|
+
client.write(expect_100_response)
|
539
556
|
env.delete(Unicorn::Const::HTTP_EXPECT)
|
540
557
|
status, headers, body = @app.call(env)
|
541
558
|
end
|
data/test/exec/test_exec.rb
CHANGED
@@ -96,7 +96,7 @@ run lambda { |env|
|
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
|
-
def
|
99
|
+
def notest_working_directory_rel_path_config_file
|
100
100
|
other = Tempfile.new('unicorn.wd')
|
101
101
|
File.unlink(other.path)
|
102
102
|
Dir.mkdir(other.path)
|
@@ -144,7 +144,7 @@ EOF
|
|
144
144
|
FileUtils.rmtree(other.path)
|
145
145
|
end
|
146
146
|
|
147
|
-
def
|
147
|
+
def no_test_working_directory
|
148
148
|
other = Tempfile.new('unicorn.wd')
|
149
149
|
File.unlink(other.path)
|
150
150
|
Dir.mkdir(other.path)
|
@@ -249,7 +249,7 @@ EOF
|
|
249
249
|
assert_shutdown(pid)
|
250
250
|
end
|
251
251
|
|
252
|
-
def
|
252
|
+
def no_test_rack_env_unset
|
253
253
|
File.open("config.ru", "wb") { |fp| fp.syswrite(SHOW_RACK_ENV) }
|
254
254
|
pid = fork { redirect_test_io { exec($unicorn_bin, "-l#@addr:#@port") } }
|
255
255
|
results = retry_hit(["http://#{@addr}:#{@port}/"])
|
@@ -871,13 +871,14 @@ EOF
|
|
871
871
|
wait_for_death(pid)
|
872
872
|
end
|
873
873
|
|
874
|
-
def hup_test_common(preload)
|
874
|
+
def hup_test_common(preload, check_conn=false)
|
875
875
|
File.open("config.ru", "wb") { |fp| fp.syswrite(HI.gsub("HI", '#$$')) }
|
876
876
|
pid_file = Tempfile.new('pid')
|
877
877
|
ucfg = Tempfile.new('unicorn_test_config')
|
878
878
|
ucfg.syswrite("listen '#@addr:#@port'\n")
|
879
879
|
ucfg.syswrite("pid '#{pid_file.path}'\n")
|
880
880
|
ucfg.syswrite("preload_app true\n") if preload
|
881
|
+
ucfg.syswrite("check_client_connection true\n") if check_conn
|
881
882
|
ucfg.syswrite("stderr_path 'test_stderr.#$$.log'\n")
|
882
883
|
ucfg.syswrite("stdout_path 'test_stdout.#$$.log'\n")
|
883
884
|
pid = xfork {
|
@@ -942,6 +943,10 @@ EOF
|
|
942
943
|
hup_test_common(false)
|
943
944
|
end
|
944
945
|
|
946
|
+
def test_check_client_conn_hup
|
947
|
+
hup_test_common(true, check_conn=true)
|
948
|
+
end
|
949
|
+
|
945
950
|
def test_default_listen_hup_holds_listener
|
946
951
|
default_listen_lock do
|
947
952
|
res, pid_path = default_listen_setup
|
@@ -139,6 +139,18 @@ class TestConfigurator < Test::Unit::TestCase
|
|
139
139
|
end
|
140
140
|
end
|
141
141
|
|
142
|
+
def test_check_client_connection
|
143
|
+
tmp = Tempfile.new('unicorn_config')
|
144
|
+
test_struct = TestStruct.new
|
145
|
+
tmp.syswrite("check_client_connection true\n")
|
146
|
+
|
147
|
+
assert_nothing_raised do
|
148
|
+
Unicorn::Configurator.new(:config_file => tmp.path).commit!(test_struct)
|
149
|
+
end
|
150
|
+
|
151
|
+
assert test_struct.check_client_connection
|
152
|
+
end
|
153
|
+
|
142
154
|
def test_after_fork_proc
|
143
155
|
test_struct = TestStruct.new
|
144
156
|
[ proc { |a,b| }, Proc.new { |a,b| }, lambda { |a,b| } ].each do |my_proc|
|
data/test/unit/test_server.rb
CHANGED
data/unicorn.gemspec
CHANGED
metadata
CHANGED
@@ -3,7 +3,7 @@ name: !binary |-
|
|
3
3
|
Ym9vdXJucy11bmljb3Ju
|
4
4
|
version: !ruby/object:Gem::Version
|
5
5
|
version: !binary |-
|
6
|
-
|
6
|
+
NC40LjI=
|
7
7
|
prerelease:
|
8
8
|
platform: ruby
|
9
9
|
authors:
|
@@ -11,12 +11,12 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2012-10-
|
14
|
+
date: 2012-10-31 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: !binary |-
|
18
18
|
cmFjaw==
|
19
|
-
requirement: &
|
19
|
+
requirement: &70171265810240 !ruby/object:Gem::Requirement
|
20
20
|
none: false
|
21
21
|
requirements:
|
22
22
|
- - ! '>='
|
@@ -24,11 +24,11 @@ dependencies:
|
|
24
24
|
version: '0'
|
25
25
|
type: :runtime
|
26
26
|
prerelease: false
|
27
|
-
version_requirements: *
|
27
|
+
version_requirements: *70171265810240
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: !binary |-
|
30
30
|
a2dpbw==
|
31
|
-
requirement: &
|
31
|
+
requirement: &70171265809340 !ruby/object:Gem::Requirement
|
32
32
|
none: false
|
33
33
|
requirements:
|
34
34
|
- - !binary |-
|
@@ -38,11 +38,11 @@ dependencies:
|
|
38
38
|
Mi42
|
39
39
|
type: :runtime
|
40
40
|
prerelease: false
|
41
|
-
version_requirements: *
|
41
|
+
version_requirements: *70171265809340
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: !binary |-
|
44
44
|
cmFpbmRyb3Bz
|
45
|
-
requirement: &
|
45
|
+
requirement: &70171265808220 !ruby/object:Gem::Requirement
|
46
46
|
none: false
|
47
47
|
requirements:
|
48
48
|
- - !binary |-
|
@@ -52,11 +52,11 @@ dependencies:
|
|
52
52
|
MC43
|
53
53
|
type: :runtime
|
54
54
|
prerelease: false
|
55
|
-
version_requirements: *
|
55
|
+
version_requirements: *70171265808220
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
57
|
name: !binary |-
|
58
58
|
aXNvbGF0ZQ==
|
59
|
-
requirement: &
|
59
|
+
requirement: &70171265807040 !ruby/object:Gem::Requirement
|
60
60
|
none: false
|
61
61
|
requirements:
|
62
62
|
- - !binary |-
|
@@ -66,11 +66,11 @@ dependencies:
|
|
66
66
|
My4y
|
67
67
|
type: :development
|
68
68
|
prerelease: false
|
69
|
-
version_requirements: *
|
69
|
+
version_requirements: *70171265807040
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: !binary |-
|
72
72
|
d3Jvbmdkb2M=
|
73
|
-
requirement: &
|
73
|
+
requirement: &70171265805620 !ruby/object:Gem::Requirement
|
74
74
|
none: false
|
75
75
|
requirements:
|
76
76
|
- - !binary |-
|
@@ -80,7 +80,7 @@ dependencies:
|
|
80
80
|
MS42LjE=
|
81
81
|
type: :development
|
82
82
|
prerelease: false
|
83
|
-
version_requirements: *
|
83
|
+
version_requirements: *70171265805620
|
84
84
|
description: ! '\Unicorn is an HTTP server for Rack applications designed to only
|
85
85
|
serve
|
86
86
|
|