[DRE-commits] [unicorn] 01/02: Imported Upstream version 5.0.0

Hleb Valoshka tsfgnu-guest at moszumanska.debian.org
Mon Nov 2 13:07:36 UTC 2015


This is an automated email from the git hooks/post-receive script.

tsfgnu-guest pushed a commit to branch master
in repository unicorn.

commit 080130046ec44cd19ec563a870e0532a83e426ce
Author: Hleb Valoshka <375gnu at gmail.com>
Date:   Mon Nov 2 16:07:30 2015 +0300

    Imported Upstream version 5.0.0
---
 .manifest                             |  10 -
 Application_Timeouts                  |   6 +-
 DESIGN                                |   6 +-
 Documentation/unicorn.1.txt           |  13 +-
 Documentation/unicorn_rails.1.txt     |   4 +-
 FAQ                                   |  25 +-
 GIT-VERSION-FILE                      |   2 +-
 GIT-VERSION-GEN                       |   2 +-
 GNUmakefile                           |   7 +-
 ISSUES                                |  48 ++-
 KNOWN_ISSUES                          |  18 +-
 LATEST                                |  57 ++--
 Links                                 |  31 +-
 NEWS                                  | 159 +++++++++
 PHILOSOPHY                            |   6 -
 README                                |  39 ++-
 SIGNALS                               |   2 +-
 Sandbox                               |   8 +-
 TUNING                                |  19 +-
 bin/unicorn                           |   2 +-
 bin/unicorn_rails                     |   2 +-
 examples/git.ru                       |  13 -
 examples/nginx.conf                   |  21 +-
 examples/unicorn.conf.rb              |   5 +-
 ext/unicorn_http/extconf.rb           |   1 +
 ext/unicorn_http/httpdate.c           |   2 +-
 ext/unicorn_http/unicorn_http.c       | 601 +++++++++++++++-------------------
 ext/unicorn_http/unicorn_http.rl      | 245 +++++---------
 lib/unicorn.rb                        |  28 +-
 lib/unicorn/app/exec_cgi.rb           | 154 ---------
 lib/unicorn/app/inetd.rb              | 109 ------
 lib/unicorn/configurator.rb           |  48 +--
 lib/unicorn/const.rb                  |  27 +-
 lib/unicorn/http_request.rb           |  55 ++--
 lib/unicorn/http_response.rb          |  46 +--
 lib/unicorn/http_server.rb            | 251 +++++++-------
 lib/unicorn/socket_helper.rb          | 108 ++----
 lib/unicorn/ssl_client.rb             |  11 -
 lib/unicorn/ssl_configurator.rb       | 104 ------
 lib/unicorn/ssl_server.rb             |  42 ---
 lib/unicorn/stream_input.rb           |   6 +-
 lib/unicorn/tmpio.rb                  |   5 -
 lib/unicorn/util.rb                   |   3 +-
 lib/unicorn/version.rb                |   2 +-
 lib/unicorn/worker.rb                 |  18 +-
 man/man1/unicorn.1                    |  12 +-
 man/man1/unicorn_rails.1              |   4 +-
 metadata.yml                          |  33 +-
 t/hijack.ru                           |   3 +-
 t/t0016-trust-x-forwarded-false.sh    |  30 --
 t/t0017-trust-x-forwarded-true.sh     |  30 --
 t/t0200-rack-hijack.sh                |   7 +-
 test/exec/test_exec.rb                |  52 +++
 test/test_helper.rb                   |   5 +-
 test/unit/test_http_parser_ng.rb      | 130 +-------
 test/unit/test_http_parser_xftrust.rb |  38 ---
 test/unit/test_response.rb            |  35 +-
 test/unit/test_sni_hostnames.rb       |  47 ---
 test/unit/test_socket_helper.rb       |   2 +-
 unicorn.gemspec                       |  11 +-
 60 files changed, 1045 insertions(+), 1765 deletions(-)

diff --git a/.manifest b/.manifest
index 93d192a..d79d470 100644
--- a/.manifest
+++ b/.manifest
@@ -36,7 +36,6 @@ bin/unicorn
 bin/unicorn_rails
 examples/big_app_gc.rb
 examples/echo.ru
-examples/git.ru
 examples/init.sh
 examples/logger_mp_safe.rb
 examples/logrotate.conf
@@ -54,8 +53,6 @@ ext/unicorn_http/unicorn_http.c
 ext/unicorn_http/unicorn_http.rl
 ext/unicorn_http/unicorn_http_common.rl
 lib/unicorn.rb
-lib/unicorn/app/exec_cgi.rb
-lib/unicorn/app/inetd.rb
 lib/unicorn/app/old_rails.rb
 lib/unicorn/app/old_rails/static.rb
 lib/unicorn/cgi_wrapper.rb
@@ -68,9 +65,6 @@ lib/unicorn/launcher.rb
 lib/unicorn/oob_gc.rb
 lib/unicorn/preread_input.rb
 lib/unicorn/socket_helper.rb
-lib/unicorn/ssl_client.rb
-lib/unicorn/ssl_configurator.rb
-lib/unicorn/ssl_server.rb
 lib/unicorn/stream_input.rb
 lib/unicorn/tee_input.rb
 lib/unicorn/tmpio.rb
@@ -121,8 +115,6 @@ t/t0013.ru
 t/t0014-rewindable-input-true.sh
 t/t0014.ru
 t/t0015-configurator-internals.sh
-t/t0016-trust-x-forwarded-false.sh
-t/t0017-trust-x-forwarded-true.sh
 t/t0018-write-on-close.sh
 t/t0019-max_header_len.sh
 t/t0020-at_exit-handler.sh
@@ -149,12 +141,10 @@ test/unit/test_configurator.rb
 test/unit/test_droplet.rb
 test/unit/test_http_parser.rb
 test/unit/test_http_parser_ng.rb
-test/unit/test_http_parser_xftrust.rb
 test/unit/test_request.rb
 test/unit/test_response.rb
 test/unit/test_server.rb
 test/unit/test_signals.rb
-test/unit/test_sni_hostnames.rb
 test/unit/test_socket_helper.rb
 test/unit/test_stream_input.rb
 test/unit/test_tee_input.rb
diff --git a/Application_Timeouts b/Application_Timeouts
index 5f0370d..561a1cc 100644
--- a/Application_Timeouts
+++ b/Application_Timeouts
@@ -4,10 +4,10 @@ This article focuses on _application_ setup for Rack applications, but
 can be expanded to all applications that connect to external resources
 and expect short response times.
 
-This article is not specific to \Unicorn, but exists to discourage
+This article is not specific to unicorn, but exists to discourage
 the overuse of the built-in
 {timeout}[link:Unicorn/Configurator.html#method-i-timeout] directive
-in \Unicorn.
+in unicorn.
 
 == ALL External Resources Are Considered Unreliable
 
@@ -71,7 +71,7 @@ handle network/server failures.
 == The Last Line Of Defense
 
 The {timeout}[link:Unicorn/Configurator.html#method-i-timeout] mechanism
-in \Unicorn is an extreme solution that should be avoided whenever
+in unicorn is an extreme solution that should be avoided whenever
 possible.  It will help catch bugs in your application where and when
 your application forgets to use timeouts, but it is expensive as it
 kills and respawns a worker process.
diff --git a/DESIGN b/DESIGN
index bff6a8b..46d7923 100644
--- a/DESIGN
+++ b/DESIGN
@@ -7,9 +7,7 @@
   all clients down, just one.  Only UNIX-like systems supporting
   fork() and file descriptor inheritance are supported.
 
-* The Ragel+C HTTP parser is taken from Mongrel.  This is the
-  only non-Ruby part and there are no plans to add any more
-  non-Ruby components.
+* The Ragel+C HTTP parser is taken from Mongrel.
 
 * All HTTP parsing and I/O is done much like Mongrel:
     1. read/parse HTTP request headers in full
@@ -31,7 +29,7 @@
 * One master process spawns and reaps worker processes.  The
   Rack application itself is called only within the worker process (but
   can be loaded within the master).  A copy-on-write friendly garbage
-  collector like the one found in Ruby 2.0.0dev or Ruby Enterprise Edition
+  collector like the one found in mainline Ruby 2.0.0 and later
   can be used to minimize memory usage along with the "preload_app true"
   directive (see Unicorn::Configurator).
 
diff --git a/Documentation/unicorn.1.txt b/Documentation/unicorn.1.txt
index b03962e..efdda4b 100644
--- a/Documentation/unicorn.1.txt
+++ b/Documentation/unicorn.1.txt
@@ -166,9 +166,12 @@ variable internally when doing transparent upgrades.
 UNICORN_FD is a comma-delimited list of one or more file descriptors
 used to implement USR2 upgrades.  Init systems may bind listen sockets
 itself and spawn unicorn with UNICORN_FD set to the file descriptor
-numbers of the listen socket(s).  The unicorn CONFIG_FILE must still
-have the inherited listen socket parameters defined as in a normal
-startup, otherwise the socket will be closed.
+numbers of the listen socket(s).
+
+As of unicorn 5.0, LISTEN_PID and LISTEN_FDS are used for socket
+activation as documented in the sd_listen_fds(3) manpage.  Users
+relying on this feature do not need to specify a listen socket in
+the unicorn config file.
 
 # SEE ALSO
 
@@ -180,6 +183,6 @@ startup, otherwise the socket will be closed.
 * [Rackup HowTo][3]
 
 [1]: http://unicorn.bogomips.org/
-[2]: http://rdoc.info/gems/r#/gems/rack/frames
-[3]: http://wiki.github.com/rack/rack/tutorial-rackup-howto
+[2]: http://www.rubydoc.info/github/rack/rack/
+[3]: https://github.com/rack/rack/wiki/tutorial-rackup-howto
 [4]: http://unicorn.bogomips.org/SIGNALS.html
diff --git a/Documentation/unicorn_rails.1.txt b/Documentation/unicorn_rails.1.txt
index c5db3a1..bff703e 100644
--- a/Documentation/unicorn_rails.1.txt
+++ b/Documentation/unicorn_rails.1.txt
@@ -170,6 +170,6 @@ used by Unicorn.
 * [Rackup HowTo][3]
 
 [1]: http://unicorn.bogomips.org/
-[2]: http://rdoc.info/gems/r#/gems/rack/frames
-[3]: http://wiki.github.com/rack/rack/tutorial-rackup-howto
+[2]: http://www.rubydoc.info/github/rack/rack/
+[3]: https://github.com/rack/rack/wiki/tutorial-rackup-howto
 [4]: http://unicorn.bogomips.org/SIGNALS.html
diff --git a/FAQ b/FAQ
index 66f1a09..bc70493 100644
--- a/FAQ
+++ b/FAQ
@@ -1,5 +1,14 @@
 = Frequently Asked Questions about Unicorn
 
+=== Why is nginx getting ECONNRESET as a reverse proxy?
+
+Request body data (commonly from POST and PUT requests) may not be
+drained entirely by the application.  This may happen when request
+bodies are gzipped, as unicorn reads request body data lazily to avoid
+overhead from bad requests.
+
+Ref: http://mid.gmane.org/FC91211E-FD32-432C-92FC-0318714C2170@zendesk.com
+
 === Why aren't my Rails log files rotated when I use SIGUSR1?
 
 The Rails autoflush_log option must remain disabled with multiprocess
@@ -8,14 +17,6 @@ partially written and lead to corruption in the presence of multiple
 processes.  With reasonable amounts of logging, the performance impact
 of autoflush_log should be negligible on Linux and other modern kernels.
 
-=== I've installed Rack 1.1.x, why can't Unicorn load Rails (2.3.5)?
-
-Rails 2.3.5 is not compatible with Rack 1.1.x.  Unicorn is compatible
-with both Rack 1.1.x and Rack 1.0.x, and RubyGems will load the latest
-version of Rack installed on the system.  Uninstalling the Rack 1.1.x
-gem should solve gem loading issues with Rails 2.3.5.  Rails 2.3.6
-and later correctly support Rack 1.1.x.
-
 === Why are my redirects going to "http" URLs when my site uses https?
 
 If your site is entirely behind https, then Rack applications that use
@@ -59,3 +60,11 @@ queue makes failover to a different machine more difficult.
 
 See the TUNING and Unicorn::Configurator documents for more information
 on :backlog-related topics.
+
+=== I've installed Rack 1.1.x, why can't Unicorn load Rails (2.3.5)?
+
+Rails 2.3.5 is not compatible with Rack 1.1.x.  Unicorn is compatible
+with both Rack 1.1.x and Rack 1.0.x, and RubyGems will load the latest
+version of Rack installed on the system.  Uninstalling the Rack 1.1.x
+gem should solve gem loading issues with Rails 2.3.5.  Rails 2.3.6
+and later correctly support Rack 1.1.x.
diff --git a/GIT-VERSION-FILE b/GIT-VERSION-FILE
index 1641239..70f818f 100644
--- a/GIT-VERSION-FILE
+++ b/GIT-VERSION-FILE
@@ -1 +1 @@
-GIT_VERSION = 4.9.0
+GIT_VERSION = 5.0.0
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 0030ca4..9141c74 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,5 +1,5 @@
 #!/usr/bin/env ruby
-DEF_VER = "v4.9.0"
+DEF_VER = "v5.0.0"
 CONSTANT = "Unicorn::Const::UNICORN_VERSION"
 RVF = "lib/unicorn/version.rb"
 GVF = "GIT-VERSION-FILE"
diff --git a/GNUmakefile b/GNUmakefile
index 7cf1023..3f9c441 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -86,10 +86,14 @@ test-unit: $(wildcard test/unit/test_*.rb)
 $(slow_tests): $(test_prefix)/.stamp
 	@$(MAKE) $(shell $(awk_slow) $@)
 
+# ensure we can require just the HTTP parser without the rest of unicorn
+test-require: $(ext)/unicorn_http.$(DLEXT)
+	$(RUBY) --disable-gems -I$(ext) -runicorn_http -e Unicorn
+
 test-integration: $(test_prefix)/.stamp
 	$(MAKE) -C t
 
-check: test test-integration
+check: test-require test test-integration
 test-all: check
 
 TEST_OPTS = -v
@@ -174,6 +178,7 @@ doc: .document $(ext)/unicorn_http.c man html .olddoc.yml $(PLACEHOLDERS)
 	$(RDOC) -f oldweb
 	$(OLDDOC) merge
 	install -m644 COPYING doc/COPYING
+	install -m644 NEWS.atom.xml doc/NEWS.atom.xml
 	install -m644 $(shell LC_ALL=C grep '^[A-Z]' .document) doc/
 	install -m644 $(man1_paths) doc/
 	tar cf - $$(git ls-files examples/) | (cd doc && tar xf -)
diff --git a/ISSUES b/ISSUES
index 8910180..394c852 100644
--- a/ISSUES
+++ b/ISSUES
@@ -9,7 +9,10 @@ submit patches and/or obtain support after you have searched the
 * Cc: all participants in a thread or commit, as subscription is optional
 * Do not {top post}[http://catb.org/jargon/html/T/top-post.html] in replies
 * Quote as little as possible of the message you're replying to
-* Do not send HTML mail, it will likely be flagged as spam
+* Do not send HTML mail or images, it will be flagged as spam
+* Anonymous and pseudonymous messages will always be welcome.
+* The email submission port (587) is enabled on the bogomips.org MX:
+  http://bogomips.org/unicorn-public/20141004232241.GA23908@dcvr.yhbt.net/t/
 
 If your issue is of a sensitive nature or you're just shy in public,
 then feel free to email us privately at mailto:unicorn at bogomips.org
@@ -62,39 +65,28 @@ document distributed with git) on guidelines for patch submission.
 
 * public: mailto:unicorn-public at bogomips.org
 * private: mailto:unicorn at bogomips.org
+* nntp://news.gmane.org/gmane.comp.lang.ruby.unicorn.general
+* nntp://news.public-inbox.org/inbox.comp.lang.ruby.unicorn
+* http://bogomips.org/unicorn-public/
 
 We operate a {public-inbox}[http://public-inbox.org/] which
-feeds the mailing list.  You may subscribe either using
-{ssoma}[http://ssoma.public-inbox.org/] or by sending a mail
-to mailto:unicorn-public+subscribe at bogomips.org
+feeds the mailing list.  Subscription is optional, so Cc:
+all participants.
 
-ssoma is a mail archiver/fetcher using git.  It operates in a similar
-fashion to tools such as slrnpull, fetchmail, or getmail.  ssoma
-subscription instructions:
+You can follow along via NNTP:
 
-	URL=git://bogomips.org/unicorn-public
-	LISTNAME=unicorn
+	nntp://news.public-inbox.org/inbox.comp.lang.ruby.unicorn
+	nntp://news.gmane.org/gmane.comp.lang.ruby.unicorn.general
 
-	# to initialize a maildir (this may be a new or existing maildir,
-	# ssoma will not touch existing messages)
-	# If you prefer mbox, use mbox:/path/to/mbox as the last argument
-	# You may also use imap://$MAILSERVER/INBOX for an IMAP account
-	# or imaps:// for an IMAPS account, as well.
-	ssoma add $LISTNAME $URL maildir:/path/to/maildir
+Or Atom feeds:
 
-	# read with your favorite MUA (only using mutt as an example)
-	mutt -f /path/to/maildir # (or /path/to/mbox)
+	http://bogomips.org/unicorn-public/new.atom
 
-	# to keep your mbox or maildir up-to-date, periodically run the following:
-	ssoma sync $LISTNAME
+	The HTML archives at http://bogomips.org/unicorn-public/
+	also has links to per-thread Atom feeds and downloadable
+	mboxes.
 
-	# your MUA may modify and delete messages from the maildir or mbox,
-	# this does not affect ssoma functionality at all
+You may also subscribe via plain-text email:
 
-	# to sync all your ssoma subscriptions
-	ssoma sync
-
-	# You may wish to sync in your cronjob
-	ssoma sync --cron
-
-HTML archives are available here: http://bogomips.org/unicorn-public/
+	mailto:unicorn-public+subscribe at bogomips.org
+	(and confirming the auto-reply)
diff --git a/KNOWN_ISSUES b/KNOWN_ISSUES
index 69e4f57..6b80517 100644
--- a/KNOWN_ISSUES
+++ b/KNOWN_ISSUES
@@ -13,7 +13,7 @@ acceptable solution.  Those issues are documented here.
 
 * PRNGs (pseudo-random number generators) loaded before forking
   (e.g. "preload_app true") may need to have their internal state
-  reset in the after_fork hook.  Starting with \Unicorn 3.6.1, we
+  reset in the after_fork hook.  Starting with unicorn 3.6.1, we
   have builtin workarounds for Kernel#rand and OpenSSL::Random users,
   but applications may use other PRNGs.
 
@@ -36,29 +36,29 @@ acceptable solution.  Those issues are documented here.
 
 * Under some versions of Ruby 1.8, it is necessary to call +srand+ in an
   after_fork hook to get correct random number generation.  We have a builtin
-  workaround for this starting with \Unicorn 3.6.1
+  workaround for this starting with unicorn 3.6.1
 
-  See http://redmine.ruby-lang.org/issues/show/4338
+  See http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/36450
 
 * On Ruby 1.8 prior to Ruby 1.8.7-p248, *BSD platforms have a broken
   stdio that causes failure for file uploads larger than 112K.  Upgrade
-  your version of Ruby or continue using Unicorn 1.x/3.4.x.
+  your version of Ruby or continue using unicorn 1.x/3.4.x.
 
 * Under Ruby 1.9.1, methods like Array#shuffle and Array#sample will
   segfault if called after forking.  Upgrade to Ruby 1.9.2 or call
   "Kernel.rand" in your after_fork hook to reinitialize the random
   number generator.
 
-  See http://redmine.ruby-lang.org/issues/show/2962 for more details
+  See http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/28655
 
 * Rails 2.3.2 bundles its own version of Rack.  This may cause subtle
   bugs when simultaneously loaded with the system-wide Rack Rubygem
-  which Unicorn depends on.  Upgrading to Rails 2.3.4 (or later) is
+  which unicorn depends on.  Upgrading to Rails 2.3.4 (or later) is
   strongly recommended for all Rails 2.3.x users for this (and security
   reasons).  Rails 2.2.x series (or before) did not bundle Rack and are
   should be unnaffected.  If there is any reason which forces your
   application to use Rails 2.3.2 and you have no other choice, then
-  you may edit your Unicorn gemspec and remove the Rack dependency.
+  you may edit your unicorn gemspec and remove the Rack dependency.
 
   ref: http://mid.gmane.org/20091014221552.GA30624@dcvr.yhbt.net
   Note: the workaround described in the article above only made
@@ -71,9 +71,9 @@ acceptable solution.  Those issues are documented here.
     set :env, :production
     set :run, false
   Since this is no longer an issue with Sinatra 0.9.x apps, this will not be
-  fixed on our end.  Since Unicorn is itself the application launcher, the
+  fixed on our end.  Since unicorn is itself the application launcher, the
   at_exit handler used in old Sinatra always caused Mongrel to be launched
-  whenever a Unicorn worker was about to exit.
+  whenever a unicorn worker was about to exit.
 
   Also remember we're capable of replacing the running binary without dropping
   any connections regardless of framework :)
diff --git a/LATEST b/LATEST
index 15cc649..bf758f6 100644
--- a/LATEST
+++ b/LATEST
@@ -1,30 +1,29 @@
-=== unicorn 4.8.3 - the end of an era / 2014-05-07 07:50 UTC
-
-  This release updates documentation to reflect the migration of the
-  mailing list to a new public-inbox[1] instance.  This is necessary
-  due to the impending RubyForge shutdown on May 15, 2014.
-
-  The public-inbox address is: unicorn-public at bogomips.org
-      (no subscription required, plain text only)
-  ssoma[2] git archives: git://bogomips.org/unicorn-public
-  browser-friendly archives: http://bogomips.org/unicorn-public/
-
-  Using, getting help for, and contributing to unicorn will never
-  require any of the following:
-
-  1) non-Free software (including SaaS)
-  2) registration or sign-in of any kind
-  3) a real identity (we accept mail from Mixmaster)
-  4) a graphical user interface
-
-  Nowadays, plain-text email is the only ubiquitous platform which
-  meets all our requirements for communication.
-
-  There is also one small bugfix to handle premature grandparent death
-  upon initial startup.  Most users are unaffected.
-
-  [1] policy: http://public-inbox.org/ - git://80x24.org/public-inbox
-      an "archives first" approach to mailing lists
-  [2] mechanism: http://ssoma.public-inbox.org/ - git://80x24.org/ssoma
-      some sort of mail archiver (using git)
+=== unicorn 5.0.0.pre2 - another prerelease! / 2015-07-06 21:37 UTC
+
+  There is a minor TCP socket options are now applied to inherited
+  sockets, and we have native support for inheriting sockets from
+  systemd (by emulating the sd_listen_fds(3) function).
+
+  Dynamic changes in the application to Rack::Utils::HTTP_STATUS
+  codes is now supported, so you can use your own custom status
+  lines.
+
+  Ruby 2.2 and later is now favored for performance.
+  Optimizations by using constants which made sense in earlier
+  versions of Ruby are gone: so users of old Ruby versions
+  will see performance regressions.  Ruby 2.2 users should
+  see the same or better performance, and we have less code
+  as a result.
+
+  * doc: update some invalid URLs
+  * apply TCP socket options on inherited sockets
+  * reflect changes in Rack::Utils::HTTP_STATUS_CODES
+  * reduce constants and optimize for Ruby 2.2
+  * http_response: reduce size of multi-line header path
+  * emulate sd_listen_fds for systemd support
+  * test/unit/test_response.rb: compatibility with older test-unit
+
+  This also includes all changes in unicorn 5.0.0.pre1:
+
+  http://bogomips.org/unicorn-public/m/20150615225652.GA16164@dcvr.yhbt.net.html
 
diff --git a/Links b/Links
index 5e868fd..6474a9d 100644
--- a/Links
+++ b/Links
@@ -1,13 +1,13 @@
 = Related Projects
 
-If you're interested in \Unicorn, you may be interested in some of the projects
+If you're interested in unicorn, you may be interested in some of the projects
 listed below.  If you have any links to add/change/remove, please tell us at
 mailto:unicorn-public at bogomips.org!
 
 == Disclaimer
 
-The \Unicorn project is not responsible for the content in these links.
-Furthermore, the \Unicorn project has never, does not and will never endorse:
+The unicorn project is not responsible for the content in these links.
+Furthermore, the unicorn project has never, does not and will never endorse:
 
 * any for-profit entities or services
 * any non-{Free Software}[http://www.gnu.org/philosophy/free-sw.html]
@@ -15,13 +15,13 @@ Furthermore, the \Unicorn project has never, does not and will never endorse:
 The existence of these links does not imply endorsement of any entities
 or services behind them.
 
-=== For use with \Unicorn
+=== For use with unicorn
 
 * {Bluepill}[https://github.com/arya/bluepill] -
   a simple process monitoring tool written in Ruby
 
 * {golden_brindle}[https://github.com/simonoff/golden_brindle] - tool to
-  manage multiple \Unicorn instances/applications on a single server
+  manage multiple unicorn instances/applications on a single server
 
 * {raindrops}[http://raindrops.bogomips.org/] - real-time stats for
   preforking Rack servers
@@ -29,26 +29,23 @@ or services behind them.
 * {UnXF}[http://bogomips.org/unxf/]  Un-X-Forward* the Rack environment,
   useful since unicorn is designed to be deployed behind a reverse proxy.
 
-=== \Unicorn is written to work with
+=== unicorn is written to work with
 
 * {Rack}[http://rack.github.io/] - a minimal interface between webservers
   supporting Ruby and Ruby frameworks
 
-* {Ruby}[http://www.ruby-lang.org/] - the programming language of Rack and \Unicorn
+* {Ruby}[https://www.ruby-lang.org/en/] - the programming language of
+  Rack and unicorn
 
-* {nginx}[http://nginx.org/] - the reverse proxy for use with \Unicorn
-
-* {kgio}[http://bogomips.org/kgio/] - the I/O library written for \Unicorn
+* {nginx}[http://nginx.org/] (Free versions) -
+  the reverse proxy for use with unicorn
 
 === Derivatives
 
-* {Green Unicorn}[http://gunicorn.org/] - a Python version of \Unicorn
-
-* {Rainbows!}[http://rainbows.bogomips.org/] - \Unicorn for sleepy
-  apps and slow clients (historical).
+* {Green Unicorn}[http://gunicorn.org/] - a Python version of unicorn
 
-* {yahns}[http://yahns.yhbt.net/] - like Rainbows!, but with fewer options
-  and designed for energy efficiency on idle sites.
+* {Starman}[http://search.cpan.org/dist/Starman/] - Plack/PSGI version
+  of unicorn
 
 === Prior Work
 
@@ -56,4 +53,4 @@ or services behind them.
   unicorn is based on
 
 * {david}[http://bogomips.org/david.git] - a tool to explain why you need
-  nginx in front of \Unicorn
+  nginx in front of unicorn
diff --git a/NEWS b/NEWS
index 995d2ed..2219860 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,162 @@
+=== unicorn 5.0.0.pre2 - another prerelease! / 2015-07-06 21:37 UTC
+
+  There is a minor TCP socket options are now applied to inherited
+  sockets, and we have native support for inheriting sockets from
+  systemd (by emulating the sd_listen_fds(3) function).
+
+  Dynamic changes in the application to Rack::Utils::HTTP_STATUS
+  codes is now supported, so you can use your own custom status
+  lines.
+
+  Ruby 2.2 and later is now favored for performance.
+  Optimizations by using constants which made sense in earlier
+  versions of Ruby are gone: so users of old Ruby versions
+  will see performance regressions.  Ruby 2.2 users should
+  see the same or better performance, and we have less code
+  as a result.
+
+  * doc: update some invalid URLs
+  * apply TCP socket options on inherited sockets
+  * reflect changes in Rack::Utils::HTTP_STATUS_CODES
+  * reduce constants and optimize for Ruby 2.2
+  * http_response: reduce size of multi-line header path
+  * emulate sd_listen_fds for systemd support
+  * test/unit/test_response.rb: compatibility with older test-unit
+
+  This also includes all changes in unicorn 5.0.0.pre1:
+
+  http://bogomips.org/unicorn-public/m/20150615225652.GA16164@dcvr.yhbt.net.html
+
+=== unicorn 5.0.0.pre1 - incompatible changes! / 2015-06-15 22:49 UTC
+
+  This release finally drops Ruby 1.8 support and requires Ruby 1.9.3
+  or later.  The horrible "Status:" header in our HTTP response is
+  finally gone, saving at least 16 precious bytes in every single HTTP
+  response.
+
+  Under Ruby 2.1 and later, the monotonic clock is used for timeout
+  handling for better accuracy.
+
+  Several experimental, unused and undocumented features are removed.
+
+  There's also tiny, minor performance and memory improvements from
+  dropping 1.8 compatibility, but probably nothing noticeable on a
+  typical real-life (bloated) app.
+
+  The biggest performance improvement we made was to our website by
+  switching to olddoc.  Depending on connection speed, latency, and
+  renderer performance, it typically loads two to four times faster.
+
+  Finally, for the billionth time: unicorn must never be exposed
+  to slow clients, as it will never ever use new-fangled things
+  like non-blocking socket I/O, threads, epoll or kqueue.  unicorn
+  must be used with a fully-buffering reverse proxy such as nginx
+  for slow clients.
+
+  * ISSUES: update with mailing list subscription
+  * GIT-VERSION-GEN: start 5.0.0 development
+  * http: remove xftrust options
+  * FAQ: add entry for Rails autoflush_log
+  * dev: remove isolate dependency
+  * unicorn.gemspec: depend on test-unit 3.0
+  * http_response: remove Status: header
+  * remove RubyForge and Freecode references
+  * remove mongrel.rubyforge.org references
+  * http: remove the keepalive requests limit
+  * http: reduce parser from 72 to 56 bytes on 64-bit
+  * examples: add run_once to before_fork hook example
+  * worker: remove old tmp accessor
+  * http_server: save 450+ bytes of memory on x86-64
+  * t/t0002-parser-error.sh: relax test for rack 1.6.0
+  * remove SSL support
+  * tmpio: drop the "size" method
+  * switch docs + website to olddoc
+  * README: clarify/reduce references to unicorn_rails
+  * gemspec: fixup olddoc migration
+  * use the monotonic clock under Ruby 2.1+
+  * http: -Wshorten-64-to-32 warnings on clang
+  * remove old inetd+git examples and exec_cgi
+  * http: standalone require + reduction in binary size
+  * GNUmakefile: fix clean gem build + reduce build cruft
+  * socket_helper: reduce constant lookups and caching
+  * remove 1.8, <= 1.9.1 fallback for missing IO#autoclose=
+  * favor IO#close_on_exec= over fcntl in 1.9+
+  * use require_relative to reduce syscalls at startup
+  * doc: update support status for Ruby versions
+  * fix uninstalled testing and reduce require paths
+  * test_socket_helper: do not depend on SO_REUSEPORT
+  * favor "a.b(&:c)" form over "a.b { |x| x.c }"
+  * ISSUES: add section for bugs in other projects
+  * http_server: favor ivars over constants
+  * explain 11 byte magic number for self-pipe
+  * const: drop constants used by Rainbows!
+  * reduce and localize constant string use
+  * Links: mark Rainbows! as historical, reference yahns
+  * save about 200 bytes of memory on x86-64
+  * http: remove deprecated reset method
+  * http: remove experimental dechunk! method
+  * socket_helper: update comments
+  * doc: document UNICORN_FD in manpage
+  * doc: document Etc.nprocessors for worker_processes
+  * favor more string literals for cold call sites
+  * tee_input: support for Rack::TempfileReaper middleware
+  * support TempfileReaper in deployment and development envs
+  * favor kgio_wait_readable for single FD over select
+  * Merge tag 'v4.9.0'
+  * http_request: support rack.hijack by default
+  * avoid extra allocation for hijack proc creation
+  * FAQ: add note about ECONNRESET errors from bodies
+  * process SIGWINCH unless stdin is a TTY
+  * ISSUES: discourage HTML mail strongly, welcome nyms
+  * http: use rb_hash_clear in Ruby 2.0+
+  * http_response: avoid special-casing for Rack < 1.5
+  * www: install NEWS.atom.xml properly
+  * http_server: remove a few more accessors and constants
+  * http_response: simplify regular expression
+  * move the socket into Rack env for hijacking
+  * http: move response_start_sent into the C ext
+  * FAQ: reorder bit on Rack 1.1.x and Rails 2.3.x
+  * ensure body is closed during hijack
+
+=== unicorn 4.9.0 - TempfileReaper support in Rack 1.6 / 2015-04-24 03:09 UTC
+
+  This release supports the Rack::TempfileReaper middleware found
+  in rack 1.6 for cleaning up disk space used by temporary files.
+  We also use Rack::TempfileReaper for cleaning up large temporary
+  files buffered with TeeInput.  Users on rack 1.5 and earlier
+  will see no changes.
+
+  There's also a bunch of documentation/build system improvements.
+
+  This is likely to be the last Ruby 1.8-compatible release,
+  unicorn 5.x will require 1.9.3 or later as well as dropping lots
+  of cruft (the stupid "Status:" header in responses being the
+  most notable).
+
+  21 changes backported from master:
+
+        ISSUES: update with mailing list subscription
+        FAQ: add entry for Rails autoflush_log
+        dev: remove isolate dependency
+        unicorn.gemspec: depend on test-unit 3.0
+        remove RubyForge and Freecode references
+        remove mongrel.rubyforge.org references
+        examples: add run_once to before_fork hook example
+        t/t0002-parser-error.sh: relax test for rack 1.6.0
+        switch docs + website to olddoc
+        README: clarify/reduce references to unicorn_rails
+        gemspec: fixup olddoc migration
+        GNUmakefile: fix clean gem build + reduce build cruft
+        doc: update support status for Ruby versions
+        fix uninstalled testing and reduce require paths
+        test_socket_helper: do not depend on SO_REUSEPORT
+        ISSUES: add section for bugs in other projects
+        explain 11 byte magic number for self-pipe
+        Links: mark Rainbows! as historical, reference yahns
+        doc: document UNICORN_FD in manpage
+        tee_input: support for Rack::TempfileReaper middleware
+        support TempfileReaper in deployment and development envs
+
 === unicorn 4.8.3 - the end of an era / 2014-05-07 07:50 UTC
 
   This release updates documentation to reflect the migration of the
diff --git a/PHILOSOPHY b/PHILOSOPHY
index 18b2d82..feb83d9 100644
--- a/PHILOSOPHY
+++ b/PHILOSOPHY
@@ -137,9 +137,3 @@ unicorn is highly inefficient for Comet/reverse-HTTP/push applications
 where the HTTP connection spends a large amount of time idle.
 Nevertheless, the ease of troubleshooting, debugging, and management of
 unicorn may still outweigh the drawbacks for these applications.
-
-The {Rainbows!}[http://rainbows.bogomips.org/] aims to fill the gap for
-odd corner cases where the nginx + unicorn combination is not enough.
-While Rainbows! management/administration is largely identical to
-unicorn, Rainbows! is far more ambitious and has seen little real-world
-usage.
diff --git a/README b/README
index f084d0c..db9f0d4 100644
--- a/README
+++ b/README
@@ -1,23 +1,23 @@
-= Unicorn: Rack HTTP server for fast clients and Unix
+= unicorn: Rack HTTP server for fast clients and Unix
 
-\Unicorn is an HTTP server for Rack applications designed to only serve
+unicorn is an HTTP server for Rack applications designed to only serve
 fast clients on low-latency, high-bandwidth connections and take
 advantage of features in Unix/Unix-like kernels.  Slow clients should
 only be served by placing a reverse proxy capable of fully buffering
-both the the request and response in between \Unicorn and slow clients.
+both the the request and response in between unicorn and slow clients.
 
 == Features
 
 * Designed for Rack, Unix, fast clients, and ease-of-debugging.  We
   cut out everything that is better supported by the operating system,
-  {nginx}[http://nginx.net/] or {Rack}[http://rack.github.io/].
+  {nginx}[http://nginx.org/] or {Rack}[http://rack.github.io/].
 
 * Compatible with Ruby 1.9.3 and later.
   unicorn 4.8.x will remain supported for Ruby 1.8 users.
 
-* Process management: \Unicorn will reap and restart workers that
+* Process management: unicorn will reap and restart workers that
   die from broken apps.  There is no need to manage multiple processes
-  or ports yourself.  \Unicorn can spawn and manage any number of
+  or ports yourself.  unicorn can spawn and manage any number of
   worker processes you choose to scale to your backend.
 
 * Load balancing is done entirely by the operating system kernel.
@@ -33,11 +33,11 @@ both the the request and response in between \Unicorn and slow clients.
 * Builtin reopening of all log files in your application via
   USR1 signal.  This allows logrotate to rotate files atomically and
   quickly via rename instead of the racy and slow copytruncate method.
-  \Unicorn also takes steps to ensure multi-line log entries from one
+  unicorn also takes steps to ensure multi-line log entries from one
   request all stay within the same file.
 
 * nginx-style binary upgrades without losing connections.
-  You can upgrade \Unicorn, your entire application, libraries
+  You can upgrade unicorn, your entire application, libraries
   and even your Ruby interpreter without dropping clients.
 
 * before_fork and after_fork hooks in case your application
@@ -60,15 +60,15 @@ both the the request and response in between \Unicorn and slow clients.
 
 == License
 
-\Unicorn is copyright 2009 by all contributors (see logs in git).
+unicorn is copyright 2009 by all contributors (see logs in git).
 It is based on Mongrel 1.1.5.
 Mongrel is copyright 2007 Zed A. Shaw and contributors.
 
-\Unicorn is licensed under (your choice) of the GPLv2 or later
+unicorn is licensed under (your choice) of the GPLv2 or later
 (GPLv3+ preferred), or Ruby (1.8)-specific terms.
 See the included LICENSE file for details.
 
-\Unicorn is 100% Free Software.
+unicorn is 100% Free Software.
 
 == Install
 
@@ -108,17 +108,17 @@ In RAILS_ROOT, run:
 
   unicorn_rails
 
-\Unicorn will bind to all interfaces on TCP port 8080 by default.
+unicorn will bind to all interfaces on TCP port 8080 by default.
 You may use the +--listen/-l+ switch to bind to a different
 address:port or a UNIX socket.
 
 === Configuration File(s)
 
-\Unicorn will look for the config.ru file used by rackup in APP_ROOT.
+unicorn will look for the config.ru file used by rackup in APP_ROOT.
 
-For deployments, it can use a config file for \Unicorn-specific options
+For deployments, it can use a config file for unicorn-specific options
 specified by the +--config-file/-c+ command-line switch.  See
-Unicorn::Configurator for the syntax of the \Unicorn-specific options.
+Unicorn::Configurator for the syntax of the unicorn-specific options.
 The default settings are designed for maximum out-of-the-box
 compatibility with existing applications.
 
@@ -130,7 +130,7 @@ supported.  Run `unicorn -h` to see command-line options.
 There is NO WARRANTY whatsoever if anything goes wrong, but
 {let us know}[link:ISSUES.html] and we'll try our best to fix it.
 
-\Unicorn is designed to only serve fast clients either on the local host
+unicorn is designed to only serve fast clients either on the local host
 or a fast LAN.  See the PHILOSOPHY and DESIGN documents for more details
 regarding this.
 
@@ -140,6 +140,11 @@ All feedback (bug reports, user/development dicussion, patches, pull
 requests) go to the mailing list/newsgroup.  See the ISSUES document for
 information on the {mailing list}[mailto:unicorn-public at bogomips.org].
 
-For the latest on \Unicorn releases, you may also finger us at
+The mailing list is archived at http://bogomips.org/unicorn-public/
+Read-only NNTP access is available at:
+nntp://news.public-inbox.org/inbox.comp.lang.ruby.unicorn and
+nntp://news.gmane.org/gmane.comp.lang.ruby.unicorn.general
+
+For the latest on unicorn releases, you may also finger us at
 unicorn at bogomips.org or check our NEWS page (and subscribe to our Atom
 feed).
diff --git a/SIGNALS b/SIGNALS
index ef0b0d9..4d78065 100644
--- a/SIGNALS
+++ b/SIGNALS
@@ -3,7 +3,7 @@
 In general, signals need only be sent to the master process.  However,
 the signals Unicorn uses internally to communicate with the worker
 processes are documented here as well.  With the exception of TTIN/TTOU,
-signal handling matches the behavior of {nginx}[http://nginx.net/] so it
+signal handling matches the behavior of {nginx}[http://nginx.org/] so it
 should be possible to easily share process management scripts between
 Unicorn and nginx.
 
diff --git a/Sandbox b/Sandbox
index f662b27..997b92f 100644
--- a/Sandbox
+++ b/Sandbox
@@ -1,10 +1,10 @@
-= Tips for using \Unicorn with Sandbox installation tools
+= Tips for using unicorn with Sandbox installation tools
 
 Since unicorn includes executables and is usually used to start a Ruby
 process, there are certain caveats to using it with tools that sandbox
 RubyGems installations such as
-{Bundler}[http://gembundler.com/] or
-{Isolate}[http://github.com/jbarnette/isolate].
+{Bundler}[http://bundler.io/] or
+{Isolate}[https://github.com/jbarnette/isolate].
 
 == General deployment
 
@@ -58,7 +58,7 @@ the before_exec hook:
 
 If you're using an older Bundler version (0.9.x), you may need to set or
 reset GEM_HOME, GEM_PATH and PATH environment variables in the
-before_exec hook as illustrated by http://gist.github.com/534668
+before_exec hook as illustrated by https://gist.github.com/534668
 
 === Ruby 2.0.0 close-on-exec and SIGUSR2 incompatibility
 
diff --git a/TUNING b/TUNING
index 542ebdc..247090b 100644
--- a/TUNING
+++ b/TUNING
@@ -1,10 +1,10 @@
-= Tuning \Unicorn
+= Tuning unicorn
 
-\Unicorn performance is generally as good as a (mostly) Ruby web server
+unicorn performance is generally as good as a (mostly) Ruby web server
 can provide.  Most often the performance bottleneck is in the web
 application running on Unicorn rather than Unicorn itself.
 
-== \Unicorn Configuration
+== unicorn Configuration
 
 See Unicorn::Configurator for details on the config file format.
 +worker_processes+ is the most-commonly needed tuning parameter.
@@ -14,12 +14,15 @@ See Unicorn::Configurator for details on the config file format.
 * worker_processes should be scaled to the number of processes your
   backend system(s) can support.  DO NOT scale it to the number of
   external network clients your application expects to be serving.
-  \Unicorn is NOT for serving slow clients, that is the job of nginx.
+  unicorn is NOT for serving slow clients, that is the job of nginx.
 
 * worker_processes should be *at* *least* the number of CPU cores on
-  a dedicated server.  If your application has occasionally slow
-  responses that are /not/ CPU-intensive, you may increase this to
-  workaround those inefficiencies.
+  a dedicated server (unless you do not have enough memory).
+  If your application has occasionally slow responses that are /not/
+  CPU-intensive, you may increase this to workaround those inefficiencies.
+
+* Under Ruby 2.2 or later, Etc.nprocessors may be used to determine
+  the number of CPU cores present.
 
 * worker_processes may be increased for Unicorn::OobGC users to provide
   more consistent response times.
@@ -55,7 +58,7 @@ See Unicorn::Configurator for details on the config file format.
 * UNIX domain sockets are slightly faster than TCP sockets, but only
   work if nginx is on the same machine.
 
-== Other \Unicorn settings
+== Other unicorn settings
 
 * Setting "preload_app true" can allow copy-on-write-friendly GC to
   be used to save memory.  It will probably not work out of the box with
diff --git a/bin/unicorn b/bin/unicorn
index c272e43..3c5e5cb 100755
--- a/bin/unicorn
+++ b/bin/unicorn
@@ -29,7 +29,7 @@ op = OptionParser.new("", 24, '  ') do |opts|
 
   opts.on("-I", "--include PATH",
           "specify $LOAD_PATH (may be used more than once)") do |path|
-    $LOAD_PATH.unshift(*path.split(/:/))
+    $LOAD_PATH.unshift(*path.split(':'))
   end
 
   opts.on("-r", "--require LIBRARY",
diff --git a/bin/unicorn_rails b/bin/unicorn_rails
index b080846..ea4f822 100755
--- a/bin/unicorn_rails
+++ b/bin/unicorn_rails
@@ -30,7 +30,7 @@ op = OptionParser.new("", 24, '  ') do |opts|
 
   opts.on("-I", "--include PATH",
           "specify $LOAD_PATH (may be used more than once)") do |path|
-    $LOAD_PATH.unshift(*path.split(/:/))
+    $LOAD_PATH.unshift(*path.split(':'))
   end
 
   opts.on("-r", "--require LIBRARY",
diff --git a/examples/git.ru b/examples/git.ru
deleted file mode 100644
index 59a31c9..0000000
--- a/examples/git.ru
+++ /dev/null
@@ -1,13 +0,0 @@
-#\-E none
-
-# See http://thread.gmane.org/gmane.comp.web.curl.general/10473/raw on
-# how to setup git for this.  A better version of the above patch was
-# accepted and committed on June 15, 2009, so you can pull the latest
-# curl CVS snapshot to try this out.
-require 'unicorn/app/inetd'
-
-use Rack::Lint
-use Rack::Chunked # important!
-run Unicorn::App::Inetd.new(
- *%w(git daemon --verbose --inetd --export-all --base-path=/home/ew/unicorn)
-)
diff --git a/examples/nginx.conf b/examples/nginx.conf
index a68fe6f..0583c1f 100644
--- a/examples/nginx.conf
+++ b/examples/nginx.conf
@@ -1,5 +1,5 @@
 # This is example contains the bare mininum to get nginx going with
-# Unicorn or Rainbows! servers.  Generally these configuration settings
+# unicorn servers.  Generally these configuration settings
 # are applicable to other HTTP application servers (and not just Ruby
 # ones), so if you have one working well for proxying another app
 # server, feel free to continue using it.
@@ -44,8 +44,8 @@ http {
   # click tracking!
   access_log /path/to/nginx.access.log combined;
 
-  # you generally want to serve static files with nginx since neither
-  # Unicorn nor Rainbows! is optimized for it at the moment
+  # you generally want to serve static files with nginx since
+  # unicorn is not and will never be optimized for it
   sendfile on;
 
   tcp_nopush on; # off may be better for *some* Comet/long-poll stuff
@@ -67,10 +67,10 @@ http {
              text/javascript application/x-javascript
              application/atom+xml;
 
-  # this can be any application server, not just Unicorn/Rainbows!
+  # this can be any application server, not just unicorn
   upstream app_server {
     # fail_timeout=0 means we always retry an upstream even if it failed
-    # to return a good HTTP response (in case the Unicorn master nukes a
+    # to return a good HTTP response (in case the unicorn master nukes a
     # single worker for timing out).
 
     # for UNIX domain socket setups:
@@ -132,12 +132,11 @@ http {
       # redirects, we set the Host: header above already.
       proxy_redirect off;
 
-      # set "proxy_buffering off" *only* for Rainbows! when doing
-      # Comet/long-poll/streaming.  It's also safe to set if you're using
-      # only serving fast clients with Unicorn + nginx, but not slow
-      # clients.  You normally want nginx to buffer responses to slow
-      # clients, even with Rails 3.1 streaming because otherwise a slow
-      # client can become a bottleneck of Unicorn.
+      # It's also safe to set if you're using only serving fast clients
+      # with unicorn + nginx, but not slow clients.  You normally want
+      # nginx to buffer responses to slow clients, even with Rails 3.1
+      # streaming because otherwise a slow client can become a bottleneck
+      # of unicorn.
       #
       # The Rack application may also set "X-Accel-Buffering (yes|no)"
       # in the response headers do disable/enable buffering on a
diff --git a/examples/unicorn.conf.rb b/examples/unicorn.conf.rb
index 4b28a5a..1e05cbb 100644
--- a/examples/unicorn.conf.rb
+++ b/examples/unicorn.conf.rb
@@ -40,11 +40,8 @@ pid "/path/to/app/shared/pids/unicorn.pid"
 stderr_path "/path/to/app/shared/log/unicorn.stderr.log"
 stdout_path "/path/to/app/shared/log/unicorn.stdout.log"
 
-# combine Ruby 2.0.0dev or REE with "preload_app true" for memory savings
-# http://rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
+# combine Ruby 2.0.0+ with "preload_app true" for memory savings
 preload_app true
-GC.respond_to?(:copy_on_write_friendly=) and
-  GC.copy_on_write_friendly = true
 
 # Enable this flag to have unicorn test client connections by writing the
 # beginning of the HTTP headers before calling the application.  This
diff --git a/ext/unicorn_http/extconf.rb b/ext/unicorn_http/extconf.rb
index 7a1b0cd..1da0282 100644
--- a/ext/unicorn_http/extconf.rb
+++ b/ext/unicorn_http/extconf.rb
@@ -5,6 +5,7 @@ have_macro("SIZEOF_OFF_T", "ruby.h") or check_sizeof("off_t", "sys/types.h")
 have_macro("SIZEOF_SIZE_T", "ruby.h") or check_sizeof("size_t", "sys/types.h")
 have_macro("SIZEOF_LONG", "ruby.h") or check_sizeof("long", "sys/types.h")
 have_func("rb_str_set_len", "ruby.h")
+have_func("rb_hash_clear", "ruby.h") # Ruby 2.0+
 have_func("gmtime_r", "time.h")
 
 create_makefile("unicorn_http")
diff --git a/ext/unicorn_http/httpdate.c b/ext/unicorn_http/httpdate.c
index bf54fdd..0a1045f 100644
--- a/ext/unicorn_http/httpdate.c
+++ b/ext/unicorn_http/httpdate.c
@@ -66,7 +66,7 @@ static VALUE httpdate(VALUE self)
 
 void init_unicorn_httpdate(void)
 {
-	VALUE mod = rb_const_get(rb_cObject, rb_intern("Unicorn"));
+	VALUE mod = rb_define_module("Unicorn");
 	mod = rb_define_module_under(mod, "HttpResponse");
 
 	buf = rb_str_new(0, buf_capa - 1);
diff --git a/ext/unicorn_http/unicorn_http.c b/ext/unicorn_http/unicorn_http.c
index 7dfa5d0..198f6eb 100644
--- a/ext/unicorn_http/unicorn_http.c
+++ b/ext/unicorn_http/unicorn_http.c
@@ -27,86 +27,32 @@ void init_unicorn_httpdate(void);
 #define UH_FL_KAVERSION 0x80
 #define UH_FL_HASHEADER 0x100
 #define UH_FL_TO_CLEAR 0x200
+#define UH_FL_RESSTART 0x400 /* for check_client_connection */
 
 /* all of these flags need to be set for keepalive to be supported */
 #define UH_FL_KEEPALIVE (UH_FL_KAVERSION | UH_FL_REQEOF | UH_FL_HASHEADER)
 
-/*
- * whether or not to trust X-Forwarded-Proto and X-Forwarded-SSL when
- * setting rack.url_scheme
- */
-static VALUE trust_x_forward = Qtrue;
-
-static unsigned long keepalive_requests = 100; /* same as nginx */
-
-/*
- * Returns the maximum number of keepalive requests a client may make
- * before the parser refuses to continue.
- */
-static VALUE ka_req(VALUE self)
-{
-  return ULONG2NUM(keepalive_requests);
-}
-
-/*
- * Sets the maximum number of keepalive requests a client may make.
- * A special value of +nil+ causes this to be the maximum value
- * possible (this is architecture-dependent).
- */
-static VALUE set_ka_req(VALUE self, VALUE val)
-{
-  keepalive_requests = NIL_P(val) ? ULONG_MAX : NUM2ULONG(val);
-
-  return ka_req(self);
-}
-
-/*
- * Sets whether or not the parser will trust X-Forwarded-Proto and
- * X-Forwarded-SSL headers and set "rack.url_scheme" to "https" accordingly.
- * Rainbows!/Zbatery installations facing untrusted clients directly
- * should set this to +false+
- */
-static VALUE set_xftrust(VALUE self, VALUE val)
-{
-  if (Qtrue == val || Qfalse == val)
-    trust_x_forward = val;
-  else
-    rb_raise(rb_eTypeError, "must be true or false");
-
-  return val;
-}
-
-/*
- * returns whether or not the parser will trust X-Forwarded-Proto and
- * X-Forwarded-SSL headers and set "rack.url_scheme" to "https" accordingly
- */
-static VALUE xftrust(VALUE self)
-{
-  return trust_x_forward;
-}
-
-static size_t MAX_HEADER_LEN = 1024 * (80 + 32); /* same as Mongrel */
+static unsigned int MAX_HEADER_LEN = 1024 * (80 + 32); /* same as Mongrel */
 
 /* this is only intended for use with Rainbows! */
 static VALUE set_maxhdrlen(VALUE self, VALUE len)
 {
-  return SIZET2NUM(MAX_HEADER_LEN = NUM2SIZET(len));
+  return UINT2NUM(MAX_HEADER_LEN = NUM2UINT(len));
 }
 
-/* keep this small for Rainbows! since every client has one */
+/* keep this small for other servers (e.g. yahns) since every client has one */
 struct http_parser {
   int cs; /* Ragel internal state */
   unsigned int flags;
-  unsigned long nr_requests;
-  size_t mark;
-  size_t offset;
+  unsigned int mark;
+  unsigned int offset;
   union { /* these 2 fields don't nest */
-    size_t field;
-    size_t query;
+    unsigned int field;
+    unsigned int query;
   } start;
   union {
-    size_t field_len; /* only used during header processing */
-    size_t dest_offset; /* only used during body processing */
+    unsigned int field_len; /* only used during header processing */
+    unsigned int dest_offset; /* only used during body processing */
   } s;
   VALUE buf;
   VALUE env;
@@ -117,7 +63,19 @@ struct http_parser {
   } len;
 };
 
-static ID id_clear, id_set_backtrace, id_response_start_sent;
+static ID id_set_backtrace;
+
+#ifdef HAVE_RB_HASH_CLEAR /* Ruby >= 2.0 */
+#  define my_hash_clear(h) (void)rb_hash_clear(h)
+#else /* !HAVE_RB_HASH_CLEAR - Ruby <= 1.9.3 */
+
+static ID id_clear;
+
+static void my_hash_clear(VALUE h)
+{
+  rb_funcall(h, id_clear, 0);
+}
+#endif /* HAVE_RB_HASH_CLEAR */
 
 static void finalize_header(struct http_parser *hp);
 
@@ -126,13 +84,25 @@ static void parser_raise(VALUE klass, const char *msg)
   VALUE exc = rb_exc_new2(klass, msg);
   VALUE bt = rb_ary_new();
 
-	rb_funcall(exc, id_set_backtrace, 1, bt);
-	rb_exc_raise(exc);
+  rb_funcall(exc, id_set_backtrace, 1, bt);
+  rb_exc_raise(exc);
+}
+
+static inline unsigned int ulong2uint(unsigned long n)
+{
+  unsigned int i = (unsigned int)n;
+
+  if (sizeof(unsigned int) != sizeof(unsigned long)) {
+    if ((unsigned long)i != n) {
+      rb_raise(rb_eRangeError, "too large to be 32-bit uint: %lu", n);
+    }
+  }
+  return i;
 }
 
 #define REMAINING (unsigned long)(pe - p)
-#define LEN(AT, FPC) (FPC - buffer - hp->AT)
-#define MARK(M,FPC) (hp->M = (FPC) - buffer)
+#define LEN(AT, FPC) (ulong2uint(FPC - buffer) - hp->AT)
+#define MARK(M,FPC) (hp->M = ulong2uint((FPC) - buffer))
 #define PTR_TO(F) (buffer + hp->F)
 #define STR_NEW(M,FPC) rb_str_new(PTR_TO(M), LEN(M, FPC))
 #define STRIPPED_STR_NEW(M,FPC) stripped_str_new(PTR_TO(M), LEN(M, FPC))
@@ -316,12 +286,12 @@ static void write_value(struct http_parser *hp,
 /** Machine **/
 
 
-#line 423 "unicorn_http.rl"
+#line 393 "unicorn_http.rl"
 
 
 /** Data **/
 
-#line 325 "unicorn_http.c"
+#line 295 "unicorn_http.c"
 static const int http_parser_start = 1;
 static const int http_parser_first_final = 122;
 static const int http_parser_error = 0;
@@ -332,7 +302,7 @@ static const int http_parser_en_Trailers = 114;
 static const int http_parser_en_main = 1;
 
 
-#line 427 "unicorn_http.rl"
+#line 397 "unicorn_http.rl"
 
 static void http_parser_init(struct http_parser *hp)
 {
@@ -345,12 +315,12 @@ static void http_parser_init(struct http_parser *hp)
   hp->len.content = 0;
   hp->cont = Qfalse; /* zero on MRI, should be optimized away by above */
   
-#line 349 "unicorn_http.c"
+#line 319 "unicorn_http.c"
 	{
 	cs = http_parser_start;
 	}
 
-#line 439 "unicorn_http.rl"
+#line 409 "unicorn_http.rl"
   hp->cs = cs;
 }
 
@@ -378,7 +348,7 @@ http_parser_execute(struct http_parser *hp, char *buffer, size_t len)
     goto skip_chunk_data_hack;
   }
   
-#line 382 "unicorn_http.c"
+#line 352 "unicorn_http.c"
 	{
 	if ( p == pe )
 		goto _test_eof;
@@ -413,14 +383,14 @@ st0:
 cs = 0;
 	goto _out;
 tr0:
-#line 319 "unicorn_http.rl"
+#line 289 "unicorn_http.rl"
 	{MARK(mark, p); }
 	goto st2;
 st2:
 	if ( ++p == pe )
 		goto _test_eof2;
 case 2:
-#line 424 "unicorn_http.c"
+#line 394 "unicorn_http.c"
 	switch( (*p) ) {
 		case 32: goto tr3;
 		case 33: goto st49;
@@ -446,14 +416,14 @@ case 2:
 		goto st49;
 	goto st0;
 tr3:
-#line 328 "unicorn_http.rl"
+#line 298 "unicorn_http.rl"
 	{ request_method(hp, PTR_TO(mark), LEN(mark, p)); }
 	goto st3;
 st3:
 	if ( ++p == pe )
 		goto _test_eof3;
 case 3:
-#line 457 "unicorn_http.c"
+#line 427 "unicorn_http.c"
 	switch( (*p) ) {
 		case 42: goto tr5;
 		case 47: goto tr6;
@@ -462,21 +432,21 @@ case 3:
 	}
 	goto st0;
 tr5:
-#line 319 "unicorn_http.rl"
+#line 289 "unicorn_http.rl"
 	{MARK(mark, p); }
 	goto st4;
 st4:
 	if ( ++p == pe )
 		goto _test_eof4;
 case 4:
-#line 473 "unicorn_http.c"
+#line 443 "unicorn_http.c"
 	switch( (*p) ) {
 		case 32: goto tr8;
 		case 35: goto tr9;
 	}
 	goto st0;
 tr8:
-#line 333 "unicorn_http.rl"
+#line 303 "unicorn_http.rl"
 	{
     VALUE str;
 
@@ -494,23 +464,23 @@ tr8:
   }
 	goto st5;
 tr37:
-#line 319 "unicorn_http.rl"
+#line 289 "unicorn_http.rl"
 	{MARK(mark, p); }
-#line 348 "unicorn_http.rl"
+#line 318 "unicorn_http.rl"
 	{
     VALIDATE_MAX_URI_LENGTH(LEN(mark, p), FRAGMENT);
     rb_hash_aset(hp->env, g_fragment, STR_NEW(mark, p));
   }
 	goto st5;
 tr40:
-#line 348 "unicorn_http.rl"
+#line 318 "unicorn_http.rl"
 	{
     VALIDATE_MAX_URI_LENGTH(LEN(mark, p), FRAGMENT);
     rb_hash_aset(hp->env, g_fragment, STR_NEW(mark, p));
   }
 	goto st5;
 tr44:
-#line 358 "unicorn_http.rl"
+#line 328 "unicorn_http.rl"
 	{
     VALUE val;
 
@@ -521,7 +491,7 @@ tr44:
     if (!STR_CSTR_EQ(val, "*"))
       rb_hash_aset(hp->env, g_path_info, val);
   }
-#line 333 "unicorn_http.rl"
+#line 303 "unicorn_http.rl"
 	{
     VALUE str;
 
@@ -539,14 +509,14 @@ tr44:
   }
 	goto st5;
 tr50:
-#line 352 "unicorn_http.rl"
+#line 322 "unicorn_http.rl"
 	{MARK(start.query, p); }
-#line 353 "unicorn_http.rl"
+#line 323 "unicorn_http.rl"
 	{
     VALIDATE_MAX_URI_LENGTH(LEN(start.query, p), QUERY_STRING);
     rb_hash_aset(hp->env, g_query_string, STR_NEW(start.query, p));
   }
-#line 333 "unicorn_http.rl"
+#line 303 "unicorn_http.rl"
 	{
     VALUE str;
 
@@ -564,12 +534,12 @@ tr50:
   }
 	goto st5;
 tr54:
-#line 353 "unicorn_http.rl"
+#line 323 "unicorn_http.rl"
 	{
     VALIDATE_MAX_URI_LENGTH(LEN(start.query, p), QUERY_STRING);
     rb_hash_aset(hp->env, g_query_string, STR_NEW(start.query, p));
   }
-#line 333 "unicorn_http.rl"
+#line 303 "unicorn_http.rl"
 	{
     VALUE str;
 
@@ -590,19 +560,19 @@ st5:
 	if ( ++p == pe )
 		goto _test_eof5;
 case 5:
-#line 594 "unicorn_http.c"
+#line 564 "unicorn_http.c"
 	if ( (*p) == 72 )
 		goto tr10;
 	goto st0;
 tr10:
-#line 319 "unicorn_http.rl"
+#line 289 "unicorn_http.rl"
 	{MARK(mark, p); }
 	goto st6;
 st6:
 	if ( ++p == pe )
 		goto _test_eof6;
 case 6:
-#line 606 "unicorn_http.c"
+#line 576 "unicorn_http.c"
 	if ( (*p) == 84 )
 		goto st7;
 	goto st0;
@@ -660,34 +630,34 @@ case 13:
 		goto st13;
 	goto st0;
 tr18:
-#line 357 "unicorn_http.rl"
+#line 327 "unicorn_http.rl"
 	{ http_version(hp, PTR_TO(mark), LEN(mark, p)); }
 	goto st14;
 tr25:
-#line 325 "unicorn_http.rl"
+#line 295 "unicorn_http.rl"
 	{ MARK(mark, p); }
-#line 327 "unicorn_http.rl"
+#line 297 "unicorn_http.rl"
 	{ write_cont_value(hp, buffer, p); }
 	goto st14;
 tr27:
-#line 327 "unicorn_http.rl"
+#line 297 "unicorn_http.rl"
 	{ write_cont_value(hp, buffer, p); }
 	goto st14;
 tr33:
-#line 325 "unicorn_http.rl"
+#line 295 "unicorn_http.rl"
 	{ MARK(mark, p); }
-#line 326 "unicorn_http.rl"
+#line 296 "unicorn_http.rl"
 	{ write_value(hp, buffer, p); }
 	goto st14;
 tr35:
-#line 326 "unicorn_http.rl"
+#line 296 "unicorn_http.rl"
 	{ write_value(hp, buffer, p); }
 	goto st14;
 st14:
 	if ( ++p == pe )
 		goto _test_eof14;
 case 14:
-#line 691 "unicorn_http.c"
+#line 661 "unicorn_http.c"
 	if ( (*p) == 10 )
 		goto st15;
 	goto st0;
@@ -722,14 +692,14 @@ case 15:
 		goto tr22;
 	goto st0;
 tr24:
-#line 325 "unicorn_http.rl"
+#line 295 "unicorn_http.rl"
 	{ MARK(mark, p); }
 	goto st16;
 st16:
 	if ( ++p == pe )
 		goto _test_eof16;
 case 16:
-#line 733 "unicorn_http.c"
+#line 703 "unicorn_http.c"
 	switch( (*p) ) {
 		case 9: goto tr24;
 		case 13: goto tr25;
@@ -740,14 +710,14 @@ case 16:
 		goto st0;
 	goto tr23;
 tr23:
-#line 325 "unicorn_http.rl"
+#line 295 "unicorn_http.rl"
 	{ MARK(mark, p); }
 	goto st17;
 st17:
 	if ( ++p == pe )
 		goto _test_eof17;
 case 17:
-#line 751 "unicorn_http.c"
+#line 721 "unicorn_http.c"
 	switch( (*p) ) {
 		case 13: goto tr27;
 		case 127: goto st0;
@@ -759,7 +729,7 @@ case 17:
 		goto st0;
 	goto st17;
 tr99:
-#line 333 "unicorn_http.rl"
+#line 303 "unicorn_http.rl"
 	{
     VALUE str;
 
@@ -777,23 +747,23 @@ tr99:
   }
 	goto st18;
 tr102:
-#line 319 "unicorn_http.rl"
+#line 289 "unicorn_http.rl"
 	{MARK(mark, p); }
-#line 348 "unicorn_http.rl"
+#line 318 "unicorn_http.rl"
 	{
     VALIDATE_MAX_URI_LENGTH(LEN(mark, p), FRAGMENT);
     rb_hash_aset(hp->env, g_fragment, STR_NEW(mark, p));
   }
 	goto st18;
 tr105:
-#line 348 "unicorn_http.rl"
+#line 318 "unicorn_http.rl"
 	{
     VALIDATE_MAX_URI_LENGTH(LEN(mark, p), FRAGMENT);
     rb_hash_aset(hp->env, g_fragment, STR_NEW(mark, p));
   }
 	goto st18;
 tr109:
-#line 358 "unicorn_http.rl"
+#line 328 "unicorn_http.rl"
 	{
     VALUE val;
 
@@ -804,7 +774,7 @@ tr109:
     if (!STR_CSTR_EQ(val, "*"))
       rb_hash_aset(hp->env, g_path_info, val);
   }
-#line 333 "unicorn_http.rl"
+#line 303 "unicorn_http.rl"
 	{
     VALUE str;
 
@@ -822,14 +792,14 @@ tr109:
   }
 	goto st18;
 tr115:
-#line 352 "unicorn_http.rl"
+#line 322 "unicorn_http.rl"
 	{MARK(start.query, p); }
-#line 353 "unicorn_http.rl"
+#line 323 "unicorn_http.rl"
 	{
     VALIDATE_MAX_URI_LENGTH(LEN(start.query, p), QUERY_STRING);
     rb_hash_aset(hp->env, g_query_string, STR_NEW(start.query, p));
   }
-#line 333 "unicorn_http.rl"
+#line 303 "unicorn_http.rl"
 	{
     VALUE str;
 
@@ -847,12 +817,12 @@ tr115:
   }
 	goto st18;
 tr119:
-#line 353 "unicorn_http.rl"
+#line 323 "unicorn_http.rl"
 	{
     VALIDATE_MAX_URI_LENGTH(LEN(start.query, p), QUERY_STRING);
     rb_hash_aset(hp->env, g_query_string, STR_NEW(start.query, p));
   }
-#line 333 "unicorn_http.rl"
+#line 303 "unicorn_http.rl"
 	{
     VALUE str;
 
@@ -873,12 +843,12 @@ st18:
 	if ( ++p == pe )
 		goto _test_eof18;
 case 18:
-#line 877 "unicorn_http.c"
+#line 847 "unicorn_http.c"
 	if ( (*p) == 10 )
 		goto tr28;
 	goto st0;
 tr28:
-#line 373 "unicorn_http.rl"
+#line 343 "unicorn_http.rl"
 	{
     finalize_header(hp);
 
@@ -902,23 +872,23 @@ st122:
 	if ( ++p == pe )
 		goto _test_eof122;
 case 122:
-#line 906 "unicorn_http.c"
+#line 876 "unicorn_http.c"
 	goto st0;
 tr22:
-#line 321 "unicorn_http.rl"
+#line 291 "unicorn_http.rl"
 	{ MARK(start.field, p); }
-#line 322 "unicorn_http.rl"
+#line 292 "unicorn_http.rl"
 	{ snake_upcase_char(deconst(p)); }
 	goto st19;
 tr29:
-#line 322 "unicorn_http.rl"
+#line 292 "unicorn_http.rl"
 	{ snake_upcase_char(deconst(p)); }
 	goto st19;
 st19:
 	if ( ++p == pe )
 		goto _test_eof19;
 case 19:
-#line 922 "unicorn_http.c"
+#line 892 "unicorn_http.c"
 	switch( (*p) ) {
 		case 33: goto tr29;
 		case 58: goto tr30;
@@ -944,18 +914,18 @@ case 19:
 		goto tr29;
 	goto st0;
 tr32:
-#line 325 "unicorn_http.rl"
+#line 295 "unicorn_http.rl"
 	{ MARK(mark, p); }
 	goto st20;
 tr30:
-#line 324 "unicorn_http.rl"
+#line 294 "unicorn_http.rl"
 	{ hp->s.field_len = LEN(start.field, p); }
 	goto st20;
 st20:
 	if ( ++p == pe )
 		goto _test_eof20;
 case 20:
-#line 959 "unicorn_http.c"
+#line 929 "unicorn_http.c"
 	switch( (*p) ) {
 		case 9: goto tr32;
 		case 13: goto tr33;
@@ -966,14 +936,14 @@ case 20:
 		goto st0;
 	goto tr31;
 tr31:
-#line 325 "unicorn_http.rl"
+#line 295 "unicorn_http.rl"
 	{ MARK(mark, p); }
 	goto st21;
 st21:
 	if ( ++p == pe )
 		goto _test_eof21;
 case 21:
-#line 977 "unicorn_http.c"
+#line 947 "unicorn_http.c"
 	switch( (*p) ) {
 		case 13: goto tr35;
 		case 127: goto st0;
@@ -985,7 +955,7 @@ case 21:
 		goto st0;
 	goto st21;
 tr9:
-#line 333 "unicorn_http.rl"
+#line 303 "unicorn_http.rl"
 	{
     VALUE str;
 
@@ -1003,7 +973,7 @@ tr9:
   }
 	goto st22;
 tr45:
-#line 358 "unicorn_http.rl"
+#line 328 "unicorn_http.rl"
 	{
     VALUE val;
 
@@ -1014,7 +984,7 @@ tr45:
     if (!STR_CSTR_EQ(val, "*"))
       rb_hash_aset(hp->env, g_path_info, val);
   }
-#line 333 "unicorn_http.rl"
+#line 303 "unicorn_http.rl"
 	{
     VALUE str;
 
@@ -1032,14 +1002,14 @@ tr45:
   }
 	goto st22;
 tr51:
-#line 352 "unicorn_http.rl"
+#line 322 "unicorn_http.rl"
 	{MARK(start.query, p); }
-#line 353 "unicorn_http.rl"
+#line 323 "unicorn_http.rl"
 	{
     VALIDATE_MAX_URI_LENGTH(LEN(start.query, p), QUERY_STRING);
     rb_hash_aset(hp->env, g_query_string, STR_NEW(start.query, p));
   }
-#line 333 "unicorn_http.rl"
+#line 303 "unicorn_http.rl"
 	{
     VALUE str;
 
@@ -1057,12 +1027,12 @@ tr51:
   }
 	goto st22;
 tr55:
-#line 353 "unicorn_http.rl"
+#line 323 "unicorn_http.rl"
 	{
     VALIDATE_MAX_URI_LENGTH(LEN(start.query, p), QUERY_STRING);
     rb_hash_aset(hp->env, g_query_string, STR_NEW(start.query, p));
   }
-#line 333 "unicorn_http.rl"
+#line 303 "unicorn_http.rl"
 	{
     VALUE str;
 
@@ -1083,7 +1053,7 @@ st22:
 	if ( ++p == pe )
 		goto _test_eof22;
 case 22:
-#line 1087 "unicorn_http.c"
+#line 1057 "unicorn_http.c"
 	switch( (*p) ) {
 		case 32: goto tr37;
 		case 35: goto st0;
@@ -1094,14 +1064,14 @@ case 22:
 		goto st0;
 	goto tr36;
 tr36:
-#line 319 "unicorn_http.rl"
+#line 289 "unicorn_http.rl"
 	{MARK(mark, p); }
 	goto st23;
 st23:
 	if ( ++p == pe )
 		goto _test_eof23;
 case 23:
-#line 1105 "unicorn_http.c"
+#line 1075 "unicorn_http.c"
 	switch( (*p) ) {
 		case 32: goto tr40;
 		case 35: goto st0;
@@ -1112,14 +1082,14 @@ case 23:
 		goto st0;
 	goto st23;
 tr38:
-#line 319 "unicorn_http.rl"
+#line 289 "unicorn_http.rl"
 	{MARK(mark, p); }
 	goto st24;
 st24:
 	if ( ++p == pe )
 		goto _test_eof24;
 case 24:
-#line 1123 "unicorn_http.c"
+#line 1093 "unicorn_http.c"
 	if ( (*p) < 65 ) {
 		if ( 48 <= (*p) && (*p) <= 57 )
 			goto st25;
@@ -1143,20 +1113,20 @@ case 25:
 		goto st23;
 	goto st0;
 tr6:
-#line 319 "unicorn_http.rl"
+#line 289 "unicorn_http.rl"
 	{MARK(mark, p); }
 	goto st26;
 tr71:
-#line 332 "unicorn_http.rl"
+#line 302 "unicorn_http.rl"
 	{ rb_hash_aset(hp->env, g_http_host, STR_NEW(mark, p)); }
-#line 319 "unicorn_http.rl"
+#line 289 "unicorn_http.rl"
 	{MARK(mark, p); }
 	goto st26;
 st26:
 	if ( ++p == pe )
 		goto _test_eof26;
 case 26:
-#line 1160 "unicorn_http.c"
+#line 1130 "unicorn_http.c"
 	switch( (*p) ) {
 		case 32: goto tr44;
 		case 35: goto tr45;
@@ -1194,7 +1164,7 @@ case 28:
 		goto st26;
 	goto st0;
 tr47:
-#line 358 "unicorn_http.rl"
+#line 328 "unicorn_http.rl"
 	{
     VALUE val;
 
@@ -1210,7 +1180,7 @@ st29:
 	if ( ++p == pe )
 		goto _test_eof29;
 case 29:
-#line 1214 "unicorn_http.c"
+#line 1184 "unicorn_http.c"
 	switch( (*p) ) {
 		case 32: goto tr50;
 		case 35: goto tr51;
@@ -1221,14 +1191,14 @@ case 29:
 		goto st0;
 	goto tr49;
 tr49:
-#line 352 "unicorn_http.rl"
+#line 322 "unicorn_http.rl"
 	{MARK(start.query, p); }
 	goto st30;
 st30:
 	if ( ++p == pe )
 		goto _test_eof30;
 case 30:
-#line 1232 "unicorn_http.c"
+#line 1202 "unicorn_http.c"
 	switch( (*p) ) {
 		case 32: goto tr54;
 		case 35: goto tr55;
@@ -1239,14 +1209,14 @@ case 30:
 		goto st0;
 	goto st30;
 tr52:
-#line 352 "unicorn_http.rl"
+#line 322 "unicorn_http.rl"
 	{MARK(start.query, p); }
 	goto st31;
 st31:
 	if ( ++p == pe )
 		goto _test_eof31;
 case 31:
-#line 1250 "unicorn_http.c"
+#line 1220 "unicorn_http.c"
 	if ( (*p) < 65 ) {
 		if ( 48 <= (*p) && (*p) <= 57 )
 			goto st32;
@@ -1270,58 +1240,58 @@ case 32:
 		goto st30;
 	goto st0;
 tr7:
-#line 319 "unicorn_http.rl"
+#line 289 "unicorn_http.rl"
 	{MARK(mark, p); }
-#line 323 "unicorn_http.rl"
+#line 293 "unicorn_http.rl"
 	{ downcase_char(deconst(p)); }
 	goto st33;
 st33:
 	if ( ++p == pe )
 		goto _test_eof33;
 case 33:
-#line 1283 "unicorn_http.c"
+#line 1253 "unicorn_http.c"
 	switch( (*p) ) {
 		case 84: goto tr58;
 		case 116: goto tr58;
 	}
 	goto st0;
 tr58:
-#line 323 "unicorn_http.rl"
+#line 293 "unicorn_http.rl"
 	{ downcase_char(deconst(p)); }
 	goto st34;
 st34:
 	if ( ++p == pe )
 		goto _test_eof34;
 case 34:
-#line 1297 "unicorn_http.c"
+#line 1267 "unicorn_http.c"
 	switch( (*p) ) {
 		case 84: goto tr59;
 		case 116: goto tr59;
 	}
 	goto st0;
 tr59:
-#line 323 "unicorn_http.rl"
+#line 293 "unicorn_http.rl"
 	{ downcase_char(deconst(p)); }
 	goto st35;
 st35:
 	if ( ++p == pe )
 		goto _test_eof35;
 case 35:
-#line 1311 "unicorn_http.c"
+#line 1281 "unicorn_http.c"
 	switch( (*p) ) {
 		case 80: goto tr60;
 		case 112: goto tr60;
 	}
 	goto st0;
 tr60:
-#line 323 "unicorn_http.rl"
+#line 293 "unicorn_http.rl"
 	{ downcase_char(deconst(p)); }
 	goto st36;
 st36:
 	if ( ++p == pe )
 		goto _test_eof36;
 case 36:
-#line 1325 "unicorn_http.c"
+#line 1295 "unicorn_http.c"
 	switch( (*p) ) {
 		case 58: goto tr61;
 		case 83: goto tr62;
@@ -1329,7 +1299,7 @@ case 36:
 	}
 	goto st0;
 tr61:
-#line 329 "unicorn_http.rl"
+#line 299 "unicorn_http.rl"
 	{
     rb_hash_aset(hp->env, g_rack_url_scheme, STR_NEW(mark, p));
   }
@@ -1338,7 +1308,7 @@ st37:
 	if ( ++p == pe )
 		goto _test_eof37;
 case 37:
-#line 1342 "unicorn_http.c"
+#line 1312 "unicorn_http.c"
 	if ( (*p) == 47 )
 		goto st38;
 	goto st0;
@@ -1426,14 +1396,14 @@ case 42:
 		goto st40;
 	goto st0;
 tr67:
-#line 319 "unicorn_http.rl"
+#line 289 "unicorn_http.rl"
 	{MARK(mark, p); }
 	goto st43;
 st43:
 	if ( ++p == pe )
 		goto _test_eof43;
 case 43:
-#line 1437 "unicorn_http.c"
+#line 1407 "unicorn_http.c"
 	switch( (*p) ) {
 		case 37: goto st41;
 		case 47: goto tr71;
@@ -1485,14 +1455,14 @@ case 44:
 		goto st0;
 	goto st40;
 tr68:
-#line 319 "unicorn_http.rl"
+#line 289 "unicorn_http.rl"
 	{MARK(mark, p); }
 	goto st45;
 st45:
 	if ( ++p == pe )
 		goto _test_eof45;
 case 45:
-#line 1496 "unicorn_http.c"
+#line 1466 "unicorn_http.c"
 	switch( (*p) ) {
 		case 37: goto st41;
 		case 47: goto st0;
@@ -1570,14 +1540,14 @@ case 47:
 		goto st0;
 	goto st40;
 tr62:
-#line 323 "unicorn_http.rl"
+#line 293 "unicorn_http.rl"
 	{ downcase_char(deconst(p)); }
 	goto st48;
 st48:
 	if ( ++p == pe )
 		goto _test_eof48;
 case 48:
-#line 1581 "unicorn_http.c"
+#line 1551 "unicorn_http.c"
 	if ( (*p) == 58 )
 		goto tr61;
 	goto st0;
@@ -2093,14 +2063,14 @@ case 67:
 		goto tr3;
 	goto st0;
 tr2:
-#line 319 "unicorn_http.rl"
+#line 289 "unicorn_http.rl"
 	{MARK(mark, p); }
 	goto st68;
 st68:
 	if ( ++p == pe )
 		goto _test_eof68;
 case 68:
-#line 2104 "unicorn_http.c"
+#line 2074 "unicorn_http.c"
 	switch( (*p) ) {
 		case 32: goto tr3;
 		case 33: goto st49;
@@ -2184,14 +2154,14 @@ case 70:
 		goto st51;
 	goto st0;
 tr95:
-#line 328 "unicorn_http.rl"
+#line 298 "unicorn_http.rl"
 	{ request_method(hp, PTR_TO(mark), LEN(mark, p)); }
 	goto st71;
 st71:
 	if ( ++p == pe )
 		goto _test_eof71;
 case 71:
-#line 2195 "unicorn_http.c"
+#line 2165 "unicorn_http.c"
 	switch( (*p) ) {
 		case 42: goto tr96;
 		case 47: goto tr97;
@@ -2200,14 +2170,14 @@ case 71:
 	}
 	goto st0;
 tr96:
-#line 319 "unicorn_http.rl"
+#line 289 "unicorn_http.rl"
 	{MARK(mark, p); }
 	goto st72;
 st72:
 	if ( ++p == pe )
 		goto _test_eof72;
 case 72:
-#line 2211 "unicorn_http.c"
+#line 2181 "unicorn_http.c"
 	switch( (*p) ) {
 		case 13: goto tr99;
 		case 32: goto tr8;
@@ -2215,7 +2185,7 @@ case 72:
 	}
 	goto st0;
 tr100:
-#line 333 "unicorn_http.rl"
+#line 303 "unicorn_http.rl"
 	{
     VALUE str;
 
@@ -2233,7 +2203,7 @@ tr100:
   }
 	goto st73;
 tr110:
-#line 358 "unicorn_http.rl"
+#line 328 "unicorn_http.rl"
 	{
     VALUE val;
 
@@ -2244,7 +2214,7 @@ tr110:
     if (!STR_CSTR_EQ(val, "*"))
       rb_hash_aset(hp->env, g_path_info, val);
   }
-#line 333 "unicorn_http.rl"
+#line 303 "unicorn_http.rl"
 	{
     VALUE str;
 
@@ -2262,14 +2232,14 @@ tr110:
   }
 	goto st73;
 tr116:
-#line 352 "unicorn_http.rl"
+#line 322 "unicorn_http.rl"
 	{MARK(start.query, p); }
-#line 353 "unicorn_http.rl"
+#line 323 "unicorn_http.rl"
 	{
     VALIDATE_MAX_URI_LENGTH(LEN(start.query, p), QUERY_STRING);
     rb_hash_aset(hp->env, g_query_string, STR_NEW(start.query, p));
   }
-#line 333 "unicorn_http.rl"
+#line 303 "unicorn_http.rl"
 	{
     VALUE str;
 
@@ -2287,12 +2257,12 @@ tr116:
   }
 	goto st73;
 tr120:
-#line 353 "unicorn_http.rl"
+#line 323 "unicorn_http.rl"
 	{
     VALIDATE_MAX_URI_LENGTH(LEN(start.query, p), QUERY_STRING);
     rb_hash_aset(hp->env, g_query_string, STR_NEW(start.query, p));
   }
-#line 333 "unicorn_http.rl"
+#line 303 "unicorn_http.rl"
 	{
     VALUE str;
 
@@ -2313,7 +2283,7 @@ st73:
 	if ( ++p == pe )
 		goto _test_eof73;
 case 73:
-#line 2317 "unicorn_http.c"
+#line 2287 "unicorn_http.c"
 	switch( (*p) ) {
 		case 13: goto tr102;
 		case 32: goto tr37;
@@ -2325,14 +2295,14 @@ case 73:
 		goto st0;
 	goto tr101;
 tr101:
-#line 319 "unicorn_http.rl"
+#line 289 "unicorn_http.rl"
 	{MARK(mark, p); }
 	goto st74;
 st74:
 	if ( ++p == pe )
 		goto _test_eof74;
 case 74:
-#line 2336 "unicorn_http.c"
+#line 2306 "unicorn_http.c"
 	switch( (*p) ) {
 		case 13: goto tr105;
 		case 32: goto tr40;
@@ -2344,14 +2314,14 @@ case 74:
 		goto st0;
 	goto st74;
 tr103:
-#line 319 "unicorn_http.rl"
+#line 289 "unicorn_http.rl"
 	{MARK(mark, p); }
 	goto st75;
 st75:
 	if ( ++p == pe )
 		goto _test_eof75;
 case 75:
-#line 2355 "unicorn_http.c"
+#line 2325 "unicorn_http.c"
 	if ( (*p) < 65 ) {
 		if ( 48 <= (*p) && (*p) <= 57 )
 			goto st76;
@@ -2375,20 +2345,20 @@ case 76:
 		goto st74;
 	goto st0;
 tr97:
-#line 319 "unicorn_http.rl"
+#line 289 "unicorn_http.rl"
 	{MARK(mark, p); }
 	goto st77;
 tr136:
-#line 332 "unicorn_http.rl"
+#line 302 "unicorn_http.rl"
 	{ rb_hash_aset(hp->env, g_http_host, STR_NEW(mark, p)); }
-#line 319 "unicorn_http.rl"
+#line 289 "unicorn_http.rl"
 	{MARK(mark, p); }
 	goto st77;
 st77:
 	if ( ++p == pe )
 		goto _test_eof77;
 case 77:
-#line 2392 "unicorn_http.c"
+#line 2362 "unicorn_http.c"
 	switch( (*p) ) {
 		case 13: goto tr109;
 		case 32: goto tr44;
@@ -2427,7 +2397,7 @@ case 79:
 		goto st77;
 	goto st0;
 tr112:
-#line 358 "unicorn_http.rl"
+#line 328 "unicorn_http.rl"
 	{
     VALUE val;
 
@@ -2443,7 +2413,7 @@ st80:
 	if ( ++p == pe )
 		goto _test_eof80;
 case 80:
-#line 2447 "unicorn_http.c"
+#line 2417 "unicorn_http.c"
 	switch( (*p) ) {
 		case 13: goto tr115;
 		case 32: goto tr50;
@@ -2455,14 +2425,14 @@ case 80:
 		goto st0;
 	goto tr114;
 tr114:
-#line 352 "unicorn_http.rl"
+#line 322 "unicorn_http.rl"
 	{MARK(start.query, p); }
 	goto st81;
 st81:
 	if ( ++p == pe )
 		goto _test_eof81;
 case 81:
-#line 2466 "unicorn_http.c"
+#line 2436 "unicorn_http.c"
 	switch( (*p) ) {
 		case 13: goto tr119;
 		case 32: goto tr54;
@@ -2474,14 +2444,14 @@ case 81:
 		goto st0;
 	goto st81;
 tr117:
-#line 352 "unicorn_http.rl"
+#line 322 "unicorn_http.rl"
 	{MARK(start.query, p); }
 	goto st82;
 st82:
 	if ( ++p == pe )
 		goto _test_eof82;
 case 82:
-#line 2485 "unicorn_http.c"
+#line 2455 "unicorn_http.c"
 	if ( (*p) < 65 ) {
 		if ( 48 <= (*p) && (*p) <= 57 )
 			goto st83;
@@ -2505,58 +2475,58 @@ case 83:
 		goto st81;
 	goto st0;
 tr98:
-#line 319 "unicorn_http.rl"
+#line 289 "unicorn_http.rl"
 	{MARK(mark, p); }
-#line 323 "unicorn_http.rl"
+#line 293 "unicorn_http.rl"
 	{ downcase_char(deconst(p)); }
 	goto st84;
 st84:
 	if ( ++p == pe )
 		goto _test_eof84;
 case 84:
-#line 2518 "unicorn_http.c"
+#line 2488 "unicorn_http.c"
 	switch( (*p) ) {
 		case 84: goto tr123;
 		case 116: goto tr123;
 	}
 	goto st0;
 tr123:
-#line 323 "unicorn_http.rl"
+#line 293 "unicorn_http.rl"
 	{ downcase_char(deconst(p)); }
 	goto st85;
 st85:
 	if ( ++p == pe )
 		goto _test_eof85;
 case 85:
-#line 2532 "unicorn_http.c"
+#line 2502 "unicorn_http.c"
 	switch( (*p) ) {
 		case 84: goto tr124;
 		case 116: goto tr124;
 	}
 	goto st0;
 tr124:
-#line 323 "unicorn_http.rl"
+#line 293 "unicorn_http.rl"
 	{ downcase_char(deconst(p)); }
 	goto st86;
 st86:
 	if ( ++p == pe )
 		goto _test_eof86;
 case 86:
-#line 2546 "unicorn_http.c"
+#line 2516 "unicorn_http.c"
 	switch( (*p) ) {
 		case 80: goto tr125;
 		case 112: goto tr125;
 	}
 	goto st0;
 tr125:
-#line 323 "unicorn_http.rl"
+#line 293 "unicorn_http.rl"
 	{ downcase_char(deconst(p)); }
 	goto st87;
 st87:
 	if ( ++p == pe )
 		goto _test_eof87;
 case 87:
-#line 2560 "unicorn_http.c"
+#line 2530 "unicorn_http.c"
 	switch( (*p) ) {
 		case 58: goto tr126;
 		case 83: goto tr127;
@@ -2564,7 +2534,7 @@ case 87:
 	}
 	goto st0;
 tr126:
-#line 329 "unicorn_http.rl"
+#line 299 "unicorn_http.rl"
 	{
     rb_hash_aset(hp->env, g_rack_url_scheme, STR_NEW(mark, p));
   }
@@ -2573,7 +2543,7 @@ st88:
 	if ( ++p == pe )
 		goto _test_eof88;
 case 88:
-#line 2577 "unicorn_http.c"
+#line 2547 "unicorn_http.c"
 	if ( (*p) == 47 )
 		goto st89;
 	goto st0;
@@ -2661,14 +2631,14 @@ case 93:
 		goto st91;
 	goto st0;
 tr132:
-#line 319 "unicorn_http.rl"
+#line 289 "unicorn_http.rl"
 	{MARK(mark, p); }
 	goto st94;
 st94:
 	if ( ++p == pe )
 		goto _test_eof94;
 case 94:
-#line 2672 "unicorn_http.c"
+#line 2642 "unicorn_http.c"
 	switch( (*p) ) {
 		case 37: goto st92;
 		case 47: goto tr136;
@@ -2720,14 +2690,14 @@ case 95:
 		goto st0;
 	goto st91;
 tr133:
-#line 319 "unicorn_http.rl"
+#line 289 "unicorn_http.rl"
 	{MARK(mark, p); }
 	goto st96;
 st96:
 	if ( ++p == pe )
 		goto _test_eof96;
 case 96:
-#line 2731 "unicorn_http.c"
+#line 2701 "unicorn_http.c"
 	switch( (*p) ) {
 		case 37: goto st92;
 		case 47: goto st0;
@@ -2805,14 +2775,14 @@ case 98:
 		goto st0;
 	goto st91;
 tr127:
-#line 323 "unicorn_http.rl"
+#line 293 "unicorn_http.rl"
 	{ downcase_char(deconst(p)); }
 	goto st99;
 st99:
 	if ( ++p == pe )
 		goto _test_eof99;
 case 99:
-#line 2816 "unicorn_http.c"
+#line 2786 "unicorn_http.c"
 	if ( (*p) == 58 )
 		goto tr126;
 	goto st0;
@@ -2832,7 +2802,7 @@ case 100:
 		goto tr141;
 	goto st0;
 tr140:
-#line 368 "unicorn_http.rl"
+#line 338 "unicorn_http.rl"
 	{
     hp->len.chunk = step_incr(hp->len.chunk, (*p), 16);
     if (hp->len.chunk < 0)
@@ -2843,7 +2813,7 @@ st101:
 	if ( ++p == pe )
 		goto _test_eof101;
 case 101:
-#line 2847 "unicorn_http.c"
+#line 2817 "unicorn_http.c"
 	switch( (*p) ) {
 		case 13: goto st102;
 		case 48: goto tr140;
@@ -2866,7 +2836,7 @@ case 102:
 		goto tr144;
 	goto st0;
 tr144:
-#line 397 "unicorn_http.rl"
+#line 367 "unicorn_http.rl"
 	{
     HP_FL_SET(hp, INTRAILER);
     cs = http_parser_en_Trailers;
@@ -2879,10 +2849,10 @@ st123:
 	if ( ++p == pe )
 		goto _test_eof123;
 case 123:
-#line 2883 "unicorn_http.c"
+#line 2853 "unicorn_http.c"
 	goto st0;
 tr141:
-#line 368 "unicorn_http.rl"
+#line 338 "unicorn_http.rl"
 	{
     hp->len.chunk = step_incr(hp->len.chunk, (*p), 16);
     if (hp->len.chunk < 0)
@@ -2893,7 +2863,7 @@ st103:
 	if ( ++p == pe )
 		goto _test_eof103;
 case 103:
-#line 2897 "unicorn_http.c"
+#line 2867 "unicorn_http.c"
 	switch( (*p) ) {
 		case 13: goto st104;
 		case 59: goto st108;
@@ -2920,7 +2890,7 @@ st105:
 case 105:
 	goto tr148;
 tr148:
-#line 405 "unicorn_http.rl"
+#line 375 "unicorn_http.rl"
 	{
   skip_chunk_data_hack: {
     size_t nr = MIN((size_t)hp->len.chunk, REMAINING);
@@ -2942,7 +2912,7 @@ st106:
 	if ( ++p == pe )
 		goto _test_eof106;
 case 106:
-#line 2946 "unicorn_http.c"
+#line 2916 "unicorn_http.c"
 	if ( (*p) == 13 )
 		goto st107;
 	goto st0;
@@ -3164,14 +3134,14 @@ case 114:
 		goto tr157;
 	goto st0;
 tr159:
-#line 325 "unicorn_http.rl"
+#line 295 "unicorn_http.rl"
 	{ MARK(mark, p); }
 	goto st115;
 st115:
 	if ( ++p == pe )
 		goto _test_eof115;
 case 115:
-#line 3175 "unicorn_http.c"
+#line 3145 "unicorn_http.c"
 	switch( (*p) ) {
 		case 9: goto tr159;
 		case 13: goto tr160;
@@ -3182,14 +3152,14 @@ case 115:
 		goto st0;
 	goto tr158;
 tr158:
-#line 325 "unicorn_http.rl"
+#line 295 "unicorn_http.rl"
 	{ MARK(mark, p); }
 	goto st116;
 st116:
 	if ( ++p == pe )
 		goto _test_eof116;
 case 116:
-#line 3193 "unicorn_http.c"
+#line 3163 "unicorn_http.c"
 	switch( (*p) ) {
 		case 13: goto tr162;
 		case 127: goto st0;
@@ -3201,30 +3171,30 @@ case 116:
 		goto st0;
 	goto st116;
 tr160:
-#line 325 "unicorn_http.rl"
+#line 295 "unicorn_http.rl"
 	{ MARK(mark, p); }
-#line 327 "unicorn_http.rl"
+#line 297 "unicorn_http.rl"
 	{ write_cont_value(hp, buffer, p); }
 	goto st117;
 tr162:
-#line 327 "unicorn_http.rl"
+#line 297 "unicorn_http.rl"
 	{ write_cont_value(hp, buffer, p); }
 	goto st117;
 tr169:
-#line 325 "unicorn_http.rl"
+#line 295 "unicorn_http.rl"
 	{ MARK(mark, p); }
-#line 326 "unicorn_http.rl"
+#line 296 "unicorn_http.rl"
 	{ write_value(hp, buffer, p); }
 	goto st117;
 tr171:
-#line 326 "unicorn_http.rl"
+#line 296 "unicorn_http.rl"
 	{ write_value(hp, buffer, p); }
 	goto st117;
 st117:
 	if ( ++p == pe )
 		goto _test_eof117;
 case 117:
-#line 3228 "unicorn_http.c"
+#line 3198 "unicorn_http.c"
 	if ( (*p) == 10 )
 		goto st114;
 	goto st0;
@@ -3236,7 +3206,7 @@ case 118:
 		goto tr164;
 	goto st0;
 tr164:
-#line 392 "unicorn_http.rl"
+#line 362 "unicorn_http.rl"
 	{
     cs = http_parser_first_final;
     goto post_exec;
@@ -3246,23 +3216,23 @@ st124:
 	if ( ++p == pe )
 		goto _test_eof124;
 case 124:
-#line 3250 "unicorn_http.c"
+#line 3220 "unicorn_http.c"
 	goto st0;
 tr157:
-#line 321 "unicorn_http.rl"
+#line 291 "unicorn_http.rl"
 	{ MARK(start.field, p); }
-#line 322 "unicorn_http.rl"
+#line 292 "unicorn_http.rl"
 	{ snake_upcase_char(deconst(p)); }
 	goto st119;
 tr165:
-#line 322 "unicorn_http.rl"
+#line 292 "unicorn_http.rl"
 	{ snake_upcase_char(deconst(p)); }
 	goto st119;
 st119:
 	if ( ++p == pe )
 		goto _test_eof119;
 case 119:
-#line 3266 "unicorn_http.c"
+#line 3236 "unicorn_http.c"
 	switch( (*p) ) {
 		case 33: goto tr165;
 		case 58: goto tr166;
@@ -3288,18 +3258,18 @@ case 119:
 		goto tr165;
 	goto st0;
 tr168:
-#line 325 "unicorn_http.rl"
+#line 295 "unicorn_http.rl"
 	{ MARK(mark, p); }
 	goto st120;
 tr166:
-#line 324 "unicorn_http.rl"
+#line 294 "unicorn_http.rl"
 	{ hp->s.field_len = LEN(start.field, p); }
 	goto st120;
 st120:
 	if ( ++p == pe )
 		goto _test_eof120;
 case 120:
-#line 3303 "unicorn_http.c"
+#line 3273 "unicorn_http.c"
 	switch( (*p) ) {
 		case 9: goto tr168;
 		case 13: goto tr169;
@@ -3310,14 +3280,14 @@ case 120:
 		goto st0;
 	goto tr167;
 tr167:
-#line 325 "unicorn_http.rl"
+#line 295 "unicorn_http.rl"
 	{ MARK(mark, p); }
 	goto st121;
 st121:
 	if ( ++p == pe )
 		goto _test_eof121;
 case 121:
-#line 3321 "unicorn_http.c"
+#line 3291 "unicorn_http.c"
 	switch( (*p) ) {
 		case 13: goto tr171;
 		case 127: goto st0;
@@ -3457,11 +3427,11 @@ case 121:
 	_out: {}
 	}
 
-#line 466 "unicorn_http.rl"
+#line 436 "unicorn_http.rl"
 post_exec: /* "_out:" also goes here */
   if (hp->cs != http_parser_error)
     hp->cs = cs;
-  hp->offset = p - buffer;
+  hp->offset = ulong2uint(p - buffer);
 
   assert(p <= pe && "buffer overflow after parsing execute");
   assert(hp->offset <= len && "offset longer than length");
@@ -3486,26 +3456,29 @@ static void set_url_scheme(VALUE env, VALUE *server_port)
   VALUE scheme = rb_hash_aref(env, g_rack_url_scheme);
 
   if (NIL_P(scheme)) {
-    if (trust_x_forward == Qfalse) {
-      scheme = g_http;
+    /*
+     * would anybody be horribly opposed to removing the X-Forwarded-SSL
+     * and X-Forwarded-Proto handling from this parser?  We've had it
+     * forever and nobody has said anything against it, either.
+     * Anyways, please send comments to our public mailing list:
+     * unicorn-public at bogomips.org (no HTML mail, no subscription necessary)
+     */
+    scheme = rb_hash_aref(env, g_http_x_forwarded_ssl);
+    if (!NIL_P(scheme) && STR_CSTR_EQ(scheme, "on")) {
+      *server_port = g_port_443;
+      scheme = g_https;
     } else {
-      scheme = rb_hash_aref(env, g_http_x_forwarded_ssl);
-      if (!NIL_P(scheme) && STR_CSTR_EQ(scheme, "on")) {
-        *server_port = g_port_443;
-        scheme = g_https;
+      scheme = rb_hash_aref(env, g_http_x_forwarded_proto);
+      if (NIL_P(scheme)) {
+        scheme = g_http;
       } else {
-        scheme = rb_hash_aref(env, g_http_x_forwarded_proto);
-        if (NIL_P(scheme)) {
-          scheme = g_http;
+        long len = RSTRING_LEN(scheme);
+        if (len >= 5 && !memcmp(RSTRING_PTR(scheme), "https", 5)) {
+          if (len != 5)
+            scheme = g_https;
+          *server_port = g_port_443;
         } else {
-          long len = RSTRING_LEN(scheme);
-          if (len >= 5 && !memcmp(RSTRING_PTR(scheme), "https", 5)) {
-            if (len != 5)
-              scheme = g_https;
-            *server_port = g_port_443;
-          } else {
-            scheme = g_http;
-          }
+          scheme = g_http;
         }
       }
     }
@@ -3603,7 +3576,6 @@ static VALUE HttpParser_init(VALUE self)
   http_parser_init(hp);
   hp->buf = rb_str_new(NULL, 0);
   hp->env = rb_hash_new();
-  hp->nr_requests = keepalive_requests;
 
   return self;
 }
@@ -3620,61 +3592,11 @@ static VALUE HttpParser_clear(VALUE self)
   struct http_parser *hp = data_get(self);
 
   http_parser_init(hp);
-  rb_funcall(hp->env, id_clear, 0);
-  rb_ivar_set(self, id_response_start_sent, Qfalse);
+  my_hash_clear(hp->env);
 
   return self;
 }
 
-/**
- * call-seq:
- *    parser.dechunk! => parser
- *
- * Resets the parser to a state suitable for dechunking response bodies
- *
- */
-static VALUE HttpParser_dechunk_bang(VALUE self)
-{
-  struct http_parser *hp = data_get(self);
-
-  http_parser_init(hp);
-
-  /*
-   * we don't care about trailers in dechunk-only mode,
-   * but if we did we'd set UH_FL_HASTRAILER and clear hp->env
-   */
-  if (0) {
-    rb_funcall(hp->env, id_clear, 0);
-    hp->flags = UH_FL_HASTRAILER;
-  }
-
-  hp->flags |= UH_FL_HASBODY | UH_FL_INBODY | UH_FL_CHUNKED;
-  hp->cs = http_parser_en_ChunkedBody;
-
-  return self;
-}
-
-/**
- * call-seq:
- *    parser.reset => nil
- *
- * Resets the parser to it's initial state so that you can reuse it
- * rather than making new ones.
- *
- * This method is deprecated and to be removed in Unicorn 4.x
- */
-static VALUE HttpParser_reset(VALUE self)
-{
-  static int warned;
-
-  if (!warned) {
-    rb_warn("Unicorn::HttpParser#reset is deprecated; "
-            "use Unicorn::HttpParser#clear instead");
-  }
-  HttpParser_clear(self);
-  return Qnil;
-}
-
 static void advance_str(VALUE str, off_t nr)
 {
   long len = RSTRING_LEN(str);
@@ -3837,15 +3759,13 @@ static VALUE HttpParser_keepalive(VALUE self)
  *    parser.next? => true or false
  *
  * Exactly like HttpParser#keepalive?, except it will reset the internal
- * parser state on next parse if it returns true.  It will also respect
- * the maximum *keepalive_requests* value and return false if that is
- * reached.
+ * parser state on next parse if it returns true.
  */
 static VALUE HttpParser_next(VALUE self)
 {
   struct http_parser *hp = data_get(self);
 
-  if ((HP_FL_ALL(hp, KEEPALIVE)) && (hp->nr_requests-- != 0)) {
+  if (HP_FL_ALL(hp, KEEPALIVE)) {
     HP_FL_SET(hp, TO_CLEAR);
     return Qtrue;
   }
@@ -3955,6 +3875,25 @@ static VALUE HttpParser_filter_body(VALUE self, VALUE dst, VALUE src)
   return src;
 }
 
+static VALUE HttpParser_rssset(VALUE self, VALUE boolean)
+{
+  struct http_parser *hp = data_get(self);
+
+  if (RTEST(boolean))
+    HP_FL_SET(hp, RESSTART);
+  else
+    HP_FL_UNSET(hp, RESSTART);
+
+  return boolean; /* ignored by Ruby anyways */
+}
+
+static VALUE HttpParser_rssget(VALUE self)
+{
+  struct http_parser *hp = data_get(self);
+
+  return HP_FL_TEST(hp, RESSTART) ? Qtrue : Qfalse;
+}
+
 #define SET_GLOBAL(var,str) do { \
   var = find_common_field(str, sizeof(str) - 1); \
   assert(!NIL_P(var) && "missed global field"); \
@@ -3964,7 +3903,7 @@ void Init_unicorn_http(void)
 {
   VALUE mUnicorn, cHttpParser;
 
-  mUnicorn = rb_const_get(rb_cObject, rb_intern("Unicorn"));
+  mUnicorn = rb_define_module("Unicorn");
   cHttpParser = rb_define_class_under(mUnicorn, "HttpParser", rb_cObject);
   eHttpParserError =
          rb_define_class_under(mUnicorn, "HttpParserError", rb_eIOError);
@@ -3977,8 +3916,6 @@ void Init_unicorn_http(void)
   rb_define_alloc_func(cHttpParser, HttpParser_alloc);
   rb_define_method(cHttpParser, "initialize", HttpParser_init, 0);
   rb_define_method(cHttpParser, "clear", HttpParser_clear, 0);
-  rb_define_method(cHttpParser, "reset", HttpParser_reset, 0);
-  rb_define_method(cHttpParser, "dechunk!", HttpParser_dechunk_bang, 0);
   rb_define_method(cHttpParser, "parse", HttpParser_parse, 0);
   rb_define_method(cHttpParser, "add_parse", HttpParser_add_parse, 1);
   rb_define_method(cHttpParser, "headers", HttpParser_headers, 2);
@@ -3991,6 +3928,8 @@ void Init_unicorn_http(void)
   rb_define_method(cHttpParser, "next?", HttpParser_next, 0);
   rb_define_method(cHttpParser, "buf", HttpParser_buf, 0);
   rb_define_method(cHttpParser, "env", HttpParser_env, 0);
+  rb_define_method(cHttpParser, "response_start_sent=", HttpParser_rssset, 1);
+  rb_define_method(cHttpParser, "response_start_sent", HttpParser_rssget, 0);
 
   /*
    * The maximum size a single chunk when using chunked transfer encoding.
@@ -4007,14 +3946,6 @@ void Init_unicorn_http(void)
    */
   rb_define_const(cHttpParser, "LENGTH_MAX", OFFT2NUM(UH_OFF_T_MAX));
 
-  /* default value for keepalive_requests */
-  rb_define_const(cHttpParser, "KEEPALIVE_REQUESTS_DEFAULT",
-                  ULONG2NUM(keepalive_requests));
-
-  rb_define_singleton_method(cHttpParser, "keepalive_requests", ka_req, 0);
-  rb_define_singleton_method(cHttpParser, "keepalive_requests=", set_ka_req, 1);
-  rb_define_singleton_method(cHttpParser, "trust_x_forwarded=", set_xftrust, 1);
-  rb_define_singleton_method(cHttpParser, "trust_x_forwarded?", xftrust, 0);
   rb_define_singleton_method(cHttpParser, "max_header_len=", set_maxhdrlen, 1);
 
   init_common_fields();
@@ -4023,9 +3954,11 @@ void Init_unicorn_http(void)
   SET_GLOBAL(g_http_transfer_encoding, "TRANSFER_ENCODING");
   SET_GLOBAL(g_content_length, "CONTENT_LENGTH");
   SET_GLOBAL(g_http_connection, "CONNECTION");
-  id_clear = rb_intern("clear");
   id_set_backtrace = rb_intern("set_backtrace");
-  id_response_start_sent = rb_intern("@response_start_sent");
   init_unicorn_httpdate();
+
+#ifndef HAVE_RB_HASH_CLEAR
+  id_clear = rb_intern("clear");
+#endif
 }
 #undef SET_GLOBAL
diff --git a/ext/unicorn_http/unicorn_http.rl b/ext/unicorn_http/unicorn_http.rl
index 6293033..046ccb5 100644
--- a/ext/unicorn_http/unicorn_http.rl
+++ b/ext/unicorn_http/unicorn_http.rl
@@ -25,86 +25,32 @@ void init_unicorn_httpdate(void);
 #define UH_FL_KAVERSION 0x80
 #define UH_FL_HASHEADER 0x100
 #define UH_FL_TO_CLEAR 0x200
+#define UH_FL_RESSTART 0x400 /* for check_client_connection */
 
 /* all of these flags need to be set for keepalive to be supported */
 #define UH_FL_KEEPALIVE (UH_FL_KAVERSION | UH_FL_REQEOF | UH_FL_HASHEADER)
 
-/*
- * whether or not to trust X-Forwarded-Proto and X-Forwarded-SSL when
- * setting rack.url_scheme
- */
-static VALUE trust_x_forward = Qtrue;
-
-static unsigned long keepalive_requests = 100; /* same as nginx */
-
-/*
- * Returns the maximum number of keepalive requests a client may make
- * before the parser refuses to continue.
- */
-static VALUE ka_req(VALUE self)
-{
-  return ULONG2NUM(keepalive_requests);
-}
-
-/*
- * Sets the maximum number of keepalive requests a client may make.
- * A special value of +nil+ causes this to be the maximum value
- * possible (this is architecture-dependent).
- */
-static VALUE set_ka_req(VALUE self, VALUE val)
-{
-  keepalive_requests = NIL_P(val) ? ULONG_MAX : NUM2ULONG(val);
-
-  return ka_req(self);
-}
-
-/*
- * Sets whether or not the parser will trust X-Forwarded-Proto and
- * X-Forwarded-SSL headers and set "rack.url_scheme" to "https" accordingly.
- * Rainbows!/Zbatery installations facing untrusted clients directly
- * should set this to +false+
- */
-static VALUE set_xftrust(VALUE self, VALUE val)
-{
-  if (Qtrue == val || Qfalse == val)
-    trust_x_forward = val;
-  else
-    rb_raise(rb_eTypeError, "must be true or false");
-
-  return val;
-}
-
-/*
- * returns whether or not the parser will trust X-Forwarded-Proto and
- * X-Forwarded-SSL headers and set "rack.url_scheme" to "https" accordingly
- */
-static VALUE xftrust(VALUE self)
-{
-  return trust_x_forward;
-}
-
-static size_t MAX_HEADER_LEN = 1024 * (80 + 32); /* same as Mongrel */
+static unsigned int MAX_HEADER_LEN = 1024 * (80 + 32); /* same as Mongrel */
 
 /* this is only intended for use with Rainbows! */
 static VALUE set_maxhdrlen(VALUE self, VALUE len)
 {
-  return SIZET2NUM(MAX_HEADER_LEN = NUM2SIZET(len));
+  return UINT2NUM(MAX_HEADER_LEN = NUM2UINT(len));
 }
 
-/* keep this small for Rainbows! since every client has one */
+/* keep this small for other servers (e.g. yahns) since every client has one */
 struct http_parser {
   int cs; /* Ragel internal state */
   unsigned int flags;
-  unsigned long nr_requests;
-  size_t mark;
-  size_t offset;
+  unsigned int mark;
+  unsigned int offset;
   union { /* these 2 fields don't nest */
-    size_t field;
-    size_t query;
+    unsigned int field;
+    unsigned int query;
   } start;
   union {
-    size_t field_len; /* only used during header processing */
-    size_t dest_offset; /* only used during body processing */
+    unsigned int field_len; /* only used during header processing */
+    unsigned int dest_offset; /* only used during body processing */
   } s;
   VALUE buf;
   VALUE env;
@@ -115,7 +61,19 @@ struct http_parser {
   } len;
 };
 
-static ID id_clear, id_set_backtrace, id_response_start_sent;
+static ID id_set_backtrace;
+
+#ifdef HAVE_RB_HASH_CLEAR /* Ruby >= 2.0 */
+#  define my_hash_clear(h) (void)rb_hash_clear(h)
+#else /* !HAVE_RB_HASH_CLEAR - Ruby <= 1.9.3 */
+
+static ID id_clear;
+
+static void my_hash_clear(VALUE h)
+{
+  rb_funcall(h, id_clear, 0);
+}
+#endif /* HAVE_RB_HASH_CLEAR */
 
 static void finalize_header(struct http_parser *hp);
 
@@ -124,13 +82,25 @@ static void parser_raise(VALUE klass, const char *msg)
   VALUE exc = rb_exc_new2(klass, msg);
   VALUE bt = rb_ary_new();
 
-	rb_funcall(exc, id_set_backtrace, 1, bt);
-	rb_exc_raise(exc);
+  rb_funcall(exc, id_set_backtrace, 1, bt);
+  rb_exc_raise(exc);
+}
+
+static inline unsigned int ulong2uint(unsigned long n)
+{
+  unsigned int i = (unsigned int)n;
+
+  if (sizeof(unsigned int) != sizeof(unsigned long)) {
+    if ((unsigned long)i != n) {
+      rb_raise(rb_eRangeError, "too large to be 32-bit uint: %lu", n);
+    }
+  }
+  return i;
 }
 
 #define REMAINING (unsigned long)(pe - p)
-#define LEN(AT, FPC) (FPC - buffer - hp->AT)
-#define MARK(M,FPC) (hp->M = (FPC) - buffer)
+#define LEN(AT, FPC) (ulong2uint(FPC - buffer) - hp->AT)
+#define MARK(M,FPC) (hp->M = ulong2uint((FPC) - buffer))
 #define PTR_TO(F) (buffer + hp->F)
 #define STR_NEW(M,FPC) rb_str_new(PTR_TO(M), LEN(M, FPC))
 #define STRIPPED_STR_NEW(M,FPC) stripped_str_new(PTR_TO(M), LEN(M, FPC))
@@ -466,7 +436,7 @@ http_parser_execute(struct http_parser *hp, char *buffer, size_t len)
 post_exec: /* "_out:" also goes here */
   if (hp->cs != http_parser_error)
     hp->cs = cs;
-  hp->offset = p - buffer;
+  hp->offset = ulong2uint(p - buffer);
 
   assert(p <= pe && "buffer overflow after parsing execute");
   assert(hp->offset <= len && "offset longer than length");
@@ -491,26 +461,29 @@ static void set_url_scheme(VALUE env, VALUE *server_port)
   VALUE scheme = rb_hash_aref(env, g_rack_url_scheme);
 
   if (NIL_P(scheme)) {
-    if (trust_x_forward == Qfalse) {
-      scheme = g_http;
+    /*
+     * would anybody be horribly opposed to removing the X-Forwarded-SSL
+     * and X-Forwarded-Proto handling from this parser?  We've had it
+     * forever and nobody has said anything against it, either.
+     * Anyways, please send comments to our public mailing list:
+     * unicorn-public at bogomips.org (no HTML mail, no subscription necessary)
+     */
+    scheme = rb_hash_aref(env, g_http_x_forwarded_ssl);
+    if (!NIL_P(scheme) && STR_CSTR_EQ(scheme, "on")) {
+      *server_port = g_port_443;
+      scheme = g_https;
     } else {
-      scheme = rb_hash_aref(env, g_http_x_forwarded_ssl);
-      if (!NIL_P(scheme) && STR_CSTR_EQ(scheme, "on")) {
-        *server_port = g_port_443;
-        scheme = g_https;
+      scheme = rb_hash_aref(env, g_http_x_forwarded_proto);
+      if (NIL_P(scheme)) {
+        scheme = g_http;
       } else {
-        scheme = rb_hash_aref(env, g_http_x_forwarded_proto);
-        if (NIL_P(scheme)) {
-          scheme = g_http;
+        long len = RSTRING_LEN(scheme);
+        if (len >= 5 && !memcmp(RSTRING_PTR(scheme), "https", 5)) {
+          if (len != 5)
+            scheme = g_https;
+          *server_port = g_port_443;
         } else {
-          long len = RSTRING_LEN(scheme);
-          if (len >= 5 && !memcmp(RSTRING_PTR(scheme), "https", 5)) {
-            if (len != 5)
-              scheme = g_https;
-            *server_port = g_port_443;
-          } else {
-            scheme = g_http;
-          }
+          scheme = g_http;
         }
       }
     }
@@ -608,7 +581,6 @@ static VALUE HttpParser_init(VALUE self)
   http_parser_init(hp);
   hp->buf = rb_str_new(NULL, 0);
   hp->env = rb_hash_new();
-  hp->nr_requests = keepalive_requests;
 
   return self;
 }
@@ -625,61 +597,11 @@ static VALUE HttpParser_clear(VALUE self)
   struct http_parser *hp = data_get(self);
 
   http_parser_init(hp);
-  rb_funcall(hp->env, id_clear, 0);
-  rb_ivar_set(self, id_response_start_sent, Qfalse);
+  my_hash_clear(hp->env);
 
   return self;
 }
 
-/**
- * call-seq:
- *    parser.dechunk! => parser
- *
- * Resets the parser to a state suitable for dechunking response bodies
- *
- */
-static VALUE HttpParser_dechunk_bang(VALUE self)
-{
-  struct http_parser *hp = data_get(self);
-
-  http_parser_init(hp);
-
-  /*
-   * we don't care about trailers in dechunk-only mode,
-   * but if we did we'd set UH_FL_HASTRAILER and clear hp->env
-   */
-  if (0) {
-    rb_funcall(hp->env, id_clear, 0);
-    hp->flags = UH_FL_HASTRAILER;
-  }
-
-  hp->flags |= UH_FL_HASBODY | UH_FL_INBODY | UH_FL_CHUNKED;
-  hp->cs = http_parser_en_ChunkedBody;
-
-  return self;
-}
-
-/**
- * call-seq:
- *    parser.reset => nil
- *
- * Resets the parser to it's initial state so that you can reuse it
- * rather than making new ones.
- *
- * This method is deprecated and to be removed in Unicorn 4.x
- */
-static VALUE HttpParser_reset(VALUE self)
-{
-  static int warned;
-
-  if (!warned) {
-    rb_warn("Unicorn::HttpParser#reset is deprecated; "
-            "use Unicorn::HttpParser#clear instead");
-  }
-  HttpParser_clear(self);
-  return Qnil;
-}
-
 static void advance_str(VALUE str, off_t nr)
 {
   long len = RSTRING_LEN(str);
@@ -842,15 +764,13 @@ static VALUE HttpParser_keepalive(VALUE self)
  *    parser.next? => true or false
  *
  * Exactly like HttpParser#keepalive?, except it will reset the internal
- * parser state on next parse if it returns true.  It will also respect
- * the maximum *keepalive_requests* value and return false if that is
- * reached.
+ * parser state on next parse if it returns true.
  */
 static VALUE HttpParser_next(VALUE self)
 {
   struct http_parser *hp = data_get(self);
 
-  if ((HP_FL_ALL(hp, KEEPALIVE)) && (hp->nr_requests-- != 0)) {
+  if (HP_FL_ALL(hp, KEEPALIVE)) {
     HP_FL_SET(hp, TO_CLEAR);
     return Qtrue;
   }
@@ -960,6 +880,25 @@ static VALUE HttpParser_filter_body(VALUE self, VALUE dst, VALUE src)
   return src;
 }
 
+static VALUE HttpParser_rssset(VALUE self, VALUE boolean)
+{
+  struct http_parser *hp = data_get(self);
+
+  if (RTEST(boolean))
+    HP_FL_SET(hp, RESSTART);
+  else
+    HP_FL_UNSET(hp, RESSTART);
+
+  return boolean; /* ignored by Ruby anyways */
+}
+
+static VALUE HttpParser_rssget(VALUE self)
+{
+  struct http_parser *hp = data_get(self);
+
+  return HP_FL_TEST(hp, RESSTART) ? Qtrue : Qfalse;
+}
+
 #define SET_GLOBAL(var,str) do { \
   var = find_common_field(str, sizeof(str) - 1); \
   assert(!NIL_P(var) && "missed global field"); \
@@ -969,7 +908,7 @@ void Init_unicorn_http(void)
 {
   VALUE mUnicorn, cHttpParser;
 
-  mUnicorn = rb_const_get(rb_cObject, rb_intern("Unicorn"));
+  mUnicorn = rb_define_module("Unicorn");
   cHttpParser = rb_define_class_under(mUnicorn, "HttpParser", rb_cObject);
   eHttpParserError =
          rb_define_class_under(mUnicorn, "HttpParserError", rb_eIOError);
@@ -982,8 +921,6 @@ void Init_unicorn_http(void)
   rb_define_alloc_func(cHttpParser, HttpParser_alloc);
   rb_define_method(cHttpParser, "initialize", HttpParser_init, 0);
   rb_define_method(cHttpParser, "clear", HttpParser_clear, 0);
-  rb_define_method(cHttpParser, "reset", HttpParser_reset, 0);
-  rb_define_method(cHttpParser, "dechunk!", HttpParser_dechunk_bang, 0);
   rb_define_method(cHttpParser, "parse", HttpParser_parse, 0);
   rb_define_method(cHttpParser, "add_parse", HttpParser_add_parse, 1);
   rb_define_method(cHttpParser, "headers", HttpParser_headers, 2);
@@ -996,6 +933,8 @@ void Init_unicorn_http(void)
   rb_define_method(cHttpParser, "next?", HttpParser_next, 0);
   rb_define_method(cHttpParser, "buf", HttpParser_buf, 0);
   rb_define_method(cHttpParser, "env", HttpParser_env, 0);
+  rb_define_method(cHttpParser, "response_start_sent=", HttpParser_rssset, 1);
+  rb_define_method(cHttpParser, "response_start_sent", HttpParser_rssget, 0);
 
   /*
    * The maximum size a single chunk when using chunked transfer encoding.
@@ -1012,14 +951,6 @@ void Init_unicorn_http(void)
    */
   rb_define_const(cHttpParser, "LENGTH_MAX", OFFT2NUM(UH_OFF_T_MAX));
 
-  /* default value for keepalive_requests */
-  rb_define_const(cHttpParser, "KEEPALIVE_REQUESTS_DEFAULT",
-                  ULONG2NUM(keepalive_requests));
-
-  rb_define_singleton_method(cHttpParser, "keepalive_requests", ka_req, 0);
-  rb_define_singleton_method(cHttpParser, "keepalive_requests=", set_ka_req, 1);
-  rb_define_singleton_method(cHttpParser, "trust_x_forwarded=", set_xftrust, 1);
-  rb_define_singleton_method(cHttpParser, "trust_x_forwarded?", xftrust, 0);
   rb_define_singleton_method(cHttpParser, "max_header_len=", set_maxhdrlen, 1);
 
   init_common_fields();
@@ -1028,9 +959,11 @@ void Init_unicorn_http(void)
   SET_GLOBAL(g_http_transfer_encoding, "TRANSFER_ENCODING");
   SET_GLOBAL(g_content_length, "CONTENT_LENGTH");
   SET_GLOBAL(g_http_connection, "CONNECTION");
-  id_clear = rb_intern("clear");
   id_set_backtrace = rb_intern("set_backtrace");
-  id_response_start_sent = rb_intern("@response_start_sent");
   init_unicorn_httpdate();
+
+#ifndef HAVE_RB_HASH_CLEAR
+  id_clear = rb_intern("clear");
+#endif
 }
 #undef SET_GLOBAL
diff --git a/lib/unicorn.rb b/lib/unicorn.rb
index 358748f..b0e6bd1 100644
--- a/lib/unicorn.rb
+++ b/lib/unicorn.rb
@@ -1,5 +1,4 @@
 # -*- encoding: binary -*-
-require 'fcntl'
 require 'etc'
 require 'stringio'
 require 'rack'
@@ -11,10 +10,10 @@ require 'kgio'
 # enough functionality to service web application requests fast as possible.
 # :startdoc:
 
-# \Unicorn exposes very little of an user-visible API and most of its
-# internals are subject to change.  \Unicorn is designed to host Rack
+# unicorn exposes very little of an user-visible API and most of its
+# internals are subject to change.  unicorn is designed to host Rack
 # applications, so applications should be written against the Rack SPEC
-# and not \Unicorn internals.
+# and not unicorn internals.
 module Unicorn
 
   # Raised inside TeeInput when a client closes the socket inside the
@@ -22,8 +21,7 @@ module Unicorn
   # since there is nothing in the application stack that is responsible
   # for client shutdowns/disconnects.  This exception is visible to Rack
   # applications unless PrereadInput middleware is loaded.
-  class ClientShutdown < EOFError
-  end
+  ClientShutdown = Class.new(EOFError)
 
   # :stopdoc:
 
@@ -102,19 +100,13 @@ module Unicorn
 
   # remove this when we only support Ruby >= 2.0
   def self.pipe # :nodoc:
-    Kgio::Pipe.new.each { |io| io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) }
+    Kgio::Pipe.new.each { |io| io.close_on_exec = true }
   end
   # :startdoc:
 end
 # :enddoc:
-require 'unicorn/const'
-require 'unicorn/socket_helper'
-require 'unicorn/stream_input'
-require 'unicorn/tee_input'
-require 'unicorn/http_request'
-require 'unicorn/configurator'
-require 'unicorn/tmpio'
-require 'unicorn/util'
-require 'unicorn/http_response'
-require 'unicorn/worker'
-require 'unicorn/http_server'
+
+%w(const socket_helper stream_input tee_input http_request configurator
+   tmpio util http_response worker http_server).each do |s|
+  require_relative "unicorn/#{s}"
+end
diff --git a/lib/unicorn/app/exec_cgi.rb b/lib/unicorn/app/exec_cgi.rb
deleted file mode 100644
index 232b681..0000000
--- a/lib/unicorn/app/exec_cgi.rb
+++ /dev/null
@@ -1,154 +0,0 @@
-# -*- encoding: binary -*-
-# :enddoc:
-require 'unicorn'
-
-module Unicorn::App
-
-  # This class is highly experimental (even more so than the rest of Unicorn)
-  # and has never run anything other than cgit.
-  class ExecCgi < Struct.new(:args)
-
-    CHUNK_SIZE = 16384
-    PASS_VARS = %w(
-      CONTENT_LENGTH
-      CONTENT_TYPE
-      GATEWAY_INTERFACE
-      AUTH_TYPE
-      PATH_INFO
-      PATH_TRANSLATED
-      QUERY_STRING
-      REMOTE_ADDR
-      REMOTE_HOST
-      REMOTE_IDENT
-      REMOTE_USER
-      REQUEST_METHOD
-      SERVER_NAME
-      SERVER_PORT
-      SERVER_PROTOCOL
-      SERVER_SOFTWARE
-    ).map { |x| x.freeze } # frozen strings are faster for Hash assignments
-
-    class Body < Unicorn::TmpIO
-      def body_offset=(n)
-        sysseek(@body_offset = n)
-      end
-
-      def each
-        sysseek @body_offset
-        # don't use a preallocated buffer for sysread since we can't
-        # guarantee an actual socket is consuming the yielded string
-        # (or if somebody is pushing to an array for eventual concatenation
-        begin
-          yield sysread(CHUNK_SIZE)
-        rescue EOFError
-          break
-        end while true
-      end
-    end
-
-    # Intializes the app, example of usage in a config.ru
-    #   map "/cgit" do
-    #     run Unicorn::App::ExecCgi.new("/path/to/cgit.cgi")
-    #   end
-    def initialize(*args)
-      self.args = args
-      first = args[0] or
-        raise ArgumentError, "need path to executable"
-      first[0] == ?/ or args[0] = ::File.expand_path(first)
-      File.executable?(args[0]) or
-        raise ArgumentError, "#{args[0]} is not executable"
-    end
-
-    # Calls the app
-    def call(env)
-      out, err = Body.new, Unicorn::TmpIO.new
-      inp = force_file_input(env)
-      pid = fork { run_child(inp, out, err, env) }
-      inp.close
-      pid, status = Process.waitpid2(pid)
-      write_errors(env, err, status) if err.stat.size > 0
-      err.close
-
-      return parse_output!(out) if status.success?
-      out.close
-      [ 500, { 'Content-Length' => '0', 'Content-Type' => 'text/plain' }, [] ]
-    end
-
-    private
-
-    def run_child(inp, out, err, env)
-      PASS_VARS.each do |key|
-        val = env[key] or next
-        ENV[key] = val
-      end
-      ENV['SCRIPT_NAME'] = args[0]
-      ENV['GATEWAY_INTERFACE'] = 'CGI/1.1'
-      env.keys.grep(/^HTTP_/) { |key| ENV[key] = env[key] }
-
-      $stdin.reopen(inp)
-      $stdout.reopen(out)
-      $stderr.reopen(err)
-      exec(*args)
-    end
-
-    # Extracts headers from CGI out, will change the offset of out.
-    # This returns a standard Rack-compatible return value:
-    #   [ 200, HeadersHash, body ]
-    def parse_output!(out)
-      size = out.stat.size
-      out.sysseek(0)
-      head = out.sysread(CHUNK_SIZE)
-      offset = 2
-      head, body = head.split(/\n\n/, 2)
-      if body.nil?
-        head, body = head.split(/\r\n\r\n/, 2)
-        offset = 4
-      end
-      offset += head.length
-      out.body_offset = offset
-      size -= offset
-      prev = nil
-      headers = Rack::Utils::HeaderHash.new
-      head.split(/\r?\n/).each do |line|
-        case line
-        when /^([A-Za-z0-9-]+):\s*(.*)$/ then headers[prev = $1] = $2
-        when /^[ \t]/ then headers[prev] << "\n#{line}" if prev
-        end
-      end
-      status = headers.delete("Status") || 200
-      headers['Content-Length'] = size.to_s
-      [ status, headers, out ]
-    end
-
-    # ensures rack.input is a file handle that we can redirect stdin to
-    def force_file_input(env)
-      inp = env['rack.input']
-      # inp could be a StringIO or StringIO-like object
-      if inp.respond_to?(:size) && inp.size == 0
-        ::File.open('/dev/null', 'rb')
-      else
-        tmp = Unicorn::TmpIO.new
-
-        buf = inp.read(CHUNK_SIZE)
-        begin
-          tmp.syswrite(buf)
-        end while inp.read(CHUNK_SIZE, buf)
-        tmp.sysseek(0)
-        tmp
-      end
-    end
-
-    # rack.errors this may not be an IO object, so we couldn't
-    # just redirect the CGI executable to that earlier.
-    def write_errors(env, err, status)
-      err.seek(0)
-      dst = env['rack.errors']
-      pid = status.pid
-      dst.write("#{pid}: #{args.inspect} status=#{status} stderr:\n")
-      err.each_line { |line| dst.write("#{pid}: #{line}") }
-      dst.flush
-    end
-
-  end
-
-end
diff --git a/lib/unicorn/app/inetd.rb b/lib/unicorn/app/inetd.rb
deleted file mode 100644
index 13b6624..0000000
--- a/lib/unicorn/app/inetd.rb
+++ /dev/null
@@ -1,109 +0,0 @@
-# -*- encoding: binary -*-
-# :enddoc:
-# Copyright (c) 2009 Eric Wong
-# You can redistribute it and/or modify it under the same terms as Ruby 1.8 or
-# the GPLv2+ (GPLv3+ preferred)
-
-# this class *must* be used with Rack::Chunked
-module Unicorn::App
-  class Inetd < Struct.new(:cmd)
-
-    class CatBody < Struct.new(:errors, :err_rd, :out_rd, :pid_map)
-      def initialize(env, cmd)
-        self.errors = env['rack.errors']
-        in_rd, in_wr = IO.pipe
-        self.err_rd, err_wr = IO.pipe
-        self.out_rd, out_wr = IO.pipe
-
-        cmd_pid = fork {
-          inp, out, err = (0..2).map { |i| IO.new(i) }
-          inp.reopen(in_rd)
-          out.reopen(out_wr)
-          err.reopen(err_wr)
-          [ in_rd, in_wr, err_rd, err_wr, out_rd, out_wr ].each { |i| i.close }
-          exec(*cmd)
-        }
-        [ in_rd, err_wr, out_wr ].each { |io| io.close }
-        [ in_wr, err_rd, out_rd ].each { |io| io.binmode }
-        in_wr.sync = true
-
-        # Unfortunately, input here must be processed inside a seperate
-        # thread/process using blocking I/O since env['rack.input'] is not
-        # IO.select-able and attempting to make it so would trip Rack::Lint
-        inp_pid = fork {
-          input = env['rack.input']
-          [ err_rd, out_rd ].each { |io| io.close }
-
-          # this is dependent on input.read having readpartial semantics:
-          buf = input.read(16384)
-          begin
-            in_wr.write(buf)
-          end while input.read(16384, buf)
-        }
-        in_wr.close
-        self.pid_map = {
-          inp_pid => 'input streamer',
-          cmd_pid => cmd.inspect,
-        }
-      end
-
-      def each
-        begin
-          rd, = IO.select([err_rd, out_rd])
-          rd && rd.first or next
-
-          if rd.include?(err_rd)
-            begin
-              errors.write(err_rd.read_nonblock(16384))
-            rescue Errno::EINTR
-            rescue Errno::EAGAIN
-              break
-            end while true
-          end
-
-          rd.include?(out_rd) or next
-
-          begin
-            yield out_rd.read_nonblock(16384)
-          rescue Errno::EINTR
-          rescue Errno::EAGAIN
-            break
-          end while true
-        rescue EOFError,Errno::EPIPE,Errno::EBADF,Errno::EINVAL
-          break
-        end while true
-
-        self
-      end
-
-      def close
-        pid_map.each { |pid, str|
-          begin
-            pid, status = Process.waitpid2(pid)
-            status.success? or
-              errors.write("#{str}: #{status.inspect} (PID:#{pid})\n")
-          rescue Errno::ECHILD
-            errors.write("Failed to reap #{str} (PID:#{pid})\n")
-          end
-        }
-        out_rd.close
-        err_rd.close
-      end
-
-    end
-
-    def initialize(*cmd)
-      self.cmd = cmd
-    end
-
-    def call(env)
-      /\A100-continue\z/i =~ env[Unicorn::Const::HTTP_EXPECT] and
-          return [ 100, {} , [] ]
-
-      [ 200, { 'Content-Type' => 'application/octet-stream' },
-       CatBody.new(env, cmd) ]
-    end
-
-  end
-
-end
diff --git a/lib/unicorn/configurator.rb b/lib/unicorn/configurator.rb
index 0658c81..4da19bb 100644
--- a/lib/unicorn/configurator.rb
+++ b/lib/unicorn/configurator.rb
@@ -1,8 +1,7 @@
 # -*- encoding: binary -*-
 require 'logger'
-require 'unicorn/ssl_configurator'
 
-# Implements a simple DSL for configuring a \Unicorn server.
+# Implements a simple DSL for configuring a unicorn server.
 #
 # See http://unicorn.bogomips.org/examples/unicorn.conf.rb and
 # http://unicorn.bogomips.org/examples/unicorn.conf.minimal.rb
@@ -13,7 +12,6 @@ require 'unicorn/ssl_configurator'
 # See the link:/TUNING.html document for more information on tuning unicorn.
 class Unicorn::Configurator
   include Unicorn
-  include Unicorn::SSLConfigurator
 
   # :stopdoc:
   attr_accessor :set, :config_file, :after_reload
@@ -48,7 +46,6 @@ class Unicorn::Configurator
     :check_client_connection => false,
     :rewindable_input => true, # for Rack 2.x: (Rack::VERSION[0] <= 1),
     :client_body_buffer_size => Unicorn::Const::MAX_BODY,
-    :trust_x_forwarded => true,
   }
   #:startdoc:
 
@@ -257,6 +254,11 @@ class Unicorn::Configurator
   #
   #   Default: 1024
   #
+  #   Note: with the Linux kernel, the net.core.somaxconn sysctl defaults
+  #   to 128, capping this value to 128.  Raising the sysctl allows a
+  #   larger backlog (which may not be desirable with multiple,
+  #   load-balanced machines).
+  #
   # [:rcvbuf => bytes, :sndbuf => bytes]
   #
   #   Maximum receive and send buffer sizes (in bytes) of sockets.
@@ -280,20 +282,19 @@ class Unicorn::Configurator
   #   Setting this to +true+ can make streaming responses in Rails 3.1
   #   appear more quickly at the cost of slightly higher bandwidth usage.
   #   The effect of this option is most visible if nginx is not used,
-  #   but nginx remains highly recommended with \Unicorn.
+  #   but nginx remains highly recommended with unicorn.
   #
   #   This has no effect on UNIX sockets.
   #
-  #   Default: +true+ (Nagle's algorithm disabled) in \Unicorn,
-  #   +true+ in Rainbows!  This defaulted to +false+ in \Unicorn
-  #   3.x
+  #   Default: +true+ (Nagle's algorithm disabled) in unicorn
+  #   This defaulted to +false+ in unicorn 3.x
   #
   # [:tcp_nopush => true or false]
   #
   #   Enables/disables TCP_CORK in Linux or TCP_NOPUSH in FreeBSD
   #
   #   This prevents partial TCP frames from being sent out and reduces
-  #   wakeups in nginx if it is on a different machine.  Since \Unicorn
+  #   wakeups in nginx if it is on a different machine.  Since unicorn
   #   is only designed for applications that send the response body
   #   quickly without keepalive, sockets will always be flushed on close
   #   to prevent delays.
@@ -301,7 +302,7 @@ class Unicorn::Configurator
   #   This has no effect on UNIX sockets.
   #
   #   Default: +false+
-  #   This defaulted to +true+ in \Unicorn 3.4 - 3.7
+  #   This defaulted to +true+ in unicorn 3.4 - 3.7
   #
   # [:ipv6only => true or false]
   #
@@ -385,12 +386,10 @@ class Unicorn::Configurator
   #   and +false+ or +nil+ is synonymous for a value of zero.
   #
   #   A value of +1+ is a good optimization for local networks
-  #   and trusted clients.  For Rainbows! and Zbatery users, a higher
-  #   value (e.g. +60+) provides more protection against some
-  #   denial-of-service attacks.  There is no good reason to ever
-  #   disable this with a +zero+ value when serving HTTP.
+  #   and trusted clients.  There is no good reason to ever
+  #   disable this with a +zero+ value with unicorn.
   #
-  #   Default: 1 retransmit for \Unicorn, 60 for Rainbows! 0.95.0\+
+  #   Default: 1
   #
   # [:accept_filter => String]
   #
@@ -399,8 +398,7 @@ class Unicorn::Configurator
   #   This enables either the "dataready" or (default) "httpready"
   #   accept() filter under FreeBSD.  This is intended as an
   #   optimization to reduce context switches with common GET/HEAD
-  #   requests.  For Rainbows! and Zbatery users, this provides
-  #   some protection against certain denial-of-service attacks, too.
+  #   requests.
   #
   #   There is no good reason to change from the default.
   #
@@ -556,18 +554,6 @@ class Unicorn::Configurator
     set[:user] = [ user, group ]
   end
 
-  # Sets whether or not the parser will trust X-Forwarded-Proto and
-  # X-Forwarded-SSL headers and set "rack.url_scheme" to "https" accordingly.
-  # Rainbows!/Zbatery installations facing untrusted clients directly
-  # should set this to +false+.  This is +true+ by default as Unicorn
-  # is designed to only sit behind trusted nginx proxies.
-  #
-  # This has never been publically documented and is subject to removal
-  # in future releases.
-  def trust_x_forwarded(bool) # :nodoc:
-    set_bool(:trust_x_forwarded, bool)
-  end
-
   # expands "unix:path/to/foo" to a socket relative to the current path
   # expands pathnames of sockets if relative to "~" or "~username"
   # expands "*:port and ":port" to "0.0.0.0:port"
@@ -601,7 +587,7 @@ private
   def canonicalize_tcp(addr, port)
     packed = Socket.pack_sockaddr_in(port, addr)
     port, addr = Socket.unpack_sockaddr_in(packed)
-    /:/ =~ addr ? "[#{addr}]:#{port}" : "#{addr}:#{port}"
+    addr.include?(':') ? "[#{addr}]:#{port}" : "#{addr}:#{port}"
   end
 
   def set_path(var, path) #:nodoc:
@@ -657,7 +643,7 @@ private
       raise ArgumentError, "rackup file (#{ru}) not readable"
 
     # it could be a .rb file, too, we don't parse those manually
-    ru =~ /\.ru\z/ or return
+    ru.end_with?('.ru') or return
 
     /^#\\(.*)/ =~ File.read(ru) or return
     RACKUP[:optparse].parse!($1.split(/\s+/))
diff --git a/lib/unicorn/const.rb b/lib/unicorn/const.rb
index 51d7394..33ab4ac 100644
--- a/lib/unicorn/const.rb
+++ b/lib/unicorn/const.rb
@@ -1,12 +1,6 @@
 # -*- encoding: binary -*-
 
-# :enddoc:
-# Frequently used constants when constructing requests or responses.
-# Many times the constant just refers to a string with the same
-# contents.  Using these constants gave about a 3% to 10% performance
-# improvement over using the strings directly.  Symbols did not really
-# improve things much compared to constants.
-module Unicorn::Const
+module Unicorn::Const # :nodoc:
   # default TCP listen host address (0.0.0.0, all interfaces)
   DEFAULT_HOST = "0.0.0.0"
 
@@ -23,22 +17,5 @@ module Unicorn::Const
   # temporary file for reading (112 kilobytes).  This is the default
   # value of client_body_buffer_size.
   MAX_BODY = 1024 * 112
-
-  # :stopdoc:
-  # common errors we'll send back
-  # (N.B. these are not used by unicorn, but we won't drop them until
-  #  unicorn 5.x to avoid breaking Rainbows!).
-  ERROR_400_RESPONSE = "HTTP/1.1 400 Bad Request\r\n\r\n"
-  ERROR_414_RESPONSE = "HTTP/1.1 414 Request-URI Too Long\r\n\r\n"
-  ERROR_413_RESPONSE = "HTTP/1.1 413 Request Entity Too Large\r\n\r\n"
-  ERROR_500_RESPONSE = "HTTP/1.1 500 Internal Server Error\r\n\r\n"
-
-  EXPECT_100_RESPONSE = "HTTP/1.1 100 Continue\r\n\r\n"
-  EXPECT_100_RESPONSE_SUFFIXED = "100 Continue\r\n\r\nHTTP/1.1 "
-
-  HTTP_RESPONSE_START = ['HTTP', '/1.1 ']
-  HTTP_EXPECT = "HTTP_EXPECT"
-
-  # :startdoc:
 end
-require 'unicorn/version'
+require_relative 'version'
diff --git a/lib/unicorn/http_request.rb b/lib/unicorn/http_request.rb
index 6b20431..0c1f9bb 100644
--- a/lib/unicorn/http_request.rb
+++ b/lib/unicorn/http_request.rb
@@ -13,7 +13,8 @@ class Unicorn::HttpParser
     "rack.multiprocess" => true,
     "rack.multithread" => false,
     "rack.run_once" => false,
-    "rack.version" => [1, 1],
+    "rack.version" => [1, 2],
+    "rack.hijack?" => true,
     "SCRIPT_NAME" => "",
 
     # this is not in the Rack spec, but some apps may rely on it
@@ -22,12 +23,11 @@ class Unicorn::HttpParser
 
   NULL_IO = StringIO.new("")
 
-  attr_accessor :response_start_sent
-
   # :stopdoc:
   # A frozen format for this is about 15% faster
-  REMOTE_ADDR = 'REMOTE_ADDR'.freeze
-  RACK_INPUT = 'rack.input'.freeze
+  # Drop these frozen strings when Ruby 2.2 becomes more prevalent,
+  # 2.2+ optimizes hash assignments when used with literal string keys
+  HTTP_RESPONSE_START = [ 'HTTP', '/1.1 ']
   @@input_class = Unicorn::TeeInput
   @@check_client_connection = false
 
@@ -73,7 +73,7 @@ class Unicorn::HttpParser
     #  identify the client for the immediate request to the server;
     #  that client may be a proxy, gateway, or other intermediary
     #  acting on behalf of the actual source client."
-    e[REMOTE_ADDR] = socket.kgio_addr
+    e['REMOTE_ADDR'] = socket.kgio_addr
 
     # short circuit the common case with small GET requests first
     socket.kgio_read!(16384, buf)
@@ -85,38 +85,27 @@ class Unicorn::HttpParser
 
     # detect if the socket is valid by writing a partial response:
     if @@check_client_connection && headers?
-      @response_start_sent = true
-      Unicorn::Const::HTTP_RESPONSE_START.each { |c| socket.write(c) }
+      self.response_start_sent = true
+      HTTP_RESPONSE_START.each { |c| socket.write(c) }
     end
 
-    e[RACK_INPUT] = 0 == content_length ?
-                    NULL_IO : @@input_class.new(socket, self)
-    hijack_setup(e, socket)
-    e.merge!(DEFAULTS)
-  end
-
-  # Rack 1.5.0 (protocol version 1.2) adds hijack request support
-  if ((Rack::VERSION[0] << 8) | Rack::VERSION[1]) >= 0x0102
-    DEFAULTS["rack.hijack?"] = true
-    DEFAULTS["rack.version"] = [1, 2]
+    e['rack.input'] = 0 == content_length ?
+                      NULL_IO : @@input_class.new(socket, self)
 
-    RACK_HIJACK = "rack.hijack".freeze
-    RACK_HIJACK_IO = "rack.hijack_io".freeze
+    # for Rack hijacking in Rack 1.5 and later
+    e['unicorn.socket'] = socket
+    e['rack.hijack'] = self
 
-    def hijacked?
-      env.include?(RACK_HIJACK_IO)
-    end
+    e.merge!(DEFAULTS)
+  end
 
-    def hijack_setup(e, socket)
-      e[RACK_HIJACK] = proc { e[RACK_HIJACK_IO] = socket }
-    end
-  else
-    # old Rack, do nothing.
-    def hijack_setup(e, _)
-    end
+  # for rack.hijack, we respond to this method so no extra allocation
+  # of a proc object
+  def call
+    env['rack.hijack_io'] = env['unicorn.socket']
+  end
 
-    def hijacked?
-      false
-    end
+  def hijacked?
+    env.include?('rack.hijack_io'.freeze)
   end
 end
diff --git a/lib/unicorn/http_response.rb b/lib/unicorn/http_response.rb
index 083951c..c1aa738 100644
--- a/lib/unicorn/http_response.rb
+++ b/lib/unicorn/http_response.rb
@@ -10,66 +10,48 @@
 # is the job of Rack, with the exception of the "Date" and "Status" header.
 module Unicorn::HttpResponse
 
-  # Every standard HTTP code mapped to the appropriate message.
-  CODES = Rack::Utils::HTTP_STATUS_CODES.inject({}) { |hash,(code,msg)|
-    hash[code] = "#{code} #{msg}"
-    hash
-  }
-  CRLF = "\r\n"
-
+  # internal API, code will always be common-enough-for-even-old-Rack
   def err_response(code, response_start_sent)
-    "#{response_start_sent ? '' : 'HTTP/1.1 '}#{CODES[code]}\r\n\r\n"
+    "#{response_start_sent ? '' : 'HTTP/1.1 '}" \
+      "#{code} #{Rack::Utils::HTTP_STATUS_CODES[code]}\r\n\r\n"
   end
 
   # writes the rack_response to socket as an HTTP response
   def http_response_write(socket, status, headers, body,
                           response_start_sent=false)
-    status = CODES[status.to_i] || status
     hijack = nil
 
-    http_response_start = response_start_sent ? '' : 'HTTP/1.1 '
     if headers
-      buf = "#{http_response_start}#{status}\r\n" \
+      code = status.to_i
+      msg = Rack::Utils::HTTP_STATUS_CODES[code]
+      start = response_start_sent ? ''.freeze : 'HTTP/1.1 '.freeze
+      buf = "#{start}#{msg ? %Q(#{code} #{msg}) : status}\r\n" \
             "Date: #{httpdate}\r\n" \
-            "Status: #{status}\r\n" \
             "Connection: close\r\n"
       headers.each do |key, value|
         case key
-        when %r{\A(?:Date\z|Connection\z)}i
+        when %r{\A(?:Date|Connection)\z}i
           next
         when "rack.hijack"
-          # this was an illegal key in Rack < 1.5, so it should be
-          # OK to silently discard it for those older versions
-          hijack = hijack_prepare(value)
+          # This should only be hit under Rack >= 1.5, as this was an illegal
+          # key in Rack < 1.5
+          hijack = value
         else
-          if value =~ /\n/
+          if value.include?("\n".freeze)
             # avoiding blank, key-only cookies with /\n+/
-            buf << value.split(/\n+/).map! { |v| "#{key}: #{v}\r\n" }.join
+            value.split(/\n+/).each { |v| buf << "#{key}: #{v}\r\n" }
           else
             buf << "#{key}: #{value}\r\n"
           end
         end
       end
-      socket.write(buf << CRLF)
+      socket.write(buf << "\r\n".freeze)
     end
 
     if hijack
-      body = nil # ensure we do not close body
       hijack.call(socket)
     else
       body.each { |chunk| socket.write(chunk) }
     end
-  ensure
-    body.respond_to?(:close) and body.close
-  end
-
-  # Rack 1.5.0 (protocol version 1.2) adds response hijacking support
-  if ((Rack::VERSION[0] << 8) | Rack::VERSION[1]) >= 0x0102
-    def hijack_prepare(value)
-      value
-    end
-  else
-    def hijack_prepare(_)
-    end
   end
 end
diff --git a/lib/unicorn/http_server.rb b/lib/unicorn/http_server.rb
index 329c5bf..ca56ed3 100644
--- a/lib/unicorn/http_server.rb
+++ b/lib/unicorn/http_server.rb
@@ -1,5 +1,4 @@
 # -*- encoding: binary -*-
-require "unicorn/ssl_server"
 
 # This is the process manager of Unicorn. This manages worker
 # processes which in turn handle the I/O and application process.
@@ -8,50 +7,27 @@ require "unicorn/ssl_server"
 #
 # Users do not need to know the internals of this class, but reading the
 # {source}[http://bogomips.org/unicorn.git/tree/lib/unicorn/http_server.rb]
-# is education for programmers wishing to learn how \Unicorn works.
-# See Unicorn::Configurator for information on how to configure \Unicorn.
+# is education for programmers wishing to learn how unicorn works.
+# See Unicorn::Configurator for information on how to configure unicorn.
 class Unicorn::HttpServer
   # :stopdoc:
-  attr_accessor :app, :request, :timeout, :worker_processes,
+  attr_accessor :app, :timeout, :worker_processes,
                 :before_fork, :after_fork, :before_exec,
                 :listener_opts, :preload_app,
-                :reexec_pid, :orig_app, :init_listeners,
-                :master_pid, :config, :ready_pipe, :user
+                :orig_app, :config, :ready_pipe, :user
 
   attr_reader :pid, :logger
   include Unicorn::SocketHelper
   include Unicorn::HttpResponse
-  include Unicorn::SSLServer
-
-  # backwards compatibility with 1.x
-  Worker = Unicorn::Worker
 
   # all bound listener sockets
+  # note: this is public used by raindrops, but not recommended for use
+  # in new projects
   LISTENERS = []
 
   # listeners we have yet to bind
   NEW_LISTENERS = []
 
-  # This hash maps PIDs to Workers
-  WORKERS = {}
-
-  # We use SELF_PIPE differently in the master and worker processes:
-  #
-  # * The master process never closes or reinitializes this once
-  # initialized.  Signal handlers in the master process will write to
-  # it to wake up the master from IO.select in exactly the same manner
-  # djb describes in http://cr.yp.to/docs/selfpipe.html
-  #
-  # * The workers immediately close the pipe they inherit.  See the
-  # Unicorn::Worker class for the pipe workers use.
-  SELF_PIPE = []
-
-  # signal queue used for self-piping
-  SIG_QUEUE = []
-
-  # list of signals we care about and trap in master.
-  QUEUE_SIGS = [ :WINCH, :QUIT, :INT, :TERM, :USR1, :USR2, :HUP, :TTIN, :TTOU ]
-
   # :startdoc:
   # We populate this at startup so we can figure out how to reexecute
   # and upgrade the currently running instance of Unicorn
@@ -71,7 +47,7 @@ class Unicorn::HttpServer
   #
   #   Unicorn::HttpServer::START_CTX[0] = "/home/bofh/2.2.0/bin/unicorn"
   START_CTX = {
-    :argv => ARGV.map { |arg| arg.dup },
+    :argv => ARGV.map(&:dup),
     0 => $0.dup,
   }
   # We favor ENV['PWD'] since it is (usually) symlink aware for Capistrano
@@ -92,7 +68,7 @@ class Unicorn::HttpServer
   def initialize(app, options = {})
     @app = app
     @request = Unicorn::HttpRequest.new
-    self.reexec_pid = 0
+    @reexec_pid = 0
     options = options.dup
     @ready_pipe = options.delete(:ready_pipe)
     @init_listeners = options[:listeners] ? options[:listeners].dup : []
@@ -100,6 +76,19 @@ class Unicorn::HttpServer
     self.config = Unicorn::Configurator.new(options)
     self.listener_opts = {}
 
+    # We use @self_pipe differently in the master and worker processes:
+    #
+    # * The master process never closes or reinitializes this once
+    # initialized.  Signal handlers in the master process will write to
+    # it to wake up the master from IO.select in exactly the same manner
+    # djb describes in http://cr.yp.to/docs/selfpipe.html
+    #
+    # * The workers immediately close the pipe they inherit.  See the
+    # Unicorn::Worker class for the pipe workers use.
+    @self_pipe = []
+    @workers = {} # hash maps PIDs to Workers
+    @sig_queue = [] # signal queue used for self-piping
+
     # we try inheriting listeners first, so we bind them later.
     # we don't write the pid file until we've bound listeners in case
     # unicorn was started twice by mistake.  Even though our #pid= method
@@ -111,7 +100,10 @@ class Unicorn::HttpServer
     # monitoring tools may also rely on pid files existing before we
     # attempt to connect to the listener(s)
     config.commit!(self, :skip => [:listeners, :pid])
-    self.orig_app = app
+    @orig_app = app
+    # list of signals we care about and trap in master.
+    @queue_sigs = [
+      :WINCH, :QUIT, :INT, :TERM, :USR1, :USR2, :HUP, :TTIN, :TTOU ]
   end
 
   # Runs the thing.  Returns self so you can run join on it
@@ -119,13 +111,13 @@ class Unicorn::HttpServer
     inherit_listeners!
     # this pipe is used to wake us up from select(2) in #join when signals
     # are trapped.  See trap_deferred.
-    SELF_PIPE.replace(Unicorn.pipe)
+    @self_pipe.replace(Unicorn.pipe)
     @master_pid = $$
 
     # setup signal handlers before writing pid file in case people get
     # trigger happy and send signals as soon as the pid file exists.
     # Note that signals don't actually get handled until the #join method
-    QUEUE_SIGS.each { |sig| trap(sig) { SIG_QUEUE << sig; awaken_master } }
+    @queue_sigs.each { |sig| trap(sig) { @sig_queue << sig; awaken_master } }
     trap(:CHLD) { awaken_master }
 
     # write pid early for Mongrel compatibility if we're not inheriting sockets
@@ -158,9 +150,6 @@ class Unicorn::HttpServer
 
     LISTENERS.delete_if do |io|
       if dead_names.include?(sock_name(io))
-        IO_PURGATORY.delete_if do |pio|
-          pio.fileno == io.fileno && (pio.close rescue nil).nil? # true
-        end
         (io.close rescue nil).nil? # true
       else
         set_server_sockopt(io, listener_opts[sock_name(io)])
@@ -198,7 +187,7 @@ class Unicorn::HttpServer
     if path
       if x = valid_pid?(path)
         return path if pid && path == pid && x == $$
-        if x == reexec_pid && pid =~ /\.oldbin\z/
+        if x == @reexec_pid && pid.end_with?('.oldbin')
           logger.warn("will not set pid=#{path} while reexec-ed "\
                       "child is running PID:#{x}")
           return
@@ -241,7 +230,7 @@ class Unicorn::HttpServer
     begin
       io = bind_listen(address, opt)
       unless Kgio::TCPServer === io || Kgio::UNIXServer === io
-        prevent_autoclose(io)
+        io.autoclose = false
         io = server_cast(io)
       end
       logger.info "listening on addr=#{sock_name(io)} fd=#{io.fileno}"
@@ -267,7 +256,7 @@ class Unicorn::HttpServer
   # is signalling us too often.
   def join
     respawn = true
-    last_check = Time.now
+    last_check = time_now
 
     proc_name 'master'
     logger.info "master process ready" # test_exec.rb relies on this message
@@ -281,11 +270,11 @@ class Unicorn::HttpServer
     end
     begin
       reap_all_workers
-      case SIG_QUEUE.shift
+      case @sig_queue.shift
       when nil
         # avoid murdering workers after our master process (or the
         # machine) comes out of suspend/hibernation
-        if (last_check + @timeout) >= (last_check = Time.now)
+        if (last_check + @timeout) >= (last_check = time_now)
           sleep_time = murder_lazy_workers
         else
           sleep_time = @timeout/2.0 + 1
@@ -306,13 +295,13 @@ class Unicorn::HttpServer
       when :USR2 # exec binary, stay alive in case something went wrong
         reexec
       when :WINCH
-        if Unicorn::Configurator::RACKUP[:daemonized]
+        if $stdin.tty?
+          logger.info "SIGWINCH ignored because we're not daemonized"
+        else
           respawn = false
           logger.info "gracefully stopping all workers"
           soft_kill_each_worker(:QUIT)
           self.worker_processes = 0
-        else
-          logger.info "SIGWINCH ignored because we're not daemonized"
         end
       when :TTIN
         respawn = true
@@ -339,8 +328,8 @@ class Unicorn::HttpServer
   # Terminates all workers, but does not exit master process
   def stop(graceful = true)
     self.listeners = []
-    limit = Time.now + timeout
-    until WORKERS.empty? || Time.now > limit
+    limit = time_now + timeout
+    until @workers.empty? || time_now > limit
       if graceful
         soft_kill_each_worker(:QUIT)
       else
@@ -369,14 +358,6 @@ class Unicorn::HttpServer
     Unicorn::TeeInput.client_body_buffer_size = bytes
   end
 
-  def trust_x_forwarded
-    Unicorn::HttpParser.trust_x_forwarded?
-  end
-
-  def trust_x_forwarded=(bool)
-    Unicorn::HttpParser.trust_x_forwarded = bool
-  end
-
   def check_client_connection
     Unicorn::HttpRequest.check_client_connection
   end
@@ -389,17 +370,17 @@ class Unicorn::HttpServer
 
   # wait for a signal hander to wake us up and then consume the pipe
   def master_sleep(sec)
+    @self_pipe[0].kgio_wait_readable(sec) or return
     # 11 bytes is the maximum string length which can be embedded within
     # the Ruby itself and not require a separate malloc (on 32-bit MRI 1.9+).
     # Most reads are only one byte here and uncommon, so it's not worth a
     # persistent buffer, either:
-    IO.select([ SELF_PIPE[0] ], nil, nil, sec) or return
-    SELF_PIPE[0].kgio_tryread(11)
+    @self_pipe[0].kgio_tryread(11)
   end
 
   def awaken_master
     return if $$ != @master_pid
-    SELF_PIPE[1].kgio_trywrite('.') # wakeup master process from select
+    @self_pipe[1].kgio_trywrite('.') # wakeup master process from select
   end
 
   # reaps all unreaped workers
@@ -407,13 +388,13 @@ class Unicorn::HttpServer
     begin
       wpid, status = Process.waitpid2(-1, Process::WNOHANG)
       wpid or return
-      if reexec_pid == wpid
+      if @reexec_pid == wpid
         logger.error "reaped #{status.inspect} exec()-ed"
-        self.reexec_pid = 0
+        @reexec_pid = 0
         self.pid = pid.chomp('.oldbin') if pid
         proc_name 'master'
       else
-        worker = WORKERS.delete(wpid) and worker.close rescue nil
+        worker = @workers.delete(wpid) and worker.close rescue nil
         m = "reaped #{status.inspect} worker=#{worker.nr rescue 'unknown'}"
         status.success? ? logger.info(m) : logger.error(m)
       end
@@ -424,13 +405,13 @@ class Unicorn::HttpServer
 
   # reexecutes the START_CTX with a new binary
   def reexec
-    if reexec_pid > 0
+    if @reexec_pid > 0
       begin
-        Process.kill(0, reexec_pid)
-        logger.error "reexec-ed child already running PID:#{reexec_pid}"
+        Process.kill(0, @reexec_pid)
+        logger.error "reexec-ed child already running PID:#@reexec_pid"
         return
       rescue Errno::ESRCH
-        self.reexec_pid = 0
+        @reexec_pid = 0
       end
     end
 
@@ -448,13 +429,10 @@ class Unicorn::HttpServer
       end
     end
 
-    self.reexec_pid = fork do
+    @reexec_pid = fork do
       listener_fds = {}
       LISTENERS.each do |sock|
-        # IO#close_on_exec= will be available on any future version of
-        # Ruby that sets FD_CLOEXEC by default on new file descriptors
-        # ref: http://redmine.ruby-lang.org/issues/5041
-        sock.close_on_exec = false if sock.respond_to?(:close_on_exec=)
+        sock.close_on_exec = false
         listener_fds[sock.fileno] = sock
       end
       ENV['UNICORN_FD'] = listener_fds.keys.join(',')
@@ -467,13 +445,13 @@ class Unicorn::HttpServer
       (3..1024).each do |io|
         next if listener_fds.include?(io)
         io = IO.for_fd(io) rescue next
-        prevent_autoclose(io)
-        io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
+        io.autoclose = false
+        io.close_on_exec = true
       end
 
       # exec(command, hash) works in at least 1.9.1+, but will only be
       # required in 1.9.4/2.0.0 at earliest.
-      cmd << listener_fds if RUBY_VERSION >= "1.9.1"
+      cmd << listener_fds
       logger.info "executing #{cmd.inspect} (in #{Dir.pwd})"
       before_exec.call(self)
       exec(*cmd)
@@ -484,8 +462,8 @@ class Unicorn::HttpServer
   # forcibly terminate all workers that haven't checked in in timeout seconds.  The timeout is implemented using an unlinked File
   def murder_lazy_workers
     next_sleep = @timeout - 1
-    now = Time.now.to_i
-    WORKERS.dup.each_pair do |wpid, worker|
+    now = time_now.to_i
+    @workers.dup.each_pair do |wpid, worker|
       tick = worker.tick
       0 == tick and next # skip workers that haven't processed any clients
       diff = now - tick
@@ -503,12 +481,13 @@ class Unicorn::HttpServer
   end
 
   def after_fork_internal
-    SELF_PIPE.each { |io| io.close }.clear # this is master-only, now
+    @self_pipe.each(&:close).clear # this is master-only, now
     @ready_pipe.close if @ready_pipe
     Unicorn::Configurator::RACKUP.clear
     @ready_pipe = @init_listeners = @before_exec = @before_fork = nil
 
-    srand # http://redmine.ruby-lang.org/issues/4338
+    # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/36450
+    srand # remove in unicorn 6
 
     # The OpenSSL PRNG is seeded with only the pid, and apps with frequently
     # dying workers can recycle pids
@@ -518,11 +497,11 @@ class Unicorn::HttpServer
   def spawn_missing_workers
     worker_nr = -1
     until (worker_nr += 1) == @worker_processes
-      WORKERS.value?(worker_nr) and next
-      worker = Worker.new(worker_nr)
+      @workers.value?(worker_nr) and next
+      worker = Unicorn::Worker.new(worker_nr)
       before_fork.call(self, worker)
       if pid = fork
-        WORKERS[pid] = worker
+        @workers[pid] = worker
         worker.atfork_parent
       else
         after_fork_internal
@@ -536,9 +515,9 @@ class Unicorn::HttpServer
   end
 
   def maintain_worker_count
-    (off = WORKERS.size - worker_processes) == 0 and return
+    (off = @workers.size - worker_processes) == 0 and return
     off < 0 and return spawn_missing_workers
-    WORKERS.each_value { |w| w.nr >= worker_processes and w.soft_kill(:QUIT) }
+    @workers.each_value { |w| w.nr >= worker_processes and w.soft_kill(:QUIT) }
   end
 
   # if we get any error, try to write something back to the client
@@ -566,29 +545,37 @@ class Unicorn::HttpServer
     rescue
   end
 
-  def expect_100_response
-    if @request.response_start_sent
-      Unicorn::Const::EXPECT_100_RESPONSE_SUFFIXED
-    else
-      Unicorn::Const::EXPECT_100_RESPONSE
-    end
+  def e100_response_write(client, env)
+    # We use String#freeze to avoid allocations under Ruby 2.1+
+    # Not many users hit this code path, so it's better to reduce the
+    # constant table sizes even for 1.9.3-2.0 users who'll hit extra
+    # allocations here.
+    client.write(@request.response_start_sent ?
+                 "100 Continue\r\n\r\nHTTP/1.1 ".freeze :
+                 "HTTP/1.1 100 Continue\r\n\r\n".freeze)
+    env.delete('HTTP_EXPECT'.freeze)
   end
 
   # once a client is accepted, it is processed in its entirety here
   # in 3 easy steps: read request, call app, write app response
   def process_client(client)
     status, headers, body = @app.call(env = @request.read(client))
-    return if @request.hijacked?
 
-    if 100 == status.to_i
-      client.write(expect_100_response)
-      env.delete(Unicorn::Const::HTTP_EXPECT)
-      status, headers, body = @app.call(env)
+    begin
       return if @request.hijacked?
+
+      if 100 == status.to_i
+        e100_response_write(client, env)
+        status, headers, body = @app.call(env)
+        return if @request.hijacked?
+      end
+      @request.headers? or headers = nil
+      http_response_write(client, status, headers, body,
+                          @request.response_start_sent)
+    ensure
+      body.respond_to?(:close) and body.close
     end
-    @request.headers? or headers = nil
-    http_response_write(client, status, headers, body,
-                        @request.response_start_sent)
+
     unless client.closed? # rack.hijack may've close this for us
       client.shutdown # in case of fork() in Rack app
       client.close # flush and uncork socket immediately, no keepalive
@@ -597,9 +584,6 @@ class Unicorn::HttpServer
     handle_error(client, e)
   end
 
-  EXIT_SIGS = [ :QUIT, :TERM, :INT ]
-  WORKER_QUEUE_SIGS = QUEUE_SIGS - EXIT_SIGS
-
   def nuke_listeners!(readers)
     # only called from the worker, ordering is important here
     tmp = readers.dup
@@ -614,23 +598,23 @@ class Unicorn::HttpServer
   def init_worker_process(worker)
     worker.atfork_child
     # we'll re-trap :QUIT later for graceful shutdown iff we accept clients
-    EXIT_SIGS.each { |sig| trap(sig) { exit!(0) } }
-    exit!(0) if (SIG_QUEUE & EXIT_SIGS)[0]
-    WORKER_QUEUE_SIGS.each { |sig| trap(sig, nil) }
+    exit_sigs = [ :QUIT, :TERM, :INT ]
+    exit_sigs.each { |sig| trap(sig) { exit!(0) } }
+    exit!(0) if (@sig_queue & exit_sigs)[0]
+    (@queue_sigs - exit_sigs).each { |sig| trap(sig, nil) }
     trap(:CHLD, 'DEFAULT')
-    SIG_QUEUE.clear
+    @sig_queue.clear
     proc_name "worker[#{worker.nr}]"
     START_CTX.clear
-    WORKERS.clear
+    @workers.clear
 
     after_fork.call(self, worker) # can drop perms and create listeners
-    LISTENERS.each { |sock| sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) }
+    LISTENERS.each { |sock| sock.close_on_exec = true }
 
     worker.user(*user) if user.kind_of?(Array) && ! worker.switched
     self.timeout /= 2.0 # halve it for select()
     @config = nil
     build_app! unless preload_app
-    ssl_enable!
     @after_fork = @listener_opts = @orig_app = nil
     readers = LISTENERS.dup
     readers << worker
@@ -651,7 +635,7 @@ class Unicorn::HttpServer
   # for connections and doesn't die until the parent dies (or is
   # given a INT, QUIT, or TERM signal)
   def worker_loop(worker)
-    ppid = master_pid
+    ppid = @master_pid
     readers = init_worker_process(worker)
     nr = 0 # this becomes negative if we need to reopen logs
 
@@ -665,7 +649,7 @@ class Unicorn::HttpServer
     begin
       nr < 0 and reopen_worker_logs(worker.nr)
       nr = 0
-      worker.tick = Time.now.to_i
+      worker.tick = time_now.to_i
       tmp = ready.dup
       while sock = tmp.shift
         # Unicorn::Worker#kgio_tryaccept is not like accept(2) at all,
@@ -673,7 +657,7 @@ class Unicorn::HttpServer
         if client = sock.kgio_tryaccept
           process_client(client)
           nr += 1
-          worker.tick = Time.now.to_i
+          worker.tick = time_now.to_i
         end
         break if nr < 0
       end
@@ -690,7 +674,7 @@ class Unicorn::HttpServer
       ppid == Process.ppid or return
 
       # timeout used so we can detect parent death:
-      worker.tick = Time.now.to_i
+      worker.tick = time_now.to_i
       ret = IO.select(readers, nil, nil, @timeout) and ready = ret[0]
     rescue => e
       redo if nr < 0 && readers[0]
@@ -702,17 +686,17 @@ class Unicorn::HttpServer
   # is no longer running.
   def kill_worker(signal, wpid)
     Process.kill(signal, wpid)
-    rescue Errno::ESRCH
-      worker = WORKERS.delete(wpid) and worker.close rescue nil
+  rescue Errno::ESRCH
+    worker = @workers.delete(wpid) and worker.close rescue nil
   end
 
   # delivers a signal to each worker
   def kill_each_worker(signal)
-    WORKERS.keys.each { |wpid| kill_worker(signal, wpid) }
+    @workers.keys.each { |wpid| kill_worker(signal, wpid) }
   end
 
   def soft_kill_each_worker(signal)
-    WORKERS.each_value { |worker| worker.soft_kill(signal) }
+    @workers.each_value { |worker| worker.soft_kill(signal) }
   end
 
   # unlinks a PID file at given +path+ if it contains the current PID
@@ -745,7 +729,7 @@ class Unicorn::HttpServer
     config.commit!(self)
     soft_kill_each_worker(:QUIT)
     Unicorn::Util.reopen_logs
-    self.app = orig_app
+    self.app = @orig_app
     build_app! if preload_app
     logger.info "done reloading config_file=#{config.config_file}"
   rescue StandardError, LoadError, SyntaxError => e
@@ -782,12 +766,23 @@ class Unicorn::HttpServer
   def inherit_listeners!
     # inherit sockets from parents, they need to be plain Socket objects
     # before they become Kgio::UNIXServer or Kgio::TCPServer
-    inherited = ENV['UNICORN_FD'].to_s.split(/,/).map do |fd|
+    inherited = ENV['UNICORN_FD'].to_s.split(',')
+
+    # emulate sd_listen_fds() for systemd
+    sd_pid, sd_fds = ENV.values_at('LISTEN_PID', 'LISTEN_FDS')
+    if sd_pid.to_i == $$ # n.b. $$ can never be zero
+      # 3 = SD_LISTEN_FDS_START
+      inherited.concat((3...(3 + sd_fds.to_i)).to_a)
+    end
+    # to ease debugging, we will not unset LISTEN_PID and LISTEN_FDS
+
+    inherited.map! do |fd|
       io = Socket.for_fd(fd.to_i)
+      io.autoclose = false
+      io = server_cast(io)
       set_server_sockopt(io, listener_opts[sock_name(io)])
-      prevent_autoclose(io)
-      logger.info "inherited addr=#{sock_name(io)} fd=#{fd}"
-      server_cast(io)
+      logger.info "inherited addr=#{sock_name(io)} fd=#{io.fileno}"
+      io
     end
 
     config_listeners = config[:listeners].dup
@@ -810,8 +805,20 @@ class Unicorn::HttpServer
   # call only after calling inherit_listeners!
   # This binds any listeners we did NOT inherit from the parent
   def bind_new_listeners!
-    NEW_LISTENERS.each { |addr| listen(addr) }
+    NEW_LISTENERS.each { |addr| listen(addr) }.clear
     raise ArgumentError, "no listeners" if LISTENERS.empty?
-    NEW_LISTENERS.clear
+  end
+
+  # try to use the monotonic clock in Ruby >= 2.1, it is immune to clock
+  # offset adjustments and generates less garbage (Float vs Time object)
+  begin
+    Process.clock_gettime(Process::CLOCK_MONOTONIC)
+    def time_now
+      Process.clock_gettime(Process::CLOCK_MONOTONIC)
+    end
+  rescue NameError, NoMethodError
+    def time_now # Ruby <= 2.0
+      Time.now
+    end
   end
 end
diff --git a/lib/unicorn/socket_helper.rb b/lib/unicorn/socket_helper.rb
index 820b778..df8315e 100644
--- a/lib/unicorn/socket_helper.rb
+++ b/lib/unicorn/socket_helper.rb
@@ -4,25 +4,17 @@ require 'socket'
 
 module Unicorn
   module SocketHelper
-    # :stopdoc:
-    include Socket::Constants
 
-    # prevents IO objects in here from being GC-ed
-    # kill this when we drop 1.8 support
-    IO_PURGATORY = []
-
-    # internal interface, only used by Rainbows!/Zbatery
+    # internal interface
     DEFAULTS = {
       # The semantics for TCP_DEFER_ACCEPT changed in Linux 2.6.32+
       # with commit d1b99ba41d6c5aa1ed2fc634323449dd656899e9
-      # This change shouldn't affect Unicorn users behind nginx (a
-      # value of 1 remains an optimization), but Rainbows! users may
-      # want to use a higher value on Linux 2.6.32+ to protect against
-      # denial-of-service attacks
+      # This change shouldn't affect unicorn users behind nginx (a
+      # value of 1 remains an optimization).
       :tcp_defer_accept => 1,
 
       # FreeBSD, we need to override this to 'dataready' if we
-      # eventually get HTTPS support
+      # eventually support non-HTTP/1.x
       :accept_filter => 'httpready',
 
       # same default value as Mongrel
@@ -32,76 +24,47 @@ module Unicorn
       :tcp_nopush => nil,
       :tcp_nodelay => true,
     }
-    #:startdoc:
 
     # configure platform-specific options (only tested on Linux 2.6 so far)
-    case RUBY_PLATFORM
-    when /linux/
-      # from /usr/include/linux/tcp.h
-      TCP_DEFER_ACCEPT = 9 unless defined?(TCP_DEFER_ACCEPT)
-
-      # do not send out partial frames (Linux)
-      TCP_CORK = 3 unless defined?(TCP_CORK)
-
-      # Linux got SO_REUSEPORT in 3.9, BSDs have had it for ages
-      unless defined?(SO_REUSEPORT)
-        if RUBY_PLATFORM =~ /(?:alpha|mips|parisc|sparc)/
-          SO_REUSEPORT = 0x0200 # untested
-        else
-          SO_REUSEPORT = 15 # only tested on x86_64 and i686
-        end
-      end
-    when /freebsd/
-      # do not send out partial frames (FreeBSD)
-      TCP_NOPUSH = 4 unless defined?(TCP_NOPUSH)
-
-      def accf_arg(af_name)
-        [ af_name, nil ].pack('a16a240')
-      end if defined?(SO_ACCEPTFILTER)
-    end
-
-    def prevent_autoclose(io)
-      if io.respond_to?(:autoclose=)
-        io.autoclose = false
-      else
-        IO_PURGATORY << io
-      end
-    end
+    def accf_arg(af_name)
+      [ af_name, nil ].pack('a16a240')
+    end if RUBY_PLATFORM =~ /freebsd/ && Socket.const_defined?(:SO_ACCEPTFILTER)
 
     def set_tcp_sockopt(sock, opt)
       # just in case, even LANs can break sometimes.  Linux sysadmins
       # can lower net.ipv4.tcp_keepalive_* sysctl knobs to very low values.
-      sock.setsockopt(SOL_SOCKET, SO_KEEPALIVE, 1) if defined?(SO_KEEPALIVE)
+      Socket.const_defined?(:SO_KEEPALIVE) and
+        sock.setsockopt(:SOL_SOCKET, :SO_KEEPALIVE, 1)
 
-      if defined?(TCP_NODELAY)
+      if Socket.const_defined?(:TCP_NODELAY)
         val = opt[:tcp_nodelay]
-        val = DEFAULTS[:tcp_nodelay] if nil == val
-        sock.setsockopt(IPPROTO_TCP, TCP_NODELAY, val ? 1 : 0)
+        val = DEFAULTS[:tcp_nodelay] if val.nil?
+        sock.setsockopt(:IPPROTO_TCP, :TCP_NODELAY, val ? 1 : 0)
       end
 
       val = opt[:tcp_nopush]
       unless val.nil?
-        if defined?(TCP_CORK) # Linux
-          sock.setsockopt(IPPROTO_TCP, TCP_CORK, val)
-        elsif defined?(TCP_NOPUSH) # TCP_NOPUSH is lightly tested (FreeBSD)
-          sock.setsockopt(IPPROTO_TCP, TCP_NOPUSH, val)
+        if Socket.const_defined?(:TCP_CORK) # Linux
+          sock.setsockopt(:IPPROTO_TCP, :TCP_CORK, val)
+        elsif Socket.const_defined?(:TCP_NOPUSH) # FreeBSD
+          sock.setsockopt(:IPPROTO_TCP, :TCP_NOPUSH, val)
         end
       end
 
-      # No good reason to ever have deferred accepts off
-      # (except maybe benchmarking)
-      if defined?(TCP_DEFER_ACCEPT)
+      # No good reason to ever have deferred accepts off in single-threaded
+      # servers (except maybe benchmarking)
+      if Socket.const_defined?(:TCP_DEFER_ACCEPT)
         # this differs from nginx, since nginx doesn't allow us to
         # configure the the timeout...
         seconds = opt[:tcp_defer_accept]
         seconds = DEFAULTS[:tcp_defer_accept] if [true,nil].include?(seconds)
         seconds = 0 unless seconds # nil/false means disable this
-        sock.setsockopt(SOL_TCP, TCP_DEFER_ACCEPT, seconds)
+        sock.setsockopt(:IPPROTO_TCP, :TCP_DEFER_ACCEPT, seconds)
       elsif respond_to?(:accf_arg)
         name = opt[:accept_filter]
-        name = DEFAULTS[:accept_filter] if nil == name
+        name = DEFAULTS[:accept_filter] if name.nil?
         begin
-          sock.setsockopt(SOL_SOCKET, SO_ACCEPTFILTER, accf_arg(name))
+          sock.setsockopt(:SOL_SOCKET, :SO_ACCEPTFILTER, accf_arg(name))
         rescue => e
           logger.error("#{sock_name(sock)} " \
                        "failed to set accept_filter=#{name} (#{e.inspect})")
@@ -114,10 +77,11 @@ module Unicorn
 
       TCPSocket === sock and set_tcp_sockopt(sock, opt)
 
-      if opt[:rcvbuf] || opt[:sndbuf]
+      rcvbuf, sndbuf = opt.values_at(:rcvbuf, :sndbuf)
+      if rcvbuf || sndbuf
         log_buffer_sizes(sock, "before: ")
-        sock.setsockopt(SOL_SOCKET, SO_RCVBUF, opt[:rcvbuf]) if opt[:rcvbuf]
-        sock.setsockopt(SOL_SOCKET, SO_SNDBUF, opt[:sndbuf]) if opt[:sndbuf]
+        sock.setsockopt(:SOL_SOCKET, :SO_RCVBUF, rcvbuf) if rcvbuf
+        sock.setsockopt(:SOL_SOCKET, :SO_SNDBUF, sndbuf) if sndbuf
         log_buffer_sizes(sock, " after: ")
       end
       sock.listen(opt[:backlog])
@@ -126,8 +90,8 @@ module Unicorn
     end
 
     def log_buffer_sizes(sock, pfx = '')
-      rcvbuf = sock.getsockopt(SOL_SOCKET, SO_RCVBUF).unpack('i')
-      sndbuf = sock.getsockopt(SOL_SOCKET, SO_SNDBUF).unpack('i')
+      rcvbuf = sock.getsockopt(:SOL_SOCKET, :SO_RCVBUF).int
+      sndbuf = sock.getsockopt(:SOL_SOCKET, :SO_SNDBUF).int
       logger.info "#{pfx}#{sock_name(sock)} rcvbuf=#{rcvbuf} sndbuf=#{sndbuf}"
     end
 
@@ -172,25 +136,25 @@ module Unicorn
 
     def new_tcp_server(addr, port, opt)
       # n.b. we set FD_CLOEXEC in the workers
-      sock = Socket.new(opt[:ipv6] ? AF_INET6 : AF_INET, SOCK_STREAM, 0)
+      sock = Socket.new(opt[:ipv6] ? :AF_INET6 : :AF_INET, :SOCK_STREAM)
       if opt.key?(:ipv6only)
-        defined?(IPV6_V6ONLY) or
+        Socket.const_defined?(:IPV6_V6ONLY) or
           abort "Socket::IPV6_V6ONLY not defined, upgrade Ruby and/or your OS"
-        sock.setsockopt(IPPROTO_IPV6, IPV6_V6ONLY, opt[:ipv6only] ? 1 : 0)
+        sock.setsockopt(:IPPROTO_IPV6, :IPV6_V6ONLY, opt[:ipv6only] ? 1 : 0)
       end
-      sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
-      if defined?(SO_REUSEPORT) && opt[:reuseport]
-        sock.setsockopt(SOL_SOCKET, SO_REUSEPORT, 1)
+      sock.setsockopt(:SOL_SOCKET, :SO_REUSEADDR, 1)
+      if Socket.const_defined?(:SO_REUSEPORT) && opt[:reuseport]
+        sock.setsockopt(:SOL_SOCKET, :SO_REUSEPORT, 1)
       end
       sock.bind(Socket.pack_sockaddr_in(port, addr))
-      prevent_autoclose(sock)
+      sock.autoclose = false
       Kgio::TCPServer.for_fd(sock.fileno)
     end
 
     # returns rfc2732-style (e.g. "[::1]:666") addresses for IPv6
     def tcp_name(sock)
       port, addr = Socket.unpack_sockaddr_in(sock.getsockname)
-      /:/ =~ addr ? "[#{addr}]:#{port}" : "#{addr}:#{port}"
+      addr.include?(':') ? "[#{addr}]:#{port}" : "#{addr}:#{port}"
     end
     module_function :tcp_name
 
diff --git a/lib/unicorn/ssl_client.rb b/lib/unicorn/ssl_client.rb
deleted file mode 100644
index a8c79e3..0000000
--- a/lib/unicorn/ssl_client.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- encoding: binary -*-
-# :stopdoc:
-class Unicorn::SSLClient < Kgio::SSL
-  alias write kgio_write
-  alias close kgio_close
-
-  # this is no-op for now, to be fixed in kgio-monkey if people care
-  # about SSL support...
-  def shutdown(how = nil)
-  end
-end
diff --git a/lib/unicorn/ssl_configurator.rb b/lib/unicorn/ssl_configurator.rb
deleted file mode 100644
index 34f09ec..0000000
--- a/lib/unicorn/ssl_configurator.rb
+++ /dev/null
@@ -1,104 +0,0 @@
-# -*- encoding: binary -*-
-# :stopdoc:
-# This module is included in Unicorn::Configurator
-# :startdoc:
-#
-module Unicorn::SSLConfigurator
-  def ssl(&block)
-    ssl_require!
-    before = @set[:listeners].dup
-    opts = @set[:ssl_opts] = {}
-    yield
-    (@set[:listeners] - before).each do |address|
-      (@set[:listener_opts][address] ||= {})[:ssl_opts] = opts
-    end
-    ensure
-      @set.delete(:ssl_opts)
-  end
-
-  def ssl_certificate(file)
-    ssl_set(:ssl_certificate, file)
-  end
-
-  def ssl_certificate_key(file)
-    ssl_set(:ssl_certificate_key, file)
-  end
-
-  def ssl_client_certificate(file)
-    ssl_set(:ssl_client_certificate, file)
-  end
-
-  def ssl_dhparam(file)
-    ssl_set(:ssl_dhparam, file)
-  end
-
-  def ssl_ciphers(openssl_cipherlist_spec)
-    ssl_set(:ssl_ciphers, openssl_cipherlist_spec)
-  end
-
-  def ssl_crl(file)
-    ssl_set(:ssl_crl, file)
-  end
-
-  def ssl_prefer_server_ciphers(bool)
-    ssl_set(:ssl_prefer_server_ciphers, check_bool(bool))
-  end
-
-  def ssl_protocols(list)
-    ssl_set(:ssl_protocols, list)
-  end
-
-  def ssl_verify_client(on_off_optional)
-    ssl_set(:ssl_verify_client, on_off_optional)
-  end
-
-  def ssl_session_timeout(seconds)
-    ssl_set(:ssl_session_timeout, seconds)
-  end
-
-  def ssl_verify_depth(depth)
-    ssl_set(:ssl_verify_depth, depth)
-  end
-
-  # Allows specifying an engine for OpenSSL to use.  We have not been
-  # able to successfully test this feature due to a lack of hardware,
-  # Reports of success or patches to unicorn-public at bogomips.org is
-  # greatly appreciated.
-  def ssl_engine(engine)
-    ssl_warn_global(:ssl_engine)
-    ssl_require!
-    OpenSSL::Engine.load
-    OpenSSL::Engine.by_id(engine)
-    @set[:ssl_engine] = engine
-  end
-
-  def ssl_compression(bool)
-    # OpenSSL uses the SSL_OP_NO_COMPRESSION flag, Flipper follows suit
-    # with :ssl_no_compression, but we negate it to avoid exposing double
-    # negatives to the user.
-    ssl_set(:ssl_no_compression, check_bool(:ssl_compression, ! bool))
-  end
-
-private
-
-  def ssl_warn_global(func) # :nodoc:
-    Hash === @set[:ssl_opts] or return
-    warn("`#{func}' affects all SSL contexts in this process, " \
-         "not just this block")
-  end
-
-  def ssl_set(key, value) # :nodoc:
-    cur = @set[:ssl_opts]
-    Hash === cur or
-             raise ArgumentError, "#{key} must be called inside an `ssl' block"
-    cur[key] = value
-  end
-
-  def ssl_require! # :nodoc:
-    require "flipper"
-    require "unicorn/ssl_client"
-    rescue LoadError
-      warn "install 'kgio-monkey' for SSL support"
-      raise
-  end
-end
diff --git a/lib/unicorn/ssl_server.rb b/lib/unicorn/ssl_server.rb
deleted file mode 100644
index c00c3ae..0000000
--- a/lib/unicorn/ssl_server.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-# -*- encoding: binary -*-
-# :stopdoc:
-# this module is meant to be included in Unicorn::HttpServer
-# It is an implementation detail and NOT meant for users.
-module Unicorn::SSLServer
-  attr_accessor :ssl_engine
-
-  def ssl_enable!
-    sni_hostnames = rack_sni_hostnames(@app)
-    seen = {} # we map a single SSLContext to multiple listeners
-    listener_ctx = {}
-    @listener_opts.each do |address, address_opts|
-      ssl_opts = address_opts[:ssl_opts] or next
-      listener_ctx[address] = seen[ssl_opts.object_id] ||= begin
-        unless sni_hostnames.empty?
-          ssl_opts = ssl_opts.dup
-          ssl_opts[:sni_hostnames] = sni_hostnames
-        end
-        ctx = Flipper.ssl_context(ssl_opts)
-        # FIXME: make configurable
-        ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_OFF
-        ctx
-      end
-    end
-    Unicorn::HttpServer::LISTENERS.each do |listener|
-      ctx = listener_ctx[sock_name(listener)] or next
-      listener.extend(Kgio::SSLServer)
-      listener.ssl_ctx = ctx
-      listener.kgio_ssl_class = Unicorn::SSLClient
-    end
-  end
-
-  # ugh, this depends on Rack internals...
-  def rack_sni_hostnames(rack_app) # :nodoc:
-    hostnames = {}
-    if Rack::URLMap === rack_app
-      mapping = rack_app.instance_variable_get(:@mapping)
-      mapping.each { |hostname,_,_,_| hostnames[hostname] = true }
-    end
-    hostnames.keys
-  end
-end
diff --git a/lib/unicorn/stream_input.rb b/lib/unicorn/stream_input.rb
index 9278f47..de5aeea 100644
--- a/lib/unicorn/stream_input.rb
+++ b/lib/unicorn/stream_input.rb
@@ -53,7 +53,7 @@ class Unicorn::StreamInput
           rv << @rbuf
           to_read -= @rbuf.size
         end
-        @rbuf.replace('')
+        @rbuf.clear
       end
       rv = nil if rv.empty? && length != 0
     else
@@ -130,8 +130,8 @@ private
       filter_body(@rbuf, @buf)
       dst << @rbuf
     end
-    ensure
-      @rbuf.replace('')
+  ensure
+    @rbuf.clear
   end
 
   def eof!
diff --git a/lib/unicorn/tmpio.rb b/lib/unicorn/tmpio.rb
index dcdf9da..db88ed3 100644
--- a/lib/unicorn/tmpio.rb
+++ b/lib/unicorn/tmpio.rb
@@ -22,11 +22,6 @@ class Unicorn::TmpIO < File
     fp
   end
 
-  # for easier env["rack.input"] compatibility with Rack <= 1.1
-  def size
-    stat.size
-  end unless File.method_defined?(:size)
-
   # pretend we're Tempfile for Rack::TempfileReaper
   alias close! close
 end
diff --git a/lib/unicorn/util.rb b/lib/unicorn/util.rb
index 94c4e37..2f8bfeb 100644
--- a/lib/unicorn/util.rb
+++ b/lib/unicorn/util.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 
-module Unicorn::Util
+require 'fcntl'
+module Unicorn::Util # :nodoc:
 
 # :stopdoc:
   def self.is_log?(fp)
diff --git a/lib/unicorn/version.rb b/lib/unicorn/version.rb
index 5034b09..26e0db1 100644
--- a/lib/unicorn/version.rb
+++ b/lib/unicorn/version.rb
@@ -1 +1 @@
-Unicorn::Const::UNICORN_VERSION = '4.9.0'
+Unicorn::Const::UNICORN_VERSION = '5.0.0'
diff --git a/lib/unicorn/worker.rb b/lib/unicorn/worker.rb
index e74a1c9..6748a2f 100644
--- a/lib/unicorn/worker.rb
+++ b/lib/unicorn/worker.rb
@@ -3,15 +3,14 @@ require "raindrops"
 
 # This class and its members can be considered a stable interface
 # and will not change in a backwards-incompatible fashion between
-# releases of \Unicorn.  Knowledge of this class is generally not
-# not needed for most users of \Unicorn.
+# releases of unicorn.  Knowledge of this class is generally not
+# not needed for most users of unicorn.
 #
 # Some users may want to access it in the before_fork/after_fork hooks.
 # See the Unicorn::Configurator RDoc for examples.
 class Unicorn::Worker
   # :stopdoc:
   attr_accessor :nr, :switched
-  attr_writer :tmp
   attr_reader :to_io # IO.select-compatible
 
   PER_DROP = Raindrops::PAGE_SIZE / Raindrops::SIZE
@@ -23,7 +22,7 @@ class Unicorn::Worker
     @offset = nr % PER_DROP
     @raindrop[@offset] = 0
     @nr = nr
-    @tmp = @switched = false
+    @switched = false
     @to_io, @master = Unicorn.pipe
   end
 
@@ -101,18 +100,8 @@ class Unicorn::Worker
     @raindrop[@offset]
   end
 
-  # only exists for compatibility
-  def tmp # :nodoc:
-    @tmp ||= begin
-      tmp = Unicorn::TmpIO.new
-      tmp.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
-      tmp
-    end
-  end
-
   # called in both the master (reaping worker) and worker (SIGQUIT handler)
   def close # :nodoc:
-    @tmp.close if @tmp
     @master.close if @master
     @to_io.close if @to_io
   end
@@ -141,7 +130,6 @@ class Unicorn::Worker
     uid = Etc.getpwnam(user).uid
     gid = Etc.getgrnam(group).gid if group
     Unicorn::Util.chown_logs(uid, gid)
-    @tmp.chown(uid, gid) if @tmp
     if gid && Process.egid != gid
       Process.initgroups(user, gid)
       Process::GID.change_privilege(gid)
diff --git a/man/man1/unicorn.1 b/man/man1/unicorn.1
index 47d79fe..de16222 100644
--- a/man/man1/unicorn.1
+++ b/man/man1/unicorn.1
@@ -198,9 +198,11 @@ UNICORN_FD is a comma-delimited list of one or more file descriptors
 used to implement USR2 upgrades.
 Init systems may bind listen sockets itself and spawn unicorn with
 UNICORN_FD set to the file descriptor numbers of the listen socket(s).
-The unicorn CONFIG_FILE must still have the inherited listen socket
-parameters defined as in a normal startup, otherwise the socket will be
-closed.
+.PP
+As of unicorn 5.0, LISTEN_PID and LISTEN_FDS are used for socket
+activation as documented in the sd_listen_fds(3) manpage.
+Users relying on this feature do not need to specify a listen socket in
+the unicorn config file.
 .SH SEE ALSO
 .IP \[bu] 2
 unicorn_rails(1)
@@ -211,8 +213,8 @@ unicorn_rails(1)
 .IP \[bu] 2
 Unicorn RDoc (http://unicorn.bogomips.org/)
 .IP \[bu] 2
-Rack RDoc (http://rdoc.info/gems/r#/gems/rack/frames)
+Rack RDoc (http://www.rubydoc.info/github/rack/rack/)
 .IP \[bu] 2
-Rackup HowTo (http://wiki.github.com/rack/rack/tutorial-rackup-howto)
+Rackup HowTo (https://github.com/rack/rack/wiki/tutorial-rackup-howto)
 .SH AUTHORS
 The Unicorn Community <unicorn-public at bogomips.org>.
diff --git a/man/man1/unicorn_rails.1 b/man/man1/unicorn_rails.1
index f27b734..32c2ab8 100644
--- a/man/man1/unicorn_rails.1
+++ b/man/man1/unicorn_rails.1
@@ -201,8 +201,8 @@ unicorn(1)
 .IP \[bu] 2
 Unicorn RDoc (http://unicorn.bogomips.org/)
 .IP \[bu] 2
-Rack RDoc (http://rdoc.info/gems/r#/gems/rack/frames)
+Rack RDoc (http://www.rubydoc.info/github/rack/rack/)
 .IP \[bu] 2
-Rackup HowTo (http://wiki.github.com/rack/rack/tutorial-rackup-howto)
+Rackup HowTo (https://github.com/rack/rack/wiki/tutorial-rackup-howto)
 .SH AUTHORS
 The Unicorn Community <unicorn-public at bogomips.org>.
diff --git a/metadata.yml b/metadata.yml
index eb8928e..612a711 100644
--- a/metadata.yml
+++ b/metadata.yml
@@ -1,14 +1,14 @@
 --- !ruby/object:Gem::Specification
 name: unicorn
 version: !ruby/object:Gem::Version
-  version: 4.9.0
+  version: 5.0.0
 platform: ruby
 authors:
-- Unicorn hackers
+- unicorn hackers
 autorequire: 
 bindir: bin
 cert_chain: []
-date: 2015-04-24 00:00:00.000000000 Z
+date: 2015-11-01 00:00:00.000000000 Z
 dependencies:
 - !ruby/object:Gem::Dependency
   name: rack
@@ -81,11 +81,11 @@ dependencies:
       - !ruby/object:Gem::Version
         version: '1.0'
 description: |-
-  \Unicorn is an HTTP server for Rack applications designed to only serve
+  unicorn is an HTTP server for Rack applications designed to only serve
   fast clients on low-latency, high-bandwidth connections and take
   advantage of features in Unix/Unix-like kernels.  Slow clients should
   only be served by placing a reverse proxy capable of fully buffering
-  both the the request and response in between \Unicorn and slow clients.
+  both the the request and response in between unicorn and slow clients.
 email: unicorn-public at bogomips.org
 executables:
 - unicorn
@@ -160,7 +160,6 @@ files:
 - bin/unicorn_rails
 - examples/big_app_gc.rb
 - examples/echo.ru
-- examples/git.ru
 - examples/init.sh
 - examples/logger_mp_safe.rb
 - examples/logrotate.conf
@@ -178,8 +177,6 @@ files:
 - ext/unicorn_http/unicorn_http.rl
 - ext/unicorn_http/unicorn_http_common.rl
 - lib/unicorn.rb
-- lib/unicorn/app/exec_cgi.rb
-- lib/unicorn/app/inetd.rb
 - lib/unicorn/app/old_rails.rb
 - lib/unicorn/app/old_rails/static.rb
 - lib/unicorn/cgi_wrapper.rb
@@ -192,9 +189,6 @@ files:
 - lib/unicorn/oob_gc.rb
 - lib/unicorn/preread_input.rb
 - lib/unicorn/socket_helper.rb
-- lib/unicorn/ssl_client.rb
-- lib/unicorn/ssl_configurator.rb
-- lib/unicorn/ssl_server.rb
 - lib/unicorn/stream_input.rb
 - lib/unicorn/tee_input.rb
 - lib/unicorn/tmpio.rb
@@ -245,8 +239,6 @@ files:
 - t/t0014-rewindable-input-true.sh
 - t/t0014.ru
 - t/t0015-configurator-internals.sh
-- t/t0016-trust-x-forwarded-false.sh
-- t/t0017-trust-x-forwarded-true.sh
 - t/t0018-write-on-close.sh
 - t/t0019-max_header_len.sh
 - t/t0020-at_exit-handler.sh
@@ -273,12 +265,10 @@ files:
 - test/unit/test_droplet.rb
 - test/unit/test_http_parser.rb
 - test/unit/test_http_parser_ng.rb
-- test/unit/test_http_parser_xftrust.rb
 - test/unit/test_request.rb
 - test/unit/test_response.rb
 - test/unit/test_server.rb
 - test/unit/test_signals.rb
-- test/unit/test_sni_hostnames.rb
 - test/unit/test_socket_helper.rb
 - test/unit/test_stream_input.rb
 - test/unit/test_tee_input.rb
@@ -289,8 +279,8 @@ files:
 - unicorn_rails_1
 homepage: http://unicorn.bogomips.org/
 licenses:
-- GPLv2+
-- Ruby 1.8
+- GPL-2.0+
+- Ruby-1.8
 metadata: {}
 post_install_message: 
 rdoc_options: []
@@ -298,9 +288,9 @@ require_paths:
 - lib
 required_ruby_version: !ruby/object:Gem::Requirement
   requirements:
-  - - ">="
+  - - "<"
     - !ruby/object:Gem::Version
-      version: '0'
+      version: '3.0'
 required_rubygems_version: !ruby/object:Gem::Requirement
   requirements:
   - - ">="
@@ -308,7 +298,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
       version: '0'
 requirements: []
 rubyforge_project: 
-rubygems_version: 2.4.5
+rubygems_version: 2.5.0
 signing_key: 
 specification_version: 4
 summary: Rack HTTP server for fast clients and Unix
@@ -316,9 +306,6 @@ test_files:
 - test/unit/test_configurator.rb
 - test/unit/test_http_parser.rb
 - test/unit/test_http_parser_ng.rb
-- test/unit/test_http_parser_xftrust.rb
 - test/unit/test_request.rb
-- test/unit/test_response.rb
 - test/unit/test_server.rb
-- test/unit/test_sni_hostnames.rb
 - test/unit/test_util.rb
diff --git a/t/hijack.ru b/t/hijack.ru
index fcb0b6d..4adec61 100644
--- a/t/hijack.ru
+++ b/t/hijack.ru
@@ -2,12 +2,13 @@ use Rack::Lint
 use Rack::ContentLength
 use Rack::ContentType, "text/plain"
 class DieIfUsed
+  @@n = 0
   def each
     abort "body.each called after response hijack\n"
   end
 
   def close
-    abort "body.close called after response hijack\n"
+    warn "closed DieIfUsed #{@@n += 1}\n"
   end
 end
 run lambda { |env|
diff --git a/t/t0016-trust-x-forwarded-false.sh b/t/t0016-trust-x-forwarded-false.sh
deleted file mode 100755
index 3163690..0000000
--- a/t/t0016-trust-x-forwarded-false.sh
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/sh
-. ./test-lib.sh
-t_plan 5 "trust_x_forwarded=false configuration test"
-
-t_begin "setup and start" && {
-	unicorn_setup
-	echo "trust_x_forwarded false" >> $unicorn_config
-	unicorn -D -c $unicorn_config env.ru
-	unicorn_wait_start
-}
-
-t_begin "spoofed request with X-Forwarded-Proto does not trigger" && {
-	curl -H 'X-Forwarded-Proto: https' http://$listen/ | \
-		grep -F '"rack.url_scheme"=>"http"'
-}
-
-t_begin "spoofed request with X-Forwarded-SSL does not trigger" && {
-	curl -H 'X-Forwarded-SSL: on' http://$listen/ | \
-		grep -F '"rack.url_scheme"=>"http"'
-}
-
-t_begin "killing succeeds" && {
-	kill $unicorn_pid
-}
-
-t_begin "check stderr has no errors" && {
-	check_stderr
-}
-
-t_done
diff --git a/t/t0017-trust-x-forwarded-true.sh b/t/t0017-trust-x-forwarded-true.sh
deleted file mode 100755
index 11103c5..0000000
--- a/t/t0017-trust-x-forwarded-true.sh
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/sh
-. ./test-lib.sh
-t_plan 5 "trust_x_forwarded=true configuration test"
-
-t_begin "setup and start" && {
-	unicorn_setup
-	echo "trust_x_forwarded true " >> $unicorn_config
-	unicorn -D -c $unicorn_config env.ru
-	unicorn_wait_start
-}
-
-t_begin "spoofed request with X-Forwarded-Proto sets 'https'" && {
-	curl -H 'X-Forwarded-Proto: https' http://$listen/ | \
-		grep -F '"rack.url_scheme"=>"https"'
-}
-
-t_begin "spoofed request with X-Forwarded-SSL sets 'https'" && {
-	curl -H 'X-Forwarded-SSL: on' http://$listen/ | \
-		grep -F '"rack.url_scheme"=>"https"'
-}
-
-t_begin "killing succeeds" && {
-	kill $unicorn_pid
-}
-
-t_begin "check stderr has no errors" && {
-	check_stderr
-}
-
-t_done
diff --git a/t/t0200-rack-hijack.sh b/t/t0200-rack-hijack.sh
index f772071..de3eb82 100755
--- a/t/t0200-rack-hijack.sh
+++ b/t/t0200-rack-hijack.sh
@@ -16,12 +16,15 @@ t_begin "check response hijack" && {
 	test "xresponse.hijacked" = x"$(curl -sSfv http://$listen/hijack_res)"
 }
 
-t_begin "killing succeeds" && {
+t_begin "killing succeeds after hijack" && {
 	kill $unicorn_pid
 }
 
-t_begin "check stderr" && {
+t_begin "check stderr for hijacked body close" && {
 	check_stderr
+	grep 'closed DieIfUsed 1\>' $r_err
+	grep 'closed DieIfUsed 2\>' $r_err
+	! grep 'closed DieIfUsed 3\>' $r_err
 }
 
 t_done
diff --git a/test/exec/test_exec.rb b/test/exec/test_exec.rb
index 6deb96b..ca0b7bc 100644
--- a/test/exec/test_exec.rb
+++ b/test/exec/test_exec.rb
@@ -96,6 +96,58 @@ run lambda { |env|
     end
   end
 
+  def test_sd_listen_fds_emulation
+    File.open("config.ru", "wb") { |fp| fp.write(HI) }
+    sock = TCPServer.new(@addr, @port)
+
+    [ %W(-l #@addr:#@port), nil ].each do |l|
+      sock.setsockopt(:SOL_SOCKET, :SO_KEEPALIVE, 0)
+
+      pid = xfork do
+        redirect_test_io do
+          # pretend to be systemd
+          ENV['LISTEN_PID'] = "#$$"
+          ENV['LISTEN_FDS'] = '1'
+
+          # 3 = SD_LISTEN_FDS_START
+          args = [ $unicorn_bin ]
+          args.concat(l) if l
+          args << { 3 => sock }
+          exec(*args)
+        end
+      end
+      res = hit(["http://#@addr:#@port/"])
+      assert_equal [ "HI\n" ], res
+      assert_shutdown(pid)
+      assert_equal 1, sock.getsockopt(:SOL_SOCKET, :SO_KEEPALIVE).int,
+                  'unicorn should always set SO_KEEPALIVE on inherited sockets'
+    end
+  ensure
+    sock.close if sock
+    # disabled test on old Rubies: https://bugs.ruby-lang.org/issues/11336
+    # [ruby-core:69895] [Bug #11336] fixed by r51576
+  end if RUBY_VERSION.to_f >= 2.3
+
+  def test_inherit_listener_unspecified
+    File.open("config.ru", "wb") { |fp| fp.write(HI) }
+    sock = TCPServer.new(@addr, @port)
+    sock.setsockopt(:SOL_SOCKET, :SO_KEEPALIVE, 0)
+
+    pid = xfork do
+      redirect_test_io do
+        ENV['UNICORN_FD'] = sock.fileno.to_s
+        exec($unicorn_bin, sock.fileno => sock.fileno)
+      end
+    end
+    res = hit(["http://#@addr:#@port/"])
+    assert_equal [ "HI\n" ], res
+    assert_shutdown(pid)
+    assert_equal 1, sock.getsockopt(:SOL_SOCKET, :SO_KEEPALIVE).int,
+                'unicorn should always set SO_KEEPALIVE on inherited sockets'
+  ensure
+    sock.close if sock
+  end
+
   def test_working_directory_rel_path_config_file
     other = Tempfile.new('unicorn.wd')
     File.unlink(other.path)
diff --git a/test/test_helper.rb b/test/test_helper.rb
index c4fe07a..c21f75d 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -292,6 +292,7 @@ def chunked_spawn(stdout, *cmd)
 end
 
 def reset_sig_handlers
-  sigs = %w(CHLD).concat(Unicorn::HttpServer::QUEUE_SIGS)
-  sigs.each { |sig| trap(sig, "DEFAULT") }
+  %w(WINCH QUIT INT TERM USR1 USR2 HUP TTIN TTOU CHLD).each do |sig|
+    trap(sig, "DEFAULT")
+  end
 end
diff --git a/test/unit/test_http_parser_ng.rb b/test/unit/test_http_parser_ng.rb
index 4f13c9a..d186f5a 100644
--- a/test/unit/test_http_parser_ng.rb
+++ b/test/unit/test_http_parser_ng.rb
@@ -8,10 +8,15 @@ include Unicorn
 class HttpParserNgTest < Test::Unit::TestCase
 
   def setup
-    HttpParser.keepalive_requests = HttpParser::KEEPALIVE_REQUESTS_DEFAULT
     @parser = HttpParser.new
   end
 
+  def test_parser_max_len
+    assert_raises(RangeError) do
+      HttpParser.max_header_len = 0xffffffff + 1
+    end
+  end
+
   def test_next_clear
     r = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
     @parser.buf << r
@@ -29,23 +34,15 @@ class HttpParserNgTest < Test::Unit::TestCase
     assert_equal false, @parser.response_start_sent
   end
 
-  def test_keepalive_requests_default_constant
-    assert_kind_of Integer, HttpParser::KEEPALIVE_REQUESTS_DEFAULT
-    assert HttpParser::KEEPALIVE_REQUESTS_DEFAULT >= 0
-  end
-
-  def test_keepalive_requests_setting
-    HttpParser.keepalive_requests = 0
-    assert_equal 0, HttpParser.keepalive_requests
-    HttpParser.keepalive_requests = nil
-    assert HttpParser.keepalive_requests >= 0xffffffff
-    HttpParser.keepalive_requests = 1
-    assert_equal 1, HttpParser.keepalive_requests
-    HttpParser.keepalive_requests = 666
-    assert_equal 666, HttpParser.keepalive_requests
-
-    assert_raises(TypeError) { HttpParser.keepalive_requests = "666" }
-    assert_raises(TypeError) { HttpParser.keepalive_requests = [] }
+  def test_response_start_sent
+    assert_equal false, @parser.response_start_sent, "default is false"
+    @parser.response_start_sent = true
+    assert_equal true, @parser.response_start_sent
+    @parser.response_start_sent = false
+    assert_equal false, @parser.response_start_sent
+    @parser.response_start_sent = true
+    @parser.clear
+    assert_equal false, @parser.response_start_sent
   end
 
   def test_connection_TE
@@ -71,41 +68,11 @@ class HttpParserNgTest < Test::Unit::TestCase
       "REQUEST_METHOD" => "GET",
       "QUERY_STRING" => ""
     }.freeze
-    HttpParser::KEEPALIVE_REQUESTS_DEFAULT.times do |nr|
+    100.times do |nr|
       @parser.buf << req
       assert_equal expect, @parser.parse
       assert @parser.next?
     end
-    @parser.buf << req
-    assert_equal expect, @parser.parse
-    assert ! @parser.next?
-  end
-
-  def test_fewer_keepalive_requests_with_next?
-    HttpParser.keepalive_requests = 5
-    @parser = HttpParser.new
-    req = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n".freeze
-    expect = {
-      "SERVER_NAME" => "example.com",
-      "HTTP_HOST" => "example.com",
-      "rack.url_scheme" => "http",
-      "REQUEST_PATH" => "/",
-      "SERVER_PROTOCOL" => "HTTP/1.1",
-      "PATH_INFO" => "/",
-      "HTTP_VERSION" => "HTTP/1.1",
-      "REQUEST_URI" => "/",
-      "SERVER_PORT" => "80",
-      "REQUEST_METHOD" => "GET",
-      "QUERY_STRING" => ""
-    }.freeze
-    5.times do |nr|
-      @parser.buf << req
-      assert_equal expect, @parser.parse
-      assert @parser.next?
-    end
-    @parser.buf << req
-    assert_equal expect, @parser.parse
-    assert ! @parser.next?
   end
 
   def test_default_keepalive_is_off
@@ -663,69 +630,4 @@ class HttpParserNgTest < Test::Unit::TestCase
     assert_equal expect, env2
     assert_equal "", @parser.buf
   end
-
-  def test_keepalive_requests_disabled
-    req = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n".freeze
-    expect = {
-      "SERVER_NAME" => "example.com",
-      "HTTP_HOST" => "example.com",
-      "rack.url_scheme" => "http",
-      "REQUEST_PATH" => "/",
-      "SERVER_PROTOCOL" => "HTTP/1.1",
-      "PATH_INFO" => "/",
-      "HTTP_VERSION" => "HTTP/1.1",
-      "REQUEST_URI" => "/",
-      "SERVER_PORT" => "80",
-      "REQUEST_METHOD" => "GET",
-      "QUERY_STRING" => ""
-    }.freeze
-    HttpParser.keepalive_requests = 0
-    @parser = HttpParser.new
-    @parser.buf << req
-    assert_equal expect, @parser.parse
-    assert ! @parser.next?
-  end
-
-  def test_chunk_only
-    tmp = ""
-    assert_equal @parser, @parser.dechunk!
-    assert_nil @parser.filter_body(tmp, "6\r\n")
-    assert_equal "", tmp
-    assert_nil @parser.filter_body(tmp, "abcdef")
-    assert_equal "abcdef", tmp
-    assert_nil @parser.filter_body(tmp, "\r\n")
-    assert_equal "", tmp
-    src = "0\r\n\r\n"
-    assert_equal src.object_id, @parser.filter_body(tmp, src).object_id
-    assert_equal "", tmp
-  end
-
-  def test_chunk_only_bad_align
-    tmp = ""
-    assert_equal @parser, @parser.dechunk!
-    assert_nil @parser.filter_body(tmp, "6\r\na")
-    assert_equal "a", tmp
-    assert_nil @parser.filter_body(tmp, "bcde")
-    assert_equal "bcde", tmp
-    assert_nil @parser.filter_body(tmp, "f\r")
-    assert_equal "f", tmp
-    src = "\n0\r\n\r\n"
-    assert_equal src.object_id, @parser.filter_body(tmp, src).object_id
-    assert_equal "", tmp
-  end
-
-  def test_chunk_only_reset_ok
-    tmp = ""
-    assert_equal @parser, @parser.dechunk!
-    src = "1\r\na\r\n0\r\n\r\n"
-    assert_nil @parser.filter_body(tmp, src)
-    assert_equal "a", tmp
-    assert_equal src.object_id, @parser.filter_body(tmp, src).object_id
-
-    assert_equal @parser, @parser.dechunk!
-    src = "0\r\n\r\n"
-    assert_equal src.object_id, @parser.filter_body(tmp, src).object_id
-    assert_equal "", tmp
-    assert_equal src, @parser.filter_body(tmp, src)
-  end
 end
diff --git a/test/unit/test_http_parser_xftrust.rb b/test/unit/test_http_parser_xftrust.rb
deleted file mode 100644
index 8d0cc37..0000000
--- a/test/unit/test_http_parser_xftrust.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# -*- encoding: binary -*-
-require './test/test_helper'
-
-include Unicorn
-
-class HttpParserXFTrustTest < Test::Unit::TestCase
-  def setup
-    assert HttpParser.trust_x_forwarded?
-  end
-
-  def test_xf_trust_false_xfp
-    HttpParser.trust_x_forwarded = false
-    parser = HttpParser.new
-    parser.buf << "GET / HTTP/1.1\r\nHost: foo:\r\n" \
-                  "X-Forwarded-Proto: https\r\n\r\n"
-    env = parser.parse
-    assert_kind_of Hash, env
-    assert_equal 'foo', env['SERVER_NAME']
-    assert_equal '80', env['SERVER_PORT']
-    assert_equal 'http', env['rack.url_scheme']
-  end
-
-  def test_xf_trust_false_xfs
-    HttpParser.trust_x_forwarded = false
-    parser = HttpParser.new
-    parser.buf << "GET / HTTP/1.1\r\nHost: foo:\r\n" \
-                  "X-Forwarded-SSL: on\r\n\r\n"
-    env = parser.parse
-    assert_kind_of Hash, env
-    assert_equal 'foo', env['SERVER_NAME']
-    assert_equal '80', env['SERVER_PORT']
-    assert_equal 'http', env['rack.url_scheme']
-  end
-
-  def teardown
-    HttpParser.trust_x_forwarded = true
-  end
-end
diff --git a/test/unit/test_response.rb b/test/unit/test_response.rb
index 10b247b..0b14d59 100644
--- a/test/unit/test_response.rb
+++ b/test/unit/test_response.rb
@@ -38,7 +38,6 @@ class ResponseTest < Test::Unit::TestCase
     http_response_write(out,'200', {}, [])
     assert ! out.closed?
     assert out.length > 0, "output didn't have data"
-    assert_equal 1, out.string.split(/\r\n/).grep(/^Status: 200 OK/).size
   end
 
   def test_response_200
@@ -71,18 +70,6 @@ class ResponseTest < Test::Unit::TestCase
     out = StringIO.new
     http_response_write(out,200, {"X-Whatever" => "stuff"}, [])
     assert ! out.closed?
-    assert_equal 1, out.string.split(/\r\n/).grep(/^Status: 200 OK/i).size
-  end
-
-  def test_body_closed
-    expect_body = %w(1 2 3 4).join("\n")
-    body = StringIO.new(expect_body)
-    body.rewind
-    out = StringIO.new
-    http_response_write(out,200, {}, body)
-    assert ! out.closed?
-    assert body.closed?
-    assert_match(expect_body, out.string.split(/\r\n/).last)
   end
 
   def test_unknown_status_pass_through
@@ -91,9 +78,25 @@ class ResponseTest < Test::Unit::TestCase
     assert ! out.closed?
     headers = out.string.split(/\r\n\r\n/).first.split(/\r\n/)
     assert %r{\AHTTP/\d\.\d 666 I AM THE BEAST\z}.match(headers[0])
-    status = headers.grep(/\AStatus:/i).first
-    assert status
-    assert_equal "Status: 666 I AM THE BEAST", status
   end
 
+  def test_modified_rack_http_status_codes_late
+    r, w = IO.pipe
+    pid = fork do
+      r.close
+      # Users may want to globally override the status text associated
+      # with an HTTP status code in their app.
+      Rack::Utils::HTTP_STATUS_CODES[200] = "HI"
+      http_response_write(w, 200, {}, [])
+      w.close
+    end
+    w.close
+    assert_equal "HTTP/1.1 200 HI\r\n", r.gets
+    r.read # just drain the pipe
+    pid, status = Process.waitpid2(pid)
+    assert status.success?, status.inspect
+  ensure
+    r.close
+    w.close unless w.closed?
+  end
 end
diff --git a/test/unit/test_sni_hostnames.rb b/test/unit/test_sni_hostnames.rb
deleted file mode 100644
index 457afee..0000000
--- a/test/unit/test_sni_hostnames.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-# -*- encoding: binary -*-
-require "test/unit"
-require "unicorn"
-
-# this tests an implementation detail, it may change so this test
-# can be removed later.
-class TestSniHostnames < Test::Unit::TestCase
-  include Unicorn::SSLServer
-
-  def setup
-    GC.start
-  end
-
-  def teardown
-    GC.start
-  end
-
-  def test_host_name_detect_one
-    app = Rack::Builder.new do
-      map "http://sni1.example.com/" do
-        use Rack::ContentLength
-        use Rack::ContentType, "text/plain"
-        run lambda { |env| [ 200, {}, [] ] }
-      end
-    end.to_app
-    hostnames = rack_sni_hostnames(app)
-    assert hostnames.include?("sni1.example.com")
-  end
-
-  def test_host_name_detect_multiple
-    app = Rack::Builder.new do
-      map "http://sni2.example.com/" do
-        use Rack::ContentLength
-        use Rack::ContentType, "text/plain"
-        run lambda { |env| [ 200, {}, [] ] }
-      end
-      map "http://sni3.example.com/" do
-        use Rack::ContentLength
-        use Rack::ContentType, "text/plain"
-        run lambda { |env| [ 200, {}, [] ] }
-      end
-    end.to_app
-    hostnames = rack_sni_hostnames(app)
-    assert hostnames.include?("sni2.example.com")
-    assert hostnames.include?("sni3.example.com")
-  end
-end
diff --git a/test/unit/test_socket_helper.rb b/test/unit/test_socket_helper.rb
index 09d65af..7526e82 100644
--- a/test/unit/test_socket_helper.rb
+++ b/test/unit/test_socket_helper.rb
@@ -189,7 +189,7 @@ class TestSocketHelper < Test::Unit::TestCase
     port = unused_port @test_addr
     name = "#@test_addr:#{port}"
     sock = bind_listen(name, :reuseport => true)
-    cur = sock.getsockopt(Socket::SOL_SOCKET, SO_REUSEPORT).unpack('i')[0]
+    cur = sock.getsockopt(:SOL_SOCKET, :SO_REUSEPORT).int
     assert_operator cur, :>, 0
   rescue Errno::ENOPROTOOPT
     # kernel does not support SO_REUSEPORT (older Linux)
diff --git a/unicorn.gemspec b/unicorn.gemspec
index 47d5670..1099361 100644
--- a/unicorn.gemspec
+++ b/unicorn.gemspec
@@ -26,6 +26,11 @@ Gem::Specification.new do |s|
   s.homepage = Olddoc.config['rdoc_url']
   s.test_files = test_files
 
+  # technically we need ">= 1.9.3", too, but avoid the array here since
+  # old rubygems versions (1.8.23.2 at least) do not support multiple
+  # version requirements here.
+  s.required_ruby_version = '< 3.0'
+
   # for people that are absolutely stuck on Rails 2.3.2 and can't
   # up/downgrade to any other version, the Rack dependency may be
   # commented out.  Nevertheless, upgrading to Rails 2.3.4 or later is
@@ -37,5 +42,9 @@ Gem::Specification.new do |s|
   s.add_development_dependency('test-unit', '~> 3.0')
   s.add_development_dependency('olddoc', '~> 1.0')
 
-  s.licenses = ["GPLv2+", "Ruby 1.8"]
+  # Note: To avoid ambiguity, we intentionally avoid the SPDX-compatible
+  # 'Ruby' here since Ruby 1.9.3 switched to BSD-2-Clause, but we
+  # inherited our license from Mongrel when Ruby was at 1.8.
+  # We cannot automatically switch licenses when Ruby changes.
+  s.licenses = ['GPL-2.0+', 'Ruby-1.8']
 end

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/unicorn.git



More information about the Pkg-ruby-extras-commits mailing list