unicorn 4.1.1 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/DESIGN CHANGED
@@ -31,9 +31,9 @@
31
31
  * One master process spawns and reaps worker processes. The
32
32
  Rack application itself is called only within the worker process (but
33
33
  can be loaded within the master). A copy-on-write friendly garbage
34
- collector like Ruby Enterprise Edition can be used to minimize memory
35
- usage along with the "preload_app true" directive (see
36
- Unicorn::Configurator).
34
+ collector like the one found in Ruby 2.0.0dev or Ruby Enterprise Edition
35
+ can be used to minimize memory usage along with the "preload_app true"
36
+ directive (see Unicorn::Configurator).
37
37
 
38
38
  * The number of worker processes should be scaled to the number of
39
39
  CPUs, memory or even spindles you have. If you have an existing
data/GIT-VERSION-GEN CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v4.1.1.GIT
4
+ DEF_VER=v4.2.0.GIT
5
5
 
6
6
  LF='
7
7
  '
data/LICENSE CHANGED
@@ -1,8 +1,17 @@
1
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
- {GPL2}[http://www.gnu.org/licenses/gpl-2.0.txt] (see link:COPYING) or
5
- the conditions below:
2
+ revision control for names and email addresses of all of them.
3
+
4
+ You can redistribute it and/or modify it under either the terms of the
5
+ GNU General Public License (GPL) as published by the Free Software
6
+ Foundation (FSF), version {3.0}[http://www.gnu.org/licenses/gpl-3.0.txt]
7
+ or version {2.0}[http://www.gnu.org/licenses/gpl-2.0.txt]
8
+ or the Ruby-specific license terms (see below).
9
+
10
+ The unicorn project leader (Eric Wong) reserves the right to add future
11
+ versions of the GPL (and no other licenses) as published by the FSF to
12
+ the licensing terms.
13
+
14
+ === Ruby-specific terms (if you're not using the GPLv2 or GPLv3)
6
15
 
7
16
  1. You may make and give away verbatim copies of the source form of the
8
17
  software without restriction, provided that you duplicate all of the
data/Links CHANGED
@@ -26,6 +26,9 @@ or services behind them.
26
26
  * {raindrops}[http://raindrops.bogomips.org/] - real-time stats for
27
27
  preforking Rack servers
28
28
 
29
+ * {UnXF}[http://bogomips.org/unxf/] Un-X-Forward* the Rack environment,
30
+ useful since unicorn is designed to be deployed behind a reverse proxy.
31
+
29
32
  === \Unicorn is written to work with
30
33
 
31
34
  * {Rack}[http://rack.rubyforge.org/] - a minimal interface between webservers
data/README CHANGED
@@ -62,9 +62,9 @@ both the the request and response in between \Unicorn and slow clients.
62
62
  \Unicorn is copyright 2009 by all contributors (see logs in git).
63
63
  It is based on Mongrel 1.1.5 and carries the same license.
64
64
 
65
- Mongrel is copyright 2007 Zed A. Shaw and contributors. It is licensed
66
- under the Ruby (1.8) license and the GPL2. See the included LICENSE file
67
- for details.
65
+ Mongrel is copyright 2007 Zed A. Shaw and contributors. It is
66
+ tri-licensed under (your choice) of the GPLv3, GPLv2 or Ruby-specific
67
+ terms. See the included LICENSE file for details.
68
68
 
69
69
  \Unicorn is 100% Free Software.
70
70
 
data/Rakefile CHANGED
@@ -49,7 +49,7 @@ task :fm_update do
49
49
  require 'net/netrc'
50
50
  require 'json'
51
51
  version = ENV['VERSION'] or abort "VERSION= needed"
52
- uri = URI.parse('http://freshmeat.net/projects/unicorn/releases.json')
52
+ uri = URI.parse('http://freecode.com/projects/unicorn/releases.json')
53
53
  rc = Net::Netrc.locate('unicorn-fm') or abort "~/.netrc not found"
54
54
  api_token = rc.password
55
55
  _, subject, body = `git cat-file tag v#{version}`.split(/\n\n/, 3)
@@ -40,7 +40,7 @@ pid "/path/to/app/shared/pids/unicorn.pid"
40
40
  stderr_path "/path/to/app/shared/log/unicorn.stderr.log"
41
41
  stdout_path "/path/to/app/shared/log/unicorn.stdout.log"
42
42
 
43
- # combine REE with "preload_app true" for memory savings
43
+ # combine Ruby 2.0.0dev or REE with "preload_app true" for memory savings
44
44
  # http://rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
45
45
  preload_app true
46
46
  GC.respond_to?(:copy_on_write_friendly=) and
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Copyright (c) 2009 Eric Wong (all bugs are Eric's fault)
3
3
  * Copyright (c) 2005 Zed A. Shaw
4
- * You can redistribute it and/or modify it under the same terms as Ruby.
4
+ * You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
5
+ * the GPLv3
5
6
  */
6
7
  #include "ruby.h"
7
8
  #include "ext_help.h"
@@ -1,7 +1,8 @@
1
1
  # -*- encoding: binary -*-
2
2
  # :enddoc:
3
3
  # Copyright (c) 2009 Eric Wong
4
- # You can redistribute it and/or modify it under the same terms as Ruby.
4
+ # You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
5
+ # the GPLv3
5
6
 
6
7
  # this class *must* be used with Rack::Chunked
7
8
  module Unicorn::App
@@ -4,7 +4,8 @@
4
4
  # This code is based on the original Rails handler in Mongrel
5
5
  # Copyright (c) 2005 Zed A. Shaw
6
6
  # Copyright (c) 2009 Eric Wong
7
- # You can redistribute it and/or modify it under the same terms as Ruby.
7
+ # You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
8
+ # the GPLv3
8
9
  # Additional work donated by contributors. See CONTRIBUTORS for more info.
9
10
  require 'unicorn/cgi_wrapper'
10
11
  require 'dispatcher'
@@ -3,7 +3,8 @@
3
3
  # This code is based on the original Rails handler in Mongrel
4
4
  # Copyright (c) 2005 Zed A. Shaw
5
5
  # Copyright (c) 2009 Eric Wong
6
- # You can redistribute it and/or modify it under the same terms as Ruby.
6
+ # You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
7
+ # the GPLv3
7
8
 
8
9
  # Static file handler for Rails < 2.3. This handler is only provided
9
10
  # as a convenience for developers. Performance-minded deployments should
@@ -4,7 +4,8 @@
4
4
  # This code is based on the original CGIWrapper from Mongrel
5
5
  # Copyright (c) 2005 Zed A. Shaw
6
6
  # Copyright (c) 2009 Eric Wong
7
- # You can redistribute it and/or modify it under the same terms as Ruby.
7
+ # You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
8
+ # the GPLv3
8
9
  #
9
10
  # Additional work donated by contributors. See CONTRIBUTORS for more info.
10
11
 
@@ -1,5 +1,6 @@
1
1
  # -*- encoding: binary -*-
2
2
  require 'logger'
3
+ require 'unicorn/ssl_configurator'
3
4
 
4
5
  # Implements a simple DSL for configuring a \Unicorn server.
5
6
  #
@@ -12,6 +13,7 @@ require 'logger'
12
13
  # See the link:/TUNING.html document for more information on tuning unicorn.
13
14
  class Unicorn::Configurator
14
15
  include Unicorn
16
+ include Unicorn::SSLConfigurator
15
17
 
16
18
  # :stopdoc:
17
19
  attr_accessor :set, :config_file, :after_reload
@@ -186,7 +188,8 @@ class Unicorn::Configurator
186
188
  # }
187
189
  def timeout(seconds)
188
190
  set_int(:timeout, seconds, 3)
189
- max = 0x7ffffffe # Rainbows! adds one second to this for safety
191
+ # POSIX says 31 days is the smallest allowed maximum timeout for select()
192
+ max = 30 * 60 * 60 * 24
190
193
  set[:timeout] = seconds > max ? max : seconds
191
194
  end
192
195
 
@@ -563,13 +566,16 @@ private
563
566
  end
564
567
  end
565
568
 
566
- def set_bool(var, bool) #:nodoc:
569
+ def check_bool(var, bool) # :nodoc:
567
570
  case bool
568
571
  when true, false
569
- set[var] = bool
570
- else
571
- raise ArgumentError, "#{var}=#{bool.inspect} not a boolean"
572
+ return bool
572
573
  end
574
+ raise ArgumentError, "#{var}=#{bool.inspect} not a boolean"
575
+ end
576
+
577
+ def set_bool(var, bool) #:nodoc:
578
+ set[var] = check_bool(var, bool)
573
579
  end
574
580
 
575
581
  def set_hook(var, my_proc, req_arity = 2) #:nodoc:
data/lib/unicorn/const.rb CHANGED
@@ -8,7 +8,7 @@
8
8
  # improve things much compared to constants.
9
9
  module Unicorn::Const
10
10
 
11
- UNICORN_VERSION = "4.1.1"
11
+ UNICORN_VERSION = "4.2.0"
12
12
 
13
13
  # default TCP listen host address (0.0.0.0, all interfaces)
14
14
  DEFAULT_HOST = "0.0.0.0"
@@ -1,4 +1,5 @@
1
1
  # -*- encoding: binary -*-
2
+ require "unicorn/ssl_server"
2
3
 
3
4
  # This is the process manager of Unicorn. This manages worker
4
5
  # processes which in turn handle the I/O and application process.
@@ -19,6 +20,7 @@ class Unicorn::HttpServer
19
20
  attr_reader :pid, :logger
20
21
  include Unicorn::SocketHelper
21
22
  include Unicorn::HttpResponse
23
+ include Unicorn::SSLServer
22
24
 
23
25
  # backwards compatibility with 1.x
24
26
  Worker = Unicorn::Worker
@@ -282,7 +284,7 @@ class Unicorn::HttpServer
282
284
  when :USR2 # exec binary, stay alive in case something went wrong
283
285
  reexec
284
286
  when :WINCH
285
- if Process.ppid == 1 || Process.getpgrp != $$
287
+ if Unicorn::Configurator::RACKUP[:daemonized]
286
288
  respawn = false
287
289
  logger.info "gracefully stopping all workers"
288
290
  kill_each_worker(:QUIT)
@@ -445,7 +447,7 @@ class Unicorn::HttpServer
445
447
  now = Time.now.to_i
446
448
  WORKERS.dup.each_pair do |wpid, worker|
447
449
  tick = worker.tick
448
- 0 == tick and next # skip workers that are sleeping
450
+ 0 == tick and next # skip workers that haven't processed any clients
449
451
  diff = now - tick
450
452
  tmp = @timeout - diff
451
453
  if tmp >= 0
@@ -563,6 +565,8 @@ class Unicorn::HttpServer
563
565
  self.timeout /= 2.0 # halve it for select()
564
566
  @config = nil
565
567
  build_app! unless preload_app
568
+ ssl_enable!
569
+ @after_fork = @listener_opts = @orig_app = nil
566
570
  end
567
571
 
568
572
  def reopen_worker_logs(worker_nr)
@@ -618,9 +622,8 @@ class Unicorn::HttpServer
618
622
  # timeout used so we can detect parent death:
619
623
  worker.tick = Time.now.to_i
620
624
  ret = IO.select(l, nil, SELF_PIPE, @timeout) and ready = ret[0]
621
- rescue Errno::EBADF
622
- nr < 0 or return
623
625
  rescue => e
626
+ redo if nr < 0 && (Errno::EBADF === e || IOError === e) # reopen logs
624
627
  Unicorn.log_error(@logger, "listen loop error", e) if worker
625
628
  end while worker
626
629
  end
@@ -61,7 +61,9 @@ module Unicorn::OobGC
61
61
  if OOBGC_PATH =~ OOBGC_ENV[PATH_INFO] && ((@@nr -= 1) <= 0)
62
62
  @@nr = OOBGC_INTERVAL
63
63
  OOBGC_ENV.clear
64
+ disabled = GC.enable
64
65
  GC.start
66
+ GC.disable if disabled
65
67
  end
66
68
  end
67
69
 
@@ -51,7 +51,10 @@ module Unicorn
51
51
  end
52
52
 
53
53
  def set_tcp_sockopt(sock, opt)
54
- # highly portable, but off by default because we don't do keepalive
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
+
55
58
  if defined?(TCP_NODELAY)
56
59
  val = opt[:tcp_nodelay]
57
60
  val = DEFAULTS[:tcp_nodelay] if nil == val
@@ -0,0 +1,6 @@
1
+ # -*- encoding: binary -*-
2
+ # :stopdoc:
3
+ class Unicorn::SSLClient < Kgio::SSL
4
+ alias write kgio_write
5
+ alias close kgio_close
6
+ 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
@@ -0,0 +1,42 @@
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
@@ -16,10 +16,13 @@ opts = {
16
16
 
17
17
  pid = fork do
18
18
  Isolate.now!(opts) do
19
- gem 'sqlite3-ruby', '1.2.5'
20
- gem 'raindrops', '0.7.0'
21
- gem 'kgio', '2.6.0'
22
- gem 'rack', '1.3.2'
19
+ if RUBY_VERSION.to_f < 2.0
20
+ gem 'sqlite3-ruby', '1.2.5'
21
+ end
22
+ gem 'raindrops', '0.8.0'
23
+ gem 'kgio-monkey', '0.3.0'
24
+ gem 'kgio', '2.7.2'
25
+ gem 'rack', '1.4.1'
23
26
  end
24
27
  end
25
28
  _, status = Process.waitpid2(pid)