about summary refs log tree commit homepage
diff options
context:
space:
mode:
-rw-r--r--Documentation/unicorn.1.txt11
-rw-r--r--Documentation/unicorn_rails.1.txt10
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--GNUmakefile44
-rwxr-xr-xbin/unicorn4
-rwxr-xr-xbin/unicorn_rails4
-rw-r--r--ext/unicorn_http/unicorn_http_common.rl3
-rw-r--r--lib/unicorn.rb17
-rw-r--r--lib/unicorn/const.rb2
-rw-r--r--lib/unicorn/launcher.rb38
-rw-r--r--lib/unicorn/tee_input.rb55
-rw-r--r--local.mk.sample4
-rw-r--r--test/exec/test_exec.rb2
-rw-r--r--test/rails/app-2.3.5/.gitignore (renamed from test/rails/app-2.3.3.1/.gitignore)0
-rw-r--r--test/rails/app-2.3.5/Rakefile (renamed from test/rails/app-2.3.3.1/Rakefile)0
-rw-r--r--test/rails/app-2.3.5/app/controllers/application_controller.rb (renamed from test/rails/app-2.3.3.1/app/controllers/application_controller.rb)0
-rw-r--r--test/rails/app-2.3.5/app/controllers/foo_controller.rb (renamed from test/rails/app-2.3.3.1/app/controllers/foo_controller.rb)0
-rw-r--r--test/rails/app-2.3.5/app/helpers/application_helper.rb (renamed from test/rails/app-2.3.3.1/app/helpers/application_helper.rb)0
-rw-r--r--test/rails/app-2.3.5/config/boot.rb (renamed from test/rails/app-2.3.3.1/config/boot.rb)0
-rw-r--r--test/rails/app-2.3.5/config/database.yml (renamed from test/rails/app-2.3.3.1/config/database.yml)0
-rw-r--r--test/rails/app-2.3.5/config/environment.rb (renamed from test/rails/app-2.3.3.1/config/environment.rb)0
-rw-r--r--test/rails/app-2.3.5/config/environments/development.rb (renamed from test/rails/app-2.3.3.1/config/environments/development.rb)0
-rw-r--r--test/rails/app-2.3.5/config/environments/production.rb (renamed from test/rails/app-2.3.3.1/config/environments/production.rb)0
-rw-r--r--test/rails/app-2.3.5/config/routes.rb (renamed from test/rails/app-2.3.3.1/config/routes.rb)0
-rw-r--r--test/rails/app-2.3.5/db/.gitignore (renamed from test/rails/app-2.3.3.1/db/.gitignore)0
-rw-r--r--test/rails/app-2.3.5/log/.gitignore (renamed from test/rails/app-2.3.3.1/log/.gitignore)0
-rw-r--r--test/rails/app-2.3.5/public/404.html (renamed from test/rails/app-2.3.3.1/public/404.html)0
-rw-r--r--test/rails/app-2.3.5/public/500.html (renamed from test/rails/app-2.3.3.1/public/500.html)0
-rw-r--r--test/rails/app-2.3.5/public/x.txt (renamed from test/rails/app-2.3.3.1/public/x.txt)0
-rw-r--r--test/unit/test_http_parser.rb39
30 files changed, 174 insertions, 61 deletions
diff --git a/Documentation/unicorn.1.txt b/Documentation/unicorn.1.txt
index 7077690..e05a916 100644
--- a/Documentation/unicorn.1.txt
+++ b/Documentation/unicorn.1.txt
@@ -13,8 +13,8 @@ unicorn [-c CONFIG_FILE] [-E RACK_ENV] [-D] [RACKUP_FILE]
 # DESCRIPTION
 
 A rackup(1)-like command to launch Rack applications using Unicorn.
-It is expected to be started in your application root (APP_ROOT), but
-"Dir.chdir" may also be executed in the CONFIG_FILE or RACKUP_FILE.
+It is expected to be started in your application root (APP_ROOT),
+but the "working_directory" directive may be used in the CONFIG_FILE.
 
 While Unicorn takes a myriad of command-line options for
 compatibility with ruby(1) and rackup(1), it is recommended to stick
@@ -33,10 +33,9 @@ with rackup(1) but strongly discouraged.
 # UNICORN OPTIONS
 -c, \--config-file CONFIG_FILE
 :   Path to the Unicorn-specific config file.  The config file is
-    implemented as a Ruby DSL, so Ruby code may executed (e.g.
-    "Dir.chdir", "Process::UID.change_privilege").  See the RDoc/ri
-    for the *Unicorn::Configurator* class for the full list of
-    directives available from the DSL.
+    implemented as a Ruby DSL, so Ruby code may executed.
+    See the RDoc/ri for the *Unicorn::Configurator* class for the full
+    list of directives available from the DSL.
 
 -D, \--daemonize
 :   Run daemonized in the background.  The process is detached from
diff --git a/Documentation/unicorn_rails.1.txt b/Documentation/unicorn_rails.1.txt
index 5ffb4b4..d2d8190 100644
--- a/Documentation/unicorn_rails.1.txt
+++ b/Documentation/unicorn_rails.1.txt
@@ -14,8 +14,7 @@ unicorn_rails [-c CONFIG_FILE] [-E RAILS_ENV] [-D] [RACKUP_FILE]
 
 A rackup(1)-like command to launch Rails applications using Unicorn.  It
 is expected to be started in your Rails application root (RAILS_ROOT),
-but "Dir.chdir" may also be executed in the CONFIG_FILE or
-optionally, RACKUP_FILE.
+but the "working_directory" directive may be used in the CONFIG_FILE.
 
 The outward interface resembles rackup(1), the internals and default
 middleware loading is designed like the `script/server` command
@@ -29,10 +28,9 @@ as much as possible.
 # UNICORN OPTIONS
 -c, \--config-file CONFIG_FILE
 :   Path to the Unicorn-specific config file.  The config file is
-    implemented as a Ruby DSL, so Ruby code may executed (e.g.
-    "Dir.chdir", "Process::UID.change_privilege").  See the RDoc/ri
-    for the *Unicorn::Configurator* class for the full list of
-    directives available from the DSL.
+    implemented as a Ruby DSL, so Ruby code may executed.
+    See the RDoc/ri for the *Unicorn::Configurator* class for the
+    full list of directives available from the DSL.
 
 -D, \--daemonize
 :   Run daemonized in the background.  The process is detached from
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 4822e1c..605d9e9 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v0.95.2.GIT
+DEF_VER=v0.95.3.GIT
 
 LF='
 '
diff --git a/GNUmakefile b/GNUmakefile
index bd2e0a5..976d728 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -1,21 +1,28 @@
 # use GNU Make to run tests in parallel, and without depending on RubyGems
 all:: test
+
 ruby = ruby
 rake = rake
 ragel = ragel
+
 GIT_URL = git://git.bogomips.org/unicorn.git
 RLFLAGS = -G2
 
+# lower-case vars are deprecated
+RUBY = $(ruby)
+RAKE = $(rake)
+RAGEL = $(ragel)
+
 GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
         @./GIT-VERSION-GEN
 -include GIT-VERSION-FILE
 -include local.mk
-ruby_bin := $(shell which $(ruby))
+ruby_bin := $(shell which $(RUBY))
 ifeq ($(DLEXT),) # "so" for Linux
-  DLEXT := $(shell $(ruby) -rrbconfig -e 'puts Config::CONFIG["DLEXT"]')
+  DLEXT := $(shell $(RUBY) -rrbconfig -e 'puts Config::CONFIG["DLEXT"]')
 endif
 ifeq ($(RUBY_VERSION),)
-  RUBY_VERSION := $(shell $(ruby) -e 'puts RUBY_VERSION')
+  RUBY_VERSION := $(shell $(RUBY) -e 'puts RUBY_VERSION')
 endif
 
 # dunno how to implement this as concisely in Ruby, and hell, I love awk
@@ -45,9 +52,9 @@ inst_deps := $(c_files) $(rb_files) GNUmakefile test/test_helper.rb
 
 ragel: $(ext)/unicorn_http.c
 $(ext)/unicorn_http.c: $(rl_files)
-        cd $(@D) && $(ragel) unicorn_http.rl -C $(RLFLAGS) -o $(@F)
+        cd $(@D) && $(RAGEL) unicorn_http.rl -C $(RLFLAGS) -o $(@F)
 $(ext)/Makefile: $(ext)/extconf.rb $(c_files)
-        cd $(@D) && $(ruby) extconf.rb
+        cd $(@D) && $(RUBY) extconf.rb
 $(ext)/unicorn_http.$(DLEXT): $(ext)/Makefile
         $(MAKE) -C $(@D)
 lib/unicorn_http.$(DLEXT): $(ext)/unicorn_http.$(DLEXT)
@@ -65,11 +72,11 @@ $(test_prefix)/.stamp: $(inst_deps)
 
 # this is only intended to be run within $(test_prefix)
 shebang: $(bins)
-        $(ruby) -i -p -e '$$_.gsub!(%r{^#!.*$$},"#!$(ruby_bin)")' $^
+        $(RUBY) -i -p -e '$$_.gsub!(%r{^#!.*$$},"#!$(ruby_bin)")' $^
 
 t_log := $(T_log) $(T_n_log)
 test: $(T) $(T_n)
-        @cat $(t_log) | $(ruby) test/aggregate.rb
+        @cat $(t_log) | $(RUBY) test/aggregate.rb
         @$(RM) $(t_log)
 
 test-exec: $(wildcard test/exec/test_*.rb)
@@ -87,18 +94,18 @@ else
        # so we use a stamp file to indicate success and
        # have rm fail if the stamp didn't get created
        stamp = $@$(log_suffix).ok
-       quiet_pre = @echo $(ruby) $(arg) $(TEST_OPTS); ! test -f $(stamp) && (
+       quiet_pre = @echo $(RUBY) $(arg) $(TEST_OPTS); ! test -f $(stamp) && (
        quiet_post = && > $(stamp) )2>&1 | tee $(t); \
          rm $(stamp) 2>/dev/null && $(check_test)
 endif
 
 # not all systems have setsid(8), we need it because we spam signals
 # stupidly in some tests...
-rb_setsid := $(ruby) -e 'Process.setsid' -e 'exec *ARGV'
+rb_setsid := $(RUBY) -e 'Process.setsid' -e 'exec *ARGV'
 
 # TRACER='strace -f -o $(t).strace -s 100000'
 run_test = $(quiet_pre) \
-  $(rb_setsid) $(TRACER) $(ruby) -w $(arg) $(TEST_OPTS) $(quiet_post) || \
+  $(rb_setsid) $(TRACER) $(RUBY) -w $(arg) $(TEST_OPTS) $(quiet_post) || \
   (sed "s,^,$(extra): ," >&2 < $(t); exit 1)
 
 %.n: arg = $(subst .n,,$(subst --, -n ,$@))
@@ -121,7 +128,7 @@ install: $(bins) $(ext)/unicorn_http.c
         $(RM) -r .install-tmp
         mkdir .install-tmp
         cp -p bin/* .install-tmp
-        $(ruby) setup.rb all
+        $(RUBY) setup.rb all
         $(RM) $^
         mv .install-tmp/* bin/
         $(RM) -r .install-tmp
@@ -152,8 +159,8 @@ manifest: $(pkg_extra) man
         cmp $@+ $@ || mv $@+ $@
         $(RM) $@+
 
-NEWS: GIT-VERSION-FILE
-        $(rake) -s news_rdoc > $@+
+NEWS: GIT-VERSION-FILE .manifest
+        $(RAKE) -s news_rdoc > $@+
         mv $@+ $@
 
 SINCE = 0.94.0
@@ -175,6 +182,7 @@ atom = <link rel="alternate" title="Atom feed" href="$(1)" \
 # using rdoc 2.4.1+
 doc: .document $(ext)/unicorn_http.c NEWS ChangeLog
         for i in $(man1_bins); do > $$i; done
+        find bin lib -type f -name '*.rbc' -exec rm -f '{}' ';'
         rdoc -Na -t "$(shell sed -ne '1s/^= //p' README)"
         install -m644 COPYING doc/COPYING
         install -m644 $(shell grep '^[A-Z]' .document)  doc/
@@ -183,13 +191,13 @@ doc: .document $(ext)/unicorn_http.c NEWS ChangeLog
         cd doc && for i in $(base_bins); do \
           sed -e '/"documentation">/r man1/'$$i'.1.html' \
                 < $${i}_1.html > tmp && mv tmp $${i}_1.html; done
-        $(ruby) -i -p -e \
+        $(RUBY) -i -p -e \
           '$$_.gsub!("</title>",%q{\&$(call atom,$(cgit_atom))})' \
           doc/ChangeLog.html
-        $(ruby) -i -p -e \
+        $(RUBY) -i -p -e \
           '$$_.gsub!("</title>",%q{\&$(call atom,$(news_atom))})' \
           doc/NEWS.html doc/README.html
-        $(rake) -s news_atom > doc/NEWS.atom.xml
+        $(RAKE) -s news_atom > doc/NEWS.atom.xml
         cd doc && ln README.html tmp && mv tmp index.html
         $(RM) $(man1_bins)
 
@@ -223,10 +231,10 @@ release_changes := release_changes-$(VERSION)
 release-notes: $(release_notes)
 release-changes: $(release_changes)
 $(release_changes):
-        $(rake) -s release_changes > $@+
+        $(RAKE) -s release_changes > $@+
         $(VISUAL) $@+ && test -s $@+ && mv $@+ $@
 $(release_notes):
-        GIT_URL=$(GIT_URL) $(rake) -s release_notes > $@+
+        GIT_URL=$(GIT_URL) $(RAKE) -s release_notes > $@+
         $(VISUAL) $@+ && test -s $@+ && mv $@+ $@
 
 # ensures we're actually on the tagged $(VERSION), only used for release
diff --git a/bin/unicorn b/bin/unicorn
index 325afb3..5af021d 100755
--- a/bin/unicorn
+++ b/bin/unicorn
@@ -1,4 +1,4 @@
-#!/home/ew/bin/ruby
+#!/this/will/be/overwritten/or/wrapped/anyways/do/not/worry/ruby
 # -*- encoding: binary -*-
 require 'unicorn/launcher'
 require 'optparse'
@@ -161,5 +161,5 @@ if $DEBUG
   })
 end
 
-Unicorn::Launcher.daemonize! if daemonize
+Unicorn::Launcher.daemonize!(options) if daemonize
 Unicorn.run(app, options)
diff --git a/bin/unicorn_rails b/bin/unicorn_rails
index e46de70..b1458fc 100755
--- a/bin/unicorn_rails
+++ b/bin/unicorn_rails
@@ -1,4 +1,4 @@
-#!/home/ew/bin/ruby
+#!/this/will/be/overwritten/or/wrapped/anyways/do/not/worry/ruby
 # -*- encoding: binary -*-
 require 'unicorn/launcher'
 require 'optparse'
@@ -202,6 +202,6 @@ end
 
 if daemonize
   options[:pid] = rails_pid
-  Unicorn::Launcher.daemonize!
+  Unicorn::Launcher.daemonize!(options)
 end
 Unicorn.run(app, options)
diff --git a/ext/unicorn_http/unicorn_http_common.rl b/ext/unicorn_http/unicorn_http_common.rl
index 041dfec..6fca604 100644
--- a/ext/unicorn_http/unicorn_http_common.rl
+++ b/ext/unicorn_http/unicorn_http_common.rl
@@ -28,6 +28,7 @@
   scheme = ( "http"i ("s"i)? ) $downcase_char >mark %scheme;
   hostname = (alnum | "-" | "." | "_")+;
   host_with_port = (hostname (":" digit*)?) >mark %host;
+  userinfo = ((unreserved | escape | ";" | ":" | "&" | "=" | "+")+ "@")*;
 
   path = ( pchar+ ( "/" pchar* )* ) ;
   query = ( uchar | reserved )* %query_string ;
@@ -36,7 +37,7 @@
   rel_path = (path? (";" params)? %request_path) ("?" %start_query query)?;
   absolute_path = ( "/"+ rel_path );
   path_uri = absolute_path > mark %request_uri;
-  Absolute_URI = (scheme "://" host_with_port path_uri);
+  Absolute_URI = (scheme "://" userinfo host_with_port path_uri);
 
   Request_URI = ((absolute_path | "*") >mark %request_uri) | Absolute_URI;
   Fragment = ( uchar | reserved )* >mark %fragment;
diff --git a/lib/unicorn.rb b/lib/unicorn.rb
index cf58165..7a1ef34 100644
--- a/lib/unicorn.rb
+++ b/lib/unicorn.rb
@@ -38,7 +38,7 @@ module Unicorn
                                 :before_fork, :after_fork, :before_exec,
                                 :logger, :pid, :app, :preload_app,
                                 :reexec_pid, :orig_app, :init_listeners,
-                                :master_pid, :config)
+                                :master_pid, :config, :ready_pipe)
     include ::Unicorn::SocketHelper
 
     # prevents IO objects in here from being GC-ed
@@ -162,6 +162,7 @@ module Unicorn
     def initialize(app, options = {})
       self.app = app
       self.reexec_pid = 0
+      self.ready_pipe = options.delete(:ready_pipe)
       self.init_listeners = options[:listeners] ? options[:listeners].dup : []
       self.config = Configurator.new(options.merge(:use_defaults => true))
       self.listener_opts = {}
@@ -310,6 +311,9 @@ module Unicorn
                      "(#{tries < 0 ? 'infinite' : tries} tries left)"
         sleep(delay)
         retry
+      rescue => err
+        logger.fatal "error adding listener addr=#{address}"
+        raise err
       end
     end
 
@@ -328,6 +332,11 @@ module Unicorn
       trap(:CHLD) { |sig_nr| awaken_master }
       proc_name 'master'
       logger.info "master process ready" # test_exec.rb relies on this message
+      if ready_pipe
+        ready_pipe.syswrite($$.to_s)
+        ready_pipe.close rescue nil
+        self.ready_pipe = nil
+      end
       begin
         loop do
           reap_all_workers
@@ -532,7 +541,11 @@ module Unicorn
         WORKERS.values.include?(worker_nr) and next
         worker = Worker.new(worker_nr, Unicorn::Util.tmpio)
         before_fork.call(self, worker)
-        WORKERS[fork { worker_loop(worker) }] = worker
+        WORKERS[fork {
+          ready_pipe.close if ready_pipe
+          self.ready_pipe = nil
+          worker_loop(worker)
+        }] = worker
       end
     end
 
diff --git a/lib/unicorn/const.rb b/lib/unicorn/const.rb
index 81f61c8..f70502e 100644
--- a/lib/unicorn/const.rb
+++ b/lib/unicorn/const.rb
@@ -7,7 +7,7 @@ module Unicorn
   # gave about a 3% to 10% performance improvement over using the strings directly.
   # Symbols did not really improve things much compared to constants.
   module Const
-    UNICORN_VERSION="0.95.2"
+    UNICORN_VERSION="0.95.3"
 
     DEFAULT_HOST = "0.0.0.0" # default TCP listen host address
     DEFAULT_PORT = 8080      # default TCP listen port
diff --git a/lib/unicorn/launcher.rb b/lib/unicorn/launcher.rb
index 1229b84..e71f93b 100644
--- a/lib/unicorn/launcher.rb
+++ b/lib/unicorn/launcher.rb
@@ -1,6 +1,6 @@
 # -*- encoding: binary -*-
 
-$stdin.sync = $stdout.sync = $stderr.sync = true
+$stdout.sync = $stderr.sync = true
 $stdin.binmode
 $stdout.binmode
 $stderr.binmode
@@ -19,21 +19,47 @@ class Unicorn::Launcher
   #     the directory it was started in when being re-executed
   #     to pickup code changes if the original deployment directory
   #     is a symlink or otherwise got replaced.
-  def self.daemonize!
+  def self.daemonize!(options = nil)
     $stdin.reopen("/dev/null")
 
     # We only start a new process group if we're not being reexecuted
     # and inheriting file descriptors from our parent
     unless ENV['UNICORN_FD']
-      exit if fork
-      Process.setsid
-      exit if fork
+      if options
+        # grandparent - reads pipe, exits when master is ready
+        #  \_ parent  - exits immediately ASAP
+        #      \_ unicorn master - writes to pipe when ready
 
+        rd, wr = IO.pipe
+        grandparent = $$
+        if fork
+          wr.close # grandparent does not write
+        else
+          rd.close # unicorn master does not read
+          Process.setsid
+          exit if fork # parent dies now
+        end
+
+        if grandparent == $$
+          # this will block until HttpServer#join runs (or it dies)
+          master_pid = (rd.readpartial(16) rescue nil).to_i
+          unless master_pid > 1
+            warn "master failed to start, check stderr log for details"
+            exit!(1)
+          end
+          exit 0
+        else # unicorn master process
+          options[:ready_pipe] = wr
+        end
+      else # backwards compat
+        exit if fork
+        Process.setsid
+        exit if fork
+      end
       # $stderr/$stderr can/will be redirected separately in the Unicorn config
       Unicorn::Configurator::DEFAULTS[:stderr_path] = "/dev/null"
       Unicorn::Configurator::DEFAULTS[:stdout_path] = "/dev/null"
     end
-    $stdin.sync = $stdout.sync = $stderr.sync = true
   end
 
 end
diff --git a/lib/unicorn/tee_input.rb b/lib/unicorn/tee_input.rb
index 0669b48..bb86c40 100644
--- a/lib/unicorn/tee_input.rb
+++ b/lib/unicorn/tee_input.rb
@@ -3,15 +3,20 @@
 module Unicorn
 
   # acts like tee(1) on an input input to provide a input-like stream
-  # while providing rewindable semantics through a File/StringIO
-  # backing store.  On the first pass, the input is only read on demand
-  # so your Rack application can use input notification (upload progress
-  # and like).  This should fully conform to the Rack::InputWrapper
+  # while providing rewindable semantics through a File/StringIO backing
+  # store.  On the first pass, the input is only read on demand so your
+  # Rack application can use input notification (upload progress and
+  # like).  This should fully conform to the Rack::Lint::InputWrapper
   # specification on the public API.  This class is intended to be a
-  # strict interpretation of Rack::InputWrapper functionality and will
-  # not support any deviations from it.
+  # strict interpretation of Rack::Lint::InputWrapper functionality and
+  # will not support any deviations from it.
+  #
+  # When processing uploads, Unicorn exposes a TeeInput object under
+  # "rack.input" of the Rack environment.
   class TeeInput < Struct.new(:socket, :req, :parser, :buf)
 
+    # Initializes a new TeeInput object.  You normally do not have to call
+    # this unless you are writing an HTTP server.
     def initialize(*args)
       super(*args)
       @size = parser.content_length
@@ -24,10 +29,16 @@ module Unicorn
       end
     end
 
-    # returns the size of the input.  This is what the Content-Length
-    # header value should be, and how large our input is expected to be.
-    # For TE:chunked, this requires consuming all of the input stream
-    # before returning since there's no other way
+    # :call-seq:
+    #   ios.size  => Integer
+    #
+    # Returns the size of the input.  For requests with a Content-Length
+    # header value, this will not read data off the socket and just return
+    # the value of the Content-Length header as an Integer.
+    #
+    # For Transfer-Encoding:chunked requests, this requires consuming
+    # all of the input stream before returning since there's no other
+    # way to determine the size of the request body beforehand.
     def size
       @size and return @size
 
@@ -41,8 +52,7 @@ module Unicorn
       @size = @tmp.size
     end
 
-    # call-seq:
-    #   ios = env['rack.input']
+    # :call-seq:
     #   ios.read([length [, buffer ]]) => string, buffer, or nil
     #
     # Reads at most length bytes from the I/O stream, or to the end of
@@ -82,7 +92,15 @@ module Unicorn
       end
     end
 
-    # takes zero arguments for strict Rack::Lint compatibility, unlike IO#gets
+    # :call-seq:
+    #   ios.gets   => string or nil
+    #
+    # Reads the next ``line'' from the I/O stream; lines are separated
+    # by the global record separator ($/, typically "\n"). A global
+    # record separator of nil reads the entire unread contents of ios.
+    # Returns nil if called at the end of file.
+    # This takes zero arguments for strict Rack::Lint compatibility,
+    # unlike IO#gets.
     def gets
       socket or return @tmp.gets
       nil == $/ and return read
@@ -109,6 +127,11 @@ module Unicorn
       line
     end
 
+    # :call-seq:
+    #   ios.each { |line| block }  => ios
+    #
+    # Executes the block for every ``line'' in *ios*, where lines are
+    # separated by the global record separator ($/, typically "\n").
     def each(&block)
       while line = gets
         yield line
@@ -117,6 +140,12 @@ module Unicorn
       self # Rack does not specify what the return value is here
     end
 
+    # :call-seq:
+    #   ios.rewind    => 0
+    #
+    # Positions the *ios* pointer to the beginning of input, returns
+    # the offset (zero) of the +ios+ pointer.  Subsequent reads will
+    # start from the beginning of the previously-buffered input.
     def rewind
       @tmp.rewind # Rack does not specify what the return value is here
     end
diff --git a/local.mk.sample b/local.mk.sample
index 2b331fc..5019576 100644
--- a/local.mk.sample
+++ b/local.mk.sample
@@ -11,12 +11,12 @@ gems := rack-1.1.0
 # fork+exec heavy with Ruby.
 prefix = $(HOME)
 ifeq ($(r19),)
-  ruby := $(prefix)/bin/ruby
+  RUBY := $(prefix)/bin/ruby
   gem_paths := $(addprefix $(prefix)/lib/ruby/gems/1.8/gems/,$(gems))
 else
   prefix := $(prefix)/ruby-1.9
   export PATH := $(prefix)/bin:$(PATH)
-  ruby := $(prefix)/bin/ruby --disable-gems
+  RUBY := $(prefix)/bin/ruby --disable-gems
   gem_paths := $(addprefix $(prefix)/lib/ruby/gems/1.9.1/gems/,$(gems))
 endif
 
diff --git a/test/exec/test_exec.rb b/test/exec/test_exec.rb
index fc0719b..24ba856 100644
--- a/test/exec/test_exec.rb
+++ b/test/exec/test_exec.rb
@@ -805,7 +805,7 @@ EOF
       exec($unicorn_bin, "-D", "-l#{@addr}:#{@port}", "-c#{ucfg.path}")
     end
     pid, status = Process.waitpid2(pid)
-    assert status.success?, "original process exited successfully"
+    assert ! status.success?, "original process exited successfully"
     sleep 1 # can't waitpid on a daemonized process :<
     assert err.stat.size > 0
   end
diff --git a/test/rails/app-2.3.3.1/.gitignore b/test/rails/app-2.3.5/.gitignore
index f451f91..f451f91 100644
--- a/test/rails/app-2.3.3.1/.gitignore
+++ b/test/rails/app-2.3.5/.gitignore
diff --git a/test/rails/app-2.3.3.1/Rakefile b/test/rails/app-2.3.5/Rakefile
index fbebfca..fbebfca 100644
--- a/test/rails/app-2.3.3.1/Rakefile
+++ b/test/rails/app-2.3.5/Rakefile
diff --git a/test/rails/app-2.3.3.1/app/controllers/application_controller.rb b/test/rails/app-2.3.5/app/controllers/application_controller.rb
index 07c333e..07c333e 100644
--- a/test/rails/app-2.3.3.1/app/controllers/application_controller.rb
+++ b/test/rails/app-2.3.5/app/controllers/application_controller.rb
diff --git a/test/rails/app-2.3.3.1/app/controllers/foo_controller.rb b/test/rails/app-2.3.5/app/controllers/foo_controller.rb
index 54ca1ed..54ca1ed 100644
--- a/test/rails/app-2.3.3.1/app/controllers/foo_controller.rb
+++ b/test/rails/app-2.3.5/app/controllers/foo_controller.rb
diff --git a/test/rails/app-2.3.3.1/app/helpers/application_helper.rb b/test/rails/app-2.3.5/app/helpers/application_helper.rb
index d9889b3..d9889b3 100644
--- a/test/rails/app-2.3.3.1/app/helpers/application_helper.rb
+++ b/test/rails/app-2.3.5/app/helpers/application_helper.rb
diff --git a/test/rails/app-2.3.3.1/config/boot.rb b/test/rails/app-2.3.5/config/boot.rb
index b6c80d5..b6c80d5 100644
--- a/test/rails/app-2.3.3.1/config/boot.rb
+++ b/test/rails/app-2.3.5/config/boot.rb
diff --git a/test/rails/app-2.3.3.1/config/database.yml b/test/rails/app-2.3.5/config/database.yml
index 9f77843..9f77843 100644
--- a/test/rails/app-2.3.3.1/config/database.yml
+++ b/test/rails/app-2.3.5/config/database.yml
diff --git a/test/rails/app-2.3.3.1/config/environment.rb b/test/rails/app-2.3.5/config/environment.rb
index 6eb092c..6eb092c 100644
--- a/test/rails/app-2.3.3.1/config/environment.rb
+++ b/test/rails/app-2.3.5/config/environment.rb
diff --git a/test/rails/app-2.3.3.1/config/environments/development.rb b/test/rails/app-2.3.5/config/environments/development.rb
index 3d381d2..3d381d2 100644
--- a/test/rails/app-2.3.3.1/config/environments/development.rb
+++ b/test/rails/app-2.3.5/config/environments/development.rb
diff --git a/test/rails/app-2.3.3.1/config/environments/production.rb b/test/rails/app-2.3.5/config/environments/production.rb
index 08710a4..08710a4 100644
--- a/test/rails/app-2.3.3.1/config/environments/production.rb
+++ b/test/rails/app-2.3.5/config/environments/production.rb
diff --git a/test/rails/app-2.3.3.1/config/routes.rb b/test/rails/app-2.3.5/config/routes.rb
index ac7877c..ac7877c 100644
--- a/test/rails/app-2.3.3.1/config/routes.rb
+++ b/test/rails/app-2.3.5/config/routes.rb
diff --git a/test/rails/app-2.3.3.1/db/.gitignore b/test/rails/app-2.3.5/db/.gitignore
index e69de29..e69de29 100644
--- a/test/rails/app-2.3.3.1/db/.gitignore
+++ b/test/rails/app-2.3.5/db/.gitignore
diff --git a/test/rails/app-2.3.3.1/log/.gitignore b/test/rails/app-2.3.5/log/.gitignore
index 397b4a7..397b4a7 100644
--- a/test/rails/app-2.3.3.1/log/.gitignore
+++ b/test/rails/app-2.3.5/log/.gitignore
diff --git a/test/rails/app-2.3.3.1/public/404.html b/test/rails/app-2.3.5/public/404.html
index 44d986c..44d986c 100644
--- a/test/rails/app-2.3.3.1/public/404.html
+++ b/test/rails/app-2.3.5/public/404.html
diff --git a/test/rails/app-2.3.3.1/public/500.html b/test/rails/app-2.3.5/public/500.html
index e534a49..e534a49 100644
--- a/test/rails/app-2.3.3.1/public/500.html
+++ b/test/rails/app-2.3.5/public/500.html
diff --git a/test/rails/app-2.3.3.1/public/x.txt b/test/rails/app-2.3.5/public/x.txt
index e427984..e427984 100644
--- a/test/rails/app-2.3.3.1/public/x.txt
+++ b/test/rails/app-2.3.5/public/x.txt
diff --git a/test/unit/test_http_parser.rb b/test/unit/test_http_parser.rb
index 1b3faaf..0443b46 100644
--- a/test/unit/test_http_parser.rb
+++ b/test/unit/test_http_parser.rb
@@ -298,6 +298,45 @@ class HttpParserTest < Test::Unit::TestCase
     assert ! parser.keepalive?
   end
 
+  # some dumb clients add users because they're stupid
+  def test_absolute_uri_w_user
+    parser = HttpParser.new
+    req = {}
+    http = "GET http://user%20space@example.com/foo?q=bar HTTP/1.0\r\n\r\n"
+    assert_equal req, parser.headers(req, http)
+    assert_equal 'http', req['rack.url_scheme']
+    assert_equal '/foo?q=bar', req['REQUEST_URI']
+    assert_equal '/foo', req['REQUEST_PATH']
+    assert_equal 'q=bar', req['QUERY_STRING']
+
+    assert_equal 'example.com', req['HTTP_HOST']
+    assert_equal 'example.com', req['SERVER_NAME']
+    assert_equal '80', req['SERVER_PORT']
+    assert_equal "", http
+    assert ! parser.keepalive?
+  end
+
+  # since Mongrel supported anything URI.parse supported, we're stuck
+  # supporting everything URI.parse supports
+  def test_absolute_uri_uri_parse
+    "#{URI::REGEXP::PATTERN::UNRESERVED};:&=+$,".split(//).each do |char|
+      parser = HttpParser.new
+      req = {}
+      http = "GET http://#{char}@example.com/ HTTP/1.0\r\n\r\n"
+      assert_equal req, parser.headers(req, http)
+      assert_equal 'http', req['rack.url_scheme']
+      assert_equal '/', req['REQUEST_URI']
+      assert_equal '/', req['REQUEST_PATH']
+      assert_equal '', req['QUERY_STRING']
+
+      assert_equal 'example.com', req['HTTP_HOST']
+      assert_equal 'example.com', req['SERVER_NAME']
+      assert_equal '80', req['SERVER_PORT']
+      assert_equal "", http
+      assert ! parser.keepalive?
+    end
+  end
+
   def test_absolute_uri
     parser = HttpParser.new
     req = {}