unicorn 4.9.0 → 5.0.1

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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +5 -0
  3. data/.manifest +3 -10
  4. data/Application_Timeouts +3 -3
  5. data/DESIGN +2 -4
  6. data/Documentation/unicorn.1.txt +8 -5
  7. data/Documentation/unicorn_rails.1.txt +2 -2
  8. data/FAQ +17 -8
  9. data/GIT-VERSION-FILE +1 -1
  10. data/GIT-VERSION-GEN +1 -1
  11. data/GNUmakefile +6 -1
  12. data/ISSUES +20 -28
  13. data/KNOWN_ISSUES +9 -9
  14. data/LATEST +28 -29
  15. data/Links +14 -17
  16. data/NEWS +159 -0
  17. data/PHILOSOPHY +0 -6
  18. data/README +22 -17
  19. data/SIGNALS +1 -1
  20. data/Sandbox +4 -4
  21. data/TUNING +11 -8
  22. data/bin/unicorn +1 -1
  23. data/bin/unicorn_rails +1 -1
  24. data/examples/nginx.conf +10 -11
  25. data/examples/unicorn.conf.rb +1 -4
  26. data/examples/unicorn.socket +11 -0
  27. data/examples/unicorn@.service +26 -0
  28. data/ext/unicorn_http/extconf.rb +1 -0
  29. data/ext/unicorn_http/httpdate.c +1 -1
  30. data/ext/unicorn_http/unicorn_http.c +267 -334
  31. data/ext/unicorn_http/unicorn_http.rl +89 -156
  32. data/lib/unicorn/configurator.rb +17 -31
  33. data/lib/unicorn/const.rb +2 -25
  34. data/lib/unicorn/http_request.rb +22 -33
  35. data/lib/unicorn/http_response.rb +13 -31
  36. data/lib/unicorn/http_server.rb +129 -122
  37. data/lib/unicorn/socket_helper.rb +36 -72
  38. data/lib/unicorn/stream_input.rb +3 -3
  39. data/lib/unicorn/tmpio.rb +0 -5
  40. data/lib/unicorn/util.rb +2 -1
  41. data/lib/unicorn/version.rb +1 -1
  42. data/lib/unicorn/worker.rb +3 -15
  43. data/lib/unicorn.rb +10 -18
  44. data/man/man1/unicorn.1 +7 -5
  45. data/man/man1/unicorn_rails.1 +2 -2
  46. data/t/hijack.ru +2 -1
  47. data/t/t0200-rack-hijack.sh +5 -2
  48. data/test/exec/test_exec.rb +52 -0
  49. data/test/test_helper.rb +3 -2
  50. data/test/unit/test_http_parser_ng.rb +16 -114
  51. data/test/unit/test_response.rb +28 -16
  52. data/test/unit/test_socket_helper.rb +1 -1
  53. data/unicorn.gemspec +10 -1
  54. metadata +13 -23
  55. data/examples/git.ru +0 -13
  56. data/lib/unicorn/app/exec_cgi.rb +0 -154
  57. data/lib/unicorn/app/inetd.rb +0 -109
  58. data/lib/unicorn/ssl_client.rb +0 -11
  59. data/lib/unicorn/ssl_configurator.rb +0 -104
  60. data/lib/unicorn/ssl_server.rb +0 -42
  61. data/t/t0016-trust-x-forwarded-false.sh +0 -30
  62. data/t/t0017-trust-x-forwarded-true.sh +0 -30
  63. data/test/unit/test_http_parser_xftrust.rb +0 -38
  64. data/test/unit/test_sni_hostnames.rb +0 -47
@@ -33,12 +33,20 @@ class ResponseTest < Test::Unit::TestCase
33
33
  assert out.length > 0, "output didn't have data"
34
34
  end
35
35
 
36
+ # ref: <CAO47=rJa=zRcLn_Xm4v2cHPr6c0UswaFC_omYFEH+baSxHOWKQ@mail.gmail.com>
37
+ def test_response_header_broken_nil
38
+ out = StringIO.new
39
+ http_response_write(out, 200, {"Nil" => nil}, %w(hysterical raisin))
40
+ assert ! out.closed?
41
+
42
+ assert_match %r{^Nil: \r\n}sm, out.string, 'nil accepted'
43
+ end
44
+
36
45
  def test_response_string_status
37
46
  out = StringIO.new
38
47
  http_response_write(out,'200', {}, [])
39
48
  assert ! out.closed?
40
49
  assert out.length > 0, "output didn't have data"
41
- assert_equal 1, out.string.split(/\r\n/).grep(/^Status: 200 OK/).size
42
50
  end
43
51
 
44
52
  def test_response_200
@@ -71,18 +79,6 @@ class ResponseTest < Test::Unit::TestCase
71
79
  out = StringIO.new
72
80
  http_response_write(out,200, {"X-Whatever" => "stuff"}, [])
73
81
  assert ! out.closed?
74
- assert_equal 1, out.string.split(/\r\n/).grep(/^Status: 200 OK/i).size
75
- end
76
-
77
- def test_body_closed
78
- expect_body = %w(1 2 3 4).join("\n")
79
- body = StringIO.new(expect_body)
80
- body.rewind
81
- out = StringIO.new
82
- http_response_write(out,200, {}, body)
83
- assert ! out.closed?
84
- assert body.closed?
85
- assert_match(expect_body, out.string.split(/\r\n/).last)
86
82
  end
87
83
 
88
84
  def test_unknown_status_pass_through
@@ -91,9 +87,25 @@ class ResponseTest < Test::Unit::TestCase
91
87
  assert ! out.closed?
92
88
  headers = out.string.split(/\r\n\r\n/).first.split(/\r\n/)
93
89
  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
90
  end
98
91
 
92
+ def test_modified_rack_http_status_codes_late
93
+ r, w = IO.pipe
94
+ pid = fork do
95
+ r.close
96
+ # Users may want to globally override the status text associated
97
+ # with an HTTP status code in their app.
98
+ Rack::Utils::HTTP_STATUS_CODES[200] = "HI"
99
+ http_response_write(w, 200, {}, [])
100
+ w.close
101
+ end
102
+ w.close
103
+ assert_equal "HTTP/1.1 200 HI\r\n", r.gets
104
+ r.read # just drain the pipe
105
+ pid, status = Process.waitpid2(pid)
106
+ assert status.success?, status.inspect
107
+ ensure
108
+ r.close
109
+ w.close unless w.closed?
110
+ end
99
111
  end
@@ -189,7 +189,7 @@ class TestSocketHelper < Test::Unit::TestCase
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(Socket::SOL_SOCKET, SO_REUSEPORT).unpack('i')[0]
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)
data/unicorn.gemspec CHANGED
@@ -26,6 +26,11 @@ Gem::Specification.new do |s|
26
26
  s.homepage = Olddoc.config['rdoc_url']
27
27
  s.test_files = test_files
28
28
 
29
+ # technically we need ">= 1.9.3", too, but avoid the array here since
30
+ # old rubygems versions (1.8.23.2 at least) do not support multiple
31
+ # version requirements here.
32
+ s.required_ruby_version = '< 3.0'
33
+
29
34
  # for people that are absolutely stuck on Rails 2.3.2 and can't
30
35
  # up/downgrade to any other version, the Rack dependency may be
31
36
  # commented out. Nevertheless, upgrading to Rails 2.3.4 or later is
@@ -37,5 +42,9 @@ Gem::Specification.new do |s|
37
42
  s.add_development_dependency('test-unit', '~> 3.0')
38
43
  s.add_development_dependency('olddoc', '~> 1.0')
39
44
 
40
- s.licenses = ["GPLv2+", "Ruby 1.8"]
45
+ # Note: To avoid ambiguity, we intentionally avoid the SPDX-compatible
46
+ # 'Ruby' here since Ruby 1.9.3 switched to BSD-2-Clause, but we
47
+ # inherited our license from Mongrel when Ruby was at 1.8.
48
+ # We cannot automatically switch licenses when Ruby changes.
49
+ s.licenses = ['GPL-2.0+', 'Ruby-1.8']
41
50
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unicorn
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.9.0
4
+ version: 5.0.1
5
5
  platform: ruby
6
6
  authors:
7
- - Unicorn hackers
7
+ - unicorn hackers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-24 00:00:00.000000000 Z
11
+ date: 2015-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -81,11 +81,11 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '1.0'
83
83
  description: |-
84
- \Unicorn is an HTTP server for Rack applications designed to only serve
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
- both the the request and response in between \Unicorn and slow clients.
88
+ both the the request and response in between unicorn and slow clients.
89
89
  email: unicorn-public@bogomips.org
90
90
  executables:
91
91
  - unicorn
@@ -124,6 +124,7 @@ extra_rdoc_files:
124
124
  files:
125
125
  - ".CHANGELOG.old"
126
126
  - ".document"
127
+ - ".gitattributes"
127
128
  - ".gitignore"
128
129
  - ".mailmap"
129
130
  - ".manifest"
@@ -160,13 +161,14 @@ files:
160
161
  - bin/unicorn_rails
161
162
  - examples/big_app_gc.rb
162
163
  - examples/echo.ru
163
- - examples/git.ru
164
164
  - examples/init.sh
165
165
  - examples/logger_mp_safe.rb
166
166
  - examples/logrotate.conf
167
167
  - examples/nginx.conf
168
168
  - examples/unicorn.conf.minimal.rb
169
169
  - examples/unicorn.conf.rb
170
+ - examples/unicorn.socket
171
+ - examples/unicorn@.service
170
172
  - ext/unicorn_http/CFLAGS
171
173
  - ext/unicorn_http/c_util.h
172
174
  - ext/unicorn_http/common_field_optimization.h
@@ -178,8 +180,6 @@ files:
178
180
  - ext/unicorn_http/unicorn_http.rl
179
181
  - ext/unicorn_http/unicorn_http_common.rl
180
182
  - lib/unicorn.rb
181
- - lib/unicorn/app/exec_cgi.rb
182
- - lib/unicorn/app/inetd.rb
183
183
  - lib/unicorn/app/old_rails.rb
184
184
  - lib/unicorn/app/old_rails/static.rb
185
185
  - lib/unicorn/cgi_wrapper.rb
@@ -192,9 +192,6 @@ files:
192
192
  - lib/unicorn/oob_gc.rb
193
193
  - lib/unicorn/preread_input.rb
194
194
  - lib/unicorn/socket_helper.rb
195
- - lib/unicorn/ssl_client.rb
196
- - lib/unicorn/ssl_configurator.rb
197
- - lib/unicorn/ssl_server.rb
198
195
  - lib/unicorn/stream_input.rb
199
196
  - lib/unicorn/tee_input.rb
200
197
  - lib/unicorn/tmpio.rb
@@ -245,8 +242,6 @@ files:
245
242
  - t/t0014-rewindable-input-true.sh
246
243
  - t/t0014.ru
247
244
  - t/t0015-configurator-internals.sh
248
- - t/t0016-trust-x-forwarded-false.sh
249
- - t/t0017-trust-x-forwarded-true.sh
250
245
  - t/t0018-write-on-close.sh
251
246
  - t/t0019-max_header_len.sh
252
247
  - t/t0020-at_exit-handler.sh
@@ -273,12 +268,10 @@ files:
273
268
  - test/unit/test_droplet.rb
274
269
  - test/unit/test_http_parser.rb
275
270
  - test/unit/test_http_parser_ng.rb
276
- - test/unit/test_http_parser_xftrust.rb
277
271
  - test/unit/test_request.rb
278
272
  - test/unit/test_response.rb
279
273
  - test/unit/test_server.rb
280
274
  - test/unit/test_signals.rb
281
- - test/unit/test_sni_hostnames.rb
282
275
  - test/unit/test_socket_helper.rb
283
276
  - test/unit/test_stream_input.rb
284
277
  - test/unit/test_tee_input.rb
@@ -289,8 +282,8 @@ files:
289
282
  - unicorn_rails_1
290
283
  homepage: http://unicorn.bogomips.org/
291
284
  licenses:
292
- - GPLv2+
293
- - Ruby 1.8
285
+ - GPL-2.0+
286
+ - Ruby-1.8
294
287
  metadata: {}
295
288
  post_install_message:
296
289
  rdoc_options: []
@@ -298,9 +291,9 @@ require_paths:
298
291
  - lib
299
292
  required_ruby_version: !ruby/object:Gem::Requirement
300
293
  requirements:
301
- - - ">="
294
+ - - "<"
302
295
  - !ruby/object:Gem::Version
303
- version: '0'
296
+ version: '3.0'
304
297
  required_rubygems_version: !ruby/object:Gem::Requirement
305
298
  requirements:
306
299
  - - ">="
@@ -308,7 +301,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
308
301
  version: '0'
309
302
  requirements: []
310
303
  rubyforge_project:
311
- rubygems_version: 2.4.5
304
+ rubygems_version: 2.5.0
312
305
  signing_key:
313
306
  specification_version: 4
314
307
  summary: Rack HTTP server for fast clients and Unix
@@ -316,9 +309,6 @@ test_files:
316
309
  - test/unit/test_configurator.rb
317
310
  - test/unit/test_http_parser.rb
318
311
  - test/unit/test_http_parser_ng.rb
319
- - test/unit/test_http_parser_xftrust.rb
320
312
  - test/unit/test_request.rb
321
- - test/unit/test_response.rb
322
313
  - test/unit/test_server.rb
323
- - test/unit/test_sni_hostnames.rb
324
314
  - 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
- )
@@ -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
@@ -1,109 +0,0 @@
1
- # -*- encoding: binary -*-
2
- # :enddoc:
3
- # Copyright (c) 2009 Eric Wong
4
- # You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
5
- # the GPLv2+ (GPLv3+ preferred)
6
-
7
- # this class *must* be used with Rack::Chunked
8
- module Unicorn::App
9
- class Inetd < Struct.new(:cmd)
10
-
11
- class CatBody < Struct.new(:errors, :err_rd, :out_rd, :pid_map)
12
- def initialize(env, cmd)
13
- self.errors = env['rack.errors']
14
- in_rd, in_wr = IO.pipe
15
- self.err_rd, err_wr = IO.pipe
16
- self.out_rd, out_wr = IO.pipe
17
-
18
- cmd_pid = fork {
19
- inp, out, err = (0..2).map { |i| IO.new(i) }
20
- inp.reopen(in_rd)
21
- out.reopen(out_wr)
22
- err.reopen(err_wr)
23
- [ in_rd, in_wr, err_rd, err_wr, out_rd, out_wr ].each { |i| i.close }
24
- exec(*cmd)
25
- }
26
- [ in_rd, err_wr, out_wr ].each { |io| io.close }
27
- [ in_wr, err_rd, out_rd ].each { |io| io.binmode }
28
- in_wr.sync = true
29
-
30
- # Unfortunately, input here must be processed inside a seperate
31
- # thread/process using blocking I/O since env['rack.input'] is not
32
- # IO.select-able and attempting to make it so would trip Rack::Lint
33
- inp_pid = fork {
34
- input = env['rack.input']
35
- [ err_rd, out_rd ].each { |io| io.close }
36
-
37
- # this is dependent on input.read having readpartial semantics:
38
- buf = input.read(16384)
39
- begin
40
- in_wr.write(buf)
41
- end while input.read(16384, buf)
42
- }
43
- in_wr.close
44
- self.pid_map = {
45
- inp_pid => 'input streamer',
46
- cmd_pid => cmd.inspect,
47
- }
48
- end
49
-
50
- def each
51
- begin
52
- rd, = IO.select([err_rd, out_rd])
53
- rd && rd.first or next
54
-
55
- if rd.include?(err_rd)
56
- begin
57
- errors.write(err_rd.read_nonblock(16384))
58
- rescue Errno::EINTR
59
- rescue Errno::EAGAIN
60
- break
61
- end while true
62
- end
63
-
64
- rd.include?(out_rd) or next
65
-
66
- begin
67
- yield out_rd.read_nonblock(16384)
68
- rescue Errno::EINTR
69
- rescue Errno::EAGAIN
70
- break
71
- end while true
72
- rescue EOFError,Errno::EPIPE,Errno::EBADF,Errno::EINVAL
73
- break
74
- end while true
75
-
76
- self
77
- end
78
-
79
- def close
80
- pid_map.each { |pid, str|
81
- begin
82
- pid, status = Process.waitpid2(pid)
83
- status.success? or
84
- errors.write("#{str}: #{status.inspect} (PID:#{pid})\n")
85
- rescue Errno::ECHILD
86
- errors.write("Failed to reap #{str} (PID:#{pid})\n")
87
- end
88
- }
89
- out_rd.close
90
- err_rd.close
91
- end
92
-
93
- end
94
-
95
- def initialize(*cmd)
96
- self.cmd = cmd
97
- end
98
-
99
- def call(env)
100
- /\A100-continue\z/i =~ env[Unicorn::Const::HTTP_EXPECT] and
101
- return [ 100, {} , [] ]
102
-
103
- [ 200, { 'Content-Type' => 'application/octet-stream' },
104
- CatBody.new(env, cmd) ]
105
- end
106
-
107
- end
108
-
109
- end
@@ -1,11 +0,0 @@
1
- # -*- encoding: binary -*-
2
- # :stopdoc:
3
- class Unicorn::SSLClient < Kgio::SSL
4
- alias write kgio_write
5
- alias close kgio_close
6
-
7
- # this is no-op for now, to be fixed in kgio-monkey if people care
8
- # about SSL support...
9
- def shutdown(how = nil)
10
- end
11
- end
@@ -1,104 +0,0 @@
1
- # -*- encoding: binary -*-
2
- # :stopdoc:
3
- # This module is included in Unicorn::Configurator
4
- # :startdoc:
5
- #
6
- module Unicorn::SSLConfigurator
7
- def ssl(&block)
8
- ssl_require!
9
- before = @set[:listeners].dup
10
- opts = @set[:ssl_opts] = {}
11
- yield
12
- (@set[:listeners] - before).each do |address|
13
- (@set[:listener_opts][address] ||= {})[:ssl_opts] = opts
14
- end
15
- ensure
16
- @set.delete(:ssl_opts)
17
- end
18
-
19
- def ssl_certificate(file)
20
- ssl_set(:ssl_certificate, file)
21
- end
22
-
23
- def ssl_certificate_key(file)
24
- ssl_set(:ssl_certificate_key, file)
25
- end
26
-
27
- def ssl_client_certificate(file)
28
- ssl_set(:ssl_client_certificate, file)
29
- end
30
-
31
- def ssl_dhparam(file)
32
- ssl_set(:ssl_dhparam, file)
33
- end
34
-
35
- def ssl_ciphers(openssl_cipherlist_spec)
36
- ssl_set(:ssl_ciphers, openssl_cipherlist_spec)
37
- end
38
-
39
- def ssl_crl(file)
40
- ssl_set(:ssl_crl, file)
41
- end
42
-
43
- def ssl_prefer_server_ciphers(bool)
44
- ssl_set(:ssl_prefer_server_ciphers, check_bool(bool))
45
- end
46
-
47
- def ssl_protocols(list)
48
- ssl_set(:ssl_protocols, list)
49
- end
50
-
51
- def ssl_verify_client(on_off_optional)
52
- ssl_set(:ssl_verify_client, on_off_optional)
53
- end
54
-
55
- def ssl_session_timeout(seconds)
56
- ssl_set(:ssl_session_timeout, seconds)
57
- end
58
-
59
- def ssl_verify_depth(depth)
60
- ssl_set(:ssl_verify_depth, depth)
61
- end
62
-
63
- # Allows specifying an engine for OpenSSL to use. We have not been
64
- # able to successfully test this feature due to a lack of hardware,
65
- # Reports of success or patches to unicorn-public@bogomips.org is
66
- # greatly appreciated.
67
- def ssl_engine(engine)
68
- ssl_warn_global(:ssl_engine)
69
- ssl_require!
70
- OpenSSL::Engine.load
71
- OpenSSL::Engine.by_id(engine)
72
- @set[:ssl_engine] = engine
73
- end
74
-
75
- def ssl_compression(bool)
76
- # OpenSSL uses the SSL_OP_NO_COMPRESSION flag, Flipper follows suit
77
- # with :ssl_no_compression, but we negate it to avoid exposing double
78
- # negatives to the user.
79
- ssl_set(:ssl_no_compression, check_bool(:ssl_compression, ! bool))
80
- end
81
-
82
- private
83
-
84
- def ssl_warn_global(func) # :nodoc:
85
- Hash === @set[:ssl_opts] or return
86
- warn("`#{func}' affects all SSL contexts in this process, " \
87
- "not just this block")
88
- end
89
-
90
- def ssl_set(key, value) # :nodoc:
91
- cur = @set[:ssl_opts]
92
- Hash === cur or
93
- raise ArgumentError, "#{key} must be called inside an `ssl' block"
94
- cur[key] = value
95
- end
96
-
97
- def ssl_require! # :nodoc:
98
- require "flipper"
99
- require "unicorn/ssl_client"
100
- rescue LoadError
101
- warn "install 'kgio-monkey' for SSL support"
102
- raise
103
- end
104
- end
@@ -1,42 +0,0 @@
1
- # -*- encoding: binary -*-
2
- # :stopdoc:
3
- # this module is meant to be included in Unicorn::HttpServer
4
- # It is an implementation detail and NOT meant for users.
5
- module Unicorn::SSLServer
6
- attr_accessor :ssl_engine
7
-
8
- def ssl_enable!
9
- sni_hostnames = rack_sni_hostnames(@app)
10
- seen = {} # we map a single SSLContext to multiple listeners
11
- listener_ctx = {}
12
- @listener_opts.each do |address, address_opts|
13
- ssl_opts = address_opts[:ssl_opts] or next
14
- listener_ctx[address] = seen[ssl_opts.object_id] ||= begin
15
- unless sni_hostnames.empty?
16
- ssl_opts = ssl_opts.dup
17
- ssl_opts[:sni_hostnames] = sni_hostnames
18
- end
19
- ctx = Flipper.ssl_context(ssl_opts)
20
- # FIXME: make configurable
21
- ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_OFF
22
- ctx
23
- end
24
- end
25
- Unicorn::HttpServer::LISTENERS.each do |listener|
26
- ctx = listener_ctx[sock_name(listener)] or next
27
- listener.extend(Kgio::SSLServer)
28
- listener.ssl_ctx = ctx
29
- listener.kgio_ssl_class = Unicorn::SSLClient
30
- end
31
- end
32
-
33
- # ugh, this depends on Rack internals...
34
- def rack_sni_hostnames(rack_app) # :nodoc:
35
- hostnames = {}
36
- if Rack::URLMap === rack_app
37
- mapping = rack_app.instance_variable_get(:@mapping)
38
- mapping.each { |hostname,_,_,_| hostnames[hostname] = true }
39
- end
40
- hostnames.keys
41
- end
42
- end