boourns-unicorn 4.4.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 (155) hide show
  1. data/.CHANGELOG.old +25 -0
  2. data/.document +29 -0
  3. data/.gitignore +24 -0
  4. data/.mailmap +26 -0
  5. data/.wrongdoc.yml +10 -0
  6. data/Application_Timeouts +77 -0
  7. data/CONTRIBUTORS +35 -0
  8. data/COPYING +674 -0
  9. data/DESIGN +97 -0
  10. data/Documentation/.gitignore +5 -0
  11. data/Documentation/GNUmakefile +30 -0
  12. data/Documentation/unicorn.1.txt +174 -0
  13. data/Documentation/unicorn_rails.1.txt +175 -0
  14. data/FAQ +53 -0
  15. data/GIT-VERSION-GEN +40 -0
  16. data/GNUmakefile +267 -0
  17. data/HACKING +134 -0
  18. data/ISSUES +36 -0
  19. data/KNOWN_ISSUES +79 -0
  20. data/LICENSE +64 -0
  21. data/Links +56 -0
  22. data/PHILOSOPHY +145 -0
  23. data/README +149 -0
  24. data/Rakefile +97 -0
  25. data/SIGNALS +114 -0
  26. data/Sandbox +96 -0
  27. data/TODO +5 -0
  28. data/TUNING +98 -0
  29. data/bin/unicorn +121 -0
  30. data/bin/unicorn_rails +209 -0
  31. data/examples/big_app_gc.rb +2 -0
  32. data/examples/echo.ru +27 -0
  33. data/examples/git.ru +13 -0
  34. data/examples/init.sh +74 -0
  35. data/examples/logger_mp_safe.rb +25 -0
  36. data/examples/logrotate.conf +29 -0
  37. data/examples/nginx.conf +156 -0
  38. data/examples/unicorn.conf.minimal.rb +13 -0
  39. data/examples/unicorn.conf.rb +94 -0
  40. data/ext/unicorn_http/CFLAGS +13 -0
  41. data/ext/unicorn_http/c_util.h +124 -0
  42. data/ext/unicorn_http/common_field_optimization.h +111 -0
  43. data/ext/unicorn_http/ext_help.h +86 -0
  44. data/ext/unicorn_http/extconf.rb +10 -0
  45. data/ext/unicorn_http/global_variables.h +97 -0
  46. data/ext/unicorn_http/httpdate.c +82 -0
  47. data/ext/unicorn_http/unicorn_http.rl +1036 -0
  48. data/ext/unicorn_http/unicorn_http_common.rl +76 -0
  49. data/lib/unicorn.rb +107 -0
  50. data/lib/unicorn/app/exec_cgi.rb +154 -0
  51. data/lib/unicorn/app/inetd.rb +109 -0
  52. data/lib/unicorn/app/old_rails.rb +35 -0
  53. data/lib/unicorn/app/old_rails/static.rb +59 -0
  54. data/lib/unicorn/cgi_wrapper.rb +147 -0
  55. data/lib/unicorn/configurator.rb +630 -0
  56. data/lib/unicorn/const.rb +40 -0
  57. data/lib/unicorn/http_request.rb +83 -0
  58. data/lib/unicorn/http_response.rb +45 -0
  59. data/lib/unicorn/http_server.rb +755 -0
  60. data/lib/unicorn/launcher.rb +62 -0
  61. data/lib/unicorn/oob_gc.rb +71 -0
  62. data/lib/unicorn/preread_input.rb +33 -0
  63. data/lib/unicorn/socket_helper.rb +208 -0
  64. data/lib/unicorn/ssl_client.rb +11 -0
  65. data/lib/unicorn/ssl_configurator.rb +104 -0
  66. data/lib/unicorn/ssl_server.rb +42 -0
  67. data/lib/unicorn/stream_input.rb +149 -0
  68. data/lib/unicorn/tee_input.rb +126 -0
  69. data/lib/unicorn/tmpio.rb +29 -0
  70. data/lib/unicorn/util.rb +69 -0
  71. data/lib/unicorn/worker.rb +88 -0
  72. data/local.mk.sample +59 -0
  73. data/script/isolate_for_tests +32 -0
  74. data/setup.rb +1586 -0
  75. data/t/.gitignore +5 -0
  76. data/t/GNUmakefile +82 -0
  77. data/t/README +42 -0
  78. data/t/bin/content-md5-put +36 -0
  79. data/t/bin/sha1sum.rb +17 -0
  80. data/t/bin/unused_listen +40 -0
  81. data/t/bin/utee +12 -0
  82. data/t/broken-app.ru +12 -0
  83. data/t/detach.ru +11 -0
  84. data/t/env.ru +3 -0
  85. data/t/heartbeat-timeout.ru +12 -0
  86. data/t/listener_names.ru +4 -0
  87. data/t/my-tap-lib.sh +201 -0
  88. data/t/oob_gc.ru +21 -0
  89. data/t/oob_gc_path.ru +21 -0
  90. data/t/pid.ru +3 -0
  91. data/t/preread_input.ru +17 -0
  92. data/t/rack-input-tests.ru +21 -0
  93. data/t/sslgen.sh +71 -0
  94. data/t/t0000-http-basic.sh +50 -0
  95. data/t/t0001-reload-bad-config.sh +53 -0
  96. data/t/t0002-config-conflict.sh +49 -0
  97. data/t/t0002-parser-error.sh +94 -0
  98. data/t/t0003-working_directory.sh +51 -0
  99. data/t/t0004-heartbeat-timeout.sh +69 -0
  100. data/t/t0004-working_directory_broken.sh +24 -0
  101. data/t/t0005-working_directory_app.rb.sh +37 -0
  102. data/t/t0006-reopen-logs.sh +83 -0
  103. data/t/t0006.ru +13 -0
  104. data/t/t0007-working_directory_no_embed_cli.sh +44 -0
  105. data/t/t0008-back_out_of_upgrade.sh +110 -0
  106. data/t/t0009-broken-app.sh +56 -0
  107. data/t/t0009-winch_ttin.sh +59 -0
  108. data/t/t0010-reap-logging.sh +55 -0
  109. data/t/t0011-active-unix-socket.sh +79 -0
  110. data/t/t0012-reload-empty-config.sh +85 -0
  111. data/t/t0013-rewindable-input-false.sh +24 -0
  112. data/t/t0013.ru +12 -0
  113. data/t/t0014-rewindable-input-true.sh +24 -0
  114. data/t/t0014.ru +12 -0
  115. data/t/t0015-configurator-internals.sh +25 -0
  116. data/t/t0016-trust-x-forwarded-false.sh +30 -0
  117. data/t/t0017-trust-x-forwarded-true.sh +30 -0
  118. data/t/t0018-write-on-close.sh +23 -0
  119. data/t/t0019-max_header_len.sh +49 -0
  120. data/t/t0020-at_exit-handler.sh +49 -0
  121. data/t/t0021-process_detach.sh +29 -0
  122. data/t/t0022-listener_names-preload_app.sh +32 -0
  123. data/t/t0100-rack-input-tests.sh +124 -0
  124. data/t/t0116-client_body_buffer_size.sh +80 -0
  125. data/t/t0116.ru +16 -0
  126. data/t/t0600-https-server-basic.sh +48 -0
  127. data/t/t9000-preread-input.sh +48 -0
  128. data/t/t9001-oob_gc.sh +47 -0
  129. data/t/t9002-oob_gc-path.sh +75 -0
  130. data/t/test-lib.sh +113 -0
  131. data/t/write-on-close.ru +11 -0
  132. data/test/aggregate.rb +15 -0
  133. data/test/benchmark/README +50 -0
  134. data/test/benchmark/dd.ru +18 -0
  135. data/test/benchmark/stack.ru +8 -0
  136. data/test/exec/README +5 -0
  137. data/test/exec/test_exec.rb +1041 -0
  138. data/test/test_helper.rb +300 -0
  139. data/test/unit/test_configurator.rb +158 -0
  140. data/test/unit/test_droplet.rb +28 -0
  141. data/test/unit/test_http_parser.rb +860 -0
  142. data/test/unit/test_http_parser_ng.rb +716 -0
  143. data/test/unit/test_http_parser_xftrust.rb +38 -0
  144. data/test/unit/test_request.rb +197 -0
  145. data/test/unit/test_response.rb +99 -0
  146. data/test/unit/test_server.rb +289 -0
  147. data/test/unit/test_signals.rb +207 -0
  148. data/test/unit/test_sni_hostnames.rb +47 -0
  149. data/test/unit/test_socket_helper.rb +192 -0
  150. data/test/unit/test_stream_input.rb +204 -0
  151. data/test/unit/test_tee_input.rb +296 -0
  152. data/test/unit/test_upload.rb +306 -0
  153. data/test/unit/test_util.rb +99 -0
  154. data/unicorn.gemspec +44 -0
  155. metadata +333 -0
@@ -0,0 +1,62 @@
1
+ # -*- encoding: binary -*-
2
+
3
+ # :enddoc:
4
+ $stdout.sync = $stderr.sync = true
5
+ $stdin.binmode
6
+ $stdout.binmode
7
+ $stderr.binmode
8
+
9
+ require 'unicorn'
10
+
11
+ module Unicorn::Launcher
12
+
13
+ # We don't do a lot of standard daemonization stuff:
14
+ # * umask is whatever was set by the parent process at startup
15
+ # and can be set in config.ru and config_file, so making it
16
+ # 0000 and potentially exposing sensitive log data can be bad
17
+ # policy.
18
+ # * don't bother to chdir("/") here since unicorn is designed to
19
+ # run inside APP_ROOT. Unicorn will also re-chdir() to
20
+ # the directory it was started in when being re-executed
21
+ # to pickup code changes if the original deployment directory
22
+ # is a symlink or otherwise got replaced.
23
+ def self.daemonize!(options)
24
+ cfg = Unicorn::Configurator
25
+ $stdin.reopen("/dev/null")
26
+
27
+ # We only start a new process group if we're not being reexecuted
28
+ # and inheriting file descriptors from our parent
29
+ unless ENV['UNICORN_FD']
30
+ # grandparent - reads pipe, exits when master is ready
31
+ # \_ parent - exits immediately ASAP
32
+ # \_ unicorn master - writes to pipe when ready
33
+
34
+ rd, wr = IO.pipe
35
+ grandparent = $$
36
+ if fork
37
+ wr.close # grandparent does not write
38
+ else
39
+ rd.close # unicorn master does not read
40
+ Process.setsid
41
+ exit if fork # parent dies now
42
+ end
43
+
44
+ if grandparent == $$
45
+ # this will block until HttpServer#join runs (or it dies)
46
+ master_pid = (rd.readpartial(16) rescue nil).to_i
47
+ unless master_pid > 1
48
+ warn "master failed to start, check stderr log for details"
49
+ exit!(1)
50
+ end
51
+ exit 0
52
+ else # unicorn master process
53
+ options[:ready_pipe] = wr
54
+ end
55
+ end
56
+ # $stderr/$stderr can/will be redirected separately in the Unicorn config
57
+ cfg::DEFAULTS[:stderr_path] ||= "/dev/null"
58
+ cfg::DEFAULTS[:stdout_path] ||= "/dev/null"
59
+ cfg::RACKUP[:daemonized] = true
60
+ end
61
+
62
+ end
@@ -0,0 +1,71 @@
1
+ # -*- encoding: binary -*-
2
+
3
+ # Runs GC after requests, after closing the client socket and
4
+ # before attempting to accept more connections.
5
+ #
6
+ # This shouldn't hurt overall performance as long as the server cluster
7
+ # is at <50% CPU capacity, and improves the performance of most memory
8
+ # intensive requests. This serves to improve _client-visible_
9
+ # performance (possibly at the cost of overall performance).
10
+ #
11
+ # Increasing the number of +worker_processes+ may be necessary to
12
+ # improve average client response times because some of your workers
13
+ # will be busy doing GC and unable to service clients. Think of
14
+ # using more workers with this module as a poor man's concurrent GC.
15
+ #
16
+ # We'll call GC after each request is been written out to the socket, so
17
+ # the client never sees the extra GC hit it.
18
+ #
19
+ # This middleware is _only_ effective for applications that use a lot
20
+ # of memory, and will hurt simpler apps/endpoints that can process
21
+ # multiple requests before incurring GC.
22
+ #
23
+ # This middleware is only designed to work with unicorn, as it harms
24
+ # performance with keepalive-enabled servers.
25
+ #
26
+ # Example (in config.ru):
27
+ #
28
+ # require 'unicorn/oob_gc'
29
+ #
30
+ # # GC ever two requests that hit /expensive/foo or /more_expensive/foo
31
+ # # in your app. By default, this will GC once every 5 requests
32
+ # # for all endpoints in your app
33
+ # use Unicorn::OobGC, 2, %r{\A/(?:expensive/foo|more_expensive/foo)}
34
+ #
35
+ # Feedback from users of early implementations of this module:
36
+ # * http://comments.gmane.org/gmane.comp.lang.ruby.unicorn.general/486
37
+ # * http://article.gmane.org/gmane.comp.lang.ruby.unicorn.general/596
38
+ module Unicorn::OobGC
39
+
40
+ # this pretends to be Rack middleware because it used to be
41
+ # But we need to hook into unicorn internals so we need to close
42
+ # the socket before clearing the request env.
43
+ #
44
+ # +interval+ is the number of requests matching the +path+ regular
45
+ # expression before invoking GC.
46
+ def self.new(app, interval = 5, path = %r{\A/})
47
+ @@nr = interval
48
+ self.const_set :OOBGC_PATH, path
49
+ self.const_set :OOBGC_INTERVAL, interval
50
+ ObjectSpace.each_object(Unicorn::HttpServer) do |s|
51
+ s.extend(self)
52
+ self.const_set :OOBGC_ENV, s.instance_variable_get(:@request).env
53
+ end
54
+ app # pretend to be Rack middleware since it was in the past
55
+ end
56
+
57
+ #:stopdoc:
58
+ PATH_INFO = "PATH_INFO"
59
+ def process_client(client)
60
+ super(client) # Unicorn::HttpServer#process_client
61
+ if OOBGC_PATH =~ OOBGC_ENV[PATH_INFO] && ((@@nr -= 1) <= 0)
62
+ @@nr = OOBGC_INTERVAL
63
+ OOBGC_ENV.clear
64
+ disabled = GC.enable
65
+ GC.start
66
+ GC.disable if disabled
67
+ end
68
+ end
69
+
70
+ # :startdoc:
71
+ end
@@ -0,0 +1,33 @@
1
+ # -*- encoding: binary -*-
2
+
3
+ module Unicorn
4
+ # This middleware is used to ensure input is buffered to memory
5
+ # or disk (depending on size) before the application is dispatched
6
+ # by entirely consuming it (from TeeInput) beforehand.
7
+ #
8
+ # Usage (in config.ru):
9
+ #
10
+ # require 'unicorn/preread_input'
11
+ # if defined?(Unicorn)
12
+ # use Unicorn::PrereadInput
13
+ # end
14
+ # run YourApp.new
15
+ class PrereadInput
16
+
17
+ # :stopdoc:
18
+ def initialize(app)
19
+ @app = app
20
+ end
21
+
22
+ def call(env)
23
+ buf = ""
24
+ input = env["rack.input"]
25
+ if input.respond_to?(:rewind)
26
+ true while input.read(16384, buf)
27
+ input.rewind
28
+ end
29
+ @app.call(env)
30
+ end
31
+ # :startdoc:
32
+ end
33
+ end
@@ -0,0 +1,208 @@
1
+ # -*- encoding: binary -*-
2
+ # :enddoc:
3
+ require 'socket'
4
+
5
+ module Unicorn
6
+ module SocketHelper
7
+ # :stopdoc:
8
+ include Socket::Constants
9
+
10
+ # prevents IO objects in here from being GC-ed
11
+ IO_PURGATORY = []
12
+
13
+ # internal interface, only used by Rainbows!/Zbatery
14
+ DEFAULTS = {
15
+ # The semantics for TCP_DEFER_ACCEPT changed in Linux 2.6.32+
16
+ # with commit d1b99ba41d6c5aa1ed2fc634323449dd656899e9
17
+ # This change shouldn't affect Unicorn users behind nginx (a
18
+ # value of 1 remains an optimization), but Rainbows! users may
19
+ # want to use a higher value on Linux 2.6.32+ to protect against
20
+ # denial-of-service attacks
21
+ :tcp_defer_accept => 1,
22
+
23
+ # FreeBSD, we need to override this to 'dataready' if we
24
+ # eventually get HTTPS support
25
+ :accept_filter => 'httpready',
26
+
27
+ # same default value as Mongrel
28
+ :backlog => 1024,
29
+
30
+ # favor latency over bandwidth savings
31
+ :tcp_nopush => nil,
32
+ :tcp_nodelay => true,
33
+ }
34
+ #:startdoc:
35
+
36
+ # configure platform-specific options (only tested on Linux 2.6 so far)
37
+ case RUBY_PLATFORM
38
+ when /linux/
39
+ # from /usr/include/linux/tcp.h
40
+ TCP_DEFER_ACCEPT = 9 unless defined?(TCP_DEFER_ACCEPT)
41
+
42
+ # do not send out partial frames (Linux)
43
+ TCP_CORK = 3 unless defined?(TCP_CORK)
44
+ when /freebsd/
45
+ # do not send out partial frames (FreeBSD)
46
+ TCP_NOPUSH = 4 unless defined?(TCP_NOPUSH)
47
+
48
+ def accf_arg(af_name)
49
+ [ af_name, nil ].pack('a16a240')
50
+ end if defined?(SO_ACCEPTFILTER)
51
+ end
52
+
53
+ def set_tcp_sockopt(sock, opt)
54
+ # just in case, even LANs can break sometimes. Linux sysadmins
55
+ # can lower net.ipv4.tcp_keepalive_* sysctl knobs to very low values.
56
+ sock.setsockopt(SOL_SOCKET, SO_KEEPALIVE, 1) if defined?(SO_KEEPALIVE)
57
+
58
+ if defined?(TCP_NODELAY)
59
+ val = opt[:tcp_nodelay]
60
+ val = DEFAULTS[:tcp_nodelay] if nil == val
61
+ sock.setsockopt(IPPROTO_TCP, TCP_NODELAY, val ? 1 : 0)
62
+ end
63
+
64
+ val = opt[:tcp_nopush]
65
+ unless val.nil?
66
+ if defined?(TCP_CORK) # Linux
67
+ sock.setsockopt(IPPROTO_TCP, TCP_CORK, val)
68
+ elsif defined?(TCP_NOPUSH) # TCP_NOPUSH is lightly tested (FreeBSD)
69
+ sock.setsockopt(IPPROTO_TCP, TCP_NOPUSH, val)
70
+ end
71
+ end
72
+
73
+ # No good reason to ever have deferred accepts off
74
+ # (except maybe benchmarking)
75
+ if defined?(TCP_DEFER_ACCEPT)
76
+ # this differs from nginx, since nginx doesn't allow us to
77
+ # configure the the timeout...
78
+ seconds = opt[:tcp_defer_accept]
79
+ seconds = DEFAULTS[:tcp_defer_accept] if [true,nil].include?(seconds)
80
+ seconds = 0 unless seconds # nil/false means disable this
81
+ sock.setsockopt(SOL_TCP, TCP_DEFER_ACCEPT, seconds)
82
+ elsif respond_to?(:accf_arg)
83
+ name = opt[:accept_filter]
84
+ name = DEFAULTS[:accept_filter] if nil == name
85
+ begin
86
+ sock.setsockopt(SOL_SOCKET, SO_ACCEPTFILTER, accf_arg(name))
87
+ rescue => e
88
+ logger.error("#{sock_name(sock)} " \
89
+ "failed to set accept_filter=#{name} (#{e.inspect})")
90
+ end
91
+ end
92
+ end
93
+
94
+ def set_server_sockopt(sock, opt)
95
+ opt = DEFAULTS.merge(opt || {})
96
+
97
+ TCPSocket === sock and set_tcp_sockopt(sock, opt)
98
+
99
+ if opt[:rcvbuf] || opt[:sndbuf]
100
+ log_buffer_sizes(sock, "before: ")
101
+ sock.setsockopt(SOL_SOCKET, SO_RCVBUF, opt[:rcvbuf]) if opt[:rcvbuf]
102
+ sock.setsockopt(SOL_SOCKET, SO_SNDBUF, opt[:sndbuf]) if opt[:sndbuf]
103
+ log_buffer_sizes(sock, " after: ")
104
+ end
105
+ sock.listen(opt[:backlog])
106
+ rescue => e
107
+ Unicorn.log_error(logger, "#{sock_name(sock)} #{opt.inspect}", e)
108
+ end
109
+
110
+ def log_buffer_sizes(sock, pfx = '')
111
+ rcvbuf = sock.getsockopt(SOL_SOCKET, SO_RCVBUF).unpack('i')
112
+ sndbuf = sock.getsockopt(SOL_SOCKET, SO_SNDBUF).unpack('i')
113
+ logger.info "#{pfx}#{sock_name(sock)} rcvbuf=#{rcvbuf} sndbuf=#{sndbuf}"
114
+ end
115
+
116
+ # creates a new server, socket. address may be a HOST:PORT or
117
+ # an absolute path to a UNIX socket. address can even be a Socket
118
+ # object in which case it is immediately returned
119
+ def bind_listen(address = '0.0.0.0:8080', opt = {})
120
+ return address unless String === address
121
+
122
+ sock = if address[0] == ?/
123
+ if File.exist?(address)
124
+ if File.socket?(address)
125
+ begin
126
+ UNIXSocket.new(address).close
127
+ # fall through, try to bind(2) and fail with EADDRINUSE
128
+ # (or succeed from a small race condition we can't sanely avoid).
129
+ rescue Errno::ECONNREFUSED
130
+ logger.info "unlinking existing socket=#{address}"
131
+ File.unlink(address)
132
+ end
133
+ else
134
+ raise ArgumentError,
135
+ "socket=#{address} specified but it is not a socket!"
136
+ end
137
+ end
138
+ old_umask = File.umask(opt[:umask] || 0)
139
+ begin
140
+ Kgio::UNIXServer.new(address)
141
+ ensure
142
+ File.umask(old_umask)
143
+ end
144
+ elsif /\A\[([a-fA-F0-9:]+)\]:(\d+)\z/ =~ address
145
+ new_ipv6_server($1, $2.to_i, opt)
146
+ elsif /\A(\d+\.\d+\.\d+\.\d+):(\d+)\z/ =~ address
147
+ Kgio::TCPServer.new($1, $2.to_i)
148
+ else
149
+ raise ArgumentError, "Don't know how to bind: #{address}"
150
+ end
151
+ set_server_sockopt(sock, opt)
152
+ sock
153
+ end
154
+
155
+ def new_ipv6_server(addr, port, opt)
156
+ opt.key?(:ipv6only) or return Kgio::TCPServer.new(addr, port)
157
+ defined?(IPV6_V6ONLY) or
158
+ abort "Socket::IPV6_V6ONLY not defined, upgrade Ruby and/or your OS"
159
+ sock = Socket.new(AF_INET6, SOCK_STREAM, 0)
160
+ sock.setsockopt(IPPROTO_IPV6, IPV6_V6ONLY, opt[:ipv6only] ? 1 : 0)
161
+ sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
162
+ sock.bind(Socket.pack_sockaddr_in(port, addr))
163
+ IO_PURGATORY << sock
164
+ Kgio::TCPServer.for_fd(sock.fileno)
165
+ end
166
+
167
+ # returns rfc2732-style (e.g. "[::1]:666") addresses for IPv6
168
+ def tcp_name(sock)
169
+ port, addr = Socket.unpack_sockaddr_in(sock.getsockname)
170
+ /:/ =~ addr ? "[#{addr}]:#{port}" : "#{addr}:#{port}"
171
+ end
172
+ module_function :tcp_name
173
+
174
+ # Returns the configuration name of a socket as a string. sock may
175
+ # be a string value, in which case it is returned as-is
176
+ # Warning: TCP sockets may not always return the name given to it.
177
+ def sock_name(sock)
178
+ case sock
179
+ when String then sock
180
+ when UNIXServer
181
+ Socket.unpack_sockaddr_un(sock.getsockname)
182
+ when TCPServer
183
+ tcp_name(sock)
184
+ when Socket
185
+ begin
186
+ tcp_name(sock)
187
+ rescue ArgumentError
188
+ Socket.unpack_sockaddr_un(sock.getsockname)
189
+ end
190
+ else
191
+ raise ArgumentError, "Unhandled class #{sock.class}: #{sock.inspect}"
192
+ end
193
+ end
194
+
195
+ module_function :sock_name
196
+
197
+ # casts a given Socket to be a TCPServer or UNIXServer
198
+ def server_cast(sock)
199
+ begin
200
+ Socket.unpack_sockaddr_in(sock.getsockname)
201
+ Kgio::TCPServer.for_fd(sock.fileno)
202
+ rescue ArgumentError
203
+ Kgio::UNIXServer.for_fd(sock.fileno)
204
+ end
205
+ end
206
+
207
+ end # module SocketHelper
208
+ end # module Unicorn
@@ -0,0 +1,11 @@
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
@@ -0,0 +1,104 @@
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 mongrel-unicorn@rubyforge.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